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(lib): den.lib.perHost and den.lib.perUser (#288)

These are shortcuts for `exactly {host}` and `exactly {host,user}`
respectively.

authored by

Victor Borja and committed by
GitHub
09b6cf7b 679b9e86

+167 -16
+1 -1
docs/src/content/docs/explanation/parametric.mdx
··· 20 20 ({ host, ... }: { nixos.x = host.hostName; }) 21 21 22 22 # Matches: {host, user} only 23 - (den.lib.take.exactly ({ host, user }: { nixos.x = user.userName; })) 23 + (den.lib.perUser ({ host, user }: { nixos.x = user.userName; })) 24 24 25 25 # Matches: {home} **or** {home, foo} 26 26 ({ home }: { homeManager.x = home.userName; })
+4 -4
docs/src/content/docs/guides/bidirectional.mdx
··· 131 131 they must take care of the following: 132 132 133 133 ```nix 134 - # use den.lib.take.exactly to avoid being called with `{host, user}` 135 - take.exactly ({ host }: ...) 134 + # avoid being called with `{host, user}` 135 + den.lib.perHost ({ host }: ...) 136 136 137 - # use den.lib.take.atLeast to avoid being called with `{host}` 138 - take.atLeast ({ host, user }: ...) 137 + # avoid being called with `{host}` 138 + den.lib.perUser ({ host, user }: ...) 139 139 ``` 140 140 141 141 Read the documentation at [`context/user.nix`](https://github.com/vic/den/blob/main/modules/context/user.nix) for all the details.
+2 -2
docs/src/content/docs/guides/debug.md
··· 85 85 86 86 **Duplicate values in lists**: Den deduplicates owned and static configs 87 87 from `den.default`, but parametric functions in `den.default.includes` 88 - run at every context stage. Use `den.lib.take.exactly` to restrict: 88 + run at every context stage. Use `den.lib.perHost` to restrict: 89 89 90 90 ```nix 91 - den.lib.take.exactly ({ host }: { nixos.x = 1; }) 91 + den.lib.perHost ({ host }: { nixos.x = 1; }) 92 92 ``` 93 93 94 94 **Missing attribute**: The context does not have the expected parameter.
+15
modules/context/perHost-perUser.nix
··· 1 + { 2 + lib, 3 + inputs, 4 + config, 5 + ... 6 + }: 7 + let 8 + inherit (config.den.lib) take parametric; 9 + fixed = ctx: aspect: parametric.fixedTo ctx { includes = [ aspect ]; }; 10 + perHost = aspect: take.exactly ({ host }@ctx: fixed ctx aspect); 11 + perUser = aspect: take.exactly ({ host, user }@ctx: fixed ctx aspect); 12 + in 13 + { 14 + den.lib = { inherit perUser perHost; }; 15 + }
+3 -3
modules/context/user.nix
··· 53 53 54 54 Do this to prevent the function being invoked with `{host,user}` 55 55 56 - take.exactly ({host}: ...) 56 + den.lib.perHost ({host}: ...) 57 57 58 58 Or this to avoid it being invoked with `{host}` 59 59 60 - take.atLeast ({host,user}: ...) 60 + den.lib.perUser ({host,user}: ...) 61 61 62 62 Static aspects, -functions like `{class,aspect-chain}: ...`- at host-aspect.includes 63 63 have **no way** to distinguish when the calling context is `{host}` or `{host,user}` if ··· 66 66 Because of this, if you have such functions, they might produce duplicate values on list or 67 67 conflicting values on package types. A work around is to wrap them in a context-aware function: 68 68 69 - take.exactly ({host}: { includes = [ ({class, aspect-chain}: ...) ]; }) 69 + den.lib.perHost ({host}: {class, aspect-chain}: ...) 70 70 71 71 ''; 72 72
+1 -3
modules/lib.nix
··· 5 5 ... 6 6 }: 7 7 { 8 - imports = [ 9 - (inputs.den.lib { inherit inputs lib config; }).nixModule 10 - ]; 8 + imports = [ (inputs.den.lib { inherit inputs lib config; }).nixModule ]; 11 9 }
+1 -1
nix/nixModule/lib.nix
··· 9 9 options.den.lib = lib.mkOption { 10 10 internal = true; 11 11 visible = false; 12 - type = lib.types.attrsOf lib.types.raw; 12 + type = lib.types.submodule { freeformType = lib.types.lazyAttrsOf lib.types.unspecified; }; 13 13 }; 14 14 }
+136
templates/ci/modules/features/perUser-perHost.nix
··· 1 + { denTest, ... }: 2 + { 3 + flake.tests.perUser-perHost = { 4 + 5 + test-included-in-default-pipeline = denTest ( 6 + { 7 + den, 8 + igloo, 9 + lib, 10 + ... 11 + }: 12 + { 13 + den.hosts.x86_64-linux.igloo.users = { 14 + tux = { }; 15 + pingu = { }; 16 + }; 17 + 18 + den.aspects.igloo.nixos.options.funny = lib.mkOption { 19 + default = [ ]; 20 + type = lib.types.listOf lib.types.str; 21 + }; 22 + 23 + den.aspects.igloo.includes = [ 24 + (den.lib.perHost { nixos.funny = [ "atHost perHost static" ]; }) 25 + (den.lib.perHost ( 26 + { host }: 27 + { 28 + nixos.funny = [ "atHost perHost ${host.name} fun" ]; 29 + } 30 + )) 31 + (den.lib.perUser { nixos.funny = [ "atHost IGNORED perUser static" ]; }) 32 + (den.lib.perUser ( 33 + { user, host }: 34 + { 35 + nixos.funny = [ "atHost IGNORED perUser ${user.name}@${host.name} fun" ]; 36 + } 37 + )) 38 + ]; 39 + 40 + den.aspects.tux.includes = [ 41 + (den.lib.perHost { nixos.funny = [ "atUser IGNORED perHost static" ]; }) 42 + (den.lib.perHost ( 43 + { host }: 44 + { 45 + nixos.funny = [ "atUser IGNORED perHost ${host.name} fun" ]; 46 + } 47 + )) 48 + (den.lib.perUser { nixos.funny = [ "atUser perUser static" ]; }) 49 + (den.lib.perUser ( 50 + { user, host }: 51 + { 52 + nixos.funny = [ "atUser perUser ${user.name}@${host.name} fun" ]; 53 + } 54 + )) 55 + ]; 56 + 57 + expr = igloo.funny; 58 + expected = [ 59 + "atUser perUser tux@igloo fun" 60 + "atUser perUser static" 61 + "atHost perHost igloo fun" 62 + "atHost perHost static" 63 + ]; 64 + } 65 + ); 66 + 67 + test-included-in-bidirectional-pipeline = denTest ( 68 + { 69 + den, 70 + igloo, 71 + lib, 72 + ... 73 + }: 74 + { 75 + den.hosts.x86_64-linux.igloo.users = { 76 + tux = { }; 77 + pingu = { }; 78 + }; 79 + 80 + den.ctx.user.includes = [ den._.bidirectional ]; 81 + 82 + den.aspects.igloo.nixos.options.funny = lib.mkOption { 83 + default = [ ]; 84 + type = lib.types.listOf lib.types.str; 85 + }; 86 + 87 + den.aspects.igloo.includes = [ 88 + (den.lib.perHost { nixos.funny = [ "atHost perHost static" ]; }) 89 + (den.lib.perHost ( 90 + { host }: 91 + { 92 + nixos.funny = [ "atHost perHost ${host.name} fun" ]; 93 + } 94 + )) 95 + (den.lib.perUser { nixos.funny = [ "atHost perUser static" ]; }) 96 + (den.lib.perUser ( 97 + { user, host }: 98 + { 99 + nixos.funny = [ "atHost perUser ${user.name}@${host.name} fun" ]; 100 + } 101 + )) 102 + ]; 103 + 104 + den.aspects.tux.includes = [ 105 + (den.lib.perHost { nixos.funny = [ "atUser ignored perHost static" ]; }) 106 + (den.lib.perHost ( 107 + { host }: 108 + { 109 + nixos.funny = [ "atUser ignored perHost ${host.name} fun" ]; 110 + } 111 + )) 112 + (den.lib.perUser { nixos.funny = [ "atUser perUser static" ]; }) 113 + (den.lib.perUser ( 114 + { user, host }: 115 + { 116 + nixos.funny = [ "atUser perUser ${user.name}@${host.name} fun" ]; 117 + } 118 + )) 119 + ]; 120 + 121 + expr = igloo.funny; 122 + expected = [ 123 + "atHost perUser pingu@igloo fun" 124 + "atHost perUser static" # pingu 125 + "atHost perUser tux@igloo fun" 126 + "atHost perUser static" # tux 127 + "atUser perUser tux@igloo fun" 128 + "atUser perUser static" 129 + "atHost perHost igloo fun" 130 + "atHost perHost static" 131 + ]; 132 + } 133 + ); 134 + 135 + }; 136 + }
+4 -2
templates/example/modules/aspects/defaults.nix
··· 33 33 # you could be duplicating config values. For example: 34 34 # 35 35 # # This will append 42 into foo option for the {host} and for EVERY {host,user} 36 - # ({ host, ... }: { nixos.foo = [ 42 ]; }) # DO-NOT-DO-THIS. 36 + # ({ host, ... }: { nixos.foo = [ 42 ]; }) # DO-NOT-DO-THIS. 37 37 # 38 38 # # Instead try to be explicit if a function is intended for ONLY { host } 39 - # den.lib.take.exactly ({ host }: { nixos.foo = [ 42 ]; }) 39 + # den.lib.perHost ({ host }: { nixos.foo = [ 42 ]; }) 40 + # # Or for { host, user } ONLY: 41 + # den.lib.perUser ({ host, user }: { nixos.foo = [ 42 ]; }) 40 42 ]; 41 43 }