about summary refs log tree commit diff
path: root/read-tree.nix
diff options
context:
space:
mode:
Diffstat (limited to 'read-tree.nix')
-rw-r--r--read-tree.nix65
1 files changed, 65 insertions, 0 deletions
diff --git a/read-tree.nix b/read-tree.nix
new file mode 100644
index 000000000000..d883d12c8171
--- /dev/null
+++ b/read-tree.nix
@@ -0,0 +1,65 @@
+path: { pkgs, ... } @ args:
+
+let
+  inherit (builtins)
+    attrNames
+    attrValues
+    filter
+    head
+    isString
+    listToAttrs
+    map
+    match
+    readDir
+    tail
+    toPath
+    toString;
+
+  zipAttrs = names: values:
+    if (names == []) || (values == [])
+    then []
+    else [{
+      name = head names;
+      value = head values;
+    }] ++ zipAttrs (tail names) (tail values);
+
+  attrsToList = attrs: zipAttrs (attrNames attrs) (attrValues attrs);
+
+  isFile = s: s == "regular";
+  isDir = s: s == "directory";
+
+  joinPath = p: f: toPath ((toString p) + "/" + f);
+
+  isNixFile = file:
+    let res = match "(.*)\.nix" file;
+    in if res == null then null else head res;
+
+  filterNixFiles = dir:
+    let files = filter (e: isFile e.value) dir;
+        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;
+
+  traverse = path: dir:
+    let nixFiles = filterNixFiles dir;
+        imported = map (f: {
+          inherit (f) name;
+          value = import (joinPath path f.value) args;
+        }) 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:
+    if dir ? "default.nix"
+      then import path args
+      else f path (attrsToList dir);
+
+  readTree = path: importOr path (readDir path) traverse;
+in readTree path