tangled
alpha
login
or
join now
quasigod.xyz
/
den
forked from
oeiuwq.com/den
Modular, context-aware and aspect-oriented dendritic Nix configurations. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/
0
fork
atom
overview
issues
pulls
pipelines
Compare changes
Choose any two refs to compare.
base:
theirs
push-nvzsmnpkpzry
main
v0.7.0
v0.6.0
v0.5.0
v0.4.0
v0.3.0
v0.2.0
v0.1.0
compare:
theirs
push-nvzsmnpkpzry
main
v0.7.0
v0.6.0
v0.5.0
v0.4.0
v0.3.0
v0.2.0
v0.1.0
go
+237
-12
8 changed files
expand all
collapse all
unified
split
.github
workflows
test.yml
nix
namespace.nix
templates
examples
flake.lock
flake.nix
modules
_example
ci
_theirs
flake.lock
flake.nix
modules
theirs.nix
namespace.nix
+1
-1
.github/workflows/test.yml
···
44
44
- run: nix flake update den
45
45
- run: nix run .#write-flake
46
46
- run: nix flake metadata
47
47
-
- run: nix flake check
47
47
+
- run: nix flake check -L
+50
-6
nix/namespace.nix
···
3
3
let
4
4
from = lib.flatten [ sources ];
5
5
isOutput = builtins.any (x: x == true) from;
6
6
-
denfuls = map (lib.getAttrFromPath [
7
7
-
"denful"
8
8
-
name
9
9
-
]) (builtins.filter builtins.isAttrs from);
6
6
+
attrs = builtins.filter builtins.isAttrs from;
7
7
+
8
8
+
# Strip module system metadata to get clean raw values
9
9
+
stripMeta = value:
10
10
+
if builtins.isList value then
11
11
+
map stripMeta value
12
12
+
else if builtins.isAttrs value then
13
13
+
let
14
14
+
# Remove module system special attributes
15
15
+
cleaned = builtins.removeAttrs value [
16
16
+
"__functor"
17
17
+
"__functionArgs"
18
18
+
"_module"
19
19
+
"config"
20
20
+
];
21
21
+
in
22
22
+
lib.mapAttrs (_: stripMeta) cleaned
23
23
+
else
24
24
+
value;
25
25
+
26
26
+
# Deep merge that concatenates lists instead of overwriting them
27
27
+
deepMergeWith = lhs: rhs:
28
28
+
if builtins.isList lhs && builtins.isList rhs then
29
29
+
lhs ++ rhs
30
30
+
else if builtins.isAttrs lhs && builtins.isAttrs rhs then
31
31
+
let
32
32
+
allKeys = lib.unique (builtins.attrNames lhs ++ builtins.attrNames rhs);
33
33
+
mergedAttrs = builtins.listToAttrs (map (name: {
34
34
+
inherit name;
35
35
+
value =
36
36
+
if lhs ? ${name} && rhs ? ${name} then
37
37
+
deepMergeWith lhs.${name} rhs.${name}
38
38
+
else if lhs ? ${name} then
39
39
+
lhs.${name}
40
40
+
else
41
41
+
rhs.${name};
42
42
+
}) allKeys);
43
43
+
in
44
44
+
mergedAttrs
45
45
+
else
46
46
+
rhs;
47
47
+
48
48
+
# Extract denful values, strip metadata, and merge them deeply before passing to module system
49
49
+
deepMerge = builtins.foldl' (acc: x:
50
50
+
deepMergeWith acc (stripMeta (lib.getAttrFromPath [ "denful" name ] x))
51
51
+
) { } attrs;
10
52
11
53
sourceModule = {
12
12
-
config.den.ful.${name} = lib.mkMerge denfuls;
54
54
+
config.den.ful.${name} = deepMerge;
13
55
};
14
56
15
57
aliasModule = lib.mkAliasOptionModule [ name ] [ "den" "ful" name ];
···
17
59
outputModule =
18
60
if isOutput then
19
61
{
20
20
-
config.flake.denful.${name} = config.den.ful.${name};
62
62
+
# Use mkOptionDefault to ensure this assignment has lower priority
63
63
+
# This prevents re-evaluation and duplication issues
64
64
+
config.flake.denful.${name} = lib.mkOptionDefault config.den.ful.${name};
21
65
}
22
66
else
23
67
{ };
+33
-4
templates/examples/flake.lock
···
22
22
},
23
23
"den": {
24
24
"locked": {
25
25
-
"lastModified": 1763707606,
26
26
-
"narHash": "sha256-l9v3NNdKj3GJvV5LhzsWDs4Sl2bg0tuKNFFkMeFvUWo=",
25
25
+
"lastModified": 1766081768,
26
26
+
"narHash": "sha256-8Ea1DW3YZHifezfdEFHWEIpZBNKvEL+3iFOEcl3eFBU=",
27
27
"owner": "vic",
28
28
"repo": "den",
29
29
-
"rev": "8164e0d89c59839d67757bc9a1fb61770dc6e8b7",
29
29
+
"rev": "7271da18c60ab4d7c275ecaab480d29729f05d17",
30
30
"type": "github"
31
31
},
32
32
"original": {
···
251
251
"nixpkgs"
252
252
],
253
253
"nixpkgs-stable": "nixpkgs-stable",
254
254
-
"systems": "systems"
254
254
+
"systems": "systems",
255
255
+
"theirs": "theirs"
255
256
}
256
257
},
257
258
"systems": {
···
268
269
"repo": "default",
269
270
"type": "github"
270
271
}
272
272
+
},
273
273
+
"theirs": {
274
274
+
"inputs": {
275
275
+
"den": [
276
276
+
"den"
277
277
+
],
278
278
+
"flake-aspects": [
279
279
+
"flake-aspects"
280
280
+
],
281
281
+
"flake-parts": [
282
282
+
"flake-parts"
283
283
+
],
284
284
+
"import-tree": [
285
285
+
"import-tree"
286
286
+
],
287
287
+
"nixpkgs": [
288
288
+
"nixpkgs"
289
289
+
]
290
290
+
},
291
291
+
"locked": {
292
292
+
"path": "./modules/_example/ci/_theirs",
293
293
+
"type": "path"
294
294
+
},
295
295
+
"original": {
296
296
+
"path": "./modules/_example/ci/_theirs",
297
297
+
"type": "path"
298
298
+
},
299
299
+
"parent": []
271
300
}
272
301
},
273
302
"root": "root",
+10
templates/examples/flake.nix
···
43
43
nixpkgs-lib.follows = "nixpkgs";
44
44
nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05";
45
45
systems.url = "github:nix-systems/default";
46
46
+
theirs = {
47
47
+
inputs = {
48
48
+
den.follows = "den";
49
49
+
flake-aspects.follows = "flake-aspects";
50
50
+
flake-parts.follows = "flake-parts";
51
51
+
import-tree.follows = "import-tree";
52
52
+
nixpkgs.follows = "nixpkgs";
53
53
+
};
54
54
+
url = "path:./modules/_example/ci/_theirs";
55
55
+
};
46
56
};
47
57
48
58
}
+96
templates/examples/modules/_example/ci/_theirs/flake.lock
···
1
1
+
{
2
2
+
"nodes": {
3
3
+
"den": {
4
4
+
"locked": {
5
5
+
"lastModified": 1766081768,
6
6
+
"narHash": "sha256-8Ea1DW3YZHifezfdEFHWEIpZBNKvEL+3iFOEcl3eFBU=",
7
7
+
"owner": "vic",
8
8
+
"repo": "den",
9
9
+
"rev": "7271da18c60ab4d7c275ecaab480d29729f05d17",
10
10
+
"type": "github"
11
11
+
},
12
12
+
"original": {
13
13
+
"owner": "vic",
14
14
+
"repo": "den",
15
15
+
"type": "github"
16
16
+
}
17
17
+
},
18
18
+
"flake-aspects": {
19
19
+
"locked": {
20
20
+
"lastModified": 1766081176,
21
21
+
"narHash": "sha256-JrsuNSIEXPS3AiIxuWZw+sJ2Td6ni1OkqbW6mO/F4Rs=",
22
22
+
"owner": "vic",
23
23
+
"repo": "flake-aspects",
24
24
+
"rev": "d0a226c84be2900d307aa1896e4e2c6e451844b2",
25
25
+
"type": "github"
26
26
+
},
27
27
+
"original": {
28
28
+
"owner": "vic",
29
29
+
"repo": "flake-aspects",
30
30
+
"type": "github"
31
31
+
}
32
32
+
},
33
33
+
"flake-parts": {
34
34
+
"inputs": {
35
35
+
"nixpkgs-lib": [
36
36
+
"nixpkgs"
37
37
+
]
38
38
+
},
39
39
+
"locked": {
40
40
+
"lastModified": 1762980239,
41
41
+
"narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=",
42
42
+
"owner": "hercules-ci",
43
43
+
"repo": "flake-parts",
44
44
+
"rev": "52a2caecc898d0b46b2b905f058ccc5081f842da",
45
45
+
"type": "github"
46
46
+
},
47
47
+
"original": {
48
48
+
"owner": "hercules-ci",
49
49
+
"repo": "flake-parts",
50
50
+
"type": "github"
51
51
+
}
52
52
+
},
53
53
+
"import-tree": {
54
54
+
"locked": {
55
55
+
"lastModified": 1763263999,
56
56
+
"narHash": "sha256-AZ4UkBJQKfaL9sX+/mzc1xBtcJk8hDQGkhjWX0Py5hU=",
57
57
+
"owner": "vic",
58
58
+
"repo": "import-tree",
59
59
+
"rev": "058bd03ac818ea349946323ae3c2837b4cab7f22",
60
60
+
"type": "github"
61
61
+
},
62
62
+
"original": {
63
63
+
"owner": "vic",
64
64
+
"repo": "import-tree",
65
65
+
"type": "github"
66
66
+
}
67
67
+
},
68
68
+
"nixpkgs": {
69
69
+
"locked": {
70
70
+
"lastModified": 1763464769,
71
71
+
"narHash": "sha256-AJHrsT7VoeQzErpBRlLJM1SODcaayp0joAoEA35yiwM=",
72
72
+
"owner": "nixos",
73
73
+
"repo": "nixpkgs",
74
74
+
"rev": "6f374686605df381de8541c072038472a5ea2e2d",
75
75
+
"type": "github"
76
76
+
},
77
77
+
"original": {
78
78
+
"owner": "nixos",
79
79
+
"ref": "nixpkgs-unstable",
80
80
+
"repo": "nixpkgs",
81
81
+
"type": "github"
82
82
+
}
83
83
+
},
84
84
+
"root": {
85
85
+
"inputs": {
86
86
+
"den": "den",
87
87
+
"flake-aspects": "flake-aspects",
88
88
+
"flake-parts": "flake-parts",
89
89
+
"import-tree": "import-tree",
90
90
+
"nixpkgs": "nixpkgs"
91
91
+
}
92
92
+
}
93
93
+
},
94
94
+
"root": "root",
95
95
+
"version": 7
96
96
+
}
+13
templates/examples/modules/_example/ci/_theirs/flake.nix
···
1
1
+
{
2
2
+
outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules);
3
3
+
4
4
+
inputs = {
5
5
+
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
6
6
+
flake-parts.url = "github:hercules-ci/flake-parts";
7
7
+
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
8
8
+
9
9
+
import-tree.url = "github:vic/import-tree";
10
10
+
flake-aspects.url = "github:vic/flake-aspects";
11
11
+
den.url = "github:vic/den";
12
12
+
};
13
13
+
}
+21
templates/examples/modules/_example/ci/_theirs/modules/theirs.nix
···
1
1
+
# This flake is for testing by ci/namespace.nix
2
2
+
{ inputs, ... }:
3
3
+
{
4
4
+
systems = [
5
5
+
"x86_64-linux"
6
6
+
"aarch64-darwin"
7
7
+
];
8
8
+
imports = [
9
9
+
inputs.den.flakeModule
10
10
+
(inputs.den.namespace "sim" true)
11
11
+
];
12
12
+
13
13
+
sim.a._.b._.c._.d = {
14
14
+
nixos.sims = [ "theirs abcd" ];
15
15
+
};
16
16
+
17
17
+
sim.ul._.a._.tion = {
18
18
+
nixos.sims = [ "theirs simulation" ];
19
19
+
};
20
20
+
21
21
+
}
+13
-1
templates/examples/modules/_example/ci/namespace.nix
···
17
17
# enable <angle/bracket> syntax for finding aspects.
18
18
_module.args.__findFile = den.lib.__findFile;
19
19
20
20
+
# example "external" flake to import some aspects from.
21
21
+
flake-file.inputs.theirs = {
22
22
+
url = "path:./modules/_example/ci/_theirs";
23
23
+
inputs.nixpkgs.follows = "nixpkgs";
24
24
+
inputs.flake-parts.follows = "flake-parts";
25
25
+
inputs.import-tree.follows = "import-tree";
26
26
+
inputs.flake-aspects.follows = "flake-aspects";
27
27
+
inputs.den.follows = "den";
28
28
+
};
29
29
+
20
30
imports = [
21
31
# create a local namespace and output at flake.denful.eg
22
32
(inputs.den.namespace "eg" true)
···
34
44
inputA
35
45
inputB
36
46
exposeToFlake
47
47
+
inputs.theirs # from actual external flake
37
48
]
38
49
)
39
50
];
···
71
82
"inputB simulation"
72
83
"local namespace"
73
84
"local simulation"
85
85
+
"theirs simulation"
74
86
];
75
87
actual = lib.sort (a: b: a < b) rockhopper.config.sims;
76
88
in
77
77
-
expected == actual
89
89
+
expected == (builtins.trace actual actual)
78
90
);
79
91
80
92
};