at 18.09-beta 12 kB view raw
1#! @shell@ 2 3if [ -x "@shell@" ]; then export SHELL="@shell@"; fi; 4 5set -e 6 7showSyntax() { 8 exec man nixos-rebuild 9 exit 1 10} 11 12 13# Parse the command line. 14origArgs=("$@") 15extraBuildFlags=() 16action= 17buildNix=1 18fast= 19rollback= 20upgrade= 21repair= 22profile=/nix/var/nix/profiles/system 23buildHost= 24targetHost= 25 26while [ "$#" -gt 0 ]; do 27 i="$1"; shift 1 28 case "$i" in 29 --help) 30 showSyntax 31 ;; 32 switch|boot|test|build|dry-build|dry-run|dry-activate|build-vm|build-vm-with-bootloader) 33 if [ "$i" = dry-run ]; then i=dry-build; fi 34 action="$i" 35 ;; 36 --install-grub) 37 echo "$0: --install-grub deprecated, use --install-bootloader instead" >&2 38 export NIXOS_INSTALL_BOOTLOADER=1 39 ;; 40 --install-bootloader) 41 export NIXOS_INSTALL_BOOTLOADER=1 42 ;; 43 --no-build-nix) 44 buildNix= 45 ;; 46 --rollback) 47 rollback=1 48 ;; 49 --upgrade) 50 upgrade=1 51 ;; 52 --repair) 53 repair=1 54 extraBuildFlags+=("$i") 55 ;; 56 --max-jobs|-j|--cores|-I) 57 j="$1"; shift 1 58 extraBuildFlags+=("$i" "$j") 59 ;; 60 --show-trace|--no-build-hook|--keep-failed|-K|--keep-going|-k|--verbose|-v|-vv|-vvv|-vvvv|-vvvvv|--fallback|--repair|--no-build-output|-Q|-j*) 61 extraBuildFlags+=("$i") 62 ;; 63 --option) 64 j="$1"; shift 1 65 k="$1"; shift 1 66 extraBuildFlags+=("$i" "$j" "$k") 67 ;; 68 --fast) 69 buildNix= 70 fast=1 71 extraBuildFlags+=(--show-trace) 72 ;; 73 --profile-name|-p) 74 if [ -z "$1" ]; then 75 echo "$0: ‘--profile-name’ requires an argument" 76 exit 1 77 fi 78 if [ "$1" != system ]; then 79 profile="/nix/var/nix/profiles/system-profiles/$1" 80 mkdir -p -m 0755 "$(dirname "$profile")" 81 fi 82 shift 1 83 ;; 84 --build-host|h) 85 buildHost="$1" 86 shift 1 87 ;; 88 --target-host|t) 89 targetHost="$1" 90 shift 1 91 ;; 92 *) 93 echo "$0: unknown option \`$i'" 94 exit 1 95 ;; 96 esac 97done 98 99 100if [ -z "$buildHost" -a -n "$targetHost" ]; then 101 buildHost="$targetHost" 102fi 103if [ "$targetHost" = localhost ]; then 104 targetHost= 105fi 106if [ "$buildHost" = localhost ]; then 107 buildHost= 108fi 109 110buildHostCmd() { 111 if [ -z "$buildHost" ]; then 112 "$@" 113 elif [ -n "$remoteNix" ]; then 114 ssh $SSHOPTS "$buildHost" PATH="$remoteNix:$PATH" "$@" 115 else 116 ssh $SSHOPTS "$buildHost" "$@" 117 fi 118} 119 120targetHostCmd() { 121 if [ -z "$targetHost" ]; then 122 "$@" 123 else 124 ssh $SSHOPTS "$targetHost" "$@" 125 fi 126} 127 128copyToTarget() { 129 if ! [ "$targetHost" = "$buildHost" ]; then 130 if [ -z "$targetHost" ]; then 131 NIX_SSHOPTS=$SSHOPTS nix-copy-closure --from "$buildHost" "$1" 132 elif [ -z "$buildHost" ]; then 133 NIX_SSHOPTS=$SSHOPTS nix-copy-closure --to "$targetHost" "$1" 134 else 135 buildHostCmd nix-copy-closure --to "$targetHost" "$1" 136 fi 137 fi 138} 139 140nixBuild() { 141 if [ -z "$buildHost" ]; then 142 nix-build "$@" 143 else 144 local instArgs=() 145 local buildArgs=() 146 147 while [ "$#" -gt 0 ]; do 148 local i="$1"; shift 1 149 case "$i" in 150 -o) 151 local out="$1"; shift 1 152 buildArgs+=("--add-root" "$out" "--indirect") 153 ;; 154 -A) 155 local j="$1"; shift 1 156 instArgs+=("$i" "$j") 157 ;; 158 -I) # We don't want this in buildArgs 159 shift 1 160 ;; 161 --no-out-link) # We don't want this in buildArgs 162 ;; 163 "<"*) # nix paths 164 instArgs+=("$i") 165 ;; 166 *) 167 buildArgs+=("$i") 168 ;; 169 esac 170 done 171 172 local drv="$(nix-instantiate "${instArgs[@]}" "${extraBuildFlags[@]}")" 173 if [ -a "$drv" ]; then 174 NIX_SSHOPTS=$SSHOPTS nix-copy-closure --to "$buildHost" "$drv" 175 buildHostCmd nix-store -r "$drv" "${buildArgs[@]}" 176 else 177 echo "nix-instantiate failed" 178 exit 1 179 fi 180 fi 181} 182 183 184if [ -z "$action" ]; then showSyntax; fi 185 186# Only run shell scripts from the Nixpkgs tree if the action is 187# "switch", "boot", or "test". With other actions (such as "build"), 188# the user may reasonably expect that no code from the Nixpkgs tree is 189# executed, so it's safe to run nixos-rebuild against a potentially 190# untrusted tree. 191canRun= 192if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then 193 canRun=1 194fi 195 196 197# If ‘--upgrade’ is given, run ‘nix-channel --update nixos’. 198if [ -n "$upgrade" -a -z "$_NIXOS_REBUILD_REEXEC" ]; then 199 nix-channel --update nixos 200 201 # If there are other channels that contain a file called 202 # ".update-on-nixos-rebuild", update them as well. 203 for channelpath in /nix/var/nix/profiles/per-user/root/channels/*; do 204 if [ -e "$channelpath/.update-on-nixos-rebuild" ]; then 205 nix-channel --update "$(basename "$channelpath")" 206 fi 207 done 208fi 209 210# Make sure that we use the Nix package we depend on, not something 211# else from the PATH for nix-{env,instantiate,build}. This is 212# important, because NixOS defaults the architecture of the rebuilt 213# system to the architecture of the nix-* binaries used. So if on an 214# amd64 system the user has an i686 Nix package in her PATH, then we 215# would silently downgrade the whole system to be i686 NixOS on the 216# next reboot. 217if [ -z "$_NIXOS_REBUILD_REEXEC" ]; then 218 export PATH=@nix@/bin:$PATH 219fi 220 221# Re-execute nixos-rebuild from the Nixpkgs tree. 222if [ -z "$_NIXOS_REBUILD_REEXEC" -a -n "$canRun" -a -z "$fast" ]; then 223 if p=$(nix-build --no-out-link --expr 'with import <nixpkgs/nixos> {}; config.system.build.nixos-rebuild' "${extraBuildFlags[@]}"); then 224 export _NIXOS_REBUILD_REEXEC=1 225 exec $p/bin/nixos-rebuild "${origArgs[@]}" 226 exit 1 227 fi 228fi 229 230 231tmpDir=$(mktemp -t -d nixos-rebuild.XXXXXX) 232SSHOPTS="$NIX_SSHOPTS -o ControlMaster=auto -o ControlPath=$tmpDir/ssh-%n -o ControlPersist=60" 233 234cleanup() { 235 for ctrl in "$tmpDir"/ssh-*; do 236 ssh -o ControlPath="$ctrl" -O exit dummyhost 2>/dev/null || true 237 done 238 rm -rf "$tmpDir" 239} 240trap cleanup EXIT 241 242 243 244# If the Nix daemon is running, then use it. This allows us to use 245# the latest Nix from Nixpkgs (below) for expression evaluation, while 246# still using the old Nix (via the daemon) for actual store access. 247# This matters if the new Nix in Nixpkgs has a schema change. It 248# would upgrade the schema, which should only happen once we actually 249# switch to the new configuration. 250# If --repair is given, don't try to use the Nix daemon, because the 251# flag can only be used directly. 252if [ -z "$repair" ] && systemctl show nix-daemon.socket nix-daemon.service | grep -q ActiveState=active; then 253 export NIX_REMOTE=${NIX_REMOTE-daemon} 254fi 255 256 257# First build Nix, since NixOS may require a newer version than the 258# current one. 259if [ -n "$rollback" -o "$action" = dry-build ]; then 260 buildNix= 261fi 262 263prebuiltNix() { 264 machine="$1" 265 if [ "$machine" = x86_64 ]; then 266 echo @nix_x86_64_linux@ 267 elif [[ "$machine" =~ i.86 ]]; then 268 echo @nix_i686_linux@ 269 else 270 echo "$0: unsupported platform" 271 exit 1 272 fi 273} 274 275remotePATH= 276 277if [ -n "$buildNix" ]; then 278 echo "building Nix..." >&2 279 nixDrv= 280 if ! nixDrv="$(nix-instantiate '<nixpkgs/nixos>' --add-root $tmpDir/nix.drv --indirect -A config.nix.package.out "${extraBuildFlags[@]}")"; then 281 if ! nixDrv="$(nix-instantiate '<nixpkgs>' --add-root $tmpDir/nix.drv --indirect -A nix "${extraBuildFlags[@]}")"; then 282 nixStorePath="$(prebuiltNix "$(uname -m)")" 283 if ! nix-store -r $nixStorePath --add-root $tmpDir/nix --indirect \ 284 --option extra-binary-caches https://cache.nixos.org/; then 285 echo "warning: don't know how to get latest Nix" >&2 286 fi 287 # Older version of nix-store -r don't support --add-root. 288 [ -e $tmpDir/nix ] || ln -sf $nixStorePath $tmpDir/nix 289 if [ -n "$buildHost" ]; then 290 remoteNixStorePath="$(prebuiltNix "$(buildHostCmd uname -m)")" 291 remoteNix="$remoteNixStorePath/bin" 292 if ! buildHostCmd nix-store -r $remoteNixStorePath \ 293 --option extra-binary-caches https://cache.nixos.org/ >/dev/null; then 294 remoteNix= 295 echo "warning: don't know how to get latest Nix" >&2 296 fi 297 fi 298 fi 299 fi 300 if [ -a "$nixDrv" ]; then 301 nix-store -r "$nixDrv"'!'"out" --add-root $tmpDir/nix --indirect >/dev/null 302 if [ -n "$buildHost" ]; then 303 nix-copy-closure --to "$buildHost" "$nixDrv" 304 # The nix build produces multiple outputs, we add them all to the remote path 305 for p in $(buildHostCmd nix-store -r "$(readlink "$nixDrv")" "${buildArgs[@]}"); do 306 remoteNix="$remoteNix${remoteNix:+:}$p/bin" 307 done 308 fi 309 fi 310 PATH="$tmpDir/nix/bin:$PATH" 311fi 312 313 314# Update the version suffix if we're building from Git (so that 315# nixos-version shows something useful). 316if [ -n "$canRun" ]; then 317 if nixpkgs=$(nix-instantiate --find-file nixpkgs "${extraBuildFlags[@]}"); then 318 suffix=$($SHELL $nixpkgs/nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}" || true) 319 if [ -n "$suffix" ]; then 320 echo -n "$suffix" > "$nixpkgs/.version-suffix" || true 321 fi 322 fi 323fi 324 325 326if [ "$action" = dry-build ]; then 327 extraBuildFlags+=(--dry-run) 328fi 329 330 331# Either upgrade the configuration in the system profile (for "switch" 332# or "boot"), or just build it and create a symlink "result" in the 333# current directory (for "build" and "test"). 334if [ -z "$rollback" ]; then 335 echo "building the system configuration..." >&2 336 if [ "$action" = switch -o "$action" = boot ]; then 337 pathToConfig="$(nixBuild '<nixpkgs/nixos>' --no-out-link -A system "${extraBuildFlags[@]}")" 338 copyToTarget "$pathToConfig" 339 targetHostCmd nix-env -p "$profile" --set "$pathToConfig" 340 elif [ "$action" = test -o "$action" = build -o "$action" = dry-build -o "$action" = dry-activate ]; then 341 pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}")" 342 elif [ "$action" = build-vm ]; then 343 pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vm -k "${extraBuildFlags[@]}")" 344 elif [ "$action" = build-vm-with-bootloader ]; then 345 pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vmWithBootLoader -k "${extraBuildFlags[@]}")" 346 else 347 showSyntax 348 fi 349 # Copy build to target host if we haven't already done it 350 if ! [ "$action" = switch -o "$action" = boot ]; then 351 copyToTarget "$pathToConfig" 352 fi 353else # [ -n "$rollback" ] 354 if [ "$action" = switch -o "$action" = boot ]; then 355 targetHostCmd nix-env --rollback -p "$profile" 356 pathToConfig="$profile" 357 elif [ "$action" = test -o "$action" = build ]; then 358 systemNumber=$( 359 targetHostCmd nix-env -p "$profile" --list-generations | 360 sed -n '/current/ {g; p;}; s/ *\([0-9]*\).*/\1/; h' 361 ) 362 pathToConfig="$profile"-${systemNumber}-link 363 if [ -z "$targetHost" ]; then 364 ln -sT "$pathToConfig" ./result 365 fi 366 else 367 showSyntax 368 fi 369fi 370 371 372# If we're not just building, then make the new configuration the boot 373# default and/or activate it now. 374if [ "$action" = switch -o "$action" = boot -o "$action" = test -o "$action" = dry-activate ]; then 375 if ! targetHostCmd $pathToConfig/bin/switch-to-configuration "$action"; then 376 echo "warning: error(s) occurred while switching to the new configuration" >&2 377 exit 1 378 fi 379fi 380 381 382if [ "$action" = build-vm ]; then 383 cat >&2 <<EOF 384 385Done. The virtual machine can be started by running $(echo $pathToConfig/bin/run-*-vm) 386EOF 387fi