nix-files/modules/lib/path.nix

58 lines
1.9 KiB
Nix
Raw Permalink Normal View History

{ lib, ... }:
2023-01-04 00:59:52 +00:00
let path = rec {
2023-01-04 00:59:52 +00:00
# split the string path into a list of string components.
# root directory "/" becomes the empty list [].
# implicitly performs normalization so that:
# split "a//b/" => ["a" "b"]
# split "/a/b" => ["a" "b"]
split = str: builtins.filter (seg: seg != "") (lib.splitString "/" str);
2023-07-03 05:28:53 +00:00
2023-01-04 00:59:52 +00:00
# given an array of components, returns the equivalent string path
join = comps: "/" + (builtins.concatStringsSep "/" comps);
2023-07-03 05:28:53 +00:00
2023-01-04 00:59:52 +00:00
# given an a sequence of string paths, concatenates them into one long string path
concat = paths: path.join (builtins.concatLists (builtins.map path.split paths));
2023-07-03 05:28:53 +00:00
2023-01-04 00:59:52 +00:00
# normalize the given path
2023-07-03 05:28:53 +00:00
# canonical form is an *absolute* path;
# always starting with '/', never trailing with '/' unless it's the empty (root) path
2023-01-04 00:59:52 +00:00
norm = str: path.join (path.split str);
2023-07-03 05:28:53 +00:00
2023-01-04 00:59:52 +00:00
# return the parent directory. doesn't care about leading/trailing slashes.
# the parent of "/" is "/".
parent = str: path.norm (builtins.dirOf (path.norm str));
hasParent = str: (path.parent str) != (path.norm str);
# return the last path component; error on the empty path
leaf = str: lib.last (split str);
2023-07-03 05:28:53 +00:00
# return the path from `from` to `to`, but keeping absolute form
# e.g. `pathFrom "/home/colin" "/home/colin/foo/bar"` -> "/foo/bar"
2023-01-04 00:59:52 +00:00
from = start: end: let
s = path.norm start;
e = path.norm end;
in (
2023-07-03 05:28:53 +00:00
assert isChild start end;
"/" + lib.removePrefix s e
2023-01-04 00:59:52 +00:00
);
2023-06-28 03:57:57 +00:00
isChild = parent: child:
lib.any
(p: p == norm parent)
(walk "/" child)
;
2023-07-03 05:28:53 +00:00
# yield every node between start and end, including each of the endpoints
# e.g. walk "/foo" "/foo/bar/baz" => [ "/foo" "/foo/bar" "/foo/bar/baz" ]
# XXX: assumes input paths are normalized
walk = start: end: if start == end then
[ start ]
else
assert end != "/"; # else there's no path from `start` to `end`!
(walk start (parent end)) ++ [ end ]
;
2023-01-04 00:59:52 +00:00
};
in path