at 23.11-beta 12 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 systemBuilder = 7 '' 8 mkdir $out 9 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 ''} 21 22 ln -s ${config.system.build.etc}/etc $out/etc 23 ln -s ${config.system.path} $out/sw 24 ln -s "$systemd" $out/systemd 25 26 echo -n "systemd ${toString config.systemd.package.interfaceVersion}" > $out/init-interface-version 27 echo -n "$nixosLabel" > $out/nixos-version 28 echo -n "${config.boot.kernelPackages.stdenv.hostPlatform.system}" > $out/system 29 30 ${config.system.systemBuilderCommands} 31 32 cp "$extraDependenciesPath" "$out/extra-dependencies" 33 34 ${optionalString (!config.boot.isContainer && config.boot.bootspec.enable) '' 35 ${config.boot.bootspec.writer} 36 ${optionalString config.boot.bootspec.enableValidation 37 ''${config.boot.bootspec.validator} "$out/${config.boot.bootspec.filename}"''} 38 ''} 39 40 ${config.system.extraSystemBuilderCmds} 41 ''; 42 43 # Putting it all together. This builds a store path containing 44 # symlinks to the various parts of the built configuration (the 45 # kernel, systemd units, init scripts, etc.) as well as a script 46 # `switch-to-configuration' that activates the configuration and 47 # makes it bootable. See `activatable-system.nix`. 48 baseSystem = pkgs.stdenvNoCC.mkDerivation ({ 49 name = "nixos-system-${config.system.name}-${config.system.nixos.label}"; 50 preferLocalBuild = true; 51 allowSubstitutes = false; 52 passAsFile = [ "extraDependencies" ]; 53 buildCommand = systemBuilder; 54 55 systemd = config.systemd.package; 56 57 nixosLabel = config.system.nixos.label; 58 59 inherit (config.system) extraDependencies; 60 } // config.system.systemBuilderArgs); 61 62 # Handle assertions and warnings 63 64 failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions); 65 66 baseSystemAssertWarn = if failedAssertions != [] 67 then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" 68 else showWarnings config.warnings baseSystem; 69 70 # Replace runtime dependencies 71 system = foldr ({ oldDependency, newDependency }: drv: 72 pkgs.replaceDependency { inherit oldDependency newDependency drv; } 73 ) baseSystemAssertWarn config.system.replaceRuntimeDependencies; 74 75 systemWithBuildDeps = system.overrideAttrs (o: { 76 systemBuildClosure = pkgs.closureInfo { rootPaths = [ system.drvPath ]; }; 77 buildCommand = o.buildCommand + '' 78 ln -sn $systemBuildClosure $out/build-closure 79 ''; 80 }); 81 82in 83 84{ 85 imports = [ 86 ../build.nix 87 (mkRemovedOptionModule [ "nesting" "clone" ] "Use `specialisation.«name» = { inheritParentConfig = true; configuration = { ... }; }` instead.") 88 (mkRemovedOptionModule [ "nesting" "children" ] "Use `specialisation.«name».configuration = { ... }` instead.") 89 ]; 90 91 options = { 92 93 system.boot.loader.id = mkOption { 94 internal = true; 95 default = ""; 96 description = lib.mdDoc '' 97 Id string of the used bootloader. 98 ''; 99 }; 100 101 system.boot.loader.kernelFile = mkOption { 102 internal = true; 103 default = pkgs.stdenv.hostPlatform.linux-kernel.target; 104 defaultText = literalExpression "pkgs.stdenv.hostPlatform.linux-kernel.target"; 105 type = types.str; 106 description = lib.mdDoc '' 107 Name of the kernel file to be passed to the bootloader. 108 ''; 109 }; 110 111 system.boot.loader.initrdFile = mkOption { 112 internal = true; 113 default = "initrd"; 114 type = types.str; 115 description = lib.mdDoc '' 116 Name of the initrd file to be passed to the bootloader. 117 ''; 118 }; 119 120 system.build = { 121 toplevel = mkOption { 122 type = types.package; 123 readOnly = true; 124 description = lib.mdDoc '' 125 This option contains the store path that typically represents a NixOS system. 126 127 You can read this path in a custom deployment tool for example. 128 ''; 129 }; 130 }; 131 132 133 system.copySystemConfiguration = mkOption { 134 type = types.bool; 135 default = false; 136 description = lib.mdDoc '' 137 If enabled, copies the NixOS configuration file 138 (usually {file}`/etc/nixos/configuration.nix`) 139 and links it from the resulting system 140 (getting to {file}`/run/current-system/configuration.nix`). 141 Note that only this single file is copied, even if it imports others. 142 ''; 143 }; 144 145 system.systemBuilderCommands = mkOption { 146 type = types.lines; 147 internal = true; 148 default = ""; 149 description = '' 150 This code will be added to the builder creating the system store path. 151 ''; 152 }; 153 154 system.systemBuilderArgs = mkOption { 155 type = types.attrsOf types.unspecified; 156 internal = true; 157 default = {}; 158 description = lib.mdDoc '' 159 `lib.mkDerivation` attributes that will be passed to the top level system builder. 160 ''; 161 }; 162 163 system.forbiddenDependenciesRegex = mkOption { 164 default = ""; 165 example = "-dev$"; 166 type = types.str; 167 description = lib.mdDoc '' 168 A POSIX Extended Regular Expression that matches store paths that 169 should not appear in the system closure, with the exception of {option}`system.extraDependencies`, which is not checked. 170 ''; 171 }; 172 173 system.extraSystemBuilderCmds = mkOption { 174 type = types.lines; 175 internal = true; 176 default = ""; 177 description = lib.mdDoc '' 178 This code will be added to the builder creating the system store path. 179 ''; 180 }; 181 182 system.extraDependencies = mkOption { 183 type = types.listOf types.pathInStore; 184 default = []; 185 description = lib.mdDoc '' 186 A list of paths that should be included in the system 187 closure but generally not visible to users. 188 189 This option has also been used for build-time checks, but the 190 `system.checks` option is more appropriate for that purpose as checks 191 should not leave a trace in the built system configuration. 192 ''; 193 }; 194 195 system.checks = mkOption { 196 type = types.listOf types.package; 197 default = []; 198 description = lib.mdDoc '' 199 Packages that are added as dependencies of the system's build, usually 200 for the purpose of validating some part of the configuration. 201 202 Unlike `system.extraDependencies`, these store paths do not 203 become part of the built system configuration. 204 ''; 205 }; 206 207 system.replaceRuntimeDependencies = mkOption { 208 default = []; 209 example = lib.literalExpression "[ ({ original = pkgs.openssl; replacement = pkgs.callPackage /path/to/openssl { }; }) ]"; 210 type = types.listOf (types.submodule ( 211 { ... }: { 212 options.original = mkOption { 213 type = types.package; 214 description = lib.mdDoc "The original package to override."; 215 }; 216 217 options.replacement = mkOption { 218 type = types.package; 219 description = lib.mdDoc "The replacement package."; 220 }; 221 }) 222 ); 223 apply = map ({ original, replacement, ... }: { 224 oldDependency = original; 225 newDependency = replacement; 226 }); 227 description = lib.mdDoc '' 228 List of packages to override without doing a full rebuild. 229 The original derivation and replacement derivation must have the same 230 name length, and ideally should have close-to-identical directory layout. 231 ''; 232 }; 233 234 system.name = mkOption { 235 type = types.str; 236 default = 237 if config.networking.hostName == "" 238 then "unnamed" 239 else config.networking.hostName; 240 defaultText = literalExpression '' 241 if config.networking.hostName == "" 242 then "unnamed" 243 else config.networking.hostName; 244 ''; 245 description = lib.mdDoc '' 246 The name of the system used in the {option}`system.build.toplevel` derivation. 247 248 That derivation has the following name: 249 `"nixos-system-''${config.system.name}-''${config.system.nixos.label}"` 250 ''; 251 }; 252 253 system.includeBuildDependencies = mkOption { 254 type = types.bool; 255 default = false; 256 description = lib.mdDoc '' 257 Whether to include the build closure of the whole system in 258 its runtime closure. This can be useful for making changes 259 fully offline, as it includes all sources, patches, and 260 intermediate outputs required to build all the derivations 261 that the system depends on. 262 263 Note that this includes _all_ the derivations, down from the 264 included applications to their sources, the compilers used to 265 build them, and even the bootstrap compiler used to compile 266 the compilers. This increases the size of the system and the 267 time needed to download its dependencies drastically: a 268 minimal configuration with no extra services enabled grows 269 from ~670MiB in size to 13.5GiB, and takes proportionally 270 longer to download. 271 ''; 272 }; 273 274 }; 275 276 277 config = { 278 assertions = [ 279 { 280 assertion = config.system.copySystemConfiguration -> !lib.inPureEvalMode; 281 message = "system.copySystemConfiguration is not supported with flakes"; 282 } 283 ]; 284 285 system.extraSystemBuilderCmds = 286 optionalString 287 config.system.copySystemConfiguration 288 ''ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>}' \ 289 "$out/configuration.nix" 290 '' + 291 optionalString 292 (config.system.forbiddenDependenciesRegex != "") 293 '' 294 if [[ $forbiddenDependenciesRegex != "" && -n $closureInfo ]]; then 295 if forbiddenPaths="$(grep -E -- "$forbiddenDependenciesRegex" $closureInfo/store-paths)"; then 296 echo -e "System closure $out contains the following disallowed paths:\n$forbiddenPaths" 297 exit 1 298 fi 299 fi 300 ''; 301 302 system.systemBuilderArgs = { 303 304 # Legacy environment variables. These were used by the activation script, 305 # but some other script might still depend on them, although unlikely. 306 installBootLoader = config.system.build.installBootLoader; 307 localeArchive = "${config.i18n.glibcLocales}/lib/locale/locale-archive"; 308 distroId = config.system.nixos.distroId; 309 perl = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp ]); 310 # End if legacy environment variables 311 312 313 # Not actually used in the builder. `passedChecks` is just here to create 314 # the build dependencies. Checks are similar to build dependencies in the 315 # sense that if they fail, the system build fails. However, checks do not 316 # produce any output of value, so they are not used by the system builder. 317 # In fact, using them runs the risk of accidentally adding unneeded paths 318 # to the system closure, which defeats the purpose of the `system.checks` 319 # option, as opposed to `system.extraDependencies`. 320 passedChecks = concatStringsSep " " config.system.checks; 321 } 322 // lib.optionalAttrs (config.system.forbiddenDependenciesRegex != "") { 323 inherit (config.system) forbiddenDependenciesRegex; 324 closureInfo = pkgs.closureInfo { rootPaths = [ 325 # override to avoid infinite recursion (and to allow using extraDependencies to add forbidden dependencies) 326 (config.system.build.toplevel.overrideAttrs (_: { extraDependencies = []; closureInfo = null; })) 327 ]; }; 328 }; 329 330 331 system.build.toplevel = if config.system.includeBuildDependencies then systemWithBuildDeps else system; 332 333 }; 334 335}