about summary refs log tree commit diff
path: root/nix
diff options
context:
space:
mode:
authorsterni <sternenseemann@systemli.org>2021-09-15T11·22+0200
committersterni <sternenseemann@systemli.org>2021-09-15T22·37+0000
commitd7f60bcb043925670c02a8ccf9067e97d647bc87 (patch)
tree927382756adc56ef8c8b63558603234cf23ab204 /nix
parentd904724adf6650747d79b80426432f59620ec175 (diff)
feat(nix/readTree): record list of children added by readTree r/2869
This change adds a new attribute to readTree nodes, `__readTreeChildren`
which is a list of attribute names added to this node by readTree.

This is then used by `gather` for `ci.targets` to avoid evaluating
attributes unnecessarily. Especially since Nix is not as lazy as we'd
like when determining types (i. e. child ? __readTree needs to force
`child` even when it's not an attribute set), evaluating attributes
unnecessarily is sometimes problematic.

Change-Id: I0a98691d41f987e23ee7e9ba21fbe465da5fe402
Diffstat (limited to 'nix')
-rw-r--r--nix/readTree/default.nix51
1 files changed, 33 insertions, 18 deletions
diff --git a/nix/readTree/default.nix b/nix/readTree/default.nix
index 5443d2edf539..68988424fb8c 100644
--- a/nix/readTree/default.nix
+++ b/nix/readTree/default.nix
@@ -47,26 +47,24 @@ let
       value = children.${name};
     }) names);
 
-  # Create a mark containing the location of this attribute.
-  marker = parts: {
+  # Create a mark containing the location of this attribute and
+  # a list of all child attribute names added by readTree.
+  marker = parts: children: {
     __readTree = parts;
+    __readTreeChildren = builtins.attrNames children;
   };
 
-  # The marker is added to every set that was imported directly by
-  # readTree.
-  importWithMark = args: scopedArgs: path: parts: filter:
+  # Import a file and enforce our calling convention
+  importFile = args: scopedArgs: path: parts: filter:
   let
       importedFile = if scopedArgs != {}
                      then builtins.scopedImport scopedArgs path
                      else import path;
       pathType = builtins.typeOf importedFile;
-      imported =
-        if pathType != "lambda"
-        then builtins.throw "readTree: trying to import ${toString path}, but it’s a ${pathType}, you need to make it a function like { depot, pkgs, ... }"
-        else importedFile (filter (argsWithPath args parts) parts);
-    in if (isAttrs imported)
-      then imported // (marker parts)
-      else imported;
+  in
+    if pathType != "lambda"
+    then builtins.throw "readTree: trying to import ${toString path}, but it’s a ${pathType}, you need to make it a function like { depot, pkgs, ... }"
+    else importedFile (filter (argsWithPath args parts) parts);
 
   nixFileName = file:
     let res = match "(.*)\\.nix" file;
@@ -79,7 +77,7 @@ let
 
       self = if rootDir
         then { __readTree = []; }
-        else importWithMark args scopedArgs initPath parts argsFilter;
+        else importFile args scopedArgs initPath parts argsFilter;
 
       # Import subdirectories of the current one, unless the special
       # `.skip-subtree` file exists which makes readTree ignore the
@@ -102,13 +100,30 @@ let
 
       # Import Nix files
       nixFiles = filter (f: f != null) (map nixFileName (attrNames dir));
-      nixChildren = map (c: let p = joinChild (c + ".nix"); in {
+      nixChildren = map (c: let
+        p = joinChild (c + ".nix");
+        childParts = parts ++ [ c ];
+        imported = importFile args scopedArgs p childParts argsFilter;
+      in {
         name = c;
-        value = importWithMark args scopedArgs p (parts ++ [ c ]) argsFilter;
+        value =
+          if isAttrs imported
+          then imported // marker parts {}
+          else imported;
       }) nixFiles;
-    in if dir ? "default.nix"
-      then (if isAttrs self then self // (listToAttrs children) else self)
-      else (listToAttrs (nixChildren ++ children) // (marker parts));
+
+      nodeValue = if dir ? "default.nix" then self else {};
+
+      allChildren = listToAttrs (
+        if dir ? "default.nix"
+        then children
+        else nixChildren ++ children
+      );
+
+    in
+      if isAttrs nodeValue
+      then nodeValue // allChildren // (marker parts allChildren)
+      else nodeValue;
 
 in {
   __functor = _: