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

move context apply functions to own file (#218)

authored by oeiuwq.com and committed by

GitHub d40fa311 6d847540

+114 -114
+2 -2
docs/src/content/docs/guides/home-manager.mdx
··· 25 25 # Per user 26 26 den.hosts.x86_64-linux.igloo.users.tux.classes = [ "homeManager" "hjem" ]; 27 27 28 - # Globally for all users 29 - den.base.user.classes = [ "homeManager" ]; 28 + # As default for all users, unless they specify other classes. 29 + den.base.user.classes = lib.mkDefault [ "homeManager" ]; 30 30 ``` 31 31 32 32 Home integration contexts, like `den.ctx.hm-host` only activate when
+1 -3
modules/_types.nix nix/types.nix
··· 1 1 { 2 2 inputs, 3 3 lib, 4 - config, 4 + den, 5 5 ... 6 6 }: 7 7 let 8 - inherit (config) den; 9 - 10 8 hostsOption = lib.mkOption { 11 9 description = "den hosts definition"; 12 10 default = { };
+13 -11
modules/aspects/provides/home-manager/hm-integration.nix
··· 46 46 den.provides.home-manager = 47 47 _: 48 48 throw '' 49 - NOTICE: den.provides.home-manager aspect is not used anymore. 50 - See https://den.oeiuwq.com/guides/home-manager/ 49 + NOTICE: den.provides.home-manager aspect is not used anymore. 50 + See https://den.oeiuwq.com/guides/home-manager/ 51 51 52 - Home Manager is now enabled via host config: 52 + Since den.ctx.hm-host requires least one user with homeManager class, 53 + Home Manager is now enabled via options. 53 54 54 - # den.ctx.hm-host requires least one user with homeManager class. 55 - den.hosts.x86_64-linux.igloo.users.tux.classes = [ "homeManager" ]; 55 + For all users unless they set a value: 56 56 57 - Globally: 57 + den.base.user.classes = lib.mkDefault [ "homeManager" ]; 58 58 59 - den.base.user.classes = [ "homeManager" ]; 59 + On specific users: 60 60 61 - See <den/home-manager/hm-os.nix> 61 + den.hosts.x86_64-linux.igloo.users.tux.classes = [ "homeManager" ]; 62 62 63 - If you had includes at den._.home-manager, you can use: 63 + See <den/home-manager/hm-os.nix> 64 64 65 - den.ctx.hm-host.includes = [ ... ]; 65 + If you had includes at den._.home-manager, you can use: 66 66 67 - For attaching aspects to home-manager enabled hosts. 67 + den.ctx.hm-host.includes = [ ... ]; 68 + 69 + For attaching aspects to home-manager enabled hosts. 68 70 ''; 69 71 70 72 den.ctx.home.description = "Standalone Home-Manager config provided by home aspect";
+9 -88
modules/context/types.nix
··· 1 1 { den, lib, ... }: 2 2 let 3 - inherit (den.lib) parametric; 4 - inherit (den.lib.aspects.types) aspectSubmodule providerType; 3 + inherit (den.lib.aspects.types) aspectSubmodule; 4 + 5 + ctxApply = import ./../../nix/ctx-apply.nix { inherit lib den; }; 5 6 6 - ctxType = lib.types.submodule ( 7 - { name, config, ... }: 7 + # a context-definiton is an aspect extended with into.* transformations 8 + # and a fixed functor to apply them. 9 + ctxSubmodule = lib.types.submodule ( 10 + { config, ... }: 8 11 { 9 12 imports = aspectSubmodule.getSubModules; 10 13 options.into = lib.mkOption { ··· 12 15 type = lib.types.lazyAttrsOf (lib.types.functionTo (lib.types.listOf lib.types.raw)); 13 16 default = { }; 14 17 }; 15 - config.__functor = lib.mkForce (ctxApply config.name); 18 + config.__functor = lib.mkForce ctxApply; 16 19 } 17 20 ); 18 21 19 - cleanCtx = 20 - self: 21 - builtins.removeAttrs self [ 22 - "name" 23 - "description" 24 - "into" 25 - "provides" 26 - "__functor" 27 - "modules" 28 - "resolve" 29 - "_module" 30 - "_" 31 - ]; 32 - 33 - collectPairs = 34 - source: self: ctx: 35 - [ 36 - { 37 - inherit ctx source; 38 - ctxDef = self; 39 - } 40 - ] 41 - ++ lib.concatLists ( 42 - lib.mapAttrsToList ( 43 - n: into: lib.concatMap (v: collectPairs self den.ctx.${n} v) (into ctx) 44 - ) self.into 45 - ); 46 - 47 - dedupIncludes = 48 - let 49 - crossProvider = 50 - p: 51 - let 52 - src = p.source; 53 - n = p.ctxDef.name; 54 - in 55 - if src == null then (_: { }) else src.provides.${n} or (_: { }); 56 - 57 - go = 58 - acc: remaining: 59 - if remaining == [ ] then 60 - acc.result 61 - else 62 - let 63 - p = builtins.head remaining; 64 - rest = builtins.tail remaining; 65 - n = p.ctxDef.name; 66 - clean = cleanCtx p.ctxDef; 67 - isFirst = !(acc.seen ? ${n}); 68 - selfProvider = p.ctxDef.provides.${n} or (_: { }); 69 - cross = crossProvider p; 70 - items = 71 - if isFirst then 72 - [ 73 - (parametric.fixedTo p.ctx clean) 74 - (selfProvider p.ctx) 75 - (cross p.ctx) 76 - ] 77 - else 78 - [ 79 - (parametric.atLeast clean p.ctx) 80 - (selfProvider p.ctx) 81 - (cross p.ctx) 82 - ]; 83 - in 84 - go { 85 - seen = acc.seen // { 86 - ${n} = true; 87 - }; 88 - result = acc.result ++ items; 89 - } rest; 90 - in 91 - pairs: 92 - go { 93 - seen = { }; 94 - result = [ ]; 95 - } pairs; 96 - 97 - ctxApply = ctxName: _self: ctx: { 98 - includes = dedupIncludes (collectPairs null den.ctx.${ctxName} ctx); 99 - }; 100 - 101 22 in 102 23 { 103 24 options.den.ctx = lib.mkOption { 104 25 default = { }; 105 - type = lib.types.lazyAttrsOf ctxType; 26 + type = lib.types.lazyAttrsOf ctxSubmodule; 106 27 }; 107 28 }
+5 -4
modules/options.nix
··· 5 5 ... 6 6 }: 7 7 let 8 - types = import ./_types.nix { inherit inputs lib config; }; 8 + inherit (config) den; 9 + types = import ./../nix/types.nix { inherit inputs lib den; }; 9 10 baseMod = lib.mkOption { 10 11 type = lib.types.deferredModule; 11 12 default = { }; ··· 21 22 home = baseMod; 22 23 }; 23 24 config.den.base = { 24 - host.imports = [ config.den.base.conf ]; 25 - user.imports = [ config.den.base.conf ]; 26 - home.imports = [ config.den.base.conf ]; 25 + host.imports = [ den.base.conf ]; 26 + user.imports = [ den.base.conf ]; 27 + home.imports = [ den.base.conf ]; 27 28 }; 28 29 }
+81
nix/ctx-apply.nix
··· 1 + { lib, den, ... }: 2 + let 3 + inherit (den.lib) parametric; 4 + 5 + cleanCtx = 6 + self: 7 + builtins.removeAttrs self [ 8 + "name" 9 + "description" 10 + "into" 11 + "provides" 12 + "__functor" 13 + "modules" 14 + "resolve" 15 + "_module" 16 + "_" 17 + ]; 18 + 19 + transformAll = 20 + source: self: ctx: 21 + [ 22 + { 23 + inherit ctx source; 24 + ctxDef = self; 25 + } 26 + ] 27 + ++ lib.concatLists ( 28 + lib.mapAttrsToList ( 29 + name: into: lib.concatMap (transformAll self den.ctx.${name}) (into ctx) 30 + ) self.into 31 + ); 32 + 33 + noop = _: { }; 34 + 35 + crossProvider = 36 + p: 37 + let 38 + src = p.source; 39 + name = p.ctxDef.name; 40 + in 41 + if src == null then noop else src.provides.${name} or noop; 42 + 43 + dedupIncludes = 44 + let 45 + go = 46 + acc: remaining: 47 + if remaining == [ ] then 48 + acc.result 49 + else 50 + let 51 + p = builtins.head remaining; 52 + rest = builtins.tail remaining; 53 + name = p.ctxDef.name; 54 + clean = cleanCtx p.ctxDef; 55 + isFirst = !(acc.seen ? ${name}); 56 + selfFun = p.ctxDef.provides.${name} or noop; 57 + crossFun = crossProvider p; 58 + items = [ 59 + (if isFirst then parametric.fixedTo p.ctx clean else parametric.atLeast clean p.ctx) 60 + (selfFun p.ctx) 61 + (crossFun p.ctx) 62 + ]; 63 + in 64 + go { 65 + seen = acc.seen // { 66 + ${name} = true; 67 + }; 68 + result = acc.result ++ items; 69 + } rest; 70 + in 71 + go { 72 + seen = { }; 73 + result = [ ]; 74 + }; 75 + 76 + ctxApply = self: ctx: { 77 + includes = dedupIncludes (transformAll null self ctx); 78 + }; 79 + 80 + in 81 + ctxApply
+1 -4
templates/bogus/modules/bug.nix
··· 12 12 }: 13 13 { 14 14 # replace <system> if you are reporting a bug in MacOS 15 - den.hosts.x86_64-linux.igloo.users.tux.classes = [ 16 - "user" 17 - "homeManager" 18 - ]; 15 + den.hosts.x86_64-linux.igloo.users.tux = { }; 19 16 20 17 # do something for testing 21 18 den.aspects.tux.user.description = "The Penguin";
+1
templates/bogus/modules/test-base.nix
··· 34 34 boot.loader.grub.enable = lib.mkForce false; 35 35 fileSystems."/".device = lib.mkForce "/dev/fake"; 36 36 }; 37 + den.base.user.classes = lib.mkDefault [ "homeManager " ]; 37 38 }; 38 39 39 40 testModule = {
-1
templates/ci/modules/features/user-classes.nix
··· 22 22 23 23 expr = lib.sort (a: b: a < b) den.hosts.x86_64-linux.igloo.users.tux.classes; 24 24 expected = [ 25 - "homeManager" # this one comes from globally enabled at test support. 26 25 "homeManager" 27 26 "maid" 28 27 ];
+1 -1
templates/ci/modules/test-support/eval-den.nix
··· 31 31 options.flake.packages = lib.mkOption { }; 32 32 options.expr = lib.mkOption { }; 33 33 options.expected = lib.mkOption { }; 34 - config.den.base.user.classes = [ "homeManager" ]; 34 + config.den.base.user.classes = lib.mkDefault [ "homeManager" ]; 35 35 }; 36 36 37 37 helpersModule =