2020-08-20 17:08:02 +00:00
#! @runtimeShell@
2021-12-06 16:07:01 +00:00
# shellcheck shell=bash
2020-04-24 23:36:52 +00:00
2020-08-20 17:08:02 +00:00
if [ -x "@runtimeShell@" ] ; then export SHELL = "@runtimeShell@" ; fi ;
2020-04-24 23:36:52 +00:00
set -e
set -o pipefail
2021-08-05 21:33:18 +00:00
shopt -s inherit_errexit
2020-04-24 23:36:52 +00:00
export PATH = @path@:$PATH
showSyntax( ) {
exec man nixos-rebuild
exit 1
}
# Parse the command line.
origArgs = ( " $@ " )
2021-09-18 10:52:07 +00:00
copyClosureFlags = ( )
2020-04-24 23:36:52 +00:00
extraBuildFlags = ( )
lockFlags = ( )
2020-09-25 04:45:31 +00:00
flakeFlags = ( )
2020-04-24 23:36:52 +00:00
action =
buildNix = 1
fast =
rollback =
upgrade =
2020-10-07 09:15:18 +00:00
upgrade_all =
2020-04-24 23:36:52 +00:00
profile = /nix/var/nix/profiles/system
2021-08-22 07:53:02 +00:00
buildHost = localhost
2020-04-24 23:36:52 +00:00
targetHost =
2021-12-06 16:07:01 +00:00
remoteSudo =
# comma separated list of vars to preserve when using sudo
preservedSudoVars = NIXOS_INSTALL_BOOTLOADER
2020-04-24 23:36:52 +00:00
while [ " $# " -gt 0 ] ; do
i = " $1 " ; shift 1
case " $i " in
--help)
showSyntax
; ;
switch| boot| test| build| edit| dry-build| dry-run| dry-activate| build-vm| build-vm-with-bootloader)
if [ " $i " = dry-run ] ; then i = dry-build; fi
action = " $i "
; ;
--install-grub)
echo " $0 : --install-grub deprecated, use --install-bootloader instead " >& 2
export NIXOS_INSTALL_BOOTLOADER = 1
; ;
--install-bootloader)
export NIXOS_INSTALL_BOOTLOADER = 1
; ;
--no-build-nix)
buildNix =
; ;
--rollback)
rollback = 1
; ;
--upgrade)
upgrade = 1
; ;
2020-10-07 09:15:18 +00:00
--upgrade-all)
upgrade = 1
upgrade_all = 1
; ;
2021-09-18 10:52:07 +00:00
-s| --use-substitutes)
copyClosureFlags += ( " $i " )
; ;
2020-04-24 23:36:52 +00:00
--max-jobs| -j| --cores| -I| --builders)
j = " $1 " ; shift 1
extraBuildFlags += ( " $i " " $j " )
; ;
2021-02-05 17:12:51 +00:00
--show-trace| --keep-failed| -K| --keep-going| -k| --verbose| -v| -vv| -vvv| -vvvv| -vvvvv| --fallback| --repair| --no-build-output| -Q| -j*| -L| --refresh| --no-net| --offline| --impure)
2020-04-24 23:36:52 +00:00
extraBuildFlags += ( " $i " )
; ;
--option)
j = " $1 " ; shift 1
k = " $1 " ; shift 1
extraBuildFlags += ( " $i " " $j " " $k " )
; ;
--fast)
buildNix =
fast = 1
; ;
--profile-name| -p)
if [ -z " $1 " ] ; then
echo " $0 : ‘ --profile-name’ requires an argument "
exit 1
fi
if [ " $1 " != system ] ; then
profile = " /nix/var/nix/profiles/system-profiles/ $1 "
mkdir -p -m 0755 " $( dirname " $profile " ) "
fi
shift 1
; ;
--build-host| h)
buildHost = " $1 "
shift 1
; ;
--target-host| t)
targetHost = " $1 "
shift 1
; ;
--use-remote-sudo)
2021-12-06 16:07:01 +00:00
remoteSudo = 1
2020-04-24 23:36:52 +00:00
; ;
--flake)
flake = " $1 "
2021-05-20 23:08:51 +00:00
flakeFlags = ( --extra-experimental-features 'nix-command flakes' )
2020-04-24 23:36:52 +00:00
shift 1
; ;
--recreate-lock-file| --no-update-lock-file| --no-write-lock-file| --no-registries| --commit-lock-file)
lockFlags += ( " $i " )
; ;
--update-input)
j = " $1 " ; shift 1
lockFlags += ( " $i " " $j " )
; ;
--override-input)
j = " $1 " ; shift 1
k = " $1 " ; shift 1
lockFlags += ( " $i " " $j " " $k " )
; ;
*)
echo " $0 : unknown option \` $i ' "
exit 1
; ;
esac
done
2021-12-06 16:07:01 +00:00
if [ [ -n " $SUDO_USER " || -n $remoteSudo ] ] ; then
maybeSudo = ( sudo --preserve-env= " $preservedSudoVars " --)
2020-04-24 23:36:52 +00:00
fi
2021-12-06 16:07:01 +00:00
if [ [ -z " $buildHost " && -n " $targetHost " ] ] ; then
2020-04-24 23:36:52 +00:00
buildHost = " $targetHost "
fi
if [ " $targetHost " = localhost ] ; then
targetHost =
fi
if [ " $buildHost " = localhost ] ; then
buildHost =
fi
buildHostCmd( ) {
if [ -z " $buildHost " ] ; then
" $@ "
elif [ -n " $remoteNix " ] ; then
2021-06-28 23:13:55 +00:00
ssh $SSHOPTS " $buildHost " " ${ maybeSudo [@] } " env PATH = " $remoteNix " :'$PATH' " $@ "
2020-04-24 23:36:52 +00:00
else
ssh $SSHOPTS " $buildHost " " ${ maybeSudo [@] } " " $@ "
fi
}
targetHostCmd( ) {
if [ -z " $targetHost " ] ; then
" ${ maybeSudo [@] } " " $@ "
else
ssh $SSHOPTS " $targetHost " " ${ maybeSudo [@] } " " $@ "
fi
}
copyToTarget( ) {
if ! [ " $targetHost " = " $buildHost " ] ; then
if [ -z " $targetHost " ] ; then
2021-09-18 10:52:07 +00:00
NIX_SSHOPTS = $SSHOPTS nix-copy-closure " ${ copyClosureFlags [@] } " --from " $buildHost " " $1 "
2020-04-24 23:36:52 +00:00
elif [ -z " $buildHost " ] ; then
2021-09-18 10:52:07 +00:00
NIX_SSHOPTS = $SSHOPTS nix-copy-closure " ${ copyClosureFlags [@] } " --to " $targetHost " " $1 "
2020-04-24 23:36:52 +00:00
else
2021-09-18 10:52:07 +00:00
buildHostCmd nix-copy-closure " ${ copyClosureFlags [@] } " --to " $targetHost " " $1 "
2020-04-24 23:36:52 +00:00
fi
fi
}
nixBuild( ) {
if [ -z " $buildHost " ] ; then
nix-build " $@ "
else
local instArgs = ( )
local buildArgs = ( )
2021-06-28 23:13:55 +00:00
local drv =
2020-04-24 23:36:52 +00:00
while [ " $# " -gt 0 ] ; do
local i = " $1 " ; shift 1
case " $i " in
-o)
local out = " $1 " ; shift 1
buildArgs += ( "--add-root" " $out " "--indirect" )
; ;
-A)
local j = " $1 " ; shift 1
instArgs += ( " $i " " $j " )
; ;
-I) # We don't want this in buildArgs
shift 1
; ;
--no-out-link) # We don't want this in buildArgs
; ;
"<" *) # nix paths
instArgs += ( " $i " )
; ;
*)
buildArgs += ( " $i " )
; ;
esac
done
2021-06-28 23:13:55 +00:00
drv = " $( nix-instantiate " ${ instArgs [@] } " " ${ extraBuildFlags [@] } " ) "
2020-04-24 23:36:52 +00:00
if [ -a " $drv " ] ; then
NIX_SSHOPTS = $SSHOPTS nix-copy-closure --to " $buildHost " " $drv "
buildHostCmd nix-store -r " $drv " " ${ buildArgs [@] } "
else
echo "nix-instantiate failed"
exit 1
fi
fi
}
2021-05-20 23:08:51 +00:00
nixFlakeBuild( ) {
2021-12-06 16:07:01 +00:00
if [ [ -z " $buildHost " && -z " $targetHost " && " $action " != switch && " $action " != boot ] ]
2021-06-28 23:13:55 +00:00
then
nix " ${ flakeFlags [@] } " build " $@ "
readlink -f ./result
elif [ -z " $buildHost " ] ; then
nix " ${ flakeFlags [@] } " build " $@ " --out-link " ${ tmpDir } /result "
2021-05-20 23:08:51 +00:00
readlink -f " ${ tmpDir } /result "
else
local attr = " $1 "
shift 1
local evalArgs = ( )
local buildArgs = ( )
2021-06-28 23:13:55 +00:00
local drv =
2021-05-20 23:08:51 +00:00
while [ " $# " -gt 0 ] ; do
local i = " $1 " ; shift 1
case " $i " in
--recreate-lock-file| --no-update-lock-file| --no-write-lock-file| --no-registries| --commit-lock-file)
evalArgs += ( " $i " )
; ;
--update-input)
local j = " $1 " ; shift 1
evalArgs += ( " $i " " $j " )
; ;
--override-input)
local j = " $1 " ; shift 1
local k = " $1 " ; shift 1
evalArgs += ( " $i " " $j " " $k " )
; ;
*)
buildArgs += ( " $i " )
; ;
esac
done
2021-06-28 23:13:55 +00:00
drv = " $( nix " ${ flakeFlags [@] } " eval --raw " ${ attr } .drvPath " " ${ evalArgs [@] } " " ${ extraBuildFlags [@] } " ) "
2021-05-20 23:08:51 +00:00
if [ -a " $drv " ] ; then
NIX_SSHOPTS = $SSHOPTS nix " ${ flakeFlags [@] } " copy --derivation --to " ssh:// $buildHost " " $drv "
buildHostCmd nix-store -r " $drv " " ${ buildArgs [@] } "
else
echo "nix eval failed"
exit 1
fi
fi
}
2020-04-24 23:36:52 +00:00
if [ -z " $action " ] ; then showSyntax; fi
# Only run shell scripts from the Nixpkgs tree if the action is
# "switch", "boot", or "test". With other actions (such as "build"),
# the user may reasonably expect that no code from the Nixpkgs tree is
# executed, so it's safe to run nixos-rebuild against a potentially
# untrusted tree.
canRun =
2021-12-06 16:07:01 +00:00
if [ [ " $action " = switch || " $action " = boot || " $action " = test ] ] ; then
2020-04-24 23:36:52 +00:00
canRun = 1
fi
2020-10-07 09:15:18 +00:00
# If ‘ --upgrade’ or `--upgrade-all` is given,
# run ‘ nix-channel --update nixos’ .
2020-04-24 23:36:52 +00:00
if [ [ -n $upgrade && -z $_NIXOS_REBUILD_REEXEC && -z $flake ] ] ; then
2020-10-07 09:15:18 +00:00
# If --upgrade-all is passed, or there are other channels that
# contain a file called ".update-on-nixos-rebuild", update them as
# well. Also upgrade the nixos channel.
2020-04-24 23:36:52 +00:00
for channelpath in /nix/var/nix/profiles/per-user/root/channels/*; do
2020-10-07 09:15:18 +00:00
channel_name = $( basename " $channelpath " )
if [ [ " $channel_name " = = "nixos" ] ] ; then
nix-channel --update " $channel_name "
elif [ -e " $channelpath /.update-on-nixos-rebuild " ] ; then
nix-channel --update " $channel_name "
elif [ [ -n $upgrade_all ] ] ; then
nix-channel --update " $channel_name "
2020-04-24 23:36:52 +00:00
fi
done
fi
# Make sure that we use the Nix package we depend on, not something
# else from the PATH for nix-{env,instantiate,build}. This is
# important, because NixOS defaults the architecture of the rebuilt
# system to the architecture of the nix-* binaries used. So if on an
# amd64 system the user has an i686 Nix package in her PATH, then we
# would silently downgrade the whole system to be i686 NixOS on the
# next reboot.
if [ -z " $_NIXOS_REBUILD_REEXEC " ] ; then
export PATH = @nix@/bin:$PATH
fi
# Use /etc/nixos/flake.nix if it exists. It can be a symlink to the
# actual flake.
if [ [ -z $flake && -e /etc/nixos/flake.nix ] ] ; then
flake = " $( dirname " $( readlink -f /etc/nixos/flake.nix) " ) "
fi
# Re-execute nixos-rebuild from the Nixpkgs tree.
# FIXME: get nixos-rebuild from $flake.
if [ [ -z $_NIXOS_REBUILD_REEXEC && -n $canRun && -z $fast && -z $flake ] ] ; then
if p = $( nix-build --no-out-link --expr 'with import <nixpkgs/nixos> {}; config.system.build.nixos-rebuild' " ${ extraBuildFlags [@] } " ) ; then
export _NIXOS_REBUILD_REEXEC = 1
2021-06-28 23:13:55 +00:00
exec " $p /bin/nixos-rebuild " " ${ origArgs [@] } "
2020-04-24 23:36:52 +00:00
exit 1
fi
fi
# For convenience, use the hostname as the default configuration to
# build from the flake.
if [ [ -n $flake ] ] ; then
if [ [ $flake = ~ ^( .*) \# ( [ ^\# \" ] *) $ ] ] ; then
flake = " ${ BASH_REMATCH [1] } "
flakeAttr = " ${ BASH_REMATCH [2] } "
fi
if [ [ -z $flakeAttr ] ] ; then
read -r hostname < /proc/sys/kernel/hostname
if [ [ -z $hostname ] ] ; then
hostname = default
fi
flakeAttr = " nixosConfigurations.\" $hostname \" "
else
flakeAttr = " nixosConfigurations.\" $flakeAttr \" "
fi
fi
# Resolve the flake.
if [ [ -n $flake ] ] ; then
2021-03-19 17:17:44 +00:00
flake = $( nix " ${ flakeFlags [@] } " flake metadata --json " ${ extraBuildFlags [@] } " " ${ lockFlags [@] } " -- " $flake " | jq -r .url)
2020-04-24 23:36:52 +00:00
fi
# Find configuration.nix and open editor instead of building.
if [ " $action " = edit ] ; then
if [ [ -z $flake ] ] ; then
NIXOS_CONFIG = ${ NIXOS_CONFIG :- $( nix-instantiate --find-file nixos-config) }
2020-09-25 04:45:31 +00:00
if [ [ -d $NIXOS_CONFIG ] ] ; then
NIXOS_CONFIG = $NIXOS_CONFIG /default.nix
fi
exec ${ EDITOR :- nano } " $NIXOS_CONFIG "
2020-04-24 23:36:52 +00:00
else
2020-09-25 04:45:31 +00:00
exec nix " ${ flakeFlags [@] } " edit " ${ lockFlags [@] } " -- " $flake # $flakeAttr "
2020-04-24 23:36:52 +00:00
fi
exit 1
fi
tmpDir = $( mktemp -t -d nixos-rebuild.XXXXXX)
SSHOPTS = " $NIX_SSHOPTS -o ControlMaster=auto -o ControlPath= $tmpDir /ssh-%n -o ControlPersist=60 "
cleanup( ) {
for ctrl in " $tmpDir " /ssh-*; do
ssh -o ControlPath = " $ctrl " -O exit dummyhost 2>/dev/null || true
done
rm -rf " $tmpDir "
}
trap cleanup EXIT
# First build Nix, since NixOS may require a newer version than the
# current one.
2021-12-06 16:07:01 +00:00
if [ [ -n " $rollback " || " $action " = dry-build ] ] ; then
2020-04-24 23:36:52 +00:00
buildNix =
fi
nixSystem( ) {
machine = " $( uname -m) "
if [ [ " $machine " = ~ i.86 ] ] ; then
machine = i686
fi
echo $machine -linux
}
prebuiltNix( ) {
machine = " $1 "
if [ " $machine " = x86_64 ] ; then
echo @nix_x86_64_linux@
elif [ [ " $machine " = ~ i.86 ] ] ; then
echo @nix_i686_linux@
2021-05-20 23:08:51 +00:00
elif [ [ " $machine " = aarch64 ] ] ; then
echo @nix_aarch64_linux@
2020-04-24 23:36:52 +00:00
else
echo " $0 : unsupported platform "
exit 1
fi
}
if [ [ -n $buildNix && -z $flake ] ] ; then
echo "building Nix..." >& 2
nixDrv =
2021-06-28 23:13:55 +00:00
if ! nixDrv = " $( nix-instantiate '<nixpkgs/nixos>' --add-root " $tmpDir /nix.drv " --indirect -A config.nix.package.out " ${ extraBuildFlags [@] } " ) " ; then
if ! nixDrv = " $( nix-instantiate '<nixpkgs>' --add-root " $tmpDir /nix.drv " --indirect -A nix " ${ extraBuildFlags [@] } " ) " ; then
if ! nixStorePath = " $( nix-instantiate --eval '<nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix>' -A " $( nixSystem) " | sed -e 's/^"//' -e 's/"$//' ) " ; then
2020-04-24 23:36:52 +00:00
nixStorePath = " $( prebuiltNix " $( uname -m) " ) "
fi
2021-12-06 16:07:01 +00:00
if ! nix-store -r " $nixStorePath " --add-root " ${ tmpDir } /nix " --indirect \
2020-04-24 23:36:52 +00:00
--option extra-binary-caches https://cache.nixos.org/; then
echo "warning: don't know how to get latest Nix" >& 2
fi
# Older version of nix-store -r don't support --add-root.
2021-06-28 23:13:55 +00:00
[ -e " $tmpDir /nix " ] || ln -sf " $nixStorePath " " $tmpDir /nix "
2020-04-24 23:36:52 +00:00
if [ -n " $buildHost " ] ; then
remoteNixStorePath = " $( prebuiltNix " $( buildHostCmd uname -m) " ) "
remoteNix = " $remoteNixStorePath /bin "
2021-06-28 23:13:55 +00:00
if ! buildHostCmd nix-store -r " $remoteNixStorePath " \
2020-04-24 23:36:52 +00:00
--option extra-binary-caches https://cache.nixos.org/ >/dev/null; then
remoteNix =
echo "warning: don't know how to get latest Nix" >& 2
fi
fi
fi
fi
if [ -a " $nixDrv " ] ; then
2021-06-28 23:13:55 +00:00
nix-store -r " $nixDrv " '!' "out" --add-root " $tmpDir /nix " --indirect >/dev/null
2020-04-24 23:36:52 +00:00
if [ -n " $buildHost " ] ; then
2021-09-18 10:52:07 +00:00
nix-copy-closure " ${ copyClosureFlags [@] } " --to " $buildHost " " $nixDrv "
2020-04-24 23:36:52 +00:00
# The nix build produces multiple outputs, we add them all to the remote path
for p in $( buildHostCmd nix-store -r " $( readlink " $nixDrv " ) " " ${ buildArgs [@] } " ) ; do
remoteNix = " $remoteNix ${ remoteNix : + : } $p /bin "
done
fi
fi
PATH = " $tmpDir /nix/bin: $PATH "
fi
# Update the version suffix if we're building from Git (so that
# nixos-version shows something useful).
if [ [ -n $canRun && -z $flake ] ] ; then
if nixpkgs = $( nix-instantiate --find-file nixpkgs " ${ extraBuildFlags [@] } " ) ; then
2021-06-28 23:13:55 +00:00
suffix = $( $SHELL " $nixpkgs /nixos/modules/installer/tools/get-version-suffix " " ${ extraBuildFlags [@] } " || true )
2020-04-24 23:36:52 +00:00
if [ -n " $suffix " ] ; then
echo -n " $suffix " > " $nixpkgs /.version-suffix " || true
fi
fi
fi
if [ " $action " = dry-build ] ; then
extraBuildFlags += ( --dry-run)
fi
# Either upgrade the configuration in the system profile (for "switch"
# or "boot"), or just build it and create a symlink "result" in the
# current directory (for "build" and "test").
if [ -z " $rollback " ] ; then
echo "building the system configuration..." >& 2
2021-12-06 16:07:01 +00:00
if [ [ " $action " = switch || " $action " = boot ] ] ; then
2020-04-24 23:36:52 +00:00
if [ [ -z $flake ] ] ; then
pathToConfig = " $( nixBuild '<nixpkgs/nixos>' --no-out-link -A system " ${ extraBuildFlags [@] } " ) "
else
2021-05-20 23:08:51 +00:00
pathToConfig = " $( nixFlakeBuild " $flake # $flakeAttr .config.system.build.toplevel " " ${ extraBuildFlags [@] } " " ${ lockFlags [@] } " ) "
2020-04-24 23:36:52 +00:00
fi
copyToTarget " $pathToConfig "
targetHostCmd nix-env -p " $profile " --set " $pathToConfig "
2021-12-06 16:07:01 +00:00
elif [ [ " $action " = test || " $action " = build || " $action " = dry-build || " $action " = dry-activate ] ] ; then
2020-04-24 23:36:52 +00:00
if [ [ -z $flake ] ] ; then
pathToConfig = " $( nixBuild '<nixpkgs/nixos>' -A system -k " ${ extraBuildFlags [@] } " ) "
else
2021-05-20 23:08:51 +00:00
pathToConfig = " $( nixFlakeBuild " $flake # $flakeAttr .config.system.build.toplevel " " ${ extraBuildFlags [@] } " " ${ lockFlags [@] } " ) "
2020-04-24 23:36:52 +00:00
fi
elif [ " $action " = build-vm ] ; then
if [ [ -z $flake ] ] ; then
pathToConfig = " $( nixBuild '<nixpkgs/nixos>' -A vm -k " ${ extraBuildFlags [@] } " ) "
else
2021-05-20 23:08:51 +00:00
pathToConfig = " $( nixFlakeBuild " $flake # $flakeAttr .config.system.build.vm " " ${ extraBuildFlags [@] } " " ${ lockFlags [@] } " ) "
2020-04-24 23:36:52 +00:00
fi
elif [ " $action " = build-vm-with-bootloader ] ; then
if [ [ -z $flake ] ] ; then
pathToConfig = " $( nixBuild '<nixpkgs/nixos>' -A vmWithBootLoader -k " ${ extraBuildFlags [@] } " ) "
else
2021-05-20 23:08:51 +00:00
pathToConfig = " $( nixFlakeBuild " $flake # $flakeAttr .config.system.build.vmWithBootLoader " " ${ extraBuildFlags [@] } " " ${ lockFlags [@] } " ) "
2020-04-24 23:36:52 +00:00
fi
else
showSyntax
fi
# Copy build to target host if we haven't already done it
2021-12-06 16:07:01 +00:00
if ! [ [ " $action " = switch || " $action " = boot ] ] ; then
2020-04-24 23:36:52 +00:00
copyToTarget " $pathToConfig "
fi
else # [ -n "$rollback" ]
2021-12-06 16:07:01 +00:00
if [ [ " $action " = switch || " $action " = boot ] ] ; then
2020-04-24 23:36:52 +00:00
targetHostCmd nix-env --rollback -p " $profile "
pathToConfig = " $profile "
2021-12-06 16:07:01 +00:00
elif [ [ " $action " = test || " $action " = build ] ] ; then
2020-04-24 23:36:52 +00:00
systemNumber = $(
targetHostCmd nix-env -p " $profile " --list-generations |
sed -n '/current/ {g; p;}; s/ *\([0-9]*\).*/\1/; h'
)
pathToConfig = " $profile " -${ systemNumber } -link
if [ -z " $targetHost " ] ; then
ln -sT " $pathToConfig " ./result
fi
else
showSyntax
fi
fi
# If we're not just building, then make the new configuration the boot
# default and/or activate it now.
2021-12-06 16:07:01 +00:00
if [ [ " $action " = switch || " $action " = boot || " $action " = test || " $action " = dry-activate ] ] ; then
2021-06-28 23:13:55 +00:00
if ! targetHostCmd " $pathToConfig /bin/switch-to-configuration " " $action " ; then
2020-04-24 23:36:52 +00:00
echo "warning: error(s) occurred while switching to the new configuration" >& 2
exit 1
fi
fi
2021-12-06 16:07:01 +00:00
if [ [ " $action " = build-vm || " $action " = build-vm-with-bootloader ] ] ; then
2020-04-24 23:36:52 +00:00
cat >& 2 <<EOF
2021-12-06 16:07:01 +00:00
Done. The virtual machine can be started by running $( echo " ${ pathToConfig } /bin/ " run-*-vm)
2020-04-24 23:36:52 +00:00
EOF
fi