Skip to content

Commit

Permalink
Merge pull request #244358 from tweag/lib.path.parts
Browse files Browse the repository at this point in the history
`lib.path.splitRoot`: init
  • Loading branch information
roberth authored Jul 27, 2023
2 parents 6fbe34c + d7bf0d7 commit 399ac29
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
49 changes: 49 additions & 0 deletions lib/path/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,57 @@ in /* No rec! Add dependencies on this file at the top. */ {
second argument: "${toString path2}" with root "${toString path2Deconstructed.root}"'';
joinRelPath components;

/*
Split the filesystem root from a [path](https://nixos.org/manual/nix/stable/language/values.html#type-path).
The result is an attribute set with these attributes:
- `root`: The filesystem root of the path, meaning that this directory has no parent directory.
- `subpath`: The [normalised subpath string](#function-library-lib.path.subpath.normalise) that when [appended](#function-library-lib.path.append) to `root` returns the original path.
Laws:
- [Appending](#function-library-lib.path.append) the `root` and `subpath` gives the original path:
p ==
append
(splitRoot p).root
(splitRoot p).subpath
- Trying to get the parent directory of `root` using [`readDir`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-readDir) returns `root` itself:
dirOf (splitRoot p).root == (splitRoot p).root
Type:
splitRoot :: Path -> { root :: Path, subpath :: String }
Example:
splitRoot /foo/bar
=> { root = /.; subpath = "./foo/bar"; }
splitRoot /.
=> { root = /.; subpath = "./."; }
# Nix neutralises `..` path components for all path values automatically
splitRoot /foo/../bar
=> { root = /.; subpath = "./bar"; }
splitRoot "/foo/bar"
=> <error>
*/
splitRoot = path:
assert assertMsg
(isPath path)
"lib.path.splitRoot: Argument is of type ${typeOf path}, but a path was expected";
let
deconstructed = deconstructPath path;
in {
root = deconstructed.root;
subpath = joinRelPath deconstructed.components;
};

/* Whether a value is a valid subpath string.
A subpath string points to a specific file or directory within an absolute base directory.
It is a stricter form of a relative path that excludes `..` components, since those could escape the base directory.
- The value is a string
- The string is not empty
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 removePrefix append subpath;
inherit (lib.path) hasPrefix removePrefix append splitRoot subpath;

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

testSplitRootExample1 = {
expr = splitRoot /foo/bar;
expected = { root = /.; subpath = "./foo/bar"; };
};
testSplitRootExample2 = {
expr = splitRoot /.;
expected = { root = /.; subpath = "./."; };
};
testSplitRootExample3 = {
expr = splitRoot /foo/../bar;
expected = { root = /.; subpath = "./bar"; };
};
testSplitRootExample4 = {
expr = (builtins.tryEval (splitRoot "/foo/bar")).success;
expected = false;
};

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

0 comments on commit 399ac29

Please sign in to comment.