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(batteries): Opt-in den._.bidirectional (#272)

See docs at den.ctx.user

Related: #267

authored by

Victor Borja and committed by
GitHub
4bdcb63e edaa0b03

+142 -36
+2 -2
.github/workflows/docs.yml
··· 2 2 on: 3 3 push: 4 4 branches: ["!main"] 5 - paths: [ "docs/**" ] 5 + paths: ["docs/**"] 6 6 pull_request: 7 7 types: [labeled, opened, synchronize, reopened, review_requested, ready_for_review] 8 - paths: [ "docs/**" ] 8 + paths: ["docs/**"] 9 9 pull_request_review: 10 10 types: [submitted] 11 11 concurrency:
+2 -2
.github/workflows/test.yml
··· 1 1 on: 2 2 push: 3 3 branches: [main] 4 - paths: [ "**/*.nix" ] 4 + paths: ["**/*.nix"] 5 5 pull_request: 6 6 types: [labeled, opened, synchronize, reopened, review_requested, ready_for_review] 7 - paths: [ "**/*.nix" ] 7 + paths: ["**/*.nix"] 8 8 pull_request_review: 9 9 types: [submitted] 10 10 concurrency:
+16
modules/aspects/provides/bidirectional.nix
··· 1 + { den, ... }: 2 + let 3 + description = '' 4 + Enable Den bidirectionality: User takes configuration from Host. 5 + 6 + **REALLY** IMPORTANT: Read the documentation for den.ctx.user 7 + 8 + Consider as alternative den.provides.mutual-provider. 9 + ''; 10 + in 11 + { 12 + den.provides.bidirectional = { 13 + inherit description; 14 + includes = [ den.ctx.user.provides.bidirectional ]; 15 + }; 16 + }
+28
modules/context/host.nix
··· 1 + { den, lib, ... }: 2 + let 3 + inherit (den.lib.parametric) fixedTo; 4 + 5 + ctx.host.description = '' 6 + ## Context: den.ctx.host{host} 7 + 8 + Host context stage configures an OS 9 + 10 + A {host} context fan-outs into many {host,user} contexts. 11 + 12 + A `den.ctx.host{host}` transitions unconditionally into `den.ctx.default{host}` 13 + 14 + A `den.ctx.host{host}` obtains OS configuration nixos/darwin by using `fixedTo{host} host-aspect`. 15 + fixedTo takes: 16 + - host-aspect's owned attrs 17 + - static includes like { nixos.foo = ... } or ({ class, aspect-chain }: { nixos.foo = ...; }) 18 + - atLeast{host} parametric includes like ({ host }: { nixos.foo = ...; }) 19 + ''; 20 + 21 + ctx.host.into.user = { host }: map (user: { inherit host user; }) (lib.attrValues host.users); 22 + ctx.host.into.default = lib.singleton; 23 + ctx.host.provides.host = { host }: fixedTo { inherit host; } den.aspects.${host.aspect}; 24 + 25 + in 26 + { 27 + den.ctx = ctx; 28 + }
-28
modules/context/os.nix
··· 1 - { den, lib, ... }: 2 - let 3 - inherit (den.lib.parametric) fixedTo atLeast; 4 - 5 - ctx.host.description = "OS"; 6 - ctx.host._.host = { host }: fixedTo { inherit host; } den.aspects.${host.aspect}; 7 - ctx.host._.user = 8 - { host, user }@ctx: 9 - { 10 - includes = [ (atLeast den.aspects.${host.aspect} ctx) ]; 11 - }; 12 - 13 - ctx.host.into.default = lib.singleton; 14 - ctx.host.into.user = { host }: map (user: { inherit host user; }) (lib.attrValues host.users); 15 - 16 - ctx.user.description = "OS user"; 17 - ctx.user._.user = 18 - { host, user }@ctx: 19 - { 20 - includes = [ (fixedTo ctx den.aspects.${user.aspect}) ]; 21 - }; 22 - 23 - ctx.user.into.default = lib.singleton; 24 - 25 - in 26 - { 27 - config.den.ctx = ctx; 28 - }
+82
modules/context/user.nix
··· 1 + { den, lib, ... }: 2 + let 3 + inherit (den.lib) take; 4 + inherit (den.lib.parametric) fixedTo atLeast; 5 + 6 + ctx.user.description = '' 7 + ## Context: den.ctx.user{host,user} 8 + 9 + User context stage is produced by Host for each user. 10 + 11 + This is a **continuation** of the pipeline started by `den.ctx.host`. 12 + 13 + IMPORTANT: The configuration obtained from `den.ctx.user` is provided to the Host OS level 14 + 15 + In Den, home-manager/hjem/maid are just forwarding classes that produce config at the OS 16 + level: `home-manager.users.<alice>`, `hjem.users.<alice>`, `users.users.<alice>`, etc. 17 + 18 + A `den.ctx.user{host,user}` transitions unconditionally into `den.ctx.default{host,user}` 19 + 20 + A `den.ctx.user{host,user}` obtains OS configuration nixos/darwin by using `fixedTo{host,user} user-aspect`. 21 + fixedTo takes: 22 + - user-aspect's owned attrs 23 + - static includes like { nixos.foo = ... } or ({ class, aspect-chain }: { nixos.foo = ...; }) 24 + - atLeast{host,user} parametric includes like ({ host,user }: { nixos.foo = ...; }) 25 + 26 + ## Bidirectionality 27 + 28 + Battery `den.provides.bidirectional` can be included on each user that needs to take configuration from the Host. 29 + 30 + Enable per user: 31 + den.aspects.tux.includes = [ den._.bidirectional ]; 32 + 33 + Enable for all users: 34 + den.ctx.user.includes = [ den._.bidirectional ]; 35 + 36 + IMPORTANT: Enabling bidirectionality means that the following piepline is enabled: 37 + 38 + host-aspect{host} => user-aspect{host,user} => host-aspect{host,user} 39 + 40 + This means that any function at host-aspect.includes can be called: 41 + - once when the host is obtaining its own configuration with context {host} 42 + - once PER user that has bidirectionality enabled with context {host,user} 43 + 44 + Because of this, parametric aspects at host-aspect must be careful 45 + 46 + Instead of -in Nix both of these have the same functionArgs- 47 + 48 + ({host}: ...) 49 + 50 + or 51 + 52 + ({host, ...}: ...) 53 + 54 + Do this to prevent the function being invoked with `{host,user}` 55 + 56 + take.exactly ({host}: ...) 57 + 58 + Or this to avoid it being invoked with `{host}` 59 + 60 + take.atLeast ({host,user}: ...) 61 + 62 + Static aspects, -functions like `{class,aspect-chain}: ...`- at host-aspect.includes 63 + have **no way** to distinguish when the calling context is `{host}` or `{host,user}` if 64 + bidirectionality is enabled. 65 + 66 + Because of this, if you have such functions, they might produce duplicate values on list or 67 + conflicting values on package types. A work around is to wrap them in a context-aware function: 68 + 69 + take.exactly ({host}: { includes = [ ({class, aspect-chain}: ...) ]; }) 70 + 71 + ''; 72 + 73 + ctx.user.into.default = lib.singleton; 74 + ctx.user.provides.user = take.exactly from-user; 75 + ctx.user.provides.bidirectional = take.exactly from-host; 76 + 77 + from-user = { host, user }: fixedTo { inherit host user; } den.aspects.${user.aspect}; 78 + from-host = { host, user }: atLeast den.aspects.${host.aspect} { inherit host user; }; 79 + in 80 + { 81 + den.ctx = ctx; 82 + }
+3
templates/ci/modules/features/auto-parametric.nix
··· 69 69 test-explicit-exactly-not-overridden-by-default = denTest ( 70 70 { den, igloo, ... }: 71 71 { 72 + den.ctx.user.includes = [ den._.bidirectional ]; 72 73 den.aspects.strict-helper = den.lib.parametric.exactly { 73 74 includes = [ 74 75 ( ··· 109 110 test-second-level-helper-owned-config-preserved = denTest ( 110 111 { den, igloo, ... }: 111 112 { 113 + den.ctx.user.includes = [ den._.bidirectional ]; 112 114 den.hosts.x86_64-linux.igloo.users.tux = { }; 113 115 114 116 den.aspects.second-with-owned = { ··· 139 141 test-second-provides-helper-owned-config-preserved = denTest ( 140 142 { den, igloo, ... }: 141 143 { 144 + den.ctx.user.includes = [ den._.bidirectional ]; 142 145 den.hosts.x86_64-linux.igloo.users.tux = { }; 143 146 144 147 den.aspects.second.provides.with-owned = {
+1
templates/ci/modules/features/batteries/define-user.nix
··· 26 26 { 27 27 den.hosts.x86_64-linux.igloo.users.tux = { }; 28 28 den.aspects.igloo.includes = [ den._.define-user ]; 29 + den.ctx.user.includes = [ den._.bidirectional ]; 29 30 expr = igloo.users.users.tux.isNormalUser; 30 31 expected = true; 31 32 }
+2
templates/ci/modules/features/conditional-config.nix
··· 41 41 users.tux.hasBar = true; 42 42 }; 43 43 44 + den.ctx.user.includes = [ den._.bidirectional ]; 45 + 44 46 den.aspects.igloo.includes = [ conditionalAspect ]; 45 47 46 48 expr = igloo.something;
+1
templates/ci/modules/features/context/host-propagation.nix
··· 20 20 { 21 21 22 22 den.hosts.x86_64-linux.igloo.users.tux = { }; 23 + den.ctx.user.includes = [ den._.bidirectional ]; 23 24 24 25 den.aspects.igloo.funny.names = [ "host-owned" ]; 25 26 den.aspects.igloo.includes = [
+2
templates/ci/modules/features/deadbugs/external-namespace-deep-aspect.nix
··· 73 73 74 74 test-functor-exactly-fires-only-in-user-context = denTest ( 75 75 { 76 + den, 76 77 provider, 77 78 igloo, 78 79 ... ··· 86 87 ]; 87 88 den.hosts.x86_64-linux.igloo.users.tux = { }; 88 89 den.aspects.igloo.includes = [ provider.tools._.dev._.user-stamp ]; 90 + den.ctx.user.includes = [ den._.bidirectional ]; 89 91 expr = igloo.users.users.tux.description; 90 92 expected = "user-of-igloo"; 91 93 }
+1
templates/ci/modules/features/deadbugs/issue-201-forward-multiple-users.nix
··· 13 13 }: 14 14 { 15 15 den.default.homeManager.home.stateVersion = "25.11"; 16 + den.ctx.user.includes = [ den._.bidirectional ]; 16 17 17 18 den.hosts.x86_64-linux.igloo.users = { 18 19 tux = { };
+2 -4
templates/ci/modules/features/host-options.nix
··· 55 55 test-user-custom-username = denTest ( 56 56 { den, igloo, ... }: 57 57 { 58 - den.hosts.x86_64-linux.igloo.users.tux = { 59 - userName = "penguin"; 60 - }; 61 - den.default.homeManager.home.stateVersion = "25.11"; 58 + den.hosts.x86_64-linux.igloo.users.tux.userName = "penguin"; 62 59 den.aspects.igloo.includes = [ den._.define-user ]; 60 + den.ctx.user.includes = [ den._.bidirectional ]; 63 61 64 62 expr = igloo.users.users.penguin.isNormalUser; 65 63 expected = true;