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

feat: `os` class forwards to NixOS and MacOS (#225)

see #222

closes #223

authored by oeiuwq.com and committed by

GitHub c142ca2f de1d6656

+113 -45
+24 -31
docs/src/content/docs/guides/custom-classes.mdx
··· 129 129 130 130 ## User contributed examples 131 131 132 + #### Example: Config across `nixos` and `darwin` classes. 133 + 134 + The `os` forward class ([provided by Den](https://github.com/vic/den/blob/main/modules/aspects/provides/os-class.nix)) can be useful for settings that must be forwarded to both on NixOS and MacOS. 135 + 136 + > Requested by @Risa-G at [#222](https://github.com/vic/den/discussions/222) 137 + 138 + ```nix 139 + # Note: this is already provided by Den at provides/os-class.nix 140 + os-class = { class, aspect-chain }: den._.forward { 141 + each = [ "nixos" "darwin" ]; 142 + fromClass = _: "os"; 143 + intoClass = lib.id; 144 + intoPath = _: [ ]; # top-level 145 + fromAspect = _: lib.head aspect-chain; 146 + }; 147 + 148 + # Note: already enabled by Den 149 + # den.ctx.host.includes = [ os-class ]; 150 + 151 + den.aspects.my-laptop = { 152 + os.networking.hostName = "Yavanna"; # on both NixOS and MacOS 153 + }; 154 + ``` 155 + 132 156 #### Example: A git class that forwards to home-manager. 133 157 134 158 ```nix ··· 178 202 179 203 # included at users who can fix things with nix. 180 204 den.aspects.tux.includes = [ nix-allowed ]; 181 - ``` 182 - 183 - #### Example: An `os` class forwarding to NixOS and nix-Darwin 184 - 185 - This forward class can be useful for settings that are common to both 186 - `nixos` and `darwin` classes. 187 - 188 - ```nix 189 - os-class = { host }: { class, aspect-chain }: den._.forward { 190 - each = lib.singleton true; 191 - fromClass = _: "os"; 192 - intoClass = _: host.class; 193 - intoPath = _: [ ]; # Forward at Top-Level 194 - fromAspect = lib.head aspect-chain; 195 - adaptArgs = lib.id; 196 - }; 197 - 198 - 199 - # enable on all hosts 200 - den.ctx.host.includes = [ os-class ]; 201 - 202 - # usage 203 - den.aspects.my-laptop = { 204 - nixos = {}; # nixos specific options 205 - darwin = {}; # darwin specific options 206 - 207 - # both on nixos and darwin 208 - os = { pkgs, ... }: { 209 - environment.packages = [ pkgs.hello ]; 210 - }; 211 - }; 212 205 ``` 213 206 214 207 #### Example: An impermanence class
+15 -11
modules/aspects/provides/forward.nix
··· 45 45 ... 46 46 }@fwd: 47 47 let 48 - forwarded = den.lib.aspects.forward clean; 49 48 clean = builtins.removeAttrs fwd [ 50 49 "guard" 51 50 "adaptArgs" ··· 57 56 freeformMod = { 58 57 config._module.freeformType = lib.types.lazyAttrsOf lib.types.unspecified; 59 58 }; 60 - adapterKey = lib.concatStringsSep "_" intoPath; 59 + adapterKey = lib.concatStringsSep "_" ( 60 + [ 61 + fromClass 62 + intoClass 63 + ] 64 + ++ intoPath 65 + ); 61 66 adapter = { 62 67 includes = [ 63 68 (den.lib.aspects.forward ( ··· 66 71 intoPath = _: [ 67 72 "den" 68 73 "fwd" 69 - "adapter" 70 - fromClass 71 74 adapterKey 72 75 ]; 73 76 } 74 77 )) 75 78 ]; 76 79 ${intoClass} = args: { 77 - options.den.fwd.adapter.${fromClass}.${adapterKey} = lib.mkOption { 80 + options.den.fwd.${adapterKey} = lib.mkOption { 78 81 default = { }; 79 82 type = lib.types.submoduleWith { 80 83 specialArgs = if adaptArgs == null then args else adaptArgs args; 81 84 modules = if adapterModule == null then [ freeformMod ] else [ adapterModule ]; 82 85 }; 83 86 }; 84 - config = 85 - if (guard == null || guard args) then 86 - lib.setAttrByPath intoPath args.config.den.fwd.adapter.${fromClass}.${adapterKey} 87 - else 88 - { }; 87 + config = lib.optionalAttrs (guard == null || guard args) ( 88 + lib.setAttrByPath intoPath args.config.den.fwd.${adapterKey} 89 + ); 89 90 }; 90 91 }; 92 + 93 + needsAdapter = guard != null || adaptArgs != null || adapterModule != null; 94 + forwarded = den.lib.aspects.forward clean; 91 95 in 92 - if guard != null || adaptArgs != null || adapterModule != null then adapter else forwarded; 96 + if needsAdapter then adapter else forwarded; 93 97 94 98 in 95 99 {
+33
modules/aspects/provides/os-class.nix
··· 1 + { den, lib, ... }: 2 + let 3 + description = '' 4 + The `os` class is a convenience for settings that should be forwarded 5 + into both `nixos` and `darwin` classes. 6 + 7 + This class is enabled by default. 8 + 9 + # Usage 10 + 11 + den.aspects.my-host = { 12 + os.networking.hostName = "foo"; 13 + }; 14 + 15 + ''; 16 + 17 + os-class = 18 + { class, aspect-chain }: 19 + den._.forward { 20 + each = [ 21 + "nixos" 22 + "darwin" 23 + ]; 24 + fromClass = _: "os"; 25 + intoClass = lib.id; 26 + intoPath = _: [ ]; 27 + fromAspect = _: lib.head aspect-chain; 28 + }; 29 + 30 + in 31 + { 32 + den.ctx.default.includes = [ os-class ]; 33 + }
+4 -3
templates/ci/flake.nix
··· 10 10 flake-parts.url = "github:hercules-ci/flake-parts"; 11 11 flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; 12 12 home-manager.url = "github:nix-community/home-manager"; 13 - home-manager.inputs = { 14 - nixpkgs.follows = "nixpkgs"; 15 - }; 13 + home-manager.inputs.nixpkgs.follows = "nixpkgs"; 14 + darwin.url = "github:nix-darwin/nix-darwin"; 15 + darwin.inputs.nixpkgs.follows = "nixpkgs"; 16 + 16 17 nix-unit.url = "github:nix-community/nix-unit"; 17 18 nix-unit.inputs = { 18 19 flake-parts.follows = "flake-parts";
+34
templates/ci/modules/features/os-class.nix
··· 1 + { denTest, ... }: 2 + { 3 + flake.tests.os-class = { 4 + 5 + test-forwards-to-nixos-and-darwin = denTest ( 6 + { 7 + den, 8 + lib, 9 + igloo, 10 + apple, 11 + ... 12 + }: 13 + { 14 + den.hosts.x86_64-linux.igloo.users.tux = { }; 15 + den.hosts.aarch64-darwin.apple.users.tux = { }; 16 + 17 + # user contributes to both NixOS and MacOS 18 + den.aspects.tux = { 19 + os.networking.hostName = "from-os-class"; 20 + }; 21 + 22 + expr = { 23 + nixos = igloo.networking.hostName; 24 + macos = apple.networking.hostName; 25 + }; 26 + expected = { 27 + nixos = "from-os-class"; 28 + macos = "from-os-class"; 29 + }; 30 + } 31 + ); 32 + 33 + }; 34 + }
+3
templates/ci/modules/test-support/eval-den.nix
··· 27 27 testModule = { 28 28 imports = [ inputs.den.flakeModule ]; 29 29 options.flake.nixosConfigurations = lib.mkOption { }; 30 + options.flake.darwinConfigurations = lib.mkOption { }; 30 31 options.flake.homeConfigurations = lib.mkOption { }; 31 32 options.flake.packages = lib.mkOption { }; 32 33 options.expr = lib.mkOption { }; ··· 39 40 let 40 41 41 42 iceberg = config.flake.nixosConfigurations.iceberg.config; 43 + apple = config.flake.darwinConfigurations.apple.config; 42 44 igloo = config.flake.nixosConfigurations.igloo.config; 43 45 tuxHm = igloo.home-manager.users.tux; 44 46 pinguHm = igloo.home-manager.users.pingu; ··· 71 73 inherit 72 74 show 73 75 funnyNames 76 + apple 74 77 igloo 75 78 iceberg 76 79 tuxHm