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{
2 inputs,
3 lib,
4 config,
5 ...
6}:
7let
8 inherit (config) den;
9
10 hostsOption = lib.mkOption {
11 description = "den hosts definition";
12 default = { };
13 type = lib.types.attrsOf systemType;
14 };
15
16 systemType = lib.types.submodule (
17 { name, ... }:
18 {
19 freeformType = lib.types.attrsOf (hostType name);
20 }
21 );
22
23 hostType =
24 system:
25 lib.types.submodule (
26 { name, config, ... }:
27 {
28 freeformType = lib.types.attrsOf lib.types.anything;
29 options = {
30 name = strOpt "host configuration name" name;
31 hostName = strOpt "Network hostname" config.name;
32 system = strOpt "platform system" system;
33 class = strOpt "os-configuration nix class for host" (
34 if lib.hasSuffix "darwin" config.system then "darwin" else "nixos"
35 );
36 aspect = strOpt "main aspect name of <class>" config.name;
37 description = strOpt "host description" "${config.class}.${config.hostName}@${config.system}";
38 users = lib.mkOption {
39 description = "user accounts";
40 default = { };
41 type = lib.types.attrsOf userType;
42 };
43 instantiate = lib.mkOption {
44 description = ''
45 Function used to instantiate the OS configuration.
46
47 Depending on class, defaults to:
48 `darwin`: inputs.darwin.lib.darwinSystem
49 `nixos`: inputs.nixpkgs.lib.nixosSystem
50 `systemManager`: inputs.system-manager.lib.makeSystemConfig
51
52 Set explicitly if you need:
53
54 - a custom input name, eg, nixos-unstable.
55 - adding specialArgs when absolutely required.
56 '';
57 example = lib.literalExpression "inputs.nixpkgs.lib.nixosSystem";
58 type = lib.types.unspecified;
59 default =
60 {
61 nixos = inputs.nixpkgs.lib.nixosSystem;
62 darwin = inputs.darwin.lib.darwinSystem;
63 systemManager = inputs.system-manager.lib.makeSystemConfig;
64 }
65 .${config.class};
66 };
67 intoAttr = lib.mkOption {
68 description = ''
69 Flake attr where to add the named result of this configuration.
70 flake.<intoAttr>.<name>
71
72 Depending on class, defaults to:
73 `darwin`: darwinConfigurations
74 `nixos`: nixosConfigurations
75 `systemManager`: systemConfigs
76 '';
77 example = lib.literalExpression ''"nixosConfigurations"'';
78 type = lib.types.str;
79 default =
80 {
81 nixos = "nixosConfigurations";
82 darwin = "darwinConfigurations";
83 systemManager = "systemConfigs";
84 }
85 .${config.class};
86 };
87 mainModule = lib.mkOption {
88 description = ''
89 Defaults to: den.modules.<class>.<aspect>
90 Can be set in order to access a module in a different place.
91 '';
92 type = lib.types.deferredModule;
93 default = den.modules.${config.class}.${config.aspect};
94 };
95 };
96 }
97 );
98
99 userType = lib.types.submodule (
100 { name, config, ... }:
101 {
102 freeformType = lib.types.attrsOf lib.types.anything;
103 options = {
104 name = strOpt "user configuration name" name;
105 userName = strOpt "user account name" config.name;
106 class = strOpt "home management nix class" "homeManager";
107 aspect = strOpt "main aspect name" config.name;
108 };
109 }
110 );
111
112 strOpt =
113 description: default:
114 lib.mkOption {
115 type = lib.types.str;
116 inherit description default;
117 };
118
119 homesOption = lib.mkOption {
120 description = "den standalone home-manager configurations";
121 default = { };
122 type = lib.types.attrsOf homeSystemType;
123 };
124
125 homeSystemType = lib.types.submodule (
126 { name, ... }:
127 {
128 freeformType = lib.types.attrsOf (homeType name);
129 }
130 );
131
132 homeType =
133 system:
134 lib.types.submodule (
135 { name, config, ... }:
136 {
137 freeformType = lib.types.attrsOf lib.types.anything;
138 options = {
139 name = strOpt "home configuration name" name;
140 userName = strOpt "user account name" config.name;
141 system = strOpt "platform system" system;
142 class = strOpt "home management nix class" "homeManager";
143 aspect = strOpt "main aspect name" config.name;
144 description = strOpt "home description" "home.${config.userName}@${config.system}";
145 instantiate = lib.mkOption {
146 description = ''
147 Function used to instantiate the home configuration.
148
149 Depending on class, defaults to:
150 `homeManager`: inputs.home-manager.lib.homeManagerConfiguration
151
152 Set explicitly if you need:
153
154 - a custom input name, eg, home-manager-unstable.
155 - adding extraSpecialArgs when absolutely required.
156 '';
157 example = lib.literalExpression "inputs.home-manager.lib.homeManagerConfiguration";
158 type = lib.types.unspecified;
159 default =
160 {
161 homeManager = inputs.home-manager.lib.homeManagerConfiguration;
162 }
163 .${config.class};
164 };
165 intoAttr = lib.mkOption {
166 description = ''
167 Flake attr where to add the named result of this configuration.
168 flake.<intoAttr>.<name>
169
170 Depending on class, defaults to:
171 `homeManager`: homeConfigurations
172 '';
173 example = lib.literalExpression ''"homeConfigurations"'';
174 type = lib.types.str;
175 default =
176 {
177 homeManager = "homeConfigurations";
178 }
179 .${config.class};
180 };
181 mainModule = lib.mkOption {
182 description = ''
183 Defaults to: den.modules.<class>.<aspect>
184 Can be set in order to access a module in a different place.
185 '';
186 type = lib.types.deferredModule;
187 default = den.modules.${config.class}.${config.aspect};
188 };
189 };
190 }
191 );
192
193in
194{
195 inherit hostsOption homesOption;
196}