Skip to content

Commit

Permalink
Merge pull request #242695 from tweag/lib.path.subpath.components
Browse files Browse the repository at this point in the history
`lib.path.subpath.components`: init
  • Loading branch information
roberth authored Aug 4, 2023
2 parents 35184dd + 407db58 commit 8fa1697
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
21 changes: 21 additions & 0 deletions lib/path/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
31 changes: 31 additions & 0 deletions lib/path/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
13 changes: 13 additions & 0 deletions lib/path/tests/unit.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 8fa1697

Please sign in to comment.