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, ... }: 1 + { 2 + den, 3 + lib, 4 + inputs, 5 + ... 6 + }: 2 7 let 8 + inherit (den.lib.home-env) 9 + intoClassUsers 10 + forwardToHost 11 + ; 12 + 3 13 hjemClass = "hjem"; 4 14 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 = _: [ 15 + ctx.hjem-host.into.hjem-user = intoClassUsers hjemClass; 16 + ctx.hjem-user._.hjem-user = forwardToHost { 17 + className = hjemClass; 18 + forwardPathFn = 19 + { user, ... }: 20 + [ 18 21 "hjem" 19 22 "users" 20 23 user.userName 21 24 ]; 22 - fromAspect = _: den.aspects.${user.aspect}; 23 - }; 24 - 25 + }; 25 26 in 26 27 { 27 - den.ctx.hjem-host.into.hjem-user = intoHjemUsers; 28 - den.ctx.hjem-user._.hjem-user = forwardedToHost; 28 + den.ctx = ctx; 29 29 }
+16 -26
modules/aspects/provides/hjem/hjem-os.nix
··· 5 5 ... 6 6 }: 7 7 let 8 + inherit (den.lib.home-env) 9 + detectHost 10 + hostOptions 11 + ; 12 + 8 13 hjemClass = "hjem"; 9 14 hjemOsClasses = [ 10 15 "nixos" 11 16 "darwin" 12 17 ]; 13 18 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; 19 + ctx.host.into.hjem-host = detectHost { 20 + className = hjemClass; 21 + supportedOses = hjemOsClasses; 22 + optionPath = "hjem"; 23 + }; 40 24 41 25 ctx.hjem-host._.hjem-host = 42 26 { host }: ··· 44 28 ${host.class}.imports = [ host.hjem.module ]; 45 29 }; 46 30 31 + hostConf = hostOptions { 32 + className = hjemClass; 33 + optionPath = "hjem"; 34 + inputsPath = "hjem"; 35 + getModule = { host, ... }: inputs.hjem."${host.class}Modules".default; 36 + }; 47 37 in 48 38 { 49 39 den.ctx = ctx;
+38 -57
modules/aspects/provides/home-manager/hm-integration.nix
··· 5 5 ... 6 6 }: 7 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. 8 + inherit (den.lib.home-env) 9 + intoClassUsers 10 + forwardToHost 11 + ; 16 12 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 - ''; 13 + inherit (den.lib) parametric; 21 14 22 15 hmClass = "homeManager"; 23 16 24 - intoHmUsers = 25 - { host }: 26 - map (user: { inherit host user; }) ( 27 - lib.filter (u: lib.elem hmClass u.classes) (lib.attrValues host.users) 28 - ); 17 + hm-aspect-deprecated = '' 18 + NOTICE: den.provides.home-manager aspect is not used anymore. 19 + See https://den.oeiuwq.com/guides/home-manager/ 29 20 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 - }; 21 + Since den.ctx.hm-host requires least one user with homeManager class, 22 + Home Manager is now enabled via options. 43 23 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/ 24 + For all users unless they set a value: 51 25 52 - Since den.ctx.hm-host requires least one user with homeManager class, 53 - Home Manager is now enabled via options. 26 + den.base.user.classes = lib.mkDefault [ "homeManager" ]; 54 27 55 - For all users unless they set a value: 28 + On specific users: 56 29 57 - den.base.user.classes = lib.mkDefault [ "homeManager" ]; 30 + den.hosts.x86_64-linux.igloo.users.tux.classes = [ "homeManager" ]; 58 31 59 - On specific users: 32 + See <den/home-manager/hm-os.nix> 60 33 61 - den.hosts.x86_64-linux.igloo.users.tux.classes = [ "homeManager" ]; 34 + If you had includes at den._.home-manager, you can use: 62 35 63 - See <den/home-manager/hm-os.nix> 36 + den.ctx.hm-host.includes = [ ... ]; 64 37 65 - If you had includes at den._.home-manager, you can use: 38 + For attaching aspects to home-manager enabled hosts. 39 + ''; 66 40 67 - den.ctx.hm-host.includes = [ ... ]; 41 + ctx.home.provides.home = { home }: parametric.fixedTo { inherit home; } den.aspects.${home.aspect}; 42 + ctx.home.into.default = lib.singleton; 68 43 69 - For attaching aspects to home-manager enabled hosts. 70 - ''; 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 + }; 71 56 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 = 57 + ctx.hm-user-internal.provides.hm-user-internal = 81 58 { host, user }: 82 59 { class, aspect-chain }: 83 60 { ··· 88 65 (parametric.atLeast den.aspects.${host.aspect} { inherit host user; }) 89 66 ]; 90 67 }; 68 + in 69 + { 70 + den.provides.home-manager = _: throw hm-aspect-deprecated; 71 + den.ctx = ctx; 91 72 }
+18 -44
modules/aspects/provides/home-manager/hm-os.nix
··· 5 5 ... 6 6 }: 7 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. 8 + inherit (den.lib.home-env) 9 + detectHost 10 + hostOptions 11 + ; 17 12 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 = [ 13 + hmClass = "homeManager"; 14 + hmOsClasses = [ 26 15 "nixos" 27 16 "darwin" 28 17 ]; 29 18 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 - }; 19 + ctx.host.into.hm-host = detectHost { 20 + className = hmClass; 21 + supportedOses = hmOsClasses; 22 + optionPath = "home-manager"; 23 + }; 44 24 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 25 ctx.hm-host.provides.hm-host = 59 26 { host }: 60 27 { 61 28 ${host.class}.imports = [ host.home-manager.module ]; 62 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 + }; 63 37 64 38 in 65 39 {
+19 -18
modules/aspects/provides/maid/maid-integration.nix
··· 1 - { den, lib, ... }: 1 + { 2 + den, 3 + lib, 4 + inputs, 5 + ... 6 + }: 2 7 let 8 + inherit (den.lib.home-env) 9 + intoClassUsers 10 + forwardToHost 11 + ; 12 + 3 13 maidClass = "maid"; 4 14 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 = _: [ 15 + ctx.maid-host.into.maid-user = intoClassUsers maidClass; 16 + ctx.maid-user._.maid-user = forwardToHost { 17 + className = maidClass; 18 + forwardPathFn = 19 + { user, ... }: 20 + [ 18 21 "users" 19 22 "users" 20 23 user.userName 21 24 "maid" 22 25 ]; 23 - fromAspect = _: den.aspects.${user.aspect}; 24 - }; 26 + }; 25 27 26 28 in 27 29 { 28 - den.ctx.maid-host.into.maid-user = intoMaidUsers; 29 - den.ctx.maid-user._.maid-user = forwardedToHost; 30 + den.ctx = ctx; 30 31 }
+19 -29
modules/aspects/provides/maid/maid-os.nix
··· 5 5 ... 6 6 }: 7 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 - }; 8 + inherit (den.lib.home-env) 9 + detectHost 10 + hostOptions 11 + ; 27 12 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; }; 13 + maidClass = "maid"; 14 + maidOsClasses = [ "nixos" ]; 37 15 38 - ctx.host.into.maid-host = maidDetect; 16 + ctx.host.into.maid-host = detectHost { 17 + className = maidClass; 18 + supportedOses = maidOsClasses; 19 + optionPath = "nix-maid"; 20 + }; 39 21 40 22 ctx.maid-host._.maid-host = 41 23 { host }: 42 24 { 43 25 ${host.class}.imports = [ host.nix-maid.module ]; 44 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 + 45 35 in 46 36 { 47 37 den.ctx = ctx;
-9
modules/aspects/provides/os-user.nix
··· 47 47 in 48 48 { 49 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 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 115 116 116 ctxApply = import ./ctx-apply.nix { inherit lib den; }; 117 117 118 + home-env = import ./home-env.nix { inherit lib den inputs; }; 119 + 118 120 den-lib = { 119 121 inherit 120 122 parametric ··· 128 130 isStatic 129 131 ctxApply 130 132 nh 133 + home-env 131 134 ; 132 135 }; 133 136 in