Import all nix files in a directory tree. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ dendrix.oeiuwq.com/Dendritic.html
dendritic inputs

checkmate update (#24)

authored by oeiuwq.com and committed by

GitHub ca69d647 6cef1639

+69 -73
+7 -7
README.md
··· 66 66 67 67 For more advanced usage, `import-tree` can be configured via its extensible API. 68 68 69 - ______________________________________________________________________ 69 + --- 70 70 71 71 #### Obtaining the API 72 72 ··· 228 228 229 229 ##### 🌳 `import-tree.initFilter` 230 230 231 - *Replaces* the initial filter which defaults to: Include files with `.nix` suffix and not having `/_` infix. 231 + _Replaces_ the initial filter which defaults to: Include files with `.nix` suffix and not having `/_` infix. 232 232 233 233 ```nix 234 234 import-tree.initFilter (p: lib.hasSuffix ".nix" p && !lib.hasInfix "/ignored/" p) ··· 257 257 (import-tree.addPath ./modules) [ ] 258 258 ``` 259 259 260 - ______________________________________________________________________ 260 + --- 261 261 262 262 ## Why 263 263 ··· 280 280 281 281 @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. 282 282 283 - This would allow us to have community-driven *sets* of configurations, 283 + This would allow us to have community-driven _sets_ of configurations, 284 284 much like those popular for editors: spacemacs/lazy-vim distributions. 285 285 286 286 Imagine an editor distribution exposing the following flake output: ··· 288 288 ```nix 289 289 # editor-distro's flakeModule 290 290 {inputs, lib, ...}: 291 - let 291 + let 292 292 flake.lib.modules-tree = lib.pipe inputs.import-tree [ 293 293 (i: i.addPath ./modules) 294 294 (i: i.addAPI { inherit on off exclusive; }) ··· 323 323 } 324 324 ``` 325 325 326 - ______________________________________________________________________ 326 + --- 327 327 328 328 ## Testing 329 329 ··· 332 332 The test suite can be found in [`checkmate.nix`](checkmate.nix). To run it locally: 333 333 334 334 ```sh 335 - nix flake check path:checkmate --override-input target path:. 335 + nix flake check github:vic/checkmate --override-input target path:. 336 336 ``` 337 337 338 338 Run the following to format files:
+59 -59
checkmate.nix checkmate/modules/tests.nix
··· 13 13 { 14 14 nix-unit.tests = { 15 15 leafs."test fails if no lib has been set" = { 16 - expr = it.leafs ./trees; 16 + expr = it.leafs ../tree; 17 17 expectedError.type = "ThrownError"; 18 18 }; 19 19 20 20 leafs."test succeeds when lib has been set" = { 21 - expr = (it.withLib lib).leafs ./tree/hello; 21 + expr = (it.withLib lib).leafs ../tree/hello; 22 22 expected = [ ]; 23 23 }; 24 24 25 25 leafs."test only returns nix non-ignored files" = { 26 - expr = lit.leafs ./tree/a; 26 + expr = lit.leafs ../tree/a; 27 27 expected = [ 28 - ./tree/a/a_b.nix 29 - ./tree/a/b/b_a.nix 30 - ./tree/a/b/m.nix 28 + ../tree/a/a_b.nix 29 + ../tree/a/b/b_a.nix 30 + ../tree/a/b/m.nix 31 31 ]; 32 32 }; 33 33 34 34 filter."test returns empty if no nix files with true predicate" = { 35 - expr = (lit.filter (_: false)).leafs ./tree; 35 + expr = (lit.filter (_: false)).leafs ../tree; 36 36 expected = [ ]; 37 37 }; 38 38 39 39 filter."test only returns nix files with true predicate" = { 40 - expr = (lit.filter (lib.hasSuffix "m.nix")).leafs ./tree; 41 - expected = [ ./tree/a/b/m.nix ]; 40 + expr = (lit.filter (lib.hasSuffix "m.nix")).leafs ../tree; 41 + expected = [ ../tree/a/b/m.nix ]; 42 42 }; 43 43 44 44 filter."test multiple `filter`s compose" = { 45 - expr = ((lit.filter (lib.hasInfix "b/")).filter (lib.hasInfix "_")).leafs ./tree; 46 - expected = [ ./tree/a/b/b_a.nix ]; 45 + expr = ((lit.filter (lib.hasInfix "b/")).filter (lib.hasInfix "_")).leafs ../tree; 46 + expected = [ ../tree/a/b/b_a.nix ]; 47 47 }; 48 48 49 49 match."test returns empty if no files match regex" = { 50 - expr = (lit.match "badregex").leafs ./tree; 50 + expr = (lit.match "badregex").leafs ../tree; 51 51 expected = [ ]; 52 52 }; 53 53 54 54 match."test returns files matching regex" = { 55 - expr = (lit.match ".*/[^/]+_[^/]+\.nix").leafs ./tree; 55 + expr = (lit.match ".*/[^/]+_[^/]+\.nix").leafs ../tree; 56 56 expected = [ 57 - ./tree/a/a_b.nix 58 - ./tree/a/b/b_a.nix 57 + ../tree/a/a_b.nix 58 + ../tree/a/b/b_a.nix 59 59 ]; 60 60 }; 61 61 62 62 matchNot."test returns files not matching regex" = { 63 - expr = (lit.matchNot ".*/[^/]+_[^/]+\.nix").leafs ./tree/a/b; 63 + expr = (lit.matchNot ".*/[^/]+_[^/]+\.nix").leafs ../tree/a/b; 64 64 expected = [ 65 - ./tree/a/b/m.nix 65 + ../tree/a/b/m.nix 66 66 ]; 67 67 }; 68 68 69 69 match."test `match` composes with `filter`" = { 70 - expr = ((lit.match ".*a_b.nix").filter (lib.hasInfix "/a/")).leafs ./tree; 71 - expected = [ ./tree/a/a_b.nix ]; 70 + expr = ((lit.match ".*a_b.nix").filter (lib.hasInfix "/a/")).leafs ../tree; 71 + expected = [ ../tree/a/a_b.nix ]; 72 72 }; 73 73 74 74 match."test multiple `match`s compose" = { 75 - expr = ((lit.match ".*/[^/]+_[^/]+\.nix").match ".*b\.nix").leafs ./tree; 76 - expected = [ ./tree/a/a_b.nix ]; 75 + expr = ((lit.match ".*/[^/]+_[^/]+\.nix").match ".*b\.nix").leafs ../tree; 76 + expected = [ ../tree/a/a_b.nix ]; 77 77 }; 78 78 79 79 map."test transforms each matching file with function" = { 80 - expr = (lit.map import).leafs ./tree/x; 80 + expr = (lit.map import).leafs ../tree/x; 81 81 expected = [ "z" ]; 82 82 }; 83 83 84 84 map."test `map` composes with `filter`" = { 85 - expr = ((lit.filter (lib.hasInfix "/x")).map import).leafs ./tree; 85 + expr = ((lit.filter (lib.hasInfix "/x")).map import).leafs ../tree; 86 86 expected = [ "z" ]; 87 87 }; 88 88 89 89 map."test multiple `map`s compose" = { 90 - expr = ((lit.map import).map builtins.stringLength).leafs ./tree/x; 90 + expr = ((lit.map import).map builtins.stringLength).leafs ../tree/x; 91 91 expected = [ 1 ]; 92 92 }; 93 93 94 94 addPath."test `addPath` prepends a path to filter" = { 95 - expr = (lit.addPath ./tree/x).files; 96 - expected = [ ./tree/x/y.nix ]; 95 + expr = (lit.addPath ../tree/x).files; 96 + expected = [ ../tree/x/y.nix ]; 97 97 }; 98 98 99 99 addPath."test `addPath` can be called multiple times" = { 100 - expr = ((lit.addPath ./tree/x).addPath ./tree/a/b).files; 100 + expr = ((lit.addPath ../tree/x).addPath ../tree/a/b).files; 101 101 expected = [ 102 - ./tree/x/y.nix 103 - ./tree/a/b/b_a.nix 104 - ./tree/a/b/m.nix 102 + ../tree/x/y.nix 103 + ../tree/a/b/b_a.nix 104 + ../tree/a/b/m.nix 105 105 ]; 106 106 }; 107 107 108 108 addPath."test `addPath` identity" = { 109 - expr = ((lit.addPath ./tree/x).addPath ./tree/a/b).files; 109 + expr = ((lit.addPath ../tree/x).addPath ../tree/a/b).files; 110 110 expected = lit.leafs [ 111 - ./tree/x 112 - ./tree/a/b 111 + ../tree/x 112 + ../tree/a/b 113 113 ]; 114 114 }; 115 115 116 116 new."test `new` returns a clear state" = { 117 117 expr = lib.pipe lit [ 118 - (i: i.addPath ./tree/x) 119 - (i: i.addPath ./tree/a/b) 118 + (i: i.addPath ../tree/x) 119 + (i: i.addPath ../tree/a/b) 120 120 (i: i.new) 121 - (i: i.addPath ./tree/modules/hello-world) 121 + (i: i.addPath ../tree/modules/hello-world) 122 122 (i: i.withLib lib) 123 123 (i: i.files) 124 124 ]; 125 - expected = [ ./tree/modules/hello-world/mod.nix ]; 125 + expected = [ ../tree/modules/hello-world/mod.nix ]; 126 126 }; 127 127 128 128 initFilter."test can change the initial filter to look for other file types" = { 129 - expr = (lit.initFilter (p: lib.hasSuffix ".txt" p)).leafs [ ./tree/a ]; 130 - expected = [ ./tree/a/a.txt ]; 129 + expr = (lit.initFilter (p: lib.hasSuffix ".txt" p)).leafs [ ../tree/a ]; 130 + expected = [ ../tree/a/a.txt ]; 131 131 }; 132 132 133 133 initFilter."test initf does filter non-paths" = { ··· 153 153 addAPI."test extends the API available on an import-tree object" = { 154 154 expr = 155 155 let 156 - extended = lit.addAPI { helloOption = self: self.addPath ./tree/modules/hello-option; }; 156 + extended = lit.addAPI { helloOption = self: self.addPath ../tree/modules/hello-option; }; 157 157 in 158 158 extended.helloOption.files; 159 - expected = [ ./tree/modules/hello-option/mod.nix ]; 159 + expected = [ ../tree/modules/hello-option/mod.nix ]; 160 160 }; 161 161 162 162 addAPI."test preserves previous API extensions on an import-tree object" = { 163 163 expr = 164 164 let 165 - first = lit.addAPI { helloOption = self: self.addPath ./tree/modules/hello-option; }; 166 - second = first.addAPI { helloWorld = self: self.addPath ./tree/modules/hello-world; }; 165 + first = lit.addAPI { helloOption = self: self.addPath ../tree/modules/hello-option; }; 166 + second = first.addAPI { helloWorld = self: self.addPath ../tree/modules/hello-world; }; 167 167 extended = second.addAPI { res = self: self.helloOption.files; }; 168 168 in 169 169 extended.res; 170 - expected = [ ./tree/modules/hello-option/mod.nix ]; 170 + expected = [ ../tree/modules/hello-option/mod.nix ]; 171 171 }; 172 172 173 173 addAPI."test API extensions are late bound" = { ··· 181 181 }; 182 182 183 183 pipeTo."test pipes list into a function" = { 184 - expr = (lit.map lib.pathType).pipeTo (lib.length) ./tree/x; 184 + expr = (lit.map lib.pathType).pipeTo (lib.length) ../tree/x; 185 185 expected = 1; 186 186 }; 187 187 188 188 import-tree."test does not break if given a path to a file instead of a directory." = { 189 - expr = lit.leafs ./tree/x/y.nix; 190 - expected = [ ./tree/x/y.nix ]; 189 + expr = lit.leafs ../tree/x/y.nix; 190 + expected = [ ../tree/x/y.nix ]; 191 191 }; 192 192 193 193 import-tree."test returns a module with a single imported nested module having leafs" = { 194 194 expr = 195 195 let 196 196 oneElement = arr: if lib.length arr == 1 then lib.elemAt arr 0 else throw "Expected one element"; 197 - module = it ./tree/x; 197 + module = it ../tree/x; 198 198 inner = (oneElement module.imports) { inherit lib; }; 199 199 in 200 200 oneElement inner.imports; 201 - expected = ./tree/x/y.nix; 201 + expected = ../tree/x/y.nix; 202 202 }; 203 203 204 204 import-tree."test evaluates returned module as part of module-eval" = { 205 205 expr = 206 206 let 207 - res = lib.modules.evalModules { modules = [ (it ./tree/modules) ]; }; 207 + res = lib.modules.evalModules { modules = [ (it ../tree/modules) ]; }; 208 208 in 209 209 res.config.hello; 210 210 expected = "world"; ··· 213 213 import-tree."test can itself be used as a module" = { 214 214 expr = 215 215 let 216 - res = lib.modules.evalModules { modules = [ (it.addPath ./tree/modules) ]; }; 216 + res = lib.modules.evalModules { modules = [ (it.addPath ../tree/modules) ]; }; 217 217 in 218 218 res.config.hello; 219 219 expected = "world"; ··· 222 222 import-tree."test take as arg anything path convertible" = { 223 223 expr = lit.leafs [ 224 224 { 225 - outPath = ./tree/modules/hello-world; 225 + outPath = ../tree/modules/hello-world; 226 226 } 227 227 ]; 228 - expected = [ ./tree/modules/hello-world/mod.nix ]; 228 + expected = [ ../tree/modules/hello-world/mod.nix ]; 229 229 }; 230 230 231 231 import-tree."test passes non-paths without string conversion" = { ··· 247 247 248 248 import-tree."test can take other import-trees as if they were paths" = { 249 249 expr = (lit.filter (lib.hasInfix "mod")).leafs [ 250 - (it.addPath ./tree/modules/hello-option) 251 - ./tree/modules/hello-world 250 + (it.addPath ../tree/modules/hello-option) 251 + ../tree/modules/hello-world 252 252 ]; 253 253 expected = [ 254 - ./tree/modules/hello-option/mod.nix 255 - ./tree/modules/hello-world/mod.nix 254 + ../tree/modules/hello-option/mod.nix 255 + ../tree/modules/hello-world/mod.nix 256 256 ]; 257 257 }; 258 258 259 259 leafs."test loads from hidden directory but excludes sub-hidden" = { 260 - expr = lit.leafs ./tree/a/b/_c; 261 - expected = [ ./tree/a/b/_c/d/e.nix ]; 260 + expr = lit.leafs ../tree/a/b/_c; 261 + expected = [ ../tree/a/b/_c/d/e.nix ]; 262 262 }; 263 263 }; 264 264
-1
checkmate/.gitignore
··· 1 - flake.lock
-6
checkmate/flake.nix
··· 1 - { 2 - inputs.target.url = "path:.."; 3 - inputs.checkmate.url = "github:vic/checkmate"; 4 - inputs.checkmate.inputs.target.follows = "target"; 5 - outputs = inputs: inputs.checkmate.lib.newFlake; 6 - }
+3
checkmate/modules/formatter.nix
··· 1 + { 2 + perSystem.treefmt.settings.global.excludes = [ "checkmate/tree/*" ]; 3 + }
tree/a/a.txt checkmate/tree/a/a.txt
tree/a/a_b.nix checkmate/tree/a/a_b.nix
tree/a/b/_c/d/_f.nix checkmate/tree/a/b/_c/d/_f.nix
tree/a/b/_c/d/e.nix checkmate/tree/a/b/_c/d/e.nix
tree/a/b/_n.nix checkmate/tree/a/b/_n.nix
tree/a/b/b_a.nix checkmate/tree/a/b/b_a.nix
tree/a/b/m.nix checkmate/tree/a/b/m.nix
tree/hello/world checkmate/tree/hello/world
tree/modules/hello-option/mod.nix checkmate/tree/modules/hello-option/mod.nix
tree/modules/hello-world/mod.nix checkmate/tree/modules/hello-world/mod.nix
tree/x/y.nix checkmate/tree/x/y.nix