at 24.11-pre 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 (mkRenamedOptionModule [ "system" "forbiddenDependenciesRegex" ] [ "system" "forbiddenDependenciesRegexes" ]) 90 ]; 91 92 options = { 93 94 system.boot.loader.id = mkOption { 95 internal = true; 96 default = ""; 97 description = '' 98 Id string of the used bootloader. 99 ''; 100 }; 101 102 system.boot.loader.kernelFile = mkOption { 103 internal = true; 104 default = pkgs.stdenv.hostPlatform.linux-kernel.target; 105 defaultText = literalExpression "pkgs.stdenv.hostPlatform.linux-kernel.target"; 106 type = types.str; 107 description = '' 108 Name of the kernel file to be passed to the bootloader. 109 ''; 110 }; 111 112 system.boot.loader.initrdFile = mkOption { 113 internal = true; 114 default = "initrd"; 115 type = types.str; 116 description = '' 117 Name of the initrd file to be passed to the bootloader. 118 ''; 119 }; 120 121 system.build = { 122 toplevel = mkOption { 123 type = types.package; 124 readOnly = true; 125 description = '' 126 This option contains the store path that typically represents a NixOS system. 127 128 You can read this path in a custom deployment tool for example. 129 ''; 130 }; 131 }; 132 133 134 system.copySystemConfiguration = mkOption { 135 type = types.bool; 136 default = false; 137 description = '' 138 If enabled, copies the NixOS configuration file 139 (usually {file}`/etc/nixos/configuration.nix`) 140 and links it from the resulting system 141 (getting to {file}`/run/current-system/configuration.nix`). 142 Note that only this single file is copied, even if it imports others. 143 ''; 144 }; 145 146 system.systemBuilderCommands = mkOption { 147 type = types.lines; 148 internal = true; 149 default = ""; 150 description = '' 151 This code will be added to the builder creating the system store path. 152 ''; 153 }; 154 155 system.systemBuilderArgs = mkOption { 156 type = types.attrsOf types.unspecified; 157 internal = true; 158 default = {}; 159 description = '' 160 `lib.mkDerivation` attributes that will be passed to the top level system builder. 161 ''; 162 }; 163 164 system.forbiddenDependenciesRegexes = mkOption { 165 default = []; 166 example = ["-dev$"]; 167 type = types.listOf types.str; 168 description = '' 169 POSIX Extended Regular Expressions that match store paths that 170 should not appear in the system closure, with the exception of {option}`system.extraDependencies`, which is not checked. 171 ''; 172 }; 173 174 system.extraSystemBuilderCmds = mkOption { 175 type = types.lines; 176 internal = true; 177 default = ""; 178 description = '' 179 This code will be added to the builder creating the system store path. 180 ''; 181 }; 182 183 system.extraDependencies = mkOption { 184 type = types.listOf types.pathInStore; 185 default = []; 186 description = '' 187 A list of paths that should be included in the system 188 closure but generally not visible to users. 189 190 This option has also been used for build-time checks, but the 191 `system.checks` option is more appropriate for that purpose as checks 192 should not leave a trace in the built system configuration. 193 ''; 194 }; 195 196 system.checks = mkOption { 197 type = types.listOf types.package; 198 default = []; 199 description = '' 200 Packages that are added as dependencies of the system's build, usually 201 for the purpose of validating some part of the configuration. 202 203 Unlike `system.extraDependencies`, these store paths do not 204 become part of the built system configuration. 205 ''; 206 }; 207 208 system.replaceRuntimeDependencies = mkOption { 209 default = []; 210 example = lib.literalExpression "[ ({ original = pkgs.openssl; replacement = pkgs.callPackage /path/to/openssl { }; }) ]"; 211 type = types.listOf (types.submodule ( 212 { ... }: { 213 options.original = mkOption { 214 type = types.package; 215 description = "The original package to override."; 216 }; 217 218 options.replacement = mkOption { 219 type = types.package; 220 description = "The replacement package."; 221 }; 222 }) 223 ); 224 apply = map ({ original, replacement, ... }: { 225 oldDependency = original; 226 newDependency = replacement; 227 }); 228 description = '' 229 List of packages to override without doing a full rebuild. 230 The original derivation and replacement derivation must have the same 231 name length, and ideally should have close-to-identical directory layout. 232 ''; 233 }; 234 235 system.name = mkOption { 236 type = types.str; 237 default = 238 if config.networking.hostName == "" 239 then "unnamed" 240 else config.networking.hostName; 241 defaultText = literalExpression '' 242 if config.networking.hostName == "" 243 then "unnamed" 244 else config.networking.hostName; 245 ''; 246 description = '' 247 The name of the system used in the {option}`system.build.toplevel` derivation. 248 249 That derivation has the following name: 250 `"nixos-system-''${config.system.name}-''${config.system.nixos.label}"` 251 ''; 252 }; 253 254 system.includeBuildDependencies = mkOption { 255 type = types.bool; 256 default = false; 257 description = '' 258 Whether to include the build closure of the whole system in 259 its runtime closure. This can be useful for making changes 260 fully offline, as it includes all sources, patches, and 261 intermediate outputs required to build all the derivations 262 that the system depends on. 263 264 Note that this includes _all_ the derivations, down from the 265 included applications to their sources, the compilers used to 266 build them, and even the bootstrap compiler used to compile 267 the compilers. This increases the size of the system and the 268 time needed to download its dependencies drastically: a 269 minimal configuration with no extra services enabled grows 270 from ~670MiB in size to 13.5GiB, and takes proportionally 271 longer to download. 272 ''; 273 }; 274 275 }; 276 277 278 config = { 279 assertions = [ 280 { 281 assertion = config.system.copySystemConfiguration -> !lib.inPureEvalMode; 282 message = "system.copySystemConfiguration is not supported with flakes"; 283 } 284 ]; 285 286 system.extraSystemBuilderCmds = 287 optionalString 288 config.system.copySystemConfiguration 289 ''ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>}' \ 290 "$out/configuration.nix" 291 '' + 292 optionalString 293 (config.system.forbiddenDependenciesRegexes != []) (lib.concatStringsSep "\n" (map (regex: '' 294 if [[ ${regex} != "" && -n $closureInfo ]]; then 295 if forbiddenPaths="$(grep -E -- "${regex}" $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 '') config.system.forbiddenDependenciesRegexes)); 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.forbiddenDependenciesRegexes != []) { 323 closureInfo = pkgs.closureInfo { rootPaths = [ 324 # override to avoid infinite recursion (and to allow using extraDependencies to add forbidden dependencies) 325 (config.system.build.toplevel.overrideAttrs (_: { extraDependencies = []; closureInfo = null; })) 326 ]; }; 327 }; 328 329 330 system.build.toplevel = if config.system.includeBuildDependencies then systemWithBuildDeps else system; 331 332 }; 333 334}