Skip to content

Commit

Permalink
Merge pull request #238013 from tweag/lib.path.removePrefix
Browse files Browse the repository at this point in the history
`lib.path.removePrefix`: init
  • Loading branch information
roberth authored Jul 19, 2023
2 parents c7d007c + 6626d8c commit 814f067
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 1 deletion.
53 changes: 53 additions & 0 deletions lib/path/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ let
concatMap
foldl'
take
drop
;

inherit (lib.strings)
Expand Down Expand Up @@ -217,6 +218,58 @@ in /* No rec! Add dependencies on this file at the top. */ {
second argument: "${toString path2}" with root "${toString path2Deconstructed.root}"'';
take (length path1Deconstructed.components) path2Deconstructed.components == path1Deconstructed.components;

/*
Remove the first path as a component-wise prefix from the second path.
The result is a normalised subpath string, see `lib.path.subpath.normalise`.
Laws:
- Inverts `append` for normalised subpaths:
removePrefix p (append p s) == subpath.normalise s
Type:
removePrefix :: Path -> Path -> String
Example:
removePrefix /foo /foo/bar/baz
=> "./bar/baz"
removePrefix /foo /foo
=> "./."
removePrefix /foo/bar /foo
=> <error>
removePrefix /. /foo
=> "./foo"
*/
removePrefix =
path1:
assert assertMsg
(isPath path1)
"lib.path.removePrefix: First argument is of type ${typeOf path1}, but a path was expected.";
let
path1Deconstructed = deconstructPath path1;
path1Length = length path1Deconstructed.components;
in
path2:
assert assertMsg
(isPath path2)
"lib.path.removePrefix: Second argument is of type ${typeOf path2}, but a path was expected.";
let
path2Deconstructed = deconstructPath path2;
success = take path1Length path2Deconstructed.components == path1Deconstructed.components;
components =
if success then
drop path1Length path2Deconstructed.components
else
throw ''
lib.path.removePrefix: The first path argument "${toString path1}" is not a component-wise prefix of the second path argument "${toString path2}".'';
in
assert assertMsg
(path1Deconstructed.root == path2Deconstructed.root) ''
lib.path.removePrefix: Filesystem roots must be the same for both paths, but paths with different roots were given:
first argument: "${toString path1}" with root "${toString path1Deconstructed.root}"
second argument: "${toString path2}" with root "${toString path2Deconstructed.root}"'';
joinRelPath components;

/* Whether a value is a valid subpath string.
Expand Down
19 changes: 18 additions & 1 deletion lib/path/tests/unit.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{ libpath }:
let
lib = import libpath;
inherit (lib.path) hasPrefix append subpath;
inherit (lib.path) hasPrefix removePrefix append subpath;

cases = lib.runTests {
# Test examples from the lib.path.append documentation
Expand Down Expand Up @@ -57,6 +57,23 @@ let
expected = true;
};

testRemovePrefixExample1 = {
expr = removePrefix /foo /foo/bar/baz;
expected = "./bar/baz";
};
testRemovePrefixExample2 = {
expr = removePrefix /foo /foo;
expected = "./.";
};
testRemovePrefixExample3 = {
expr = (builtins.tryEval (removePrefix /foo/bar /foo)).success;
expected = false;
};
testRemovePrefixExample4 = {
expr = removePrefix /. /foo;
expected = "./foo";
};

# Test examples from the lib.path.subpath.isValid documentation
testSubpathIsValidExample1 = {
expr = subpath.isValid null;
Expand Down

0 comments on commit 814f067

Please sign in to comment.