about summary refs log tree commit diff
path: root/nix/readTree/default.nix
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@google.com>2019-12-21T05·42+0000
committerVincent Ambo <tazjin@google.com>2019-12-21T05·42+0000
commit4a9c6ab6a22432a8df3ad0611dd4821e005dc0a7 (patch)
tree7b07ccce519172ba316f3ae1107017a15d22357e /nix/readTree/default.nix
parentcbc3409ce099e42e59b031bfe9bd43953206cb4c (diff)
refactor(nix/readTree): Move readTree to its own subfolder r/279
Diffstat (limited to 'nix/readTree/default.nix')
-rw-r--r--nix/readTree/default.nix63
1 files changed, 63 insertions, 0 deletions
diff --git a/nix/readTree/default.nix b/nix/readTree/default.nix
new file mode 100644
index 000000000000..c48928ee19e4
--- /dev/null
+++ b/nix/readTree/default.nix
@@ -0,0 +1,63 @@
+{ ... }:
+
+args: initPath:
+
+let
+  inherit (builtins)
+    attrNames
+    baseNameOf
+    filter
+    hasAttr
+    head
+    length
+    listToAttrs
+    map
+    match
+    isAttrs
+    readDir;
+
+  argsWithPath = parts: args // {
+    locatedAt = parts;
+  };
+
+  # The marker is added to every set that was imported directly by
+  # readTree.
+  importWithMark = path: parts:
+    let imported = import path (argsWithPath parts);
+    in if (isAttrs imported)
+      then imported // { __readTree = true; }
+      else imported;
+
+  nixFileName = file:
+    let res = match "(.*)\.nix" file;
+    in if res == null then null else head res;
+
+  readTree = path: parts:
+    let
+      dir = readDir path;
+      self = importWithMark path parts;
+      joinChild = c: path + ("/" + c);
+
+      # Import subdirectories of the current one, unless the special
+      # `.skip-subtree` file exists which makes readTree ignore the
+      # children.
+      #
+      # This file can optionally contain information on why the tree
+      # should be ignored, but its content is not inspected by
+      # readTree
+      filterDir = f: dir."${f}" == "directory";
+      children = if hasAttr ".skip-subtree" dir then [] else map (c: {
+        name = c;
+        value = readTree (joinChild c) (parts ++ [ c ]);
+      }) (filter filterDir (attrNames dir));
+
+      # Import Nix files
+      nixFiles = filter (f: f != null) (map nixFileName (attrNames dir));
+      nixChildren = map (c: let p = joinChild (c + ".nix"); in {
+        name = c;
+        value = importWithMark p (parts ++ [ c ]);
+      }) nixFiles;
+    in if dir ? "default.nix"
+      then (if isAttrs self then self // (listToAttrs children) else self)
+      else listToAttrs (nixChildren ++ children);
+in readTree initPath [ (baseNameOf initPath) ]