fake.modules transposition for aspect-oriented Dendritic Nix. with cross-aspect dependencies. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ dendrix.oeiuwq.com/Dendritic.html
dendritic nix aspect oriented
at e9be62ccf16f4e8e514b4cbe0e9e500948cc9afe 245 lines 7.3 kB view raw
1{ inputs, ... }: 2{ 3 perSystem = 4 { lib, ... }: 5 let 6 transpose = import ./. { inherit lib; }; 7 8 mkFlake = 9 mod: 10 inputs.flake-parts.lib.mkFlake 11 { 12 inputs.self = [ ]; 13 } 14 { 15 systems = [ ]; 16 imports = [ 17 ./flakeModule.nix 18 inputs.flake-parts.flakeModules.modules 19 mod 20 (fooMod "aspectOne") 21 (fooMod "aspectTwo") 22 (fooMod "aspectThree") 23 ]; 24 }; 25 26 fooMod = aspect: { 27 imports = [ 28 { flake.modules.classOne.${aspect}.imports = [ fooOpt ]; } 29 { flake.modules.classTwo.${aspect}.imports = [ fooOpt ]; } 30 { flake.modules.classThree.${aspect}.imports = [ fooOpt ]; } 31 ]; 32 }; 33 34 fooOpt = { 35 options.foo = lib.mkOption { 36 type = lib.types.string; 37 default = "<unset>"; 38 }; 39 options.bar = lib.mkOption { 40 type = lib.types.listOf lib.types.string; 41 default = [ ]; 42 }; 43 options.baz = lib.mkOption { 44 type = lib.types.lazyAttrsOf lib.types.string; 45 default = { }; 46 }; 47 }; 48 49 evalMod = 50 class: mod: 51 (lib.evalModules { 52 inherit class; 53 modules = [ mod ]; 54 }).config; 55 in 56 { 57 nix-unit.tests = { 58 transpose."test swaps parent and child attrNames" = { 59 expr = transpose { a.b.c = 1; }; 60 expected = { 61 b.a.c = 1; 62 }; 63 }; 64 65 transpose."test common childs become one parent" = { 66 expr = transpose { 67 a.b = 1; 68 c.b = 2; 69 }; 70 expected.b = { 71 a = 1; 72 c = 2; 73 }; 74 }; 75 76 aspects."test provides default" = 77 let 78 flake = 79 inputs.flake-parts.lib.mkFlake 80 { 81 inputs.self = [ ]; 82 moduleLocation = builtins.toString ./.; 83 } 84 { 85 systems = [ ]; 86 imports = [ 87 ./flakeModule.nix 88 inputs.flake-parts.flakeModules.modules 89 ]; 90 }; 91 expr = flake.modules; 92 expected = { }; 93 in 94 { 95 inherit expr expected; 96 }; 97 98 aspects."test transposes to flake.modules" = 99 let 100 flake = mkFlake { 101 flake.aspects.aspectOne = { 102 classOne.foo = "niri"; 103 classTwo.foo = "paper.spoon"; 104 }; 105 }; 106 expr = { 107 classOne = (evalMod "classOne" flake.modules.classOne.aspectOne).foo; 108 classTwo = (evalMod "classTwo" flake.modules.classTwo.aspectOne).foo; 109 }; 110 expected = { 111 classOne = "niri"; 112 classTwo = "paper.spoon"; 113 }; 114 in 115 { 116 inherit expr expected; 117 }; 118 119 aspects."test dependencies on aspects" = 120 let 121 flake = mkFlake { 122 flake.aspects = 123 { aspects, ... }: 124 { 125 aspectOne = { 126 description = "os config"; 127 includes = with aspects; [ aspectTwo ]; 128 classOne.bar = [ "os" ]; 129 }; 130 131 aspectTwo = { 132 description = "user config at os level"; 133 classOne.bar = [ "user" ]; 134 }; 135 }; 136 }; 137 expr = lib.sort (a: b: a < b) (evalMod "classOne" flake.modules.classOne.aspectOne).bar; 138 expected = [ 139 "os" 140 "user" 141 ]; 142 in 143 { 144 inherit expr expected; 145 }; 146 147 aspects."test provides" = 148 let 149 flake = mkFlake { 150 flake.aspects = 151 { aspects, ... }: 152 { 153 aspectOne.includes = with aspects.aspectTwo.provides; [ 154 foo 155 bar 156 ]; 157 aspectOne.classOne = { }; # must be present for mixing dependencies. 158 aspectTwo = { 159 classOne.bar = [ "class one not included" ]; 160 classTwo.bar = [ "class two not included" ]; 161 provides.foo = 162 { class, aspect-chain }: 163 { 164 name = "aspectTwo.foo"; 165 description = "aspectTwo foo provided"; 166 includes = [ aspects.aspectThree.provides.moo ]; 167 classOne.bar = [ "two:${class}:${lib.concatStringsSep "/" aspect-chain}" ]; 168 classTwo.bar = [ "foo class two not included" ]; 169 }; 170 provides.bar = _: { 171 # classOne is missing on bar 172 classTwo.bar = [ "bar class two not included" ]; 173 }; 174 }; 175 aspectThree.provides.moo = 176 { aspect-chain, class }: 177 { 178 classOne.bar = [ "three:${class}:${lib.concatStringsSep "/" aspect-chain}" ]; 179 }; 180 }; 181 }; 182 expr = lib.sort (a: b: a < b) (evalMod "classOne" flake.modules.classOne.aspectOne).bar; 183 expected = [ 184 "three:classOne:aspectOne/aspectTwo.foo" 185 "two:classOne:aspectOne" 186 ]; 187 in 188 { 189 inherit expr expected; 190 }; 191 192 aspects."test provides using fixpoints" = 193 let 194 flake = mkFlake { 195 flake.aspects = 196 { aspects, ... }: 197 { 198 aspectOne = { 199 classOne.bar = [ "1" ]; 200 includes = [ 201 aspects.aspectTwo 202 ]; 203 }; 204 205 aspectTwo = 206 { aspect, ... }: 207 { 208 classOne.bar = [ "2" ]; 209 includes = [ aspect.provides.three-and-four-and-five ]; 210 provides = 211 { provides, ... }: 212 { 213 three-and-four-and-five = _: { 214 classOne.bar = [ "3" ]; 215 includes = [ 216 provides.four 217 aspects.five 218 ]; 219 }; 220 four = _: { 221 classOne.bar = [ "4" ]; 222 }; 223 }; 224 }; 225 226 five.classOne.bar = [ "5" ]; 227 }; 228 }; 229 230 expr = lib.sort (a: b: a < b) (evalMod "classOne" flake.modules.classOne.aspectOne).bar; 231 expected = [ 232 "1" 233 "2" 234 "3" 235 "4" 236 "5" 237 ]; 238 in 239 { 240 inherit expr expected; 241 }; 242 }; 243 244 }; 245}