Modular, context-aware and aspect-oriented dendritic Nix configurations. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ den.oeiuwq.com
configurations den dendritic nix aspect oriented

Add more tests

+36 -10
+10 -8
nix/lib.nix
··· 67 68 parametric.atLeast = funk (lib.flip take.atLeast); 69 parametric.exactly = funk (lib.flip take.exactly); 70 - parametric.fixedTo = lib.flip parametric.atLeast; 71 - parametric.expands = attrs: funk (ctx: (lib.flip take.atLeast) (ctx // attrs)); 72 parametric.withOwn = 73 - aspect: 74 aspect 75 // { 76 __functor = self: ctx: { 77 includes = [ 78 - (parametric.atLeast self ctx) 79 (owned self) 80 ({ 81 includes = map (applyStatics ctx) self.includes; ··· 84 }; 85 }; 86 parametric.__functor = 87 - self: arg: 88 if arg == true then 89 - self.atLeast 90 else if arg == false then 91 - self.exactly 92 else if builtins.isAttrs arg then 93 - self.withOwn arg 94 else 95 funk arg; 96
··· 67 68 parametric.atLeast = funk (lib.flip take.atLeast); 69 parametric.exactly = funk (lib.flip take.exactly); 70 + parametric.fixedTo = lib.flip (parametric.withOwn parametric.atLeast); 71 + parametric.expands = 72 + attrs: aspect: ctx: 73 + parametric.fixedTo (ctx // attrs) aspect; 74 parametric.withOwn = 75 + functor: aspect: 76 aspect 77 // { 78 __functor = self: ctx: { 79 includes = [ 80 + (functor self ctx) 81 (owned self) 82 ({ 83 includes = map (applyStatics ctx) self.includes; ··· 86 }; 87 }; 88 parametric.__functor = 89 + _: arg: 90 if arg == true then 91 + parametric.atLeast 92 else if arg == false then 93 + parametric.exactly 94 else if builtins.isAttrs arg then 95 + parametric.withOwn parametric.atLeast arg 96 else 97 funk arg; 98
+26 -2
templates/examples/modules/_example/ci/parametric-with-owned.nix
··· 6 b = strOpt; 7 c = strOpt; 8 d = strOpt; 9 }; 10 strOpt = lib.mkOption { type = lib.types.str; }; 11 in 12 { 13 ··· 21 # its owned configs and static (non-functional) includes. 22 # Usage: just call `parametric` with an aspect. 23 # or alternatively, set `__functor = den.lib.parametric;` 24 - den.aspects.fwd._.first = den.lib.parametric { 25 nixos.fwd.a = "First owned A"; 26 includes = [ 27 den.aspects.fwd._.second 28 { nixos.fwd.d = "First static includes D"; } 29 den.aspects.fwd._.never 30 ]; 31 }; 32 ··· 34 # the first aspect forwards whatever context it receives. 35 den.aspects.fwd._.second = 36 { host, ... }: 37 - { 38 nixos.fwd.b = "Second owned B for ${host.name}"; 39 }; 40 41 den.aspects.fwd._.never = ··· 52 && rockhopper.config.fwd.b == "Second owned B for rockhopper" 53 && rockhopper.config.fwd.c == "host owned C" 54 && rockhopper.config.fwd.d == "First static includes D" 55 ); 56 }; 57
··· 6 b = strOpt; 7 c = strOpt; 8 d = strOpt; 9 + e = strOpt; 10 + f = strOpt; 11 }; 12 strOpt = lib.mkOption { type = lib.types.str; }; 13 + 14 + inherit (den.lib) parametric; 15 in 16 { 17 ··· 25 # its owned configs and static (non-functional) includes. 26 # Usage: just call `parametric` with an aspect. 27 # or alternatively, set `__functor = den.lib.parametric;` 28 + den.aspects.fwd._.first = parametric { 29 nixos.fwd.a = "First owned A"; 30 includes = [ 31 den.aspects.fwd._.second 32 { nixos.fwd.d = "First static includes D"; } 33 den.aspects.fwd._.never 34 + den.aspects.fwd._.fourth 35 ]; 36 }; 37 ··· 39 # the first aspect forwards whatever context it receives. 40 den.aspects.fwd._.second = 41 { host, ... }: 42 + parametric.fixedTo { third = "Impact"; } { 43 nixos.fwd.b = "Second owned B for ${host.name}"; 44 + includes = [ den.aspects.fwd._.third ]; 45 + }; 46 + 47 + den.aspects.fwd._.third = 48 + { third, ... }: 49 + { 50 + nixos.fwd.e = "Third ${third}"; 51 + }; 52 + 53 + den.aspects.fwd._.fourth = parametric.expands { planet = "Earth"; } { 54 + includes = [ den.aspects.fwd._.fifth ]; 55 + }; 56 + 57 + den.aspects.fwd._.fifth = 58 + { host, planet, ... }: 59 + { 60 + nixos.fwd.f = "Fifth ${planet} ${host.name}"; 61 }; 62 63 den.aspects.fwd._.never = ··· 74 && rockhopper.config.fwd.b == "Second owned B for rockhopper" 75 && rockhopper.config.fwd.c == "host owned C" 76 && rockhopper.config.fwd.d == "First static includes D" 77 + && rockhopper.config.fwd.e == "Third Impact" 78 + && rockhopper.config.fwd.f == "Fifth Earth rockhopper" 79 ); 80 }; 81