feat(readTree): Support scoped import arguments

This makes it possible to override Nix builtins within a readTree
structure. Why would you want to do that, you might ask? Well ...

Change-Id: Icc9cb32e5db4a2eba370cf81769c642d237d4937
Reviewed-on: https://cl.tvl.fyi/c/depot/+/3499
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
Vincent Ambo 2021-09-08 18:27:37 +03:00 committed by tazjin
parent aedde913d1
commit b1f4b530ec
2 changed files with 15 additions and 9 deletions

View file

@ -77,6 +77,9 @@ the tree as empty nodes (`{}`).
* `filter`: (optional) A function to filter the argument set on each * `filter`: (optional) A function to filter the argument set on each
import based on the location in the tree. This can be used to, for import based on the location in the tree. This can be used to, for
example, implement a "visibility" system inside of a tree. example, implement a "visibility" system inside of a tree.
* `scopedArgs`: (optional) An argument set that is passed to all
imported files via `builtins.scopedImport`. This will forcefully
override the given values in the import scope, use with care!
The package headers in this repository follow the form `{ pkgs, ... }:` where The package headers in this repository follow the form `{ pkgs, ... }:` where
`pkgs` is a fixed-point of the entire package tree (see the `default.nix` at the `pkgs` is a fixed-point of the entire package tree (see the `default.nix` at the

View file

@ -59,9 +59,11 @@ let
# The marker is added to every set that was imported directly by # The marker is added to every set that was imported directly by
# readTree. # readTree.
importWithMark = args: path: parts: filter: importWithMark = args: scopedArgs: path: parts: filter:
let let
importedFile = import path; importedFile = if scopedArgs != {}
then builtins.scopedImport scopedArgs path
else import path;
pathType = builtins.typeOf importedFile; pathType = builtins.typeOf importedFile;
imported = imported =
assert assertMsg assert assertMsg
@ -76,14 +78,14 @@ let
let res = match "(.*)\\.nix" file; let res = match "(.*)\\.nix" file;
in if res == null then null else head res; in if res == null then null else head res;
readTree = { args, initPath, rootDir, parts, argsFilter }: readTree = { args, initPath, rootDir, parts, argsFilter, scopedArgs }:
let let
dir = readDirVisible initPath; dir = readDirVisible initPath;
joinChild = c: initPath + ("/" + c); joinChild = c: initPath + ("/" + c);
self = if rootDir self = if rootDir
then { __readTree = []; } then { __readTree = []; }
else importWithMark args initPath parts argsFilter; else importWithMark 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
@ -96,7 +98,7 @@ let
children = if hasAttr ".skip-subtree" dir then [] else map (c: { children = if hasAttr ".skip-subtree" dir then [] else map (c: {
name = c; name = c;
value = readTree { value = readTree {
inherit argsFilter; inherit argsFilter scopedArgs;
args = args; args = args;
initPath = (joinChild c); initPath = (joinChild c);
rootDir = false; rootDir = false;
@ -108,7 +110,7 @@ let
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"); in {
name = c; name = c;
value = importWithMark args p (parts ++ [ c ]) argsFilter; value = importWithMark args scopedArgs p (parts ++ [ c ]) argsFilter;
}) nixFiles; }) nixFiles;
in if dir ? "default.nix" in if dir ? "default.nix"
then (if isAttrs self then self // (listToAttrs children) else self) then (if isAttrs self then self // (listToAttrs children) else self)
@ -118,9 +120,10 @@ in {
__functor = _: __functor = _:
{ path { path
, args , args
, filter ? (x: _parts: x) }: , filter ? (x: _parts: x)
, scopedArgs ? {} }:
readTree { readTree {
inherit args; inherit args scopedArgs;
argsFilter = filter; argsFilter = filter;
initPath = path; initPath = path;
rootDir = true; rootDir = true;