2019-12-09 03:40:48 +01:00
|
|
|
# TODO(tazjin): avoid {} by only calling functions *after* checking what they are
|
|
|
|
|
|
|
|
args: initPath:
|
2019-11-15 15:52:23 +01:00
|
|
|
|
|
|
|
let
|
|
|
|
inherit (builtins)
|
|
|
|
attrNames
|
|
|
|
filter
|
|
|
|
head
|
|
|
|
isString
|
2019-11-25 16:32:02 +01:00
|
|
|
length
|
2019-11-15 15:52:23 +01:00
|
|
|
listToAttrs
|
|
|
|
map
|
|
|
|
match
|
|
|
|
readDir
|
2019-11-25 16:32:02 +01:00
|
|
|
split
|
|
|
|
tail
|
2019-11-15 15:52:23 +01:00
|
|
|
toString;
|
|
|
|
|
2019-11-25 16:10:31 +01:00
|
|
|
attrsToList = attrs: map (name: {
|
|
|
|
inherit name;
|
|
|
|
value = attrs."${name}";
|
|
|
|
}) (attrNames attrs);
|
2019-11-15 15:52:23 +01:00
|
|
|
|
|
|
|
isFile = s: s == "regular";
|
|
|
|
isDir = s: s == "directory";
|
|
|
|
|
2019-12-09 03:19:44 +01:00
|
|
|
joinPath = p: f: p + ("/" + f);
|
2019-11-15 15:52:23 +01:00
|
|
|
|
|
|
|
isNixFile = file:
|
|
|
|
let res = match "(.*)\.nix" file;
|
|
|
|
in if res == null then null else head res;
|
|
|
|
|
|
|
|
filterNixFiles = dir:
|
2019-12-02 16:05:54 +01:00
|
|
|
let files = filter (e: isFile e.value && e.name != "default.nix") dir;
|
2019-11-15 15:52:23 +01:00
|
|
|
nixFiles = map (f: {
|
|
|
|
# Name and value are intentionally flipped to get the
|
|
|
|
# correct attribute set structure back out
|
|
|
|
name = isNixFile f.name;
|
|
|
|
value = f.name; # i.e. the path
|
|
|
|
}) files;
|
|
|
|
in filter (f: isString f.name) nixFiles;
|
|
|
|
|
2019-11-25 16:32:02 +01:00
|
|
|
# Some packages require that their position in the tree is passed in
|
|
|
|
# as an argument. To do this the root directory (i.e. $PWD during
|
|
|
|
# imports) is chopped off the front of the path components in
|
|
|
|
# imports.
|
|
|
|
pathParts = p: tail (filter isString (split "/" (toString p)));
|
|
|
|
initLen = length (pathParts ./.);
|
|
|
|
drop = n: l:
|
|
|
|
if n == 0
|
|
|
|
then l
|
|
|
|
else if l == []
|
|
|
|
then []
|
|
|
|
else drop (n - 1) (tail l);
|
|
|
|
|
|
|
|
argsWithPath = args: parts: args // {
|
|
|
|
locatedAt = drop initLen parts;
|
|
|
|
};
|
|
|
|
|
2019-11-15 15:52:23 +01:00
|
|
|
traverse = path: dir:
|
|
|
|
let nixFiles = filterNixFiles dir;
|
|
|
|
imported = map (f: {
|
|
|
|
inherit (f) name;
|
2019-12-09 13:22:33 +01:00
|
|
|
value = import (joinPath path f.value) (argsWithPath args (pathParts path));
|
2019-11-15 15:52:23 +01:00
|
|
|
}) nixFiles;
|
|
|
|
dirs = map (d: {
|
|
|
|
inherit (d) name;
|
|
|
|
value = readTree (joinPath path d.name);
|
|
|
|
}) (filter (e: isDir e.value) dir);
|
|
|
|
in listToAttrs (imported ++ dirs);
|
|
|
|
|
|
|
|
importOr = path: dir: f:
|
2019-12-09 04:16:02 +01:00
|
|
|
let
|
|
|
|
allContents = f path (attrsToList dir);
|
|
|
|
dirOnlyContents = f path (filter (f: f.value == "directory") (attrsToList dir));
|
2019-12-02 16:05:54 +01:00
|
|
|
in if dir ? "default.nix"
|
2019-12-09 20:51:15 +01:00
|
|
|
then import path (argsWithPath args (pathParts path))
|
|
|
|
// { __treeChildren = true; } # used downstream for traversals
|
|
|
|
// dirOnlyContents
|
2019-12-09 04:16:02 +01:00
|
|
|
else allContents;
|
2019-11-15 15:52:23 +01:00
|
|
|
|
|
|
|
readTree = path: importOr path (readDir path) traverse;
|
2019-11-25 16:32:02 +01:00
|
|
|
in readTree initPath
|