lib.path.removePrefix: init

This commit is contained in:
Silvan Mosberger 2023-06-16 00:19:33 +02:00
parent 7a49b67eb2
commit 6626d8cc4d
2 changed files with 71 additions and 1 deletions

View File

@ -20,6 +20,7 @@ let
concatMap concatMap
foldl' foldl'
take take
drop
; ;
inherit (lib.strings) inherit (lib.strings)
@ -217,6 +218,58 @@ in /* No rec! Add dependencies on this file at the top. */ {
second argument: "${toString path2}" with root "${toString path2Deconstructed.root}"''; second argument: "${toString path2}" with root "${toString path2Deconstructed.root}"'';
take (length path1Deconstructed.components) path2Deconstructed.components == path1Deconstructed.components; 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. /* Whether a value is a valid subpath string.

View File

@ -3,7 +3,7 @@
{ libpath }: { libpath }:
let let
lib = import libpath; lib = import libpath;
inherit (lib.path) hasPrefix append subpath; inherit (lib.path) hasPrefix removePrefix append subpath;
cases = lib.runTests { cases = lib.runTests {
# Test examples from the lib.path.append documentation # Test examples from the lib.path.append documentation
@ -57,6 +57,23 @@ let
expected = true; 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 # Test examples from the lib.path.subpath.isValid documentation
testSubpathIsValidExample1 = { testSubpathIsValidExample1 = {
expr = subpath.isValid null; expr = subpath.isValid null;