Unverified Commit 8fa16970 authored by Robert Hensing's avatar Robert Hensing Committed by GitHub
Browse files

Merge pull request #242695 from tweag/lib.path.subpath.components

`lib.path.subpath.components`: init
parents 35184dd3 407db583
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -187,6 +187,27 @@ Decision: All functions remove trailing slashes in their results.

</details>

### Prefer returning subpaths over components
[subpath-preference]: #prefer-returning-subpaths-over-components

Observing: Functions could return subpaths or lists of path component strings.

Considering: Subpaths are used as inputs for some functions. Using them for outputs, too, makes the library more consistent and composable.

Decision: Subpaths should be preferred over list of path component strings.

<details>
<summary>Arguments</summary>

- (+) It is consistent with functions accepting subpaths, making the library more composable
- (-) It is less efficient when the components are needed, because after creating the normalised subpath string, it will have to be parsed into components again
  - (+) If necessary, we can still make it faster by adding builtins to Nix
  - (+) Alternatively if necessary, versions of these functions that return components could later still be introduced.
- (+) It makes the path library simpler because there's only two types (paths and subpaths). Only `lib.path.subpath.components` can be used to get a list of components.
  And once we have a list of component strings, `lib.lists` and `lib.strings` can be used to operate on them.
  For completeness, `lib.path.subpath.join` allows converting the list of components back to a subpath.
</details>

## Other implementations and references

- [Rust](https://doc.rust-lang.org/std/path/struct.Path.html)
+31 −0
Original line number Diff line number Diff line
@@ -438,6 +438,37 @@ in /* No rec! Add dependencies on this file at the top. */ {
              ${subpathInvalidReason path}''
      ) 0 subpaths;

  /*
  Split [a subpath](#function-library-lib.path.subpath.isValid) into its path component strings.
  Throw an error if the subpath isn't valid.
  Note that the returned path components are also valid subpath strings, though they are intentionally not [normalised](#function-library-lib.path.subpath.normalise).

  Laws:

  - Splitting a subpath into components and [joining](#function-library-lib.path.subpath.join) the components gives the same subpath but [normalised](#function-library-lib.path.subpath.normalise):

        subpath.join (subpath.components s) == subpath.normalise s

  Type:
    subpath.components :: String -> [ String ]

  Example:
    subpath.components "."
    => [ ]

    subpath.components "./foo//bar/./baz/"
    => [ "foo" "bar" "baz" ]

    subpath.components "/foo"
    => <error>
  */
  subpath.components =
    subpath:
    assert assertMsg (isValid subpath) ''
      lib.path.subpath.components: Argument is not a valid subpath string:
          ${subpathInvalidReason subpath}'';
    splitRelPath subpath;

  /* Normalise a subpath. Throw an error if the subpath isn't valid, see
  `lib.path.subpath.isValid`

+13 −0
Original line number Diff line number Diff line
@@ -238,6 +238,19 @@ let
      expr = (builtins.tryEval (subpath.normalise "..")).success;
      expected = false;
    };

    testSubpathComponentsExample1 = {
      expr = subpath.components ".";
      expected = [ ];
    };
    testSubpathComponentsExample2 = {
      expr = subpath.components "./foo//bar/./baz/";
      expected = [ "foo" "bar" "baz" ];
    };
    testSubpathComponentsExample3 = {
      expr = (builtins.tryEval (subpath.components "/foo")).success;
      expected = false;
    };
  };
in
  if cases == [] then "Unit tests successful"