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
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(homes): OS bound standalone HM (#306)

See https://github.com/vic/den/discussions/206

authored by

Victor Borja and committed by
GitHub
899fd3fb c8d68d78

+153 -16
+30 -9
docs/src/content/docs/guides/home-manager.mdx
··· 1 1 --- 2 - title: Homes Integration 2 + title: Home Environments 3 3 description: Home Manager, hjem, and nix-maid setup with Den. 4 4 --- 5 5 ··· 13 13 [`home-env.nix`](https://github.com/vic/den/blob/main/nix/home-env.nix) 14 14 </Aside> 15 15 16 - ## Home Manager 16 + ## Enabling Homes 17 17 18 - ### Enabling on Homes 18 + Den supports several Home Nix classes: 19 + 20 + - `homeManager` 21 + - `hjem` 22 + - `maid` 23 + - `user` 19 24 20 - All Home integrations are opt-in and must be enabled explicitly. 25 + All Home integrations are opt-in and must be enabled explicitly, except for `user` which is the built-in user environment on NixOS and nix-Darwin. 21 26 22 27 ```nix 23 28 # Per user ··· 29 34 30 35 Home integration contexts, like `den.ctx.hm-host` only activate when 31 36 at least one host user has `homeManager` in their `classes`. 32 - When true, the integration imports the HomeManager OS module, 37 + If so, the integration imports the HomeManager OS module, 33 38 and forwards each user's `homeManager` class into `home-manager.users.<userName>`. 34 39 35 40 Same details regarding `home-manager` apply to other home types like `hjem` and `maid`. ··· 79 84 }; 80 85 ``` 81 86 82 - ## Standalone Homes 87 + ## Standalone Homes (homeManager) 83 88 84 89 For machines without root access: 85 90 86 91 ```nix 87 - den.homes.x86_64-linux.alice = { }; 92 + den.homes.x86_64-linux.tux = { }; 93 + ``` 94 + 95 + This produces a `homeConfigurations.tux` that can be built with the `home-manager` CLI. 96 + 97 + ### Standalone Homes bound to Host OS 98 + 99 + Also, if you define an standalone home with `tux@igloo` name _and_ you also 100 + have a host named `igloo` in the same platform with user `tux`, 101 + 102 + ``` 103 + den.homes.x86_64-linux."tux@igloo" = {}; 104 + den.hosts.x86_64-linux.igloo.users.tux = {}; 88 105 ``` 106 + Den will: 107 + 108 + - Correctly set `<home>.userName` so that batteries like `define-user` work. 109 + - Automatically bind the standalone HM instance to the OS host configuration. 89 110 90 - This produces `flake.homeConfigurations.alice`, built with 91 - `inputs.home-manager.lib.homeManagerConfiguration`. 111 + This means that by declaring `tux@igloo` you can quickly rebuild your home 112 + environment without rebuilding the whole `igloo` OS. 92 113 93 114 ## hjem 94 115
+8 -1
modules/options.nix
··· 6 6 }: 7 7 let 8 8 inherit (config) den; 9 - types = import ./../nix/lib/types.nix { inherit inputs lib den; }; 9 + types = import ./../nix/lib/types.nix { 10 + inherit 11 + inputs 12 + lib 13 + den 14 + config 15 + ; 16 + }; 10 17 baseMod = lib.mkOption { 11 18 type = lib.types.deferredModule; 12 19 default = { };
+32 -6
nix/lib/types.nix
··· 1 1 { 2 2 inputs, 3 + config, 3 4 lib, 4 5 den, 5 6 ... 6 - }: 7 + }@top: 7 8 let 8 9 hostsOption = lib.mkOption { 9 10 description = "den hosts definition"; ··· 115 116 config._module.args.user = config; 116 117 options = { 117 118 name = strOpt "user configuration name" name; 118 - userName = strOpt "user account name" config.name; 119 + userName = strOpt "user account name" name; 119 120 classes = lib.mkOption { 120 121 type = lib.types.listOf lib.types.str; 121 122 description = "home management nix classes"; 122 123 default = [ "user" ]; 123 124 }; 124 125 aspect = strOpt "main aspect name" config.name; 126 + host = lib.mkOption { default = host; }; 125 127 }; 126 128 } 127 129 ); ··· 150 152 system: 151 153 lib.types.submodule ( 152 154 { name, config, ... }: 155 + let 156 + nameWithHost = lib.hasInfix "@" name; 157 + userName = if nameWithHost then lib.head (builtins.split "@" name) else name; 158 + hostName = if nameWithHost then lib.last (builtins.split "@" name) else null; 159 + hostByName = den.hosts.${system}.${hostName}; 160 + userByName = hostByName.users.${userName}; 161 + 162 + homeManagerConfiguration = 163 + if nameWithHost then 164 + { pkgs, modules }: 165 + inputs.home-manager.lib.homeManagerConfiguration { 166 + inherit pkgs modules; 167 + extraSpecialArgs.osConfig = lib.attrByPath ( 168 + [ "flake" ] ++ hostByName.intoAttr ++ [ "config" ] 169 + ) null top.config; 170 + } 171 + else 172 + inputs.home-manager.lib.homeManagerConfiguration; 173 + in 153 174 { 154 175 freeformType = lib.types.attrsOf lib.types.anything; 155 176 imports = [ den.schema.home ]; 156 177 config._module.args.home = config; 178 + config._module.args.host = hostByName; 179 + config._module.args.user = userByName; 157 180 options = { 158 181 name = strOpt "home configuration name" name; 159 - userName = strOpt "user account name" config.name; 182 + userName = strOpt "user account name" userName; 183 + hostName = strOpt "host name" hostName; 184 + user = lib.mkOption { default = userByName; }; 185 + host = lib.mkOption { default = hostByName; }; 160 186 system = strOpt "platform system" system; 161 187 class = strOpt "home management nix class" "homeManager"; 162 - aspect = strOpt "main aspect name" config.name; 163 - description = strOpt "home description" "home.${config.userName}@${config.system}"; 188 + aspect = strOpt "main aspect name" userName; 189 + description = strOpt "home description" "home.${config.name}@${config.system}"; 164 190 pkgs = lib.mkOption { 165 191 description = '' 166 192 nixpkgs instance used to build the home configuration. ··· 185 211 type = lib.types.raw; 186 212 default = 187 213 { 188 - homeManager = inputs.home-manager.lib.homeManagerConfiguration; 214 + homeManager = homeManagerConfiguration; 189 215 } 190 216 .${config.class}; 191 217 };
+38
templates/ci/modules/features/homes.nix
··· 53 53 } 54 54 ); 55 55 56 + test-home-with-user-and-host-automatic-osArgs = denTest ( 57 + { den, config, ... }: 58 + { 59 + den.default.homeManager.home.stateVersion = "25.11"; 60 + 61 + # When an standalone home has user@host and there exist such host 62 + den.homes.x86_64-linux."tux@igloo" = { }; 63 + den.hosts.x86_64-linux.igloo.users.tux = { }; 64 + 65 + den.aspects.igloo.nixos.networking.hostName = "blizzard"; 66 + den.aspects.tux.includes = [ den._.define-user ]; 67 + den.aspects.tux.homeManager = 68 + { osConfig, ... }: 69 + { 70 + home.keyboard.model = osConfig.networking.hostName; 71 + }; 72 + 73 + expr = { 74 + homeSchema = { 75 + inherit (den.homes.x86_64-linux."tux@igloo") 76 + userName 77 + hostName 78 + aspect 79 + ; 80 + }; 81 + configuredUserName = config.flake.homeConfigurations."tux@igloo".config.home.username; 82 + hasOsConfig = config.flake.homeConfigurations."tux@igloo".config.home.keyboard.model; 83 + }; 84 + expected = { 85 + homeSchema.aspect = "tux"; # re-uses same aspect as hosted HM. 86 + homeSchema.userName = "tux"; 87 + homeSchema.hostName = "igloo"; 88 + configuredUserName = "tux"; 89 + hasOsConfig = "blizzard"; 90 + }; 91 + } 92 + ); 93 + 56 94 }; 57 95 }
+45
templates/ci/modules/features/schema-base-modules.nix
··· 3 3 { 4 4 flake.tests.schema-base-modules = { 5 5 6 + test-host-schema-module-args = denTest ( 7 + { den, lib, ... }: 8 + { 9 + den.hosts.x86_64-linux.igloo = { }; 10 + den.schema.host = 11 + { host, ... }: 12 + { 13 + options.ok = lib.mkOption { default = true; }; 14 + }; 15 + expr = den.hosts.x86_64-linux.igloo.ok; 16 + expected = true; 17 + } 18 + ); 19 + 20 + test-user-schema-module-args = denTest ( 21 + { den, lib, ... }: 22 + { 23 + den.hosts.x86_64-linux.igloo.users.tux = { }; 24 + den.schema.user = 25 + { user, host, ... }: 26 + { 27 + # host can also be read from user.host 28 + options.ok = lib.mkOption { default = user ? host; }; 29 + }; 30 + expr = den.hosts.x86_64-linux.igloo.users.tux.ok; 31 + expected = true; 32 + } 33 + ); 34 + 35 + test-home-bound-schema-module-args = denTest ( 36 + { den, lib, ... }: 37 + { 38 + den.hosts.x86_64-linux.igloo.users.tux = { }; 39 + den.homes.x86_64-linux."tux@igloo" = { }; 40 + den.schema.home = 41 + { home, ... }: 42 + { 43 + # host and user can also be read from home 44 + options.ok = lib.mkOption { default = home ? host && home ? user; }; 45 + }; 46 + expr = den.homes.x86_64-linux."tux@igloo".ok; 47 + expected = true; 48 + } 49 + ); 50 + 6 51 test-host-base = denTest ( 7 52 { den, lib, ... }: 8 53 {