1{
2 config,
3 lib,
4 options,
5 pkgs,
6 ...
7}:
8
9let
10 cfg = config.system.nixos;
11 opt = options.system.nixos;
12
13 inherit (lib)
14 concatStringsSep
15 mapAttrsToList
16 toLower
17 optionalString
18 literalExpression
19 match
20 mkRenamedOptionModule
21 mkDefault
22 mkOption
23 trivial
24 types
25 ;
26
27 needsEscaping = s: null != builtins.match "[a-zA-Z0-9]+" s;
28 escapeIfNecessary = s: if needsEscaping s then s else ''"${lib.escape [ "$" "\"" "\\" "`" ] s}"'';
29 attrsToText =
30 attrs:
31 concatStringsSep "\n" (mapAttrsToList (n: v: ''${n}=${escapeIfNecessary (toString v)}'') attrs)
32 + "\n";
33
34 osReleaseContents =
35 let
36 isNixos = cfg.distroId == "nixos";
37 in
38 {
39 NAME = "${cfg.distroName}";
40 ID = "${cfg.distroId}";
41 ID_LIKE = optionalString (!isNixos) "nixos";
42 VENDOR_NAME = cfg.vendorName;
43 VERSION = "${cfg.release} (${cfg.codeName})";
44 VERSION_CODENAME = toLower cfg.codeName;
45 VERSION_ID = cfg.release;
46 BUILD_ID = cfg.version;
47 PRETTY_NAME = "${cfg.distroName} ${cfg.release} (${cfg.codeName})";
48 CPE_NAME = "cpe:/o:${cfg.vendorId}:${cfg.distroId}:${cfg.release}";
49 LOGO = "nix-snowflake";
50 HOME_URL = optionalString isNixos "https://nixos.org/";
51 VENDOR_URL = optionalString isNixos "https://nixos.org/";
52 DOCUMENTATION_URL = optionalString isNixos "https://nixos.org/learn.html";
53 SUPPORT_URL = optionalString isNixos "https://nixos.org/community.html";
54 BUG_REPORT_URL = optionalString isNixos "https://github.com/NixOS/nixpkgs/issues";
55 ANSI_COLOR = optionalString isNixos "0;38;2;126;186;228";
56 IMAGE_ID = optionalString (config.system.image.id != null) config.system.image.id;
57 IMAGE_VERSION = optionalString (config.system.image.version != null) config.system.image.version;
58 VARIANT = optionalString (cfg.variantName != null) cfg.variantName;
59 VARIANT_ID = optionalString (cfg.variant_id != null) cfg.variant_id;
60 DEFAULT_HOSTNAME = config.system.nixos.distroId;
61 }
62 // cfg.extraOSReleaseArgs;
63
64 initrdReleaseContents = (removeAttrs osReleaseContents [ "BUILD_ID" ]) // {
65 PRETTY_NAME = "${osReleaseContents.PRETTY_NAME} (Initrd)";
66 };
67 initrdRelease = pkgs.writeText "initrd-release" (attrsToText initrdReleaseContents);
68
69in
70{
71 imports = [
72 ./label.nix
73 (mkRenamedOptionModule [ "system" "nixosVersion" ] [ "system" "nixos" "version" ])
74 (mkRenamedOptionModule [ "system" "nixosVersionSuffix" ] [ "system" "nixos" "versionSuffix" ])
75 (mkRenamedOptionModule [ "system" "nixosRevision" ] [ "system" "nixos" "revision" ])
76 (mkRenamedOptionModule [ "system" "nixosLabel" ] [ "system" "nixos" "label" ])
77 ];
78
79 options.boot.initrd.osRelease = mkOption {
80 internal = true;
81 readOnly = true;
82 default = initrdRelease;
83 };
84
85 options.system = {
86 nixos = {
87 version = mkOption {
88 internal = true;
89 type = types.str;
90 description = "The full NixOS version (e.g. `16.03.1160.f2d4ee1`).";
91 };
92
93 release = mkOption {
94 readOnly = true;
95 type = types.str;
96 default = trivial.release;
97 description = "The NixOS release (e.g. `16.03`).";
98 };
99
100 versionSuffix = mkOption {
101 internal = true;
102 type = types.str;
103 default = trivial.versionSuffix;
104 description = "The NixOS version suffix (e.g. `1160.f2d4ee1`).";
105 };
106
107 revision = mkOption {
108 internal = true;
109 type = types.nullOr types.str;
110 default = trivial.revisionWithDefault null;
111 description = "The Git revision from which this NixOS configuration was built.";
112 };
113
114 codeName = mkOption {
115 readOnly = true;
116 type = types.str;
117 default = trivial.codeName;
118 description = "The NixOS release code name (e.g. `Emu`).";
119 };
120
121 distroId = mkOption {
122 internal = true;
123 type = types.str;
124 default = "nixos";
125 description = "The id of the operating system";
126 };
127
128 distroName = mkOption {
129 internal = true;
130 type = types.str;
131 default = "NixOS";
132 description = "The name of the operating system";
133 };
134
135 variant_id = mkOption {
136 type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
137 default = null;
138 description = "A lower-case string identifying a specific variant or edition of the operating system";
139 example = "installer";
140 };
141
142 variantName = mkOption {
143 type = types.nullOr types.str;
144 default = null;
145 description = "A string identifying a specific variant or edition of the operating system suitable for presentation to the user";
146 example = "NixOS Installer Image";
147 };
148
149 vendorId = mkOption {
150 internal = true;
151 type = types.str;
152 default = "nixos";
153 description = "The id of the operating system vendor";
154 };
155
156 vendorName = mkOption {
157 internal = true;
158 type = types.str;
159 default = "NixOS";
160 description = "The name of the operating system vendor";
161 };
162
163 extraOSReleaseArgs = mkOption {
164 internal = true;
165 type = types.attrsOf types.str;
166 default = { };
167 description = "Additional attributes to be merged with the /etc/os-release generator.";
168 example = {
169 ANSI_COLOR = "1;31";
170 };
171 };
172
173 extraLSBReleaseArgs = mkOption {
174 internal = true;
175 type = types.attrsOf types.str;
176 default = { };
177 description = "Additional attributes to be merged with the /etc/lsb-release generator.";
178 example = {
179 LSB_VERSION = "1.0";
180 };
181 };
182 };
183
184 image = {
185
186 id = lib.mkOption {
187 type = types.nullOr types.str;
188 default = null;
189 description = ''
190 Image identifier.
191
192 This corresponds to the `IMAGE_ID` field in {manpage}`os-release(5)`. See the
193 upstream docs for more details on valid characters for this field:
194 <https://www.freedesktop.org/software/systemd/man/latest/os-release.html#IMAGE_ID=>
195
196 You would only want to set this option if you're build NixOS appliance images.
197 '';
198 };
199
200 version = lib.mkOption {
201 type = types.nullOr types.str;
202 default = null;
203 description = ''
204 Image version.
205
206 This corresponds to the `IMAGE_VERSION` field in {manpage}`os-release(5)`. See the
207 upstream docs for more details on valid characters for this field:
208 <https://www.freedesktop.org/software/systemd/man/latest/os-release.html#IMAGE_VERSION=>
209
210 You would only want to set this option if you're build NixOS appliance images.
211 '';
212 };
213
214 };
215
216 stateVersion = mkOption {
217 type = types.str;
218 # TODO Remove this and drop the default of the option so people are forced to set it.
219 # Doing this also means fixing the comment in nixos/modules/testing/test-instrumentation.nix
220 apply =
221 v:
222 lib.warnIf (options.system.stateVersion.highestPrio == (lib.mkOptionDefault { }).priority)
223 "system.stateVersion is not set, defaulting to ${v}. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion."
224 v;
225 default = cfg.release;
226 defaultText = literalExpression "config.${opt.release}";
227 description = ''
228 This option defines the first version of NixOS you have installed on this particular machine,
229 and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
230
231 For example, if NixOS version XX.YY ships with AwesomeDB version N by default, and is then
232 upgraded to version XX.YY+1, which ships AwesomeDB version N+1, the existing databases
233 may no longer be compatible, causing applications to fail, or even leading to data loss.
234
235 The `stateVersion` mechanism avoids this situation by making the default version of such packages
236 conditional on the first version of NixOS you've installed (encoded in `stateVersion`), instead of
237 simply always using the latest one.
238
239 Note that this generally only affects applications that can't upgrade their data automatically -
240 applications and services supporting automatic migrations will remain on latest versions when
241 you upgrade.
242
243 Most users should **never** change this value after the initial install, for any reason,
244 even if you've upgraded your system to a new NixOS release.
245
246 This value does **not** affect the Nixpkgs version your packages and OS are pulled from,
247 so changing it will **not** upgrade your system.
248
249 This value being lower than the current NixOS release does **not** mean your system is
250 out of date, out of support, or vulnerable.
251
252 Do **not** change this value unless you have manually inspected all the changes it would
253 make to your configuration, and migrated your data accordingly.
254 '';
255 };
256
257 configurationRevision = mkOption {
258 type = types.nullOr types.str;
259 default = null;
260 description = "The Git revision of the top-level flake from which this configuration was built.";
261 };
262
263 };
264
265 config = {
266
267 assertions = [
268 {
269 assertion = match "[0-9]{2}\\.[0-9]{2}" config.system.stateVersion != null;
270 message = ''
271 ${config.system.stateVersion} is an invalid value for 'system.stateVersion'; it must be in the format "YY.MM",
272 which corresponds to a prior release of NixOS.
273
274 If you want to switch releases or switch to unstable, you should change your channel and/or flake input URLs only.
275 *DO NOT* touch the 'system.stateVersion' option, as it will not help you upgrade.
276 Leave it exactly on the previous value, which is likely the value you had for it when you installed your system.
277
278 If you're unsure which value to set it to, use "${
279 if match "[0-9]{2}\\.[0-9]{2}" options.system.stateVersion.default != null then
280 options.system.stateVersion.default
281 else
282 options.system.nixos.release.default
283 }" as a default.
284 '';
285 }
286 ];
287
288 system.nixos = {
289 # These defaults are set here rather than up there so that
290 # changing them would not rebuild the manual
291 version = mkDefault (cfg.release + cfg.versionSuffix);
292 };
293
294 # Generate /etc/os-release. See
295 # https://www.freedesktop.org/software/systemd/man/os-release.html for the
296 # format.
297 environment.etc = {
298 "lsb-release".text = attrsToText (
299 {
300 LSB_VERSION = "${cfg.release} (${cfg.codeName})";
301 DISTRIB_ID = "${cfg.distroId}";
302 DISTRIB_RELEASE = cfg.release;
303 DISTRIB_CODENAME = toLower cfg.codeName;
304 DISTRIB_DESCRIPTION = "${cfg.distroName} ${cfg.release} (${cfg.codeName})";
305 }
306 // cfg.extraLSBReleaseArgs
307 );
308
309 "os-release".text = attrsToText osReleaseContents;
310 };
311
312 };
313
314 # uses version info nixpkgs, which requires a full nixpkgs path
315 meta.buildDocsInSandbox = false;
316}