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

remove duplicate code between homes (#229)

authored by oeiuwq.com and committed by

GitHub 8affc5ca 94b8721b

+225 -202
+19 -19
modules/aspects/provides/hjem/hjem-integration.nix
··· 1 - { den, lib, ... }: 2 let 3 hjemClass = "hjem"; 4 5 - intoHjemUsers = 6 - { host }: 7 - map (user: { inherit host user; }) ( 8 - lib.filter (u: lib.elem hjemClass u.classes) (lib.attrValues host.users) 9 - ); 10 - 11 - forwardedToHost = 12 - { host, user }: 13 - den._.forward { 14 - each = lib.singleton true; 15 - fromClass = _: hjemClass; 16 - intoClass = _: host.class; 17 - intoPath = _: [ 18 "hjem" 19 "users" 20 user.userName 21 ]; 22 - fromAspect = _: den.aspects.${user.aspect}; 23 - }; 24 - 25 in 26 { 27 - den.ctx.hjem-host.into.hjem-user = intoHjemUsers; 28 - den.ctx.hjem-user._.hjem-user = forwardedToHost; 29 }
··· 1 + { 2 + den, 3 + lib, 4 + inputs, 5 + ... 6 + }: 7 let 8 + inherit (den.lib.home-env) 9 + intoClassUsers 10 + forwardToHost 11 + ; 12 + 13 hjemClass = "hjem"; 14 15 + ctx.hjem-host.into.hjem-user = intoClassUsers hjemClass; 16 + ctx.hjem-user._.hjem-user = forwardToHost { 17 + className = hjemClass; 18 + forwardPathFn = 19 + { user, ... }: 20 + [ 21 "hjem" 22 "users" 23 user.userName 24 ]; 25 + }; 26 in 27 { 28 + den.ctx = ctx; 29 }
+16 -26
modules/aspects/provides/hjem/hjem-os.nix
··· 5 ... 6 }: 7 let 8 hjemClass = "hjem"; 9 hjemOsClasses = [ 10 "nixos" 11 "darwin" 12 ]; 13 14 - hostConf = 15 - { host, ... }: 16 - { 17 - options.hjem = { 18 - enable = lib.mkOption { 19 - type = lib.types.bool; 20 - default = den.lib.host-has-user-with-class host hjemClass; 21 - }; 22 - module = lib.mkOption { 23 - type = lib.types.deferredModule; 24 - default = inputs.hjem."${host.class}Modules".default; 25 - }; 26 - }; 27 - }; 28 - 29 - hjemDetect = 30 - { host }: 31 - let 32 - isOsSupported = builtins.elem host.class hjemOsClasses; 33 - hjemUsers = builtins.filter (u: lib.elem hjemClass u.classes) (lib.attrValues host.users); 34 - hasHjemUsers = builtins.length hjemUsers > 0; 35 - isHjemHost = host.hjem.enable && isOsSupported && hasHjemUsers; 36 - in 37 - lib.optional isHjemHost { inherit host; }; 38 - 39 - ctx.host.into.hjem-host = hjemDetect; 40 41 ctx.hjem-host._.hjem-host = 42 { host }: ··· 44 ${host.class}.imports = [ host.hjem.module ]; 45 }; 46 47 in 48 { 49 den.ctx = ctx;
··· 5 ... 6 }: 7 let 8 + inherit (den.lib.home-env) 9 + detectHost 10 + hostOptions 11 + ; 12 + 13 hjemClass = "hjem"; 14 hjemOsClasses = [ 15 "nixos" 16 "darwin" 17 ]; 18 19 + ctx.host.into.hjem-host = detectHost { 20 + className = hjemClass; 21 + supportedOses = hjemOsClasses; 22 + optionPath = "hjem"; 23 + }; 24 25 ctx.hjem-host._.hjem-host = 26 { host }: ··· 28 ${host.class}.imports = [ host.hjem.module ]; 29 }; 30 31 + hostConf = hostOptions { 32 + className = hjemClass; 33 + optionPath = "hjem"; 34 + inputsPath = "hjem"; 35 + getModule = { host, ... }: inputs.hjem."${host.class}Modules".default; 36 + }; 37 in 38 { 39 den.ctx = ctx;
+38 -57
modules/aspects/provides/home-manager/hm-integration.nix
··· 5 ... 6 }: 7 let 8 - inherit (den.lib) parametric; 9 - 10 - description = '' 11 - integrates home-manager into nixos/darwin OS classes. 12 - 13 - Does nothing for hosts that have no users with `homeManager` class. 14 - Expects `inputs.home-manager` to exist. If `<host>.hm-module` exists 15 - it is the home-manager.{nixos/darwin}Modules.home-manager. 16 17 - For each user produces a `den.ctx.hm` context, and 18 - forwards the `homeManager` class into os-level 19 - `home-manager.home-manager.users.<user>` 20 - ''; 21 22 hmClass = "homeManager"; 23 24 - intoHmUsers = 25 - { host }: 26 - map (user: { inherit host user; }) ( 27 - lib.filter (u: lib.elem hmClass u.classes) (lib.attrValues host.users) 28 - ); 29 30 - forwardedToHost = 31 - { host, user }: 32 - den._.forward { 33 - each = lib.singleton true; 34 - fromClass = _: hmClass; 35 - intoClass = _: host.class; 36 - intoPath = _: [ 37 - "home-manager" 38 - "users" 39 - user.userName 40 - ]; 41 - fromAspect = _: (den.ctx.hm-internal-user { inherit host user; }); 42 - }; 43 44 - in 45 - { 46 - den.provides.home-manager = 47 - _: 48 - throw '' 49 - NOTICE: den.provides.home-manager aspect is not used anymore. 50 - See https://den.oeiuwq.com/guides/home-manager/ 51 52 - Since den.ctx.hm-host requires least one user with homeManager class, 53 - Home Manager is now enabled via options. 54 55 - For all users unless they set a value: 56 57 - den.base.user.classes = lib.mkDefault [ "homeManager" ]; 58 59 - On specific users: 60 61 - den.hosts.x86_64-linux.igloo.users.tux.classes = [ "homeManager" ]; 62 63 - See <den/home-manager/hm-os.nix> 64 65 - If you had includes at den._.home-manager, you can use: 66 67 - den.ctx.hm-host.includes = [ ... ]; 68 69 - For attaching aspects to home-manager enabled hosts. 70 - ''; 71 72 - den.ctx.home.description = "Standalone Home-Manager config provided by home aspect"; 73 - den.ctx.home._.home = { home }: parametric.fixedTo { inherit home; } den.aspects.${home.aspect}; 74 - den.ctx.home.into.default = lib.singleton; 75 - 76 - den.ctx.hm-host.into.hm-user = intoHmUsers; 77 - den.ctx.hm-user.description = "(internal)"; 78 - den.ctx.hm-user._.hm-user = forwardedToHost; 79 - 80 - den.ctx.hm-internal-user._.hm-internal-user = 81 { host, user }: 82 { class, aspect-chain }: 83 { ··· 88 (parametric.atLeast den.aspects.${host.aspect} { inherit host user; }) 89 ]; 90 }; 91 }
··· 5 ... 6 }: 7 let 8 + inherit (den.lib.home-env) 9 + intoClassUsers 10 + forwardToHost 11 + ; 12 13 + inherit (den.lib) parametric; 14 15 hmClass = "homeManager"; 16 17 + hm-aspect-deprecated = '' 18 + NOTICE: den.provides.home-manager aspect is not used anymore. 19 + See https://den.oeiuwq.com/guides/home-manager/ 20 21 + Since den.ctx.hm-host requires least one user with homeManager class, 22 + Home Manager is now enabled via options. 23 24 + For all users unless they set a value: 25 26 + den.base.user.classes = lib.mkDefault [ "homeManager" ]; 27 28 + On specific users: 29 30 + den.hosts.x86_64-linux.igloo.users.tux.classes = [ "homeManager" ]; 31 32 + See <den/home-manager/hm-os.nix> 33 34 + If you had includes at den._.home-manager, you can use: 35 36 + den.ctx.hm-host.includes = [ ... ]; 37 38 + For attaching aspects to home-manager enabled hosts. 39 + ''; 40 41 + ctx.home.provides.home = { home }: parametric.fixedTo { inherit home; } den.aspects.${home.aspect}; 42 + ctx.home.into.default = lib.singleton; 43 44 + ctx.hm-host.into.hm-user = intoClassUsers hmClass; 45 + ctx.hm-user.provides.hm-user = forwardToHost { 46 + className = hmClass; 47 + forwardPathFn = 48 + { user, ... }: 49 + [ 50 + "home-manager" 51 + "users" 52 + user.userName 53 + ]; 54 + aspectFn = den.ctx.hm-user-internal; 55 + }; 56 57 + ctx.hm-user-internal.provides.hm-user-internal = 58 { host, user }: 59 { class, aspect-chain }: 60 { ··· 65 (parametric.atLeast den.aspects.${host.aspect} { inherit host user; }) 66 ]; 67 }; 68 + in 69 + { 70 + den.provides.home-manager = _: throw hm-aspect-deprecated; 71 + den.ctx = ctx; 72 }
+18 -44
modules/aspects/provides/home-manager/hm-os.nix
··· 5 ... 6 }: 7 let 8 - description = '' 9 - Detects hosts that have an HM supported OS and 10 - that have at least one user with ${hm-class} class. 11 - 12 - When this occurs it produces a context `den.ctx.hm-host` 13 - 14 - This `den.ctx.hm-os` context includes the OS-level 15 - homeManager module and is used by hm-integration.nix to then 16 - produce a `den.ctx.hm-user` for each user. 17 18 - This same context can be used to include aspects 19 - ONLY for hosts having HM enabled. 20 - 21 - den.ctx.hm-host.includes = [ den.aspects.foo ]; 22 - ''; 23 - 24 - hm-class = "homeManager"; 25 - hm-os-classes = [ 26 "nixos" 27 "darwin" 28 ]; 29 30 - hostConf = 31 - { host, ... }: 32 - { 33 - options.home-manager = { 34 - enable = lib.mkOption { 35 - type = lib.types.bool; 36 - default = den.lib.host-has-user-with-class host hm-class; 37 - }; 38 - module = lib.mkOption { 39 - type = lib.types.deferredModule; 40 - default = inputs.home-manager."${host.class}Modules".home-manager; 41 - }; 42 - }; 43 - }; 44 45 - hm-detect = 46 - { host }: 47 - let 48 - is-os-supported = builtins.elem host.class hm-os-classes; 49 - hm-users = builtins.filter (u: lib.elem hm-class u.classes) (lib.attrValues host.users); 50 - has-hm-users = builtins.length hm-users > 0; 51 - is-hm-host = host.home-manager.enable && is-os-supported && has-hm-users; 52 - in 53 - lib.optional is-hm-host { inherit host; }; 54 - 55 - ctx.host.into.hm-host = hm-detect; 56 - 57 - ctx.hm-host.description = description; 58 ctx.hm-host.provides.hm-host = 59 { host }: 60 { 61 ${host.class}.imports = [ host.home-manager.module ]; 62 }; 63 64 in 65 {
··· 5 ... 6 }: 7 let 8 + inherit (den.lib.home-env) 9 + detectHost 10 + hostOptions 11 + ; 12 13 + hmClass = "homeManager"; 14 + hmOsClasses = [ 15 "nixos" 16 "darwin" 17 ]; 18 19 + ctx.host.into.hm-host = detectHost { 20 + className = hmClass; 21 + supportedOses = hmOsClasses; 22 + optionPath = "home-manager"; 23 + }; 24 25 ctx.hm-host.provides.hm-host = 26 { host }: 27 { 28 ${host.class}.imports = [ host.home-manager.module ]; 29 }; 30 + 31 + hostConf = hostOptions { 32 + className = hmClass; 33 + optionPath = "home-manager"; 34 + inputsPath = "home-manager"; 35 + getModule = { host, ... }: inputs.home-manager."${host.class}Modules".home-manager; 36 + }; 37 38 in 39 {
+19 -18
modules/aspects/provides/maid/maid-integration.nix
··· 1 - { den, lib, ... }: 2 let 3 maidClass = "maid"; 4 5 - intoMaidUsers = 6 - { host }: 7 - map (user: { inherit host user; }) ( 8 - lib.filter (u: lib.elem maidClass u.classes) (lib.attrValues host.users) 9 - ); 10 - 11 - forwardedToHost = 12 - { host, user }: 13 - den._.forward { 14 - each = lib.singleton true; 15 - fromClass = _: maidClass; 16 - intoClass = _: host.class; 17 - intoPath = _: [ 18 "users" 19 "users" 20 user.userName 21 "maid" 22 ]; 23 - fromAspect = _: den.aspects.${user.aspect}; 24 - }; 25 26 in 27 { 28 - den.ctx.maid-host.into.maid-user = intoMaidUsers; 29 - den.ctx.maid-user._.maid-user = forwardedToHost; 30 }
··· 1 + { 2 + den, 3 + lib, 4 + inputs, 5 + ... 6 + }: 7 let 8 + inherit (den.lib.home-env) 9 + intoClassUsers 10 + forwardToHost 11 + ; 12 + 13 maidClass = "maid"; 14 15 + ctx.maid-host.into.maid-user = intoClassUsers maidClass; 16 + ctx.maid-user._.maid-user = forwardToHost { 17 + className = maidClass; 18 + forwardPathFn = 19 + { user, ... }: 20 + [ 21 "users" 22 "users" 23 user.userName 24 "maid" 25 ]; 26 + }; 27 28 in 29 { 30 + den.ctx = ctx; 31 }
+19 -29
modules/aspects/provides/maid/maid-os.nix
··· 5 ... 6 }: 7 let 8 - maidClass = "maid"; 9 - maidOsClasses = [ 10 - "nixos" 11 - ]; 12 - 13 - hostConf = 14 - { host, ... }: 15 - { 16 - options.nix-maid = { 17 - enable = lib.mkOption { 18 - type = lib.types.bool; 19 - default = den.lib.host-has-user-with-class host maidClass; 20 - }; 21 - module = lib.mkOption { 22 - type = lib.types.deferredModule; 23 - default = inputs.nix-maid.nixosModules.default; 24 - }; 25 - }; 26 - }; 27 28 - maidDetect = 29 - { host }: 30 - let 31 - isOsSupported = builtins.elem host.class maidOsClasses; 32 - maidUsers = builtins.filter (u: lib.elem maidClass u.classes) (lib.attrValues host.users); 33 - hasMaidUsers = builtins.length maidUsers > 0; 34 - isMaidHost = host.nix-maid.enable && isOsSupported && hasMaidUsers; 35 - in 36 - lib.optional isMaidHost { inherit host; }; 37 38 - ctx.host.into.maid-host = maidDetect; 39 40 ctx.maid-host._.maid-host = 41 { host }: 42 { 43 ${host.class}.imports = [ host.nix-maid.module ]; 44 }; 45 in 46 { 47 den.ctx = ctx;
··· 5 ... 6 }: 7 let 8 + inherit (den.lib.home-env) 9 + detectHost 10 + hostOptions 11 + ; 12 13 + maidClass = "maid"; 14 + maidOsClasses = [ "nixos" ]; 15 16 + ctx.host.into.maid-host = detectHost { 17 + className = maidClass; 18 + supportedOses = maidOsClasses; 19 + optionPath = "nix-maid"; 20 + }; 21 22 ctx.maid-host._.maid-host = 23 { host }: 24 { 25 ${host.class}.imports = [ host.nix-maid.module ]; 26 }; 27 + 28 + hostConf = hostOptions { 29 + className = maidClass; 30 + optionPath = "nix-maid"; 31 + inputsPath = "nix-maid"; 32 + getModule = { host, ... }: inputs.nix-maid.nixosModules.default; 33 + }; 34 + 35 in 36 { 37 den.ctx = ctx;
-9
modules/aspects/provides/os-user.nix
··· 47 in 48 { 49 den.ctx.user.includes = [ fwd ]; 50 - 51 - den.lib.host-has-user-with-class = 52 - host: class: 53 - lib.pipe host.users [ 54 - (lib.attrValues) 55 - (map (user: lib.elem class user.classes)) 56 - (lib.filter lib.id) 57 - (xs: lib.length xs > 0) 58 - ]; 59 }
··· 47 in 48 { 49 den.ctx.user.includes = [ fwd ]; 50 }
+93
nix/home-env.nix
···
··· 1 + { 2 + den, 3 + lib, 4 + inputs, 5 + ... 6 + }: 7 + let 8 + atPath = path: obj: lib.foldr (key: obj: obj.${key} or { }) obj path; 9 + 10 + host-has-user-with-class = 11 + host: class: 12 + lib.pipe host.users [ 13 + (lib.attrValues) 14 + (map (user: lib.elem class user.classes)) 15 + (lib.filter lib.id) 16 + (xs: lib.length xs > 0) 17 + ]; 18 + 19 + detectHost = 20 + { 21 + className, 22 + supportedOses ? [ 23 + "nixos" 24 + "darwin" 25 + ], 26 + optionPath, 27 + }: 28 + { host }: 29 + let 30 + isOsSupported = builtins.elem host.class supportedOses; 31 + classUsers = builtins.filter (u: lib.elem className u.classes) (lib.attrValues host.users); 32 + hasClassUsers = builtins.length classUsers > 0; 33 + getOption = atPath (lib.splitString "." optionPath); 34 + isEnabled = (getOption host).enable or false; 35 + shouldActivate = isEnabled && isOsSupported && hasClassUsers; 36 + in 37 + lib.optional shouldActivate { inherit host; }; 38 + 39 + hostOptions = 40 + { 41 + className, 42 + optionPath, 43 + inputsPath, 44 + getModule, 45 + }: 46 + { host, ... }: 47 + { 48 + options.${optionPath} = { 49 + enable = lib.mkOption { 50 + type = lib.types.bool; 51 + default = host-has-user-with-class host className; 52 + }; 53 + module = lib.mkOption { 54 + type = lib.types.deferredModule; 55 + default = getModule { inherit host inputs; }; 56 + }; 57 + }; 58 + }; 59 + 60 + intoClassUsers = 61 + className: 62 + { host }: 63 + map (user: { inherit host user; }) ( 64 + lib.filter (u: lib.elem className u.classes) (lib.attrValues host.users) 65 + ); 66 + 67 + forwardToHost = 68 + { 69 + className, 70 + forwardPathFn, 71 + aspectFn ? null, 72 + }: 73 + { host, user }: 74 + let 75 + aspect = if aspectFn != null then aspectFn { inherit host user; } else den.aspects.${user.aspect}; 76 + in 77 + den._.forward { 78 + each = lib.singleton true; 79 + fromClass = _: className; 80 + intoClass = _: host.class; 81 + intoPath = _: forwardPathFn { inherit host user; }; 82 + fromAspect = _: aspect; 83 + }; 84 + 85 + in 86 + { 87 + inherit 88 + detectHost 89 + hostOptions 90 + intoClassUsers 91 + forwardToHost 92 + ; 93 + }
+3
nix/lib.nix
··· 115 116 ctxApply = import ./ctx-apply.nix { inherit lib den; }; 117 118 den-lib = { 119 inherit 120 parametric ··· 128 isStatic 129 ctxApply 130 nh 131 ; 132 }; 133 in
··· 115 116 ctxApply = import ./ctx-apply.nix { inherit lib den; }; 117 118 + home-env = import ./home-env.nix { inherit lib den inputs; }; 119 + 120 den-lib = { 121 inherit 122 parametric ··· 130 isStatic 131 ctxApply 132 nh 133 + home-env 134 ; 135 }; 136 in