feat(nix/readTree): record list of children added by readTree
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
This commit is contained in:
parent
d904724adf
commit
d7f60bcb04
2 changed files with 35 additions and 19 deletions
|
@ -79,13 +79,14 @@ let
|
||||||
# Include the node itself if it is eligible.
|
# Include the node itself if it is eligible.
|
||||||
(if eligible node then [ node ] else [])
|
(if eligible node then [ node ] else [])
|
||||||
# Include eligible children of the node
|
# Include eligible children of the node
|
||||||
++ concatMap gather (attrValues node)
|
++ concatMap gather (map (attr: node."${attr}") node.__readTreeChildren)
|
||||||
# Include specified sub-targets of the node
|
# Include specified sub-targets of the node
|
||||||
++ filter eligible (map
|
++ filter eligible (map
|
||||||
(k: (node."${k}" or {}) // {
|
(k: (node."${k}" or {}) // {
|
||||||
# Keep the same tree location, but explicitly mark this
|
# Keep the same tree location, but explicitly mark this
|
||||||
# node as a subtarget.
|
# node as a subtarget.
|
||||||
__readTree = node.__readTree;
|
__readTree = node.__readTree;
|
||||||
|
__readTreeChildren = [];
|
||||||
__subtarget = k;
|
__subtarget = k;
|
||||||
})
|
})
|
||||||
(node.meta.targets or []))
|
(node.meta.targets or []))
|
||||||
|
|
|
@ -47,26 +47,24 @@ let
|
||||||
value = children.${name};
|
value = children.${name};
|
||||||
}) names);
|
}) names);
|
||||||
|
|
||||||
# Create a mark containing the location of this attribute.
|
# Create a mark containing the location of this attribute and
|
||||||
marker = parts: {
|
# a list of all child attribute names added by readTree.
|
||||||
|
marker = parts: children: {
|
||||||
__readTree = parts;
|
__readTree = parts;
|
||||||
|
__readTreeChildren = builtins.attrNames children;
|
||||||
};
|
};
|
||||||
|
|
||||||
# The marker is added to every set that was imported directly by
|
# Import a file and enforce our calling convention
|
||||||
# readTree.
|
importFile = args: scopedArgs: path: parts: filter:
|
||||||
importWithMark = args: scopedArgs: path: parts: filter:
|
|
||||||
let
|
let
|
||||||
importedFile = if scopedArgs != {}
|
importedFile = if scopedArgs != {}
|
||||||
then builtins.scopedImport scopedArgs path
|
then builtins.scopedImport scopedArgs path
|
||||||
else import path;
|
else import path;
|
||||||
pathType = builtins.typeOf importedFile;
|
pathType = builtins.typeOf importedFile;
|
||||||
imported =
|
in
|
||||||
if pathType != "lambda"
|
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, ... }"
|
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);
|
else importedFile (filter (argsWithPath args parts) parts);
|
||||||
in if (isAttrs imported)
|
|
||||||
then imported // (marker parts)
|
|
||||||
else imported;
|
|
||||||
|
|
||||||
nixFileName = file:
|
nixFileName = file:
|
||||||
let res = match "(.*)\\.nix" file;
|
let res = match "(.*)\\.nix" file;
|
||||||
|
@ -79,7 +77,7 @@ let
|
||||||
|
|
||||||
self = if rootDir
|
self = if rootDir
|
||||||
then { __readTree = []; }
|
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
|
# Import subdirectories of the current one, unless the special
|
||||||
# `.skip-subtree` file exists which makes readTree ignore the
|
# `.skip-subtree` file exists which makes readTree ignore the
|
||||||
|
@ -102,13 +100,30 @@ let
|
||||||
|
|
||||||
# Import Nix files
|
# Import Nix files
|
||||||
nixFiles = filter (f: f != null) (map nixFileName (attrNames dir));
|
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;
|
name = c;
|
||||||
value = importWithMark args scopedArgs p (parts ++ [ c ]) argsFilter;
|
value =
|
||||||
|
if isAttrs imported
|
||||||
|
then imported // marker parts {}
|
||||||
|
else imported;
|
||||||
}) nixFiles;
|
}) nixFiles;
|
||||||
in if dir ? "default.nix"
|
|
||||||
then (if isAttrs self then self // (listToAttrs children) else self)
|
nodeValue = if dir ? "default.nix" then self else {};
|
||||||
else (listToAttrs (nixChildren ++ children) // (marker parts));
|
|
||||||
|
allChildren = listToAttrs (
|
||||||
|
if dir ? "default.nix"
|
||||||
|
then children
|
||||||
|
else nixChildren ++ children
|
||||||
|
);
|
||||||
|
|
||||||
|
in
|
||||||
|
if isAttrs nodeValue
|
||||||
|
then nodeValue // allChildren // (marker parts allChildren)
|
||||||
|
else nodeValue;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
__functor = _:
|
__functor = _:
|
||||||
|
|
Loading…
Reference in a new issue