It's convenient for depending on sub-tree members of the current file as well as gives access to siblings. Change-Id: I74234cec6566177d88d3bc8507fa3f6ec789adb8 Reviewed-on: https://cl.snix.dev/c/snix/+/30098 Reviewed-by: adis bladis <adisbladis@gmail.com> Tested-by: besadii
3.6 KiB
readTree
This is a Nix program that builds up an attribute set tree for a large repository based on the filesystem layout.
It is in fact the tool that lays out the attribute set of this repository.
As an example, consider a root (.) of a repository and a layout such as:
.
├── third_party
│ ├── default.nix
│ └── rustpkgs
│ ├── aho-corasick.nix
│ └── serde.nix
└── tools
├── cheddar
│ └── default.nix
└── roquefort.nix
When readTree is called on that tree, it will construct an attribute set with
this shape:
{
tools = {
cheddar = ...;
roquefort = ...;
};
third_party = {
# the `default.nix` of this folder might have had arbitrary other
# attributes here, such as this:
favouriteColour = "orange";
rustpkgs = {
aho-corasick = ...;
serde = ...;
};
};
}
Every imported Nix file that yields an attribute set will have a __readTree = true; attribute merged into it.
Traversal logic
readTree will follow any subdirectories of a tree and import all Nix files,
with some exceptions:
- If a folder contains a
default.nixfile, no sibling Nix files will be imported - however children are traversed as normal. - If a folder contains a
default.nixit is loaded and, if it evaluates to a set, merged with the children. If it evaluates to anything other than a set, else the children are not traversed. - A folder can opt out from readTree completely by containing a
.skip-treefile. The content of the file is not read. These folders will be missing completely from the readTree structure. - A folder can declare that its children are off-limit by containing a
.skip-subtreefile. Since the content of the file is not checked, it can be useful to leave a note for a human in the file. - The
default.nixof the top-level folder on which readTree is called is not read to avoid infinite recursion (as, presumably, this file is where readTree itself is called).
Traversal is lazy, readTree will only build up the tree as requested. This
currently has the downside that directories with no importable files end up in
the tree as empty nodes ({}).
Import structure
readTree is called with an argument set containing a few parameters:
path: Initial path at which to start the traversal.args: Arguments to pass to all imports.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 example, implement a "visibility" system inside of a tree.scopedArgs: (optional) An argument set that is passed to all imported files viabuiltins.scopedImport. This will forcefully override the given values in the import scope, use with care!
The package headers in this repository follow the form
{depot, pkgs, lib, here, ... }: where:
depotis a fixed-point of the entire package tree (see thedefault.nixat the root of the depot).pkgsis the nixpkgs used in the repo, seethird_party/nixpkgslibis essentially a shortcut topkgs.libexposed for conveniencehereis a special argument that points to the current location in the tree. Useful to avoid specifying dependencies from the very top of thedepot
In theory readTree can pass arguments of different shapes, but I have found
this to be a good solution for the most part.
Note that readTree does not currently make functions overridable, though it is
feasible that it could do that in the future.