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

Fix home-manager integration. Use `takes.exactly` instead of just `{ host, ...}` context. (#88)

Fixes #87

authored by oeiuwq.com and committed by

GitHub 668c0fa5 0b4cbcd8

+109 -67
+17 -26
modules/aspects/dependencies.nix
··· 30 30 includes = 31 31 let 32 32 users = builtins.attrValues host.users; 33 - contrib = osUserDependencies OS host; 33 + contrib = osUserDependencies { inherit OS host; }; 34 34 in 35 35 map contrib users; 36 36 } ··· 38 38 }; 39 39 40 40 osUserDependencies = 41 - OS: host: user: 41 + { OS, host }: 42 + user: 42 43 let 43 44 USR = den.aspects.${user.aspect}; 44 - ctx = { inherit OS host user; }; 45 45 in 46 46 { 47 47 includes = [ 48 48 (owned USR) 49 49 (statics USR) 50 - (USR ctx) 50 + (USR { inherit OS host; }) 51 51 ]; 52 52 }; 53 53 54 - # from home-manager integration. 54 + # from OS home-managed integration. 55 55 hmUserDependencies = 56 56 { 57 - HM, 57 + OS-HM, 58 58 host, 59 59 user, 60 60 }: 61 + let 62 + inherit (OS-HM) OS HM; 63 + in 61 64 { 62 65 includes = [ 63 66 (owned den.default) 64 67 (statics den.default) 65 68 (owned HM) 66 69 (statics HM) 67 - (hmOsDependencies HM host user) 68 - ]; 69 - }; 70 - 71 - hmOsDependencies = 72 - HM: host: user: 73 - let 74 - OS = den.aspects.${host.aspect}; 75 - newCtx = { 76 - inherit 77 - HM 78 - OS 79 - host 80 - user 81 - ; 82 - }; 83 - in 84 - { 85 - includes = [ 86 70 (owned OS) 87 71 (statics OS) 88 - (parametric newCtx OS) 72 + (parametric { 73 + inherit 74 + OS 75 + HM 76 + user 77 + host 78 + ; 79 + } OS) 89 80 ]; 90 81 }; 91 82
+43 -39
modules/aspects/provides/home-manager.nix
··· 24 24 25 25 For each user resolves den.aspects.''${user.aspect} and imports its homeManager class module. 26 26 ''; 27 - in 28 - { 29 - den.provides.home-manager = { 30 - inherit description; 31 27 32 - __functor = 33 - _: 34 - { host, ... }: 35 - { class, aspect-chain }: 36 - let 37 - hmClass = "homeManager"; 38 - hmUsers = builtins.filter (u: u.class == hmClass) (lib.attrValues host.users); 28 + homeManager = 29 + { OS, host }: 30 + { class, aspect-chain }: 31 + let 32 + hmClass = "homeManager"; 33 + hmUsers = builtins.filter (u: u.class == hmClass) (lib.attrValues host.users); 39 34 40 - hmUserModule = 41 - user: 42 - let 43 - ctx = { 44 - inherit aspect-chain; 45 - class = hmClass; 46 - }; 47 - HM = den.aspects.${user.aspect}; 48 - aspect = HM { inherit HM host; }; 49 - module = aspect.resolve ctx; 50 - in 51 - module; 35 + hmUserModule = 36 + user: 37 + let 38 + ctx = { 39 + inherit aspect-chain; 40 + class = hmClass; 41 + }; 42 + HM = den.aspects.${user.aspect}; 43 + aspect = HM { 44 + inherit host; 45 + OS-HM = { inherit OS HM; }; 46 + }; 47 + module = aspect.resolve ctx; 48 + in 49 + module; 52 50 53 - users = map (user: { 54 - name = user.userName; 55 - value.imports = [ (hmUserModule user) ]; 56 - }) hmUsers; 51 + users = map (user: { 52 + name = user.userName; 53 + value.imports = [ (hmUserModule user) ]; 54 + }) hmUsers; 55 + 56 + hmModule = host.hm-module or inputs.home-manager."${class}Modules".home-manager; 57 + aspect.${class} = { 58 + imports = [ hmModule ]; 59 + home-manager.users = lib.listToAttrs users; 60 + }; 57 61 58 - hmModule = host.hm-module or inputs.home-manager."${class}Modules".home-manager; 59 - aspect.${class} = { 60 - imports = [ hmModule ]; 61 - home-manager.users = lib.listToAttrs users; 62 - }; 62 + supportedOS = builtins.elem class [ 63 + "nixos" 64 + "darwin" 65 + ]; 66 + enabled = supportedOS && builtins.length hmUsers > 0; 67 + in 68 + if enabled then aspect else { }; 63 69 64 - supportedOS = builtins.elem class [ 65 - "nixos" 66 - "darwin" 67 - ]; 68 - enabled = supportedOS && builtins.length hmUsers > 0; 69 - in 70 - if enabled then aspect else { }; 70 + in 71 + { 72 + den.provides.home-manager = { 73 + inherit description; 74 + __functor = _: den.lib.take.exactly homeManager; 71 75 }; 72 76 }
+8
templates/default/modules/aspects/alice.nix
··· 7 7 let 8 8 # deadnix: skip # demo: enable <> on lexical scope 9 9 inherit (den.lib) __findFile; 10 + 11 + customEmacs.homeManager = 12 + { pkgs, ... }: 13 + { 14 + programs.emacs.enable = true; 15 + programs.emacs.package = pkgs.emacs30-nox; 16 + }; 10 17 in 11 18 [ 19 + customEmacs 12 20 <eg/autologin> 13 21 <den/primary-user> # alice is admin always. 14 22 (<den/user-shell> "fish") # default user shell
+1 -1
templates/default/modules/den.nix
··· 1 1 { 2 2 den.hosts.x86_64-linux.igloo.users.alice = { }; 3 3 den.hosts.aarch64-darwin.apple.users.alice = { }; 4 - den.homes.x86_64-linux.alice = { }; 4 + # den.homes.x86_64-linux.alice = { }; 5 5 }
+10 -1
templates/default/modules/tests.nix
··· 3 3 { inputs, ... }: 4 4 { 5 5 perSystem = 6 - { pkgs, self', ... }: 6 + { 7 + pkgs, 8 + self', 9 + lib, 10 + ... 11 + }: 7 12 let 8 13 checkCond = name: cond: pkgs.runCommandLocal name { } (if cond then "touch $out" else ""); 9 14 apple = inputs.self.darwinConfigurations.apple.config; ··· 21 26 checks."alice enabled igloo nh" = checkCond "alice.provides.igloo" igloo.programs.nh.enable; 22 27 checks."igloo enabled alice helix" = 23 28 checkCond "igloo.provides.alice" alice-at-igloo.programs.helix.enable; 29 + 30 + checks."alice-custom-emacs" = checkCond "hm.programs.emacs.package" ( 31 + "emacs-nox" == lib.getName alice-at-igloo.programs.emacs.package 32 + ); 24 33 }; 25 34 }
+30
templates/examples/modules/_example/ci/custom-home-managed-package.nix
··· 1 + { 2 + # Including an static aspect should not cause duplicate definitions 3 + den.aspects.alice.includes = [ 4 + { 5 + homeManager = 6 + { pkgs, ... }: 7 + { 8 + programs.emacs.enable = true; 9 + programs.emacs.package = pkgs.emacs30-nox; 10 + }; 11 + } 12 + ]; 13 + 14 + perSystem = 15 + { 16 + checkCond, 17 + alice-at-rockhopper, 18 + lib, 19 + ... 20 + }: 21 + { 22 + checks.alice-custom-emacs = checkCond "set uniquely via a static includes" ( 23 + let 24 + expr = lib.getName alice-at-rockhopper.programs.emacs.package; 25 + expected = "emacs-nox"; 26 + in 27 + expr == expected 28 + ); 29 + }; 30 + }