python312Packages.google-auth-oauthlib: fix build in darwin sandbox (#373724)
[NixPkgs.git] / nixos / modules / system / activation / top-level.nix
blob3c42e6c04a485f300c5d7bce13e0bfcf6d780d0c
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   systemBuilder =
7     ''
8       mkdir $out
10       ${if config.boot.initrd.systemd.enable then ''
11         cp ${config.system.build.bootStage2} $out/prepare-root
12         substituteInPlace $out/prepare-root --subst-var-by systemConfig $out
13         # This must not be a symlink or the abs_path of the grub builder for the tests
14         # will resolve the symlink and we end up with a path that doesn't point to a
15         # system closure.
16         cp "$systemd/lib/systemd/systemd" $out/init
17       '' else ''
18         cp ${config.system.build.bootStage2} $out/init
19         substituteInPlace $out/init --subst-var-by systemConfig $out
20       ''}
22       ln -s ${config.system.build.etc}/etc $out/etc
24       ${lib.optionalString config.system.etc.overlay.enable ''
25         ln -s ${config.system.build.etcMetadataImage} $out/etc-metadata-image
26         ln -s ${config.system.build.etcBasedir} $out/etc-basedir
27       ''}
29       ln -s ${config.system.path} $out/sw
30       ln -s "$systemd" $out/systemd
32       echo -n "systemd ${toString config.systemd.package.interfaceVersion}" > $out/init-interface-version
33       echo -n "$nixosLabel" > $out/nixos-version
34       echo -n "${config.boot.kernelPackages.stdenv.hostPlatform.system}" > $out/system
36       ${config.system.systemBuilderCommands}
38       cp "$extraDependenciesPath" "$out/extra-dependencies"
40       ${optionalString (!config.boot.isContainer && config.boot.bootspec.enable) ''
41         ${config.boot.bootspec.writer}
42         ${optionalString config.boot.bootspec.enableValidation
43           ''${config.boot.bootspec.validator} "$out/${config.boot.bootspec.filename}"''}
44       ''}
46       ${config.system.extraSystemBuilderCmds}
47     '';
49   # Putting it all together.  This builds a store path containing
50   # symlinks to the various parts of the built configuration (the
51   # kernel, systemd units, init scripts, etc.) as well as a script
52   # `switch-to-configuration' that activates the configuration and
53   # makes it bootable. See `activatable-system.nix`.
54   baseSystem = pkgs.stdenvNoCC.mkDerivation ({
55     name = "nixos-system-${config.system.name}-${config.system.nixos.label}";
56     preferLocalBuild = true;
57     allowSubstitutes = false;
58     passAsFile = [ "extraDependencies" ];
59     buildCommand = systemBuilder;
61     systemd = config.systemd.package;
63     nixosLabel = config.system.nixos.label;
65     inherit (config.system) extraDependencies;
66   } // config.system.systemBuilderArgs);
68   # Handle assertions and warnings
70   failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions);
72   baseSystemAssertWarn = if failedAssertions != []
73     then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
74     else showWarnings config.warnings baseSystem;
76   # Replace runtime dependencies
77   system = let inherit (config.system.replaceDependencies) replacements cutoffPackages; in
78     if replacements == [] then
79       # Avoid IFD if possible, by sidestepping replaceDependencies if no replacements are specified.
80       baseSystemAssertWarn
81     else
82       (pkgs.replaceDependencies.override {
83         replaceDirectDependencies = pkgs.replaceDirectDependencies.override {
84           nix = config.nix.package;
85         };
86       }) {
87         drv = baseSystemAssertWarn;
88         inherit replacements cutoffPackages;
89       };
91   systemWithBuildDeps = system.overrideAttrs (o: {
92     systemBuildClosure = pkgs.closureInfo { rootPaths = [ system.drvPath ]; };
93     buildCommand = o.buildCommand + ''
94       ln -sn $systemBuildClosure $out/build-closure
95     '';
96   });
101   imports = [
102     ../build.nix
103     (mkRemovedOptionModule [ "nesting" "clone" ] "Use `specialisation.«name» = { inheritParentConfig = true; configuration = { ... }; }` instead.")
104     (mkRemovedOptionModule [ "nesting" "children" ] "Use `specialisation.«name».configuration = { ... }` instead.")
105     (mkRenamedOptionModule [ "system" "forbiddenDependenciesRegex" ] [ "system" "forbiddenDependenciesRegexes" ])
106     (mkRenamedOptionModule [ "system" "replaceRuntimeDependencies" ] [ "system" "replaceDependencies" "replacements" ])
107   ];
109   options = {
111     system.boot.loader.id = mkOption {
112       internal = true;
113       default = "";
114       description = ''
115         Id string of the used bootloader.
116       '';
117     };
119     system.boot.loader.kernelFile = mkOption {
120       internal = true;
121       default = pkgs.stdenv.hostPlatform.linux-kernel.target;
122       defaultText = literalExpression "pkgs.stdenv.hostPlatform.linux-kernel.target";
123       type = types.str;
124       description = ''
125         Name of the kernel file to be passed to the bootloader.
126       '';
127     };
129     system.boot.loader.initrdFile = mkOption {
130       internal = true;
131       default = "initrd";
132       type = types.str;
133       description = ''
134         Name of the initrd file to be passed to the bootloader.
135       '';
136     };
138     system.build = {
139       toplevel = mkOption {
140         type = types.package;
141         readOnly = true;
142         description = ''
143           This option contains the store path that typically represents a NixOS system.
145           You can read this path in a custom deployment tool for example.
146         '';
147       };
148     };
151     system.copySystemConfiguration = mkOption {
152       type = types.bool;
153       default = false;
154       description = ''
155         If enabled, copies the NixOS configuration file
156         (usually {file}`/etc/nixos/configuration.nix`)
157         and symlinks it from the resulting system
158         (getting to {file}`/run/current-system/configuration.nix`).
159         Note that only this single file is copied, even if it imports others.
160         Warning: This feature cannot be used when the system is configured by a flake
161       '';
162     };
164     system.systemBuilderCommands = mkOption {
165       type = types.lines;
166       internal = true;
167       default = "";
168       description = ''
169         This code will be added to the builder creating the system store path.
170       '';
171     };
173     system.systemBuilderArgs = mkOption {
174       type = types.attrsOf types.unspecified;
175       internal = true;
176       default = {};
177       description = ''
178         `lib.mkDerivation` attributes that will be passed to the top level system builder.
179       '';
180     };
182     system.forbiddenDependenciesRegexes = mkOption {
183       default = [];
184       example = ["-dev$"];
185       type = types.listOf types.str;
186       description = ''
187         POSIX Extended Regular Expressions that match store paths that
188         should not appear in the system closure, with the exception of {option}`system.extraDependencies`, which is not checked.
189       '';
190     };
192     system.extraSystemBuilderCmds = mkOption {
193       type = types.lines;
194       internal = true;
195       default = "";
196       description = ''
197         This code will be added to the builder creating the system store path.
198       '';
199     };
201     system.extraDependencies = mkOption {
202       type = types.listOf types.pathInStore;
203       default = [];
204       description = ''
205         A list of paths that should be included in the system
206         closure but generally not visible to users.
208         This option has also been used for build-time checks, but the
209         `system.checks` option is more appropriate for that purpose as checks
210         should not leave a trace in the built system configuration.
211       '';
212     };
214     system.checks = mkOption {
215       type = types.listOf types.package;
216       default = [];
217       description = ''
218         Packages that are added as dependencies of the system's build, usually
219         for the purpose of validating some part of the configuration.
221         Unlike `system.extraDependencies`, these store paths do not
222         become part of the built system configuration.
223       '';
224     };
226     system.replaceDependencies = {
227       replacements = mkOption {
228         default = [];
229         example = lib.literalExpression "[ ({ oldDependency = pkgs.openssl; newDependency = pkgs.callPackage /path/to/openssl { }; }) ]";
230         type = types.listOf (types.submodule (
231           { ... }: {
232             imports = [
233               (mkRenamedOptionModule [ "original" ] [ "oldDependency" ])
234               (mkRenamedOptionModule [ "replacement" ] [ "newDependency" ])
235             ];
237             options.oldDependency = mkOption {
238               type = types.package;
239               description = "The original package to override.";
240             };
242             options.newDependency = mkOption {
243               type = types.package;
244               description = "The replacement package.";
245             };
246           })
247         );
248         apply = map ({ oldDependency, newDependency, ... }: {
249           inherit oldDependency newDependency;
250         });
251         description = ''
252           List of packages to override without doing a full rebuild.
253           The original derivation and replacement derivation must have the same
254           name length, and ideally should have close-to-identical directory layout.
255         '';
256       };
258       cutoffPackages = mkOption {
259         default = [ config.system.build.initialRamdisk ];
260         defaultText = literalExpression "[ config.system.build.initialRamdisk ]";
261         type = types.listOf types.package;
262         description = ''
263           Packages to which no replacements should be applied.
264           The initrd is matched by default, because its structure renders the replacement process ineffective and prone to breakage.
265         '';
266       };
267     };
269     system.name = mkOption {
270       type = types.str;
271       default =
272         if config.networking.hostName == ""
273         then "unnamed"
274         else config.networking.hostName;
275       defaultText = literalExpression ''
276         if config.networking.hostName == ""
277         then "unnamed"
278         else config.networking.hostName;
279       '';
280       description = ''
281         The name of the system used in the {option}`system.build.toplevel` derivation.
283         That derivation has the following name:
284         `"nixos-system-''${config.system.name}-''${config.system.nixos.label}"`
285       '';
286     };
288     system.includeBuildDependencies = mkOption {
289       type = types.bool;
290       default = false;
291       description = ''
292         Whether to include the build closure of the whole system in
293         its runtime closure.  This can be useful for making changes
294         fully offline, as it includes all sources, patches, and
295         intermediate outputs required to build all the derivations
296         that the system depends on.
298         Note that this includes _all_ the derivations, down from the
299         included applications to their sources, the compilers used to
300         build them, and even the bootstrap compiler used to compile
301         the compilers. This increases the size of the system and the
302         time needed to download its dependencies drastically: a
303         minimal configuration with no extra services enabled grows
304         from ~670MiB in size to 13.5GiB, and takes proportionally
305         longer to download.
306       '';
307     };
309   };
312   config = {
313     assertions = [
314       {
315         assertion = config.system.copySystemConfiguration -> !lib.inPureEvalMode;
316         message = "system.copySystemConfiguration is not supported with flakes";
317       }
318     ];
320     system.extraSystemBuilderCmds =
321       optionalString
322         config.system.copySystemConfiguration ''
323           ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>}' \
324             "$out/configuration.nix"
325         '' +
326       optionalString
327         (config.system.forbiddenDependenciesRegexes != []) (lib.concatStringsSep "\n" (map (regex: ''
328           if [[ ${regex} != "" && -n $closureInfo ]]; then
329             if forbiddenPaths="$(grep -E -- "${regex}" $closureInfo/store-paths)"; then
330               echo -e "System closure $out contains the following disallowed paths:\n$forbiddenPaths"
331               exit 1
332             fi
333           fi
334         '') config.system.forbiddenDependenciesRegexes));
336     system.systemBuilderArgs = {
338       # Legacy environment variables. These were used by the activation script,
339       # but some other script might still depend on them, although unlikely.
340       installBootLoader = config.system.build.installBootLoader;
341       localeArchive = "${config.i18n.glibcLocales}/lib/locale/locale-archive";
342       distroId = config.system.nixos.distroId;
343       perl = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp ]);
344       # End if legacy environment variables
346       preSwitchCheck = config.system.preSwitchChecks.script;
348       # Not actually used in the builder. `passedChecks` is just here to create
349       # the build dependencies. Checks are similar to build dependencies in the
350       # sense that if they fail, the system build fails. However, checks do not
351       # produce any output of value, so they are not used by the system builder.
352       # In fact, using them runs the risk of accidentally adding unneeded paths
353       # to the system closure, which defeats the purpose of the `system.checks`
354       # option, as opposed to `system.extraDependencies`.
355       passedChecks = concatStringsSep " " config.system.checks;
356     }
357     // lib.optionalAttrs (config.system.forbiddenDependenciesRegexes != []) {
358       closureInfo = pkgs.closureInfo { rootPaths = [
359         # override to avoid  infinite recursion (and to allow using extraDependencies to add forbidden dependencies)
360         (config.system.build.toplevel.overrideAttrs (_: { extraDependencies = []; closureInfo = null; }))
361       ]; };
362     };
365     system.build.toplevel = if config.system.includeBuildDependencies then systemWithBuildDeps else system;
367   };