tvl-depot/nix/readTree/README.md
Vincent Ambo a559135970 refactor(readTree): Initialise repo roots without recursing
Plumbs an additional internal argument through readTree that indicates
whether the top-level of a tree is being read, and avoids recursing
into itself in that case. This changes the externally visible
behaviour of readTree (it is now expected to be called a level higher
than previously).

This allows us to reduce the amount of boilerplate needed to bootstrap
the TVL repository (by not having to specify the individual folders
that need to be read).

For reasons related to an infinite recursion we could not (be bothered
to) debug, the top-level `config` key (which held the attribute set
passed on by readTree) has been removed. This is not needed, as it is
already passed on by readTree ...

Co-Authored-By: Florian Klink <flokli@flokli.de>
Change-Id: Id6e39b57b2f5b3473c4b695a72dd1d01fcfb7a66
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2961
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Reviewed-by: grfn <grfn@gws.fyi>
2021-04-12 21:55:07 +00:00

84 lines
2.6 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 two parameters: The arguments to pass to all imports,
and the initial path at which to start the traversal.
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.