b1f4b530ec
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>
92 lines
3.1 KiB
Markdown
92 lines
3.1 KiB
Markdown
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:
|
|
|
|
```nix
|
|
{
|
|
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:
|
|
|
|
* A folder can declare that its children are off-limit by containing a
|
|
`.skip-subtree` file. Since the content of the file is not checked, it can be
|
|
useful to leave a note for a human in the file.
|
|
* If a folder contains a `default.nix` file, no *sibling* Nix files will be
|
|
imported - however children are traversed as normal.
|
|
* If a folder contains a `default.nix` it is loaded and, if it evaluates to a
|
|
set, *merged* with the children. If it evaluates to anything else the children
|
|
are *not traversed*.
|
|
* The `default.nix` of 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 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
|
|
`pkgs` is a fixed-point of the entire package tree (see the `default.nix` at the
|
|
root of the depot).
|
|
|
|
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.
|