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
1{ lib, den, ... }:
2let
3 inherit (den.lib) parametric;
4
5 cleanCtx =
6 self:
7 builtins.removeAttrs self [
8 "name"
9 "description"
10 "into"
11 "provides"
12 "__functor"
13 "modules"
14 "resolve"
15 "_module"
16 "_"
17 ];
18
19 transformAll =
20 source: self: ctx:
21 [
22 {
23 inherit ctx source;
24 ctxDef = self;
25 }
26 ]
27 ++ lib.concatLists (
28 lib.mapAttrsToList (
29 name: into:
30 if !builtins.hasAttr name den.ctx then
31 [ ]
32 else
33 lib.concatMap (transformAll self den.ctx.${name}) (into ctx)
34 ) self.into
35 );
36
37 noop = _: { };
38
39 crossProvider =
40 p:
41 let
42 src = p.source;
43 name = p.ctxDef.name;
44 in
45 if src == null then noop else src.provides.${name} or noop;
46
47 dedupIncludes =
48 let
49 go =
50 acc: remaining:
51 if remaining == [ ] then
52 acc.result
53 else
54 let
55 p = builtins.head remaining;
56 rest = builtins.tail remaining;
57 name = p.ctxDef.name;
58 clean = cleanCtx p.ctxDef;
59 isFirst = !(acc.seen ? ${name});
60 selfFun = p.ctxDef.provides.${name} or noop;
61 crossFun = crossProvider p;
62 items = [
63 (if isFirst then parametric.fixedTo p.ctx clean else parametric.atLeast clean p.ctx)
64 (selfFun p.ctx)
65 (crossFun p.ctx)
66 ];
67 in
68 go {
69 seen = acc.seen // {
70 ${name} = true;
71 };
72 result = acc.result ++ items;
73 } rest;
74 in
75 go {
76 seen = { };
77 result = [ ];
78 };
79
80 ctxApply = self: ctx: {
81 includes = dedupIncludes (transformAll null self ctx);
82 };
83
84in
85ctxApply