Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ The following goes recursively through `./modules` and imports all `.nix` files.

For more advanced usage, `import-tree` can be configured via its extensible API.

______________________________________________________________________
---

#### Obtaining the API

Expand Down Expand Up @@ -228,7 +228,7 @@ Returns a fresh import-tree with empty state.

##### 🌳 `import-tree.initFilter`

*Replaces* the initial filter which defaults to: Include files with `.nix` suffix and not having `/_` infix.
_Replaces_ the initial filter which defaults to: Include files with `.nix` suffix and not having `/_` infix.

```nix
import-tree.initFilter (p: lib.hasSuffix ".nix" p && !lib.hasInfix "/ignored/" p)
Expand Down Expand Up @@ -257,7 +257,7 @@ Exactly the same as calling the import-tree object with an empty list `[ ]`.
(import-tree.addPath ./modules) [ ]
```

______________________________________________________________________
---

## Why

Expand All @@ -280,15 +280,15 @@ particular idioms.

@vic is using this on [Dendrix](https://github.com/vic/dendrix) for [community conventions](https://github.com/vic/dendrix/blob/main/dev/modules/community/_pipeline.nix) on tagging files.

This would allow us to have community-driven *sets* of configurations,
This would allow us to have community-driven _sets_ of configurations,
much like those popular for editors: spacemacs/lazy-vim distributions.

Imagine an editor distribution exposing the following flake output:

```nix
# editor-distro's flakeModule
{inputs, lib, ...}:
let
let
flake.lib.modules-tree = lib.pipe inputs.import-tree [
(i: i.addPath ./modules)
(i: i.addAPI { inherit on off exclusive; })
Expand Down Expand Up @@ -323,7 +323,7 @@ in {
}
```

______________________________________________________________________
---

## Testing

Expand All @@ -332,7 +332,7 @@ ______________________________________________________________________
The test suite can be found in [`checkmate.nix`](checkmate.nix). To run it locally:

```sh
nix flake check path:checkmate --override-input target path:.
nix flake check github:vic/checkmate --override-input target path:.
```

Run the following to format files:
Expand Down
1 change: 0 additions & 1 deletion checkmate/.gitignore

This file was deleted.

6 changes: 0 additions & 6 deletions checkmate/flake.nix

This file was deleted.

3 changes: 3 additions & 0 deletions checkmate/modules/formatter.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
perSystem.treefmt.settings.global.excludes = [ "checkmate/tree/*" ];
}
118 changes: 59 additions & 59 deletions checkmate.nix → checkmate/modules/tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,121 +13,121 @@ in
{
nix-unit.tests = {
leafs."test fails if no lib has been set" = {
expr = it.leafs ./trees;
expr = it.leafs ../tree;
expectedError.type = "ThrownError";
};

leafs."test succeeds when lib has been set" = {
expr = (it.withLib lib).leafs ./tree/hello;
expr = (it.withLib lib).leafs ../tree/hello;
expected = [ ];
};

leafs."test only returns nix non-ignored files" = {
expr = lit.leafs ./tree/a;
expr = lit.leafs ../tree/a;
expected = [
./tree/a/a_b.nix
./tree/a/b/b_a.nix
./tree/a/b/m.nix
../tree/a/a_b.nix
../tree/a/b/b_a.nix
../tree/a/b/m.nix
];
};

filter."test returns empty if no nix files with true predicate" = {
expr = (lit.filter (_: false)).leafs ./tree;
expr = (lit.filter (_: false)).leafs ../tree;
expected = [ ];
};

filter."test only returns nix files with true predicate" = {
expr = (lit.filter (lib.hasSuffix "m.nix")).leafs ./tree;
expected = [ ./tree/a/b/m.nix ];
expr = (lit.filter (lib.hasSuffix "m.nix")).leafs ../tree;
expected = [ ../tree/a/b/m.nix ];
};

filter."test multiple `filter`s compose" = {
expr = ((lit.filter (lib.hasInfix "b/")).filter (lib.hasInfix "_")).leafs ./tree;
expected = [ ./tree/a/b/b_a.nix ];
expr = ((lit.filter (lib.hasInfix "b/")).filter (lib.hasInfix "_")).leafs ../tree;
expected = [ ../tree/a/b/b_a.nix ];
};

match."test returns empty if no files match regex" = {
expr = (lit.match "badregex").leafs ./tree;
expr = (lit.match "badregex").leafs ../tree;
expected = [ ];
};

match."test returns files matching regex" = {
expr = (lit.match ".*/[^/]+_[^/]+\.nix").leafs ./tree;
expr = (lit.match ".*/[^/]+_[^/]+\.nix").leafs ../tree;
expected = [
./tree/a/a_b.nix
./tree/a/b/b_a.nix
../tree/a/a_b.nix
../tree/a/b/b_a.nix
];
};

matchNot."test returns files not matching regex" = {
expr = (lit.matchNot ".*/[^/]+_[^/]+\.nix").leafs ./tree/a/b;
expr = (lit.matchNot ".*/[^/]+_[^/]+\.nix").leafs ../tree/a/b;
expected = [
./tree/a/b/m.nix
../tree/a/b/m.nix
];
};

match."test `match` composes with `filter`" = {
expr = ((lit.match ".*a_b.nix").filter (lib.hasInfix "/a/")).leafs ./tree;
expected = [ ./tree/a/a_b.nix ];
expr = ((lit.match ".*a_b.nix").filter (lib.hasInfix "/a/")).leafs ../tree;
expected = [ ../tree/a/a_b.nix ];
};

match."test multiple `match`s compose" = {
expr = ((lit.match ".*/[^/]+_[^/]+\.nix").match ".*b\.nix").leafs ./tree;
expected = [ ./tree/a/a_b.nix ];
expr = ((lit.match ".*/[^/]+_[^/]+\.nix").match ".*b\.nix").leafs ../tree;
expected = [ ../tree/a/a_b.nix ];
};

map."test transforms each matching file with function" = {
expr = (lit.map import).leafs ./tree/x;
expr = (lit.map import).leafs ../tree/x;
expected = [ "z" ];
};

map."test `map` composes with `filter`" = {
expr = ((lit.filter (lib.hasInfix "/x")).map import).leafs ./tree;
expr = ((lit.filter (lib.hasInfix "/x")).map import).leafs ../tree;
expected = [ "z" ];
};

map."test multiple `map`s compose" = {
expr = ((lit.map import).map builtins.stringLength).leafs ./tree/x;
expr = ((lit.map import).map builtins.stringLength).leafs ../tree/x;
expected = [ 1 ];
};

addPath."test `addPath` prepends a path to filter" = {
expr = (lit.addPath ./tree/x).files;
expected = [ ./tree/x/y.nix ];
expr = (lit.addPath ../tree/x).files;
expected = [ ../tree/x/y.nix ];
};

addPath."test `addPath` can be called multiple times" = {
expr = ((lit.addPath ./tree/x).addPath ./tree/a/b).files;
expr = ((lit.addPath ../tree/x).addPath ../tree/a/b).files;
expected = [
./tree/x/y.nix
./tree/a/b/b_a.nix
./tree/a/b/m.nix
../tree/x/y.nix
../tree/a/b/b_a.nix
../tree/a/b/m.nix
];
};

addPath."test `addPath` identity" = {
expr = ((lit.addPath ./tree/x).addPath ./tree/a/b).files;
expr = ((lit.addPath ../tree/x).addPath ../tree/a/b).files;
expected = lit.leafs [
./tree/x
./tree/a/b
../tree/x
../tree/a/b
];
};

new."test `new` returns a clear state" = {
expr = lib.pipe lit [
(i: i.addPath ./tree/x)
(i: i.addPath ./tree/a/b)
(i: i.addPath ../tree/x)
(i: i.addPath ../tree/a/b)
(i: i.new)
(i: i.addPath ./tree/modules/hello-world)
(i: i.addPath ../tree/modules/hello-world)
(i: i.withLib lib)
(i: i.files)
];
expected = [ ./tree/modules/hello-world/mod.nix ];
expected = [ ../tree/modules/hello-world/mod.nix ];
};

initFilter."test can change the initial filter to look for other file types" = {
expr = (lit.initFilter (p: lib.hasSuffix ".txt" p)).leafs [ ./tree/a ];
expected = [ ./tree/a/a.txt ];
expr = (lit.initFilter (p: lib.hasSuffix ".txt" p)).leafs [ ../tree/a ];
expected = [ ../tree/a/a.txt ];
};

initFilter."test initf does filter non-paths" = {
Expand All @@ -153,21 +153,21 @@ in
addAPI."test extends the API available on an import-tree object" = {
expr =
let
extended = lit.addAPI { helloOption = self: self.addPath ./tree/modules/hello-option; };
extended = lit.addAPI { helloOption = self: self.addPath ../tree/modules/hello-option; };
in
extended.helloOption.files;
expected = [ ./tree/modules/hello-option/mod.nix ];
expected = [ ../tree/modules/hello-option/mod.nix ];
};

addAPI."test preserves previous API extensions on an import-tree object" = {
expr =
let
first = lit.addAPI { helloOption = self: self.addPath ./tree/modules/hello-option; };
second = first.addAPI { helloWorld = self: self.addPath ./tree/modules/hello-world; };
first = lit.addAPI { helloOption = self: self.addPath ../tree/modules/hello-option; };
second = first.addAPI { helloWorld = self: self.addPath ../tree/modules/hello-world; };
extended = second.addAPI { res = self: self.helloOption.files; };
in
extended.res;
expected = [ ./tree/modules/hello-option/mod.nix ];
expected = [ ../tree/modules/hello-option/mod.nix ];
};

addAPI."test API extensions are late bound" = {
Expand All @@ -181,30 +181,30 @@ in
};

pipeTo."test pipes list into a function" = {
expr = (lit.map lib.pathType).pipeTo (lib.length) ./tree/x;
expr = (lit.map lib.pathType).pipeTo (lib.length) ../tree/x;
expected = 1;
};

import-tree."test does not break if given a path to a file instead of a directory." = {
expr = lit.leafs ./tree/x/y.nix;
expected = [ ./tree/x/y.nix ];
expr = lit.leafs ../tree/x/y.nix;
expected = [ ../tree/x/y.nix ];
};

import-tree."test returns a module with a single imported nested module having leafs" = {
expr =
let
oneElement = arr: if lib.length arr == 1 then lib.elemAt arr 0 else throw "Expected one element";
module = it ./tree/x;
module = it ../tree/x;
inner = (oneElement module.imports) { inherit lib; };
in
oneElement inner.imports;
expected = ./tree/x/y.nix;
expected = ../tree/x/y.nix;
};

import-tree."test evaluates returned module as part of module-eval" = {
expr =
let
res = lib.modules.evalModules { modules = [ (it ./tree/modules) ]; };
res = lib.modules.evalModules { modules = [ (it ../tree/modules) ]; };
in
res.config.hello;
expected = "world";
Expand All @@ -213,7 +213,7 @@ in
import-tree."test can itself be used as a module" = {
expr =
let
res = lib.modules.evalModules { modules = [ (it.addPath ./tree/modules) ]; };
res = lib.modules.evalModules { modules = [ (it.addPath ../tree/modules) ]; };
in
res.config.hello;
expected = "world";
Expand All @@ -222,10 +222,10 @@ in
import-tree."test take as arg anything path convertible" = {
expr = lit.leafs [
{
outPath = ./tree/modules/hello-world;
outPath = ../tree/modules/hello-world;
}
];
expected = [ ./tree/modules/hello-world/mod.nix ];
expected = [ ../tree/modules/hello-world/mod.nix ];
};

import-tree."test passes non-paths without string conversion" = {
Expand All @@ -247,18 +247,18 @@ in

import-tree."test can take other import-trees as if they were paths" = {
expr = (lit.filter (lib.hasInfix "mod")).leafs [
(it.addPath ./tree/modules/hello-option)
./tree/modules/hello-world
(it.addPath ../tree/modules/hello-option)
../tree/modules/hello-world
];
expected = [
./tree/modules/hello-option/mod.nix
./tree/modules/hello-world/mod.nix
../tree/modules/hello-option/mod.nix
../tree/modules/hello-world/mod.nix
];
};

leafs."test loads from hidden directory but excludes sub-hidden" = {
expr = lit.leafs ./tree/a/b/_c;
expected = [ ./tree/a/b/_c/d/e.nix ];
expr = lit.leafs ../tree/a/b/_c;
expected = [ ../tree/a/b/_c/d/e.nix ];
};
};

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.