tangled
alpha
login
or
join now
oeiuwq.com
/
den
8
fork
atom
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
atom
overview
issues
4
pulls
2
pipelines
more examples
oeiuwq.com
6 days ago
dd995a7e
8affc5ca
1/1
mirror.yml
success
3s
+120
-8
3 changed files
expand all
collapse all
unified
split
README.md
docs
src
content
docs
guides
custom-classes.mdx
templates
ci
modules
features
forward-from-custom-class.nix
+40
-7
README.md
···
174
174
```
175
175
176
176
```nix
177
177
-
# custom user-defined Nix classes.
177
177
+
# Custom Nix classes.
178
178
+
179
179
+
# Example: A class for role-based configuration between users and hosts
180
180
+
181
181
+
roleClass =
182
182
+
{ host, user }:
183
183
+
{ class, aspect-chain }:
184
184
+
den._.forward {
185
185
+
each = lib.intersectLists (host.roles or []) (user.roles or []);
186
186
+
fromClass = lib.id;
187
187
+
intoClass = _: host.class;
188
188
+
intoPath = _: [ ];
189
189
+
fromAspect = _: lib.head aspect-chain;
190
190
+
};
191
191
+
192
192
+
den.ctx.user.includes = [ roleClass ];
193
193
+
194
194
+
den.hosts.x86_64-linux.igloo = {
195
195
+
roles = [ "devops" "gaming" ];
196
196
+
users = {
197
197
+
alice.roles = [ "gaming" ];
198
198
+
bob.roles = [ "devops" ];
199
199
+
};
200
200
+
};
201
201
+
202
202
+
den.aspects.alice = {
203
203
+
# enabled when host supports gaming role
204
204
+
gaming = { pkgs, ... }: { programs.steam.enable = true; };
205
205
+
206
206
+
# enabled when host supports devops role
207
207
+
devops = { pkgs, ... }: { virtualisation.podman.enable = true; };
208
208
+
};
209
209
+
```
210
210
+
211
211
+
```nix
212
212
+
# Forward guards allow feature-detection without mkIf/mkMerge cluttering.
178
213
179
179
-
# any aspect can use my `persys` class to forward configs into
180
180
-
# nixos.environment.persistance."/nix/persist/system"
181
181
-
# **ONLY** when environment.persistance option is present at host.
214
214
+
# Aspects use the `persys` class without any conditional. And guard guarantees
215
215
+
# settings are applied **only** when impermanence module has been imported.
182
216
persys = { host }: den._.forward {
183
217
each = lib.singleton true;
184
218
fromClass = _: "persys";
185
219
intoClass = _: host.class;
186
220
intoPath = _: [ "environment" "persistance" "/nix/persist/system" ];
187
221
fromAspect = _: den.aspects.${host.aspect};
188
188
-
guard = { options, ... }: options ? environment.persistance;
222
222
+
guard = { options, config, ... }: options ? environment.persistance;
189
223
};
190
224
191
225
# enable on all hosts
192
226
den.ctx.host.includes = [ persys ];
193
227
194
194
-
# becomes nixos.environment.persistance."/nix/persist/system".hideMounts = true;
195
195
-
# no mkIf, set configs and guard ensures to include only when Impermanence exists
228
228
+
# aspects just attach config to custom class
196
229
den.aspects.my-laptop.persys.hideMounts = true;
197
230
```
+35
-1
docs/src/content/docs/guides/custom-classes.mdx
···
153
153
};
154
154
```
155
155
156
156
+
#### Example: Role based configuration between users and hosts
157
157
+
158
158
+
A dynamic class for matching roles between users and hosts.
159
159
+
160
160
+
```nix
161
161
+
roleClass =
162
162
+
{ host, user }:
163
163
+
{ class, aspect-chain }:
164
164
+
den._.forward {
165
165
+
each = lib.intersectLists (host.roles or []) (user.roles or []);
166
166
+
fromClass = lib.id;
167
167
+
intoClass = _: host.class;
168
168
+
intoPath = _: [ ];
169
169
+
fromAspect = _: lib.head aspect-chain;
170
170
+
};
171
171
+
172
172
+
den.ctx.user.includes = [ roleClass ];
173
173
+
174
174
+
den.hosts.x86_64-linux.igloo = {
175
175
+
roles = [ "devops" "gaming" ];
176
176
+
users = {
177
177
+
alice.roles = [ "gaming" ];
178
178
+
bob.roles = [ "devops" ];
179
179
+
};
180
180
+
};
181
181
+
182
182
+
den.aspects.alice = {
183
183
+
# enabled when host supports gaming role
184
184
+
gaming = { pkgs, ... }: { programs.steam.enable = true; };
185
185
+
186
186
+
# enabled when host supports devops role
187
187
+
devops = { pkgs, ... }: { virtualisation.podman.enable = true; };
188
188
+
};
189
189
+
```
190
190
+
156
191
#### Example: A git class that forwards to home-manager.
157
192
158
193
```nix
···
195
230
196
231
# enable class for all users:
197
232
den.ctx.user.includes = [ nixClass ];
198
198
-
199
233
200
234
# custom aspect that uses the `nix` class.
201
235
nix-allowed = { user, ... }: { nix.allowed-users = [ user.userName ]; };
+45
templates/ci/modules/features/forward-from-custom-class.nix
···
161
161
}
162
162
);
163
163
164
164
+
test-pair-of-hosts = denTest (
165
165
+
{
166
166
+
den,
167
167
+
lib,
168
168
+
igloo,
169
169
+
iceberg,
170
170
+
...
171
171
+
}:
172
172
+
let
173
173
+
forwarded =
174
174
+
{ host, user }:
175
175
+
{ class, aspect-chain }:
176
176
+
den._.forward {
177
177
+
each = lib.optional (lib.elem host.name [
178
178
+
"igloo"
179
179
+
"iceberg"
180
180
+
]) user;
181
181
+
fromClass = _: "iced";
182
182
+
intoClass = _: host.class;
183
183
+
intoPath = _: [ ];
184
184
+
fromAspect = _: lib.head aspect-chain;
185
185
+
};
186
186
+
in
187
187
+
{
188
188
+
den.hosts.x86_64-linux.igloo.users.tux = { };
189
189
+
den.hosts.x86_64-linux.iceberg.users.tux = { };
190
190
+
191
191
+
den.aspects.igloo.homeManager.home.stateVersion = "25.11";
192
192
+
den.ctx.default.includes = [ forwarded ];
193
193
+
194
194
+
den.aspects.tux = {
195
195
+
iced.networking.hostName = "iced";
196
196
+
};
197
197
+
198
198
+
expr = [
199
199
+
igloo.networking.hostName
200
200
+
iceberg.networking.hostName
201
201
+
];
202
202
+
expected = [
203
203
+
"iced"
204
204
+
"iced"
205
205
+
];
206
206
+
}
207
207
+
);
208
208
+
164
209
};
165
210
}