at 23.05-pre 11 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 systemBuilder = 7 let 8 kernelPath = "${config.boot.kernelPackages.kernel}/" + 9 "${config.system.boot.loader.kernelFile}"; 10 initrdPath = "${config.system.build.initialRamdisk}/" + 11 "${config.system.boot.loader.initrdFile}"; 12 in '' 13 mkdir $out 14 15 # Containers don't have their own kernel or initrd. They boot 16 # directly into stage 2. 17 ${optionalString config.boot.kernel.enable '' 18 if [ ! -f ${kernelPath} ]; then 19 echo "The bootloader cannot find the proper kernel image." 20 echo "(Expecting ${kernelPath})" 21 false 22 fi 23 24 ln -s ${kernelPath} $out/kernel 25 ln -s ${config.system.modulesTree} $out/kernel-modules 26 ${optionalString (config.hardware.deviceTree.package != null) '' 27 ln -s ${config.hardware.deviceTree.package} $out/dtbs 28 ''} 29 30 echo -n "$kernelParams" > $out/kernel-params 31 32 ln -s ${initrdPath} $out/initrd 33 34 ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out 35 36 ln -s ${config.hardware.firmware}/lib/firmware $out/firmware 37 ''} 38 39 echo "$activationScript" > $out/activate 40 echo "$dryActivationScript" > $out/dry-activate 41 substituteInPlace $out/activate --subst-var out 42 substituteInPlace $out/dry-activate --subst-var out 43 chmod u+x $out/activate $out/dry-activate 44 unset activationScript dryActivationScript 45 46 ${if config.boot.initrd.systemd.enable then '' 47 cp ${config.system.build.bootStage2} $out/prepare-root 48 substituteInPlace $out/prepare-root --subst-var-by systemConfig $out 49 # This must not be a symlink or the abs_path of the grub builder for the tests 50 # will resolve the symlink and we end up with a path that doesn't point to a 51 # system closure. 52 cp "$systemd/lib/systemd/systemd" $out/init 53 '' else '' 54 cp ${config.system.build.bootStage2} $out/init 55 substituteInPlace $out/init --subst-var-by systemConfig $out 56 ''} 57 58 ln -s ${config.system.build.etc}/etc $out/etc 59 ln -s ${config.system.path} $out/sw 60 ln -s "$systemd" $out/systemd 61 62 echo -n "systemd ${toString config.systemd.package.interfaceVersion}" > $out/init-interface-version 63 echo -n "$nixosLabel" > $out/nixos-version 64 echo -n "${config.boot.kernelPackages.stdenv.hostPlatform.system}" > $out/system 65 66 mkdir $out/bin 67 export localeArchive="${config.i18n.glibcLocales}/lib/locale/locale-archive" 68 substituteAll ${./switch-to-configuration.pl} $out/bin/switch-to-configuration 69 chmod +x $out/bin/switch-to-configuration 70 ${optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) '' 71 if ! output=$($perl/bin/perl -c $out/bin/switch-to-configuration 2>&1); then 72 echo "switch-to-configuration syntax is not valid:" 73 echo "$output" 74 exit 1 75 fi 76 ''} 77 78 ${config.system.systemBuilderCommands} 79 80 echo -n "${toString config.system.extraDependencies}" > $out/extra-dependencies 81 82 ${config.system.extraSystemBuilderCmds} 83 ''; 84 85 # Putting it all together. This builds a store path containing 86 # symlinks to the various parts of the built configuration (the 87 # kernel, systemd units, init scripts, etc.) as well as a script 88 # `switch-to-configuration' that activates the configuration and 89 # makes it bootable. 90 baseSystem = pkgs.stdenvNoCC.mkDerivation ({ 91 name = "nixos-system-${config.system.name}-${config.system.nixos.label}"; 92 preferLocalBuild = true; 93 allowSubstitutes = false; 94 buildCommand = systemBuilder; 95 96 inherit (pkgs) coreutils; 97 systemd = config.systemd.package; 98 shell = "${pkgs.bash}/bin/sh"; 99 su = "${pkgs.shadow.su}/bin/su"; 100 utillinux = pkgs.util-linux; 101 102 kernelParams = config.boot.kernelParams; 103 installBootLoader = config.system.build.installBootLoader; 104 activationScript = config.system.activationScripts.script; 105 dryActivationScript = config.system.dryActivationScript; 106 nixosLabel = config.system.nixos.label; 107 108 # Needed by switch-to-configuration. 109 perl = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp ]); 110 } // config.system.systemBuilderArgs); 111 112 # Handle assertions and warnings 113 114 failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions); 115 116 baseSystemAssertWarn = if failedAssertions != [] 117 then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" 118 else showWarnings config.warnings baseSystem; 119 120 # Replace runtime dependencies 121 system = foldr ({ oldDependency, newDependency }: drv: 122 pkgs.replaceDependency { inherit oldDependency newDependency drv; } 123 ) baseSystemAssertWarn config.system.replaceRuntimeDependencies; 124 125in 126 127{ 128 imports = [ 129 ../build.nix 130 (mkRemovedOptionModule [ "nesting" "clone" ] "Use `specialisation.«name» = { inheritParentConfig = true; configuration = { ... }; }` instead.") 131 (mkRemovedOptionModule [ "nesting" "children" ] "Use `specialisation.«name».configuration = { ... }` instead.") 132 ]; 133 134 options = { 135 136 system.boot.loader.id = mkOption { 137 internal = true; 138 default = ""; 139 description = lib.mdDoc '' 140 Id string of the used bootloader. 141 ''; 142 }; 143 144 system.boot.loader.kernelFile = mkOption { 145 internal = true; 146 default = pkgs.stdenv.hostPlatform.linux-kernel.target; 147 defaultText = literalExpression "pkgs.stdenv.hostPlatform.linux-kernel.target"; 148 type = types.str; 149 description = lib.mdDoc '' 150 Name of the kernel file to be passed to the bootloader. 151 ''; 152 }; 153 154 system.boot.loader.initrdFile = mkOption { 155 internal = true; 156 default = "initrd"; 157 type = types.str; 158 description = lib.mdDoc '' 159 Name of the initrd file to be passed to the bootloader. 160 ''; 161 }; 162 163 system.build = { 164 installBootLoader = mkOption { 165 internal = true; 166 # "; true" => make the `$out` argument from switch-to-configuration.pl 167 # go to `true` instead of `echo`, hiding the useless path 168 # from the log. 169 default = "echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2; true"; 170 description = lib.mdDoc '' 171 A program that writes a bootloader installation script to the path passed in the first command line argument. 172 173 See `nixos/modules/system/activation/switch-to-configuration.pl`. 174 ''; 175 type = types.unique { 176 message = '' 177 Only one bootloader can be enabled at a time. This requirement has not 178 been checked until NixOS 22.05. Earlier versions defaulted to the last 179 definition. Change your configuration to enable only one bootloader. 180 ''; 181 } (types.either types.str types.package); 182 }; 183 184 toplevel = mkOption { 185 type = types.package; 186 readOnly = true; 187 description = lib.mdDoc '' 188 This option contains the store path that typically represents a NixOS system. 189 190 You can read this path in a custom deployment tool for example. 191 ''; 192 }; 193 }; 194 195 196 system.copySystemConfiguration = mkOption { 197 type = types.bool; 198 default = false; 199 description = lib.mdDoc '' 200 If enabled, copies the NixOS configuration file 201 (usually {file}`/etc/nixos/configuration.nix`) 202 and links it from the resulting system 203 (getting to {file}`/run/current-system/configuration.nix`). 204 Note that only this single file is copied, even if it imports others. 205 ''; 206 }; 207 208 system.systemBuilderCommands = mkOption { 209 type = types.lines; 210 internal = true; 211 default = ""; 212 description = '' 213 This code will be added to the builder creating the system store path. 214 ''; 215 }; 216 217 system.systemBuilderArgs = mkOption { 218 type = types.attrsOf types.unspecified; 219 internal = true; 220 default = {}; 221 description = lib.mdDoc '' 222 `lib.mkDerivation` attributes that will be passed to the top level system builder. 223 ''; 224 }; 225 226 system.extraSystemBuilderCmds = mkOption { 227 type = types.lines; 228 internal = true; 229 default = ""; 230 description = lib.mdDoc '' 231 This code will be added to the builder creating the system store path. 232 ''; 233 }; 234 235 system.extraDependencies = mkOption { 236 type = types.listOf types.package; 237 default = []; 238 description = lib.mdDoc '' 239 A list of packages that should be included in the system 240 closure but not otherwise made available to users. This is 241 primarily used by the installation tests. 242 ''; 243 }; 244 245 system.replaceRuntimeDependencies = mkOption { 246 default = []; 247 example = lib.literalExpression "[ ({ original = pkgs.openssl; replacement = pkgs.callPackage /path/to/openssl { }; }) ]"; 248 type = types.listOf (types.submodule ( 249 { ... }: { 250 options.original = mkOption { 251 type = types.package; 252 description = lib.mdDoc "The original package to override."; 253 }; 254 255 options.replacement = mkOption { 256 type = types.package; 257 description = lib.mdDoc "The replacement package."; 258 }; 259 }) 260 ); 261 apply = map ({ original, replacement, ... }: { 262 oldDependency = original; 263 newDependency = replacement; 264 }); 265 description = lib.mdDoc '' 266 List of packages to override without doing a full rebuild. 267 The original derivation and replacement derivation must have the same 268 name length, and ideally should have close-to-identical directory layout. 269 ''; 270 }; 271 272 system.name = mkOption { 273 type = types.str; 274 default = 275 if config.networking.hostName == "" 276 then "unnamed" 277 else config.networking.hostName; 278 defaultText = literalExpression '' 279 if config.networking.hostName == "" 280 then "unnamed" 281 else config.networking.hostName; 282 ''; 283 description = lib.mdDoc '' 284 The name of the system used in the {option}`system.build.toplevel` derivation. 285 286 That derivation has the following name: 287 `"nixos-system-''${config.system.name}-''${config.system.nixos.label}"` 288 ''; 289 }; 290 291 }; 292 293 294 config = { 295 296 system.extraSystemBuilderCmds = 297 optionalString 298 config.system.copySystemConfiguration 299 ''ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>}' \ 300 "$out/configuration.nix" 301 ''; 302 303 system.build.toplevel = system; 304 305 }; 306 307}