summaryrefslogtreecommitdiff
path: root/lib/path
diff options
context:
space:
mode:
authorRobert Hensing <roberth@users.noreply.github.com>2023-07-19 17:28:05 +0200
committerGitHub <noreply@github.com>2023-07-19 17:28:05 +0200
commit814f067760d029f532f990974a6df240d4320105 (patch)
tree7a2e2329be756f263a0d207b71287fd4d2fffe7f /lib/path
parentMerge pull request #244351 from emilylange/grafana-agent (diff)
parentlib.path.removePrefix: init (diff)
downloadnixpkgs-814f067760d029f532f990974a6df240d4320105.tar.gz
Merge pull request #238013 from tweag/lib.path.removePrefix
`lib.path.removePrefix`: init
Diffstat (limited to 'lib/path')
-rw-r--r--lib/path/default.nix53
-rw-r--r--lib/path/tests/unit.nix19
2 files changed, 71 insertions, 1 deletions
diff --git a/lib/path/default.nix b/lib/path/default.nix
index 936e9b030253..3a871bc05283 100644
--- a/lib/path/default.nix
+++ b/lib/path/default.nix
@@ -20,6 +20,7 @@ let
concatMap
foldl'
take
+ drop
;
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}"'';
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.
diff --git a/lib/path/tests/unit.nix b/lib/path/tests/unit.nix
index 9c5b752cf64a..3e4b216f099f 100644
--- a/lib/path/tests/unit.nix
+++ b/lib/path/tests/unit.nix
@@ -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
@@ -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;