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

Example tests and documentation for forwarding classes. (#167)

Related #160

authored by oeiuwq.com and committed by

GitHub 5478f8e9 27899438

+97 -32
+31 -23
modules/aspects/provides/forward.nix
··· 1 - { lib, ... }: 1 + { den, ... }: 2 2 let 3 - 4 3 description = '' 5 - WIP: Creates a class-forwarding aspect. 6 - ''; 4 + An aspect that imports all modules defined for `from` class 5 + into a target `into` submodule. 7 6 8 - forward = 9 - cb: 10 - { class, aspect-chain }: 11 - let 12 - fwd = cb { inherit class aspect-chain; }; 13 - include = 14 - item: 15 - let 16 - from = fwd.from item; 17 - into = fwd.into item; 18 - aspect = fwd.aspect item; 19 - module = aspect.resolve { class = from; }; 20 - in 21 - lib.setAttrByPath into { imports = [ module ]; }; 22 - in 23 - { 24 - includes = map include fwd.each; 25 - }; 7 + This can be used to create custom Nix classes that help 8 + people separating concerns on huge module hierarchies. 26 9 10 + For example, using a new `user` class that forwards all its 11 + settings into `users.users.<userName>` allows: 12 + 13 + den.aspects.alice.nixos.users.users.alice.isNormalUser = true; 14 + 15 + to become: 16 + 17 + den.aspects.alice.user.isNormalUser = true; 18 + 19 + 20 + This is exactly how `homeManager` class support is implemented in Den. 21 + See home-manager/hm-integration.nix. 22 + 23 + Den also provides the mentioned `user` class (`den._.os-user`) for setting 24 + NixOS/Darwin options under `users.users.<userName>` at os-level. 25 + 26 + Any other user-environments like `nix-maid` or `hjem` or user-custom classes 27 + are easily implemented using `den._.forward`. 28 + 29 + Note: `den._.forward` is a high-level aspect, its result 30 + is another aspect that needs to be included for the new class to exist. 31 + 32 + See templates/ci/modules/forward.nix for usage example. 33 + See also: https://github.com/vic/den/issues/160, https://github.com/vic/flake-aspects/pull/31 34 + ''; 27 35 in 28 36 { 29 37 den.provides.forward = { 30 38 inherit description; 31 - __functor = _self: forward; 39 + __functor = _self: den.lib.aspects.forward; 32 40 }; 33 41 }
+11 -9
modules/aspects/provides/home-manager/hm-integration.nix
··· 49 49 in 50 50 HM { inherit HM-OS-USER; }; 51 51 52 - hmUsersAspect = den._.forward ( 52 + hmUsersAspect = 53 53 { class, aspect-chain }: 54 - den.lib.take.unused aspect-chain { 55 - each = hmUsers; 56 - from = _: hmClass; 57 - into = user: [ 58 - class 54 + den._.forward { 55 + each = lib.optionals (lib.elem class [ 56 + "nixos" 57 + "darwin" 58 + ]) hmUsers; 59 + fromClass = _: hmClass; 60 + fromAspect = den.lib.take.unused aspect-chain hmUserAspect; 61 + intoClass = _: class; 62 + intoPath = user: [ 59 63 "home-manager" 60 64 "users" 61 65 user.userName 62 66 ]; 63 - aspect = hmUserAspect; 64 - } 65 - ); 67 + }; 66 68 in 67 69 { 68 70 ${host.class}.imports = [ hmModule ];
+55
templates/ci/modules/forward.nix
··· 1 + { lib, den, ... }: 2 + let 3 + 4 + oneModule.foo = [ "one" ]; 5 + 6 + targetSubmodule = lib.mkOption { 7 + type = lib.types.submoduleWith { 8 + modules = [ 9 + { 10 + options.foo = lib.mkOption { 11 + type = lib.types.listOf lib.types.str; 12 + }; 13 + } 14 + ]; 15 + }; 16 + }; 17 + 18 + forwarded = 19 + { class, aspect-chain }: 20 + den._.forward { 21 + each = lib.singleton class; # item ignored 22 + fromClass = _item: "fwd-origin"; 23 + intoClass = _item: "nixos"; 24 + intoPath = _item: [ "fwd-target" ]; 25 + fromAspect = _item: lib.head aspect-chain; 26 + }; 27 + 28 + in 29 + { 30 + 31 + den.aspects.rockhopper = { 32 + includes = [ forwarded ]; 33 + nixos = { 34 + imports = [ { options.fwd-target = targetSubmodule; } ]; 35 + fwd-target = { 36 + foo = [ "zero" ]; 37 + imports = [ oneModule ]; 38 + }; 39 + }; 40 + fwd-origin.foo = [ "two" ]; 41 + }; 42 + 43 + perSystem = 44 + { rockhopper, checkCond, ... }: 45 + { 46 + checks.forward = checkCond "foo value was forwarded to os-level" ( 47 + rockhopper.config.fwd-target.foo == [ 48 + "two" 49 + "one" 50 + "zero" 51 + ] 52 + ); 53 + }; 54 + 55 + }