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
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}