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 = ( " $@ " )
2023-07-15 17:15:38 +00:00
copyFlags = ( )
2020-04-24 23:36:52 +00:00
extraBuildFlags = ( )
lockFlags = ( )
2022-08-12 12:06:08 +00:00
flakeFlags = ( --extra-experimental-features 'nix-command flakes' )
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
2023-01-20 10:41:00 +00:00
specialisation =
2023-01-11 07:51:40 +00:00
buildHost =
2020-04-24 23:36:52 +00:00
targetHost =
2021-12-06 16:07:01 +00:00
remoteSudo =
2022-03-30 09:31:56 +00:00
verboseScript =
noFlake =
2024-07-27 06:49:29 +00:00
attr =
buildFile = default.nix
buildingAttribute = 1
2024-02-29 20:09:43 +00:00
installBootloader =
2023-10-09 19:29:22 +00:00
json =
2020-04-24 23:36:52 +00:00
2022-03-30 09:31:56 +00:00
# log the given argument to stderr
log( ) {
echo " $@ " >& 2
}
2020-04-24 23:36:52 +00:00
while [ " $# " -gt 0 ] ; do
i = " $1 " ; shift 1
case " $i " in
--help)
showSyntax
; ;
2024-01-02 11:29:13 +00:00
switch| boot| test| build| edit| repl| dry-build| dry-run| dry-activate| build-vm| build-vm-with-bootloader| list-generations)
2020-04-24 23:36:52 +00:00
if [ " $i " = dry-run ] ; then i = dry-build; fi
2024-05-15 15:35:15 +00:00
if [ " $i " = list-generations ] ; then
buildNix =
fast = 1
fi
2022-06-26 10:26:21 +00:00
# exactly one action mandatory, bail out if multiple are given
if [ -n " $action " ] ; then showSyntax; fi
2020-04-24 23:36:52 +00:00
action = " $i "
; ;
2024-07-27 06:49:29 +00:00
--file| -f)
if [ -z " $1 " ] ; then
log " $0 : ' $i ' requires an argument "
exit 1
fi
buildFile = " $1 "
buildingAttribute =
shift 1
; ;
--attr| -A)
if [ -z " $1 " ] ; then
log " $0 : ' $i ' requires an argument "
exit 1
fi
attr = " $1 "
buildingAttribute =
shift 1
; ;
2020-04-24 23:36:52 +00:00
--install-grub)
2022-03-30 09:31:56 +00:00
log " $0 : --install-grub deprecated, use --install-bootloader instead "
2024-02-29 20:09:43 +00:00
installBootloader = 1
2020-04-24 23:36:52 +00:00
; ;
--install-bootloader)
2024-02-29 20:09:43 +00:00
installBootloader = 1
2020-04-24 23:36:52 +00:00
; ;
--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
; ;
2023-07-15 17:15:38 +00:00
--use-substitutes| --substitute-on-destination| -s)
copyFlags += ( "-s" )
2021-09-18 10:52:07 +00:00
; ;
2023-07-15 17:15:38 +00:00
-I| --max-jobs| -j| --cores| --builders| --log-format)
2020-04-24 23:36:52 +00:00
j = " $1 " ; shift 1
extraBuildFlags += ( " $i " " $j " )
; ;
2024-01-02 11:29:13 +00:00
--accept-flake-config| -j*| --quiet| --print-build-logs| -L| --no-build-output| -Q| --show-trace| --keep-going| -k| --keep-failed| -K| --fallback| --refresh| --repair| --impure| --offline| --no-net)
2022-03-30 09:31:56 +00:00
extraBuildFlags += ( " $i " )
; ;
--verbose| -v| -vv| -vvv| -vvvv| -vvvvv)
verboseScript = "true"
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
2022-03-30 09:31:56 +00:00
log " $0 : ‘ --profile-name’ requires an argument "
2020-04-24 23:36:52 +00:00
exit 1
fi
if [ " $1 " != system ] ; then
profile = " /nix/var/nix/profiles/system-profiles/ $1 "
mkdir -p -m 0755 " $( dirname " $profile " ) "
fi
shift 1
; ;
2023-01-20 10:41:00 +00:00
--specialisation| -c)
if [ -z " $1 " ] ; then
log " $0 : ‘ --specialisation’ requires an argument "
exit 1
fi
specialisation = " $1 "
shift 1
; ;
2023-11-16 04:20:00 +00:00
--build-host)
2020-04-24 23:36:52 +00:00
buildHost = " $1 "
shift 1
; ;
2023-11-16 04:20:00 +00:00
--target-host)
2020-04-24 23:36:52 +00:00
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 "
shift 1
; ;
2022-03-30 09:31:56 +00:00
--no-flake)
noFlake = 1
; ;
2020-04-24 23:36:52 +00:00
--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 " )
; ;
2023-10-09 19:29:22 +00:00
--json)
json = 1
; ;
2020-04-24 23:36:52 +00:00
*)
2022-03-30 09:31:56 +00:00
log " $0 : unknown option \` $i ' "
2020-04-24 23:36:52 +00:00
exit 1
; ;
esac
done
2022-03-30 09:31:56 +00:00
# log the given argument to stderr if verbose mode is on
logVerbose( ) {
if [ -n " $verboseScript " ] ; then
echo " $@ " >& 2
fi
}
# Run a command, logging it first if verbose mode is on
runCmd( ) {
logVerbose " $" " $@ "
" $@ "
}
2020-04-24 23:36:52 +00:00
buildHostCmd( ) {
2024-01-25 14:12:00 +00:00
local c
if [ [ " ${ useSudo :- x } " = 1 ] ] ; then
2024-02-29 20:09:43 +00:00
c = ( "sudo" )
2024-01-25 14:12:00 +00:00
else
c = ( )
fi
2020-04-24 23:36:52 +00:00
if [ -z " $buildHost " ] ; then
2022-03-30 09:31:56 +00:00
runCmd " $@ "
2020-04-24 23:36:52 +00:00
elif [ -n " $remoteNix " ] ; then
2024-01-25 14:12:00 +00:00
runCmd ssh $SSHOPTS " $buildHost " " ${ c [@] } " env PATH = " $remoteNix " :'$PATH' " $@ "
2020-04-24 23:36:52 +00:00
else
2024-01-25 14:12:00 +00:00
runCmd ssh $SSHOPTS " $buildHost " " ${ c [@] } " " $@ "
2020-04-24 23:36:52 +00:00
fi
}
targetHostCmd( ) {
2024-01-25 14:12:00 +00:00
local c
if [ [ " ${ useSudo :- x } " = 1 ] ] ; then
2024-02-29 20:09:43 +00:00
c = ( "sudo" )
2024-01-25 14:12:00 +00:00
else
c = ( )
fi
2020-04-24 23:36:52 +00:00
if [ -z " $targetHost " ] ; then
2024-01-25 14:12:00 +00:00
runCmd " ${ c [@] } " " $@ "
else
runCmd ssh $SSHOPTS " $targetHost " " ${ c [@] } " " $@ "
fi
}
targetHostSudoCmd( ) {
if [ -n " $remoteSudo " ] ; then
useSudo = 1 SSHOPTS = " $SSHOPTS -t " targetHostCmd " $@ "
2020-04-24 23:36:52 +00:00
else
2024-01-25 14:12:00 +00:00
# While a tty might not be necessary, we apply it to be consistent with
# sudo usage, and an experience that is more consistent with local deployment.
SSHOPTS = " $SSHOPTS -t " targetHostCmd " $@ "
2020-04-24 23:36:52 +00:00
fi
}
copyToTarget( ) {
if ! [ " $targetHost " = " $buildHost " ] ; then
if [ -z " $targetHost " ] ; then
2022-03-30 09:31:56 +00:00
logVerbose " Running nix-copy-closure with these NIX_SSHOPTS: $SSHOPTS "
2023-07-15 17:15:38 +00:00
NIX_SSHOPTS = $SSHOPTS runCmd nix-copy-closure " ${ copyFlags [@] } " --from " $buildHost " " $1 "
2020-04-24 23:36:52 +00:00
elif [ -z " $buildHost " ] ; then
2022-03-30 09:31:56 +00:00
logVerbose " Running nix-copy-closure with these NIX_SSHOPTS: $SSHOPTS "
2023-07-15 17:15:38 +00:00
NIX_SSHOPTS = $SSHOPTS runCmd nix-copy-closure " ${ copyFlags [@] } " --to " $targetHost " " $1 "
2020-04-24 23:36:52 +00:00
else
2023-07-15 17:15:38 +00:00
buildHostCmd nix-copy-closure " ${ copyFlags [@] } " --to " $targetHost " " $1 "
2020-04-24 23:36:52 +00:00
fi
fi
}
nixBuild( ) {
2022-03-30 09:31:56 +00:00
logVerbose "Building in legacy (non-flake) mode."
2020-04-24 23:36:52 +00:00
if [ -z " $buildHost " ] ; then
2022-03-30 09:31:56 +00:00
logVerbose "No --build-host given, running nix-build locally"
runCmd nix-build " $@ "
2020-04-24 23:36:52 +00:00
else
2022-03-30 09:31:56 +00:00
logVerbose " buildHost set to \" $buildHost \", running nix-build remotely "
2020-04-24 23:36:52 +00:00
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
2022-03-30 09:31:56 +00:00
drv = " $( runCmd nix-instantiate " ${ instArgs [@] } " " ${ extraBuildFlags [@] } " ) "
2020-04-24 23:36:52 +00:00
if [ -a " $drv " ] ; then
2022-03-30 09:31:56 +00:00
logVerbose " Running nix-copy-closure with these NIX_SSHOPTS: $SSHOPTS "
NIX_SSHOPTS = $SSHOPTS runCmd nix-copy-closure --to " $buildHost " " $drv "
2020-04-24 23:36:52 +00:00
buildHostCmd nix-store -r " $drv " " ${ buildArgs [@] } "
else
2022-03-30 09:31:56 +00:00
log "nix-instantiate failed"
2020-04-24 23:36:52 +00:00
exit 1
fi
fi
}
2021-05-20 23:08:51 +00:00
nixFlakeBuild( ) {
2022-03-30 09:31:56 +00:00
logVerbose "Building in flake mode."
2022-08-12 12:06:08 +00:00
if [ [ -z " $buildHost " && -z " $targetHost " && " $action " != switch && " $action " != boot && " $action " != test && " $action " != dry-activate ] ]
2021-06-28 23:13:55 +00:00
then
2022-03-30 09:31:56 +00:00
runCmd nix " ${ flakeFlags [@] } " build " $@ "
2021-06-28 23:13:55 +00:00
readlink -f ./result
elif [ -z " $buildHost " ] ; then
2022-03-30 09:31:56 +00:00
runCmd 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 " )
; ;
2022-02-20 05:27:41 +00:00
--impure) # We don't want this in buildArgs, it's only needed at evaluation time, and unsupported during realisation
; ;
2021-05-20 23:08:51 +00:00
*)
buildArgs += ( " $i " )
; ;
esac
done
2022-03-30 09:31:56 +00:00
drv = " $( runCmd nix " ${ flakeFlags [@] } " eval --raw " ${ attr } .drvPath " " ${ evalArgs [@] } " " ${ extraBuildFlags [@] } " ) "
2021-05-20 23:08:51 +00:00
if [ -a " $drv " ] ; then
2022-03-30 09:31:56 +00:00
logVerbose " Running nix with these NIX_SSHOPTS: $SSHOPTS "
2023-07-15 17:15:38 +00:00
NIX_SSHOPTS = $SSHOPTS runCmd nix " ${ flakeFlags [@] } " copy " ${ copyFlags [@] } " --derivation --to " ssh:// $buildHost " " $drv "
2021-05-20 23:08:51 +00:00
buildHostCmd nix-store -r " $drv " " ${ buildArgs [@] } "
else
2022-03-30 09:31:56 +00:00
log "nix eval failed"
2021-05-20 23:08:51 +00:00
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
2024-07-27 06:49:29 +00:00
# Verify that user is not trying to use attribute building and flake
# at the same time
if [ [ -z $buildingAttribute && -n $flake ] ] ; then
log "error: '--flake' cannot be used with '--file' or '--attr'"
exit 1
fi
2020-04-24 23:36:52 +00:00
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
2022-03-30 09:31:56 +00:00
runCmd nix-channel --update " $channel_name "
2020-10-07 09:15:18 +00:00
elif [ -e " $channelpath /.update-on-nixos-rebuild " ] ; then
2022-03-30 09:31:56 +00:00
runCmd nix-channel --update " $channel_name "
2020-10-07 09:15:18 +00:00
elif [ [ -n $upgrade_all ] ] ; then
2022-03-30 09:31:56 +00:00
runCmd 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.
2022-03-30 09:31:56 +00:00
if [ [ -z $flake && -e /etc/nixos/flake.nix && -z $noFlake ] ] ; then
2020-04-24 23:36:52 +00:00
flake = " $( dirname " $( readlink -f /etc/nixos/flake.nix) " ) "
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
2024-05-15 15:35:15 +00:00
hostname = " $( targetHostCmd cat /proc/sys/kernel/hostname) "
2020-04-24 23:36:52 +00:00
if [ [ -z $hostname ] ] ; then
hostname = default
fi
flakeAttr = " nixosConfigurations.\" $hostname \" "
else
flakeAttr = " nixosConfigurations.\" $flakeAttr \" "
fi
fi
2023-01-20 10:41:00 +00:00
if [ [ ! -z " $specialisation " && ! " $action " = switch && ! " $action " = test ] ] ; then
log "error: ‘ --specialisation’ can only be used with ‘ switch’ and ‘ test’ "
exit 1
fi
2022-03-30 09:31:56 +00:00
tmpDir = $( mktemp -t -d nixos-rebuild.XXXXXX)
2024-02-07 01:22:34 +00:00
if [ [ ${# tmpDir } -ge 60 ] ] ; then
# Very long tmp dirs lead to "too long for Unix domain socket"
# SSH ControlPath errors. Especially macOS sets long TMPDIR paths.
rmdir " $tmpDir "
tmpDir = $( TMPDIR = mktemp -t -d nixos-rebuild.XXXXXX)
fi
2022-03-30 09:31:56 +00:00
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
# Re-execute nixos-rebuild from the Nixpkgs tree.
if [ [ -z $_NIXOS_REBUILD_REEXEC && -n $canRun && -z $fast ] ] ; then
2024-07-27 06:49:29 +00:00
if [ [ -z $buildingAttribute ] ] ; then
p = $( runCmd nix-build --no-out-link $buildFile -A " ${ attr : + $attr . } config.system.build.nixos-rebuild " " ${ extraBuildFlags [@] } " )
SHOULD_REEXEC = 1
elif [ [ -z $flake ] ] ; then
2022-03-30 09:31:56 +00:00
if p = $( runCmd nix-build --no-out-link --expr 'with import <nixpkgs/nixos> {}; config.system.build.nixos-rebuild' " ${ extraBuildFlags [@] } " ) ; then
SHOULD_REEXEC = 1
fi
else
runCmd nix " ${ flakeFlags [@] } " build --out-link " ${ tmpDir } /nixos-rebuild " " $flake # $flakeAttr .config.system.build.nixos-rebuild " " ${ extraBuildFlags [@] } " " ${ lockFlags [@] } "
if p = $( readlink -e " ${ tmpDir } /nixos-rebuild " ) ; then
SHOULD_REEXEC = 1
fi
fi
if [ [ -n $SHOULD_REEXEC ] ] ; then
export _NIXOS_REBUILD_REEXEC = 1
# Manually call cleanup as the EXIT trap is not triggered when using exec
cleanup
runCmd exec " $p /bin/nixos-rebuild " " ${ origArgs [@] } "
exit 1
fi
fi
2020-04-24 23:36:52 +00:00
# Find configuration.nix and open editor instead of building.
if [ " $action " = edit ] ; then
2024-09-19 14:19:46 +00:00
if [ [ -z $buildingAttribute ] ] ; then
2024-07-27 06:49:29 +00:00
log "error: '--file' and '--attr' are not supported with 'edit'"
exit 1
elif [ [ -z $flake ] ] ; then
2022-03-30 09:31:56 +00:00
NIXOS_CONFIG = ${ NIXOS_CONFIG :- $( runCmd 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
2022-03-30 09:31:56 +00:00
runCmd exec ${ EDITOR :- nano } " $NIXOS_CONFIG "
2020-04-24 23:36:52 +00:00
else
2022-03-30 09:31:56 +00:00
runCmd exec nix " ${ flakeFlags [@] } " edit " ${ lockFlags [@] } " -- " $flake # $flakeAttr "
2020-04-24 23:36:52 +00:00
fi
exit 1
fi
SSHOPTS = " $NIX_SSHOPTS -o ControlMaster=auto -o ControlPath= $tmpDir /ssh-%n -o ControlPersist=60 "
# 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
2022-03-30 09:31:56 +00:00
log " $0 : unsupported platform "
2020-04-24 23:36:52 +00:00
exit 1
fi
}
2024-07-27 06:49:29 +00:00
getNixDrv( ) {
2020-04-24 23:36:52 +00:00
nixDrv =
2024-07-27 06:49:29 +00:00
if [ [ -z $buildingAttribute ] ] ; then
if nixDrv = " $( runCmd nix-instantiate $buildFile --add-root " $tmpDir /nix.drv " --indirect -A ${ attr : + $attr . } config.nix.package.out " ${ extraBuildFlags [@] } " ) " ; then return ; fi
fi
if nixDrv = " $( runCmd nix-instantiate '<nixpkgs/nixos>' --add-root " $tmpDir /nix.drv " --indirect -A config.nix.package.out " ${ extraBuildFlags [@] } " ) " ; then return ; fi
if nixDrv = " $( runCmd nix-instantiate '<nixpkgs>' --add-root " $tmpDir /nix.drv " --indirect -A nix " ${ extraBuildFlags [@] } " ) " ; then return ; fi
if ! nixStorePath = " $( runCmd nix-instantiate --eval '<nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix>' -A " $( nixSystem) " | sed -e 's/^"//' -e 's/"$//' ) " ; then
nixStorePath = " $( prebuiltNix " $( uname -m) " ) "
fi
if ! runCmd nix-store -r " $nixStorePath " --add-root " ${ tmpDir } /nix " --indirect \
--option extra-binary-caches https://cache.nixos.org/; then
log "warning: don't know how to get latest Nix"
fi
# Older version of nix-store -r don't support --add-root.
[ -e " $tmpDir /nix " ] || ln -sf " $nixStorePath " " $tmpDir /nix "
if [ -n " $buildHost " ] ; then
remoteNixStorePath = " $( runCmd prebuiltNix " $( buildHostCmd uname -m) " ) "
remoteNix = " $remoteNixStorePath /bin "
if ! buildHostCmd nix-store -r " $remoteNixStorePath " \
--option extra-binary-caches https://cache.nixos.org/ >/dev/null; then
remoteNix =
log "warning: don't know how to get latest Nix"
2020-04-24 23:36:52 +00:00
fi
fi
2024-07-27 06:49:29 +00:00
}
2024-09-26 11:04:55 +00:00
getVersion( ) {
local dir = " $1 "
local rev =
local gitDir = " $dir /.git "
if [ -e " $gitDir " ] ; then
if [ -z " $( type -P git) " ] ; then
echo " warning: Git not found; cannot figure out revision of $dir " >& 2
return
fi
cd " $dir "
rev = $( git --git-dir= " $gitDir " rev-parse --short HEAD)
if git --git-dir= " $gitDir " describe --always --dirty | grep -q dirty; then
rev += M
fi
fi
echo " .git. $rev "
}
2024-07-27 06:49:29 +00:00
if [ [ -n $buildNix && -z $flake ] ] ; then
log "building Nix..."
getNixDrv
2020-04-24 23:36:52 +00:00
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
2023-07-15 17:15:38 +00:00
nix-copy-closure " ${ copyFlags [@] } " --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
2022-03-30 09:31:56 +00:00
if nixpkgs = $( runCmd nix-instantiate --find-file nixpkgs " ${ extraBuildFlags [@] } " ) ; then
2024-09-26 11:04:55 +00:00
suffix = $( getVersion " $nixpkgs " || 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
2024-01-02 11:29:13 +00:00
if [ " $action " = repl ] ; then
# This is a very end user command, implemented using sub-optimal means.
# You should feel free to improve its behavior, as well as resolve tech
# debt in "breaking" ways. Humans adapt quite well.
2024-07-27 06:49:29 +00:00
if [ [ -z $buildingAttribute ] ] ; then
exec nix repl --file $buildFile $attr " ${ extraBuildFlags [@] } "
elif [ [ -z $flake ] ] ; then
2024-09-19 14:19:46 +00:00
exec nix repl --file '<nixpkgs/nixos>' " ${ extraBuildFlags [@] } "
2024-01-02 11:29:13 +00:00
else
if [ [ -n " ${ lockFlags [0] } " ] ] ; then
# nix repl itself does not support locking flags
log "nixos-rebuild repl does not support locking flags yet"
exit 1
fi
d = '$'
q = '"'
bold = " $( echo -e '\033[1m' ) "
blue = " $( echo -e '\033[34;1m' ) "
attention = " $( echo -e '\033[35;1m' ) "
reset = " $( echo -e '\033[0m' ) "
2024-04-21 15:54:59 +00:00
if [ [ -e $flake ] ] ; then
flakePath = $( realpath " $flake " )
else
flakePath = $flake
fi
2024-01-02 11:29:13 +00:00
# This nix repl invocation is impure, because usually the flakeref is.
# For a solution that preserves the motd and custom scope, we need
# something like https://github.com/NixOS/nix/issues/8679.
exec nix repl --impure --expr "
2024-04-21 15:54:59 +00:00
let flake = builtins.getFlake '' $flakePath '' ;
2024-01-02 11:29:13 +00:00
configuration = flake.$flakeAttr ;
motd = ''
$d { $q \n $q }
Hello and welcome to the NixOS configuration
$flakeAttr
in $flake
The following is loaded into nix repl' s scope:
- ${ blue } config${ reset } All option values
- ${ blue } options${ reset } Option data and metadata
- ${ blue } pkgs${ reset } Nixpkgs package set
2024-01-25 14:12:00 +00:00
- ${ blue } lib${ reset } Nixpkgs library functions
2024-01-02 11:29:13 +00:00
- other module arguments
- ${ blue } flake${ reset } Flake outputs, inputs and source info of $flake
Use tab completion to browse around ${ blue } config${ reset } .
Use ${ bold } :r${ reset } to ${ bold } reload${ reset } everything after making a change in the flake.
( assuming $flake is a mutable flake ref)
See ${ bold } :?${ reset } for more repl commands.
${ attention } warning:${ reset } nixos-rebuild repl does not currently enforce pure evaluation.
'' ;
scope =
assert configuration._type or null = = '' configuration'' ;
assert configuration.class or '' nixos'' = = '' nixos'' ;
configuration._module.args //
configuration._module.specialArgs //
{
inherit ( configuration) config options;
2024-01-25 14:12:00 +00:00
lib = configuration.lib or configuration.pkgs.lib;
2024-01-02 11:29:13 +00:00
inherit flake;
} ;
in builtins.seq scope builtins.trace motd scope
" " ${ extraBuildFlags [@] } "
fi
fi
2023-10-09 19:29:22 +00:00
if [ " $action " = list-generations ] ; then
if [ ! -L " $profile " ] ; then
log " No profile \` $( basename " $profile " ) ' found "
exit 1
fi
generation_from_dir( ) {
generation_dir = " $1 "
generation_base = " $( basename " $generation_dir " ) " # Has the format "system-123-link" for generation 123
no_link_gen = " ${ generation_base %-link } " # remove the "-link"
echo " ${ no_link_gen ##*- } " # remove everything before the last dash
}
describe_generation( ) {
generation_dir = " $1 "
generation_number = " $( generation_from_dir " $generation_dir " ) "
nixos_version = " $( cat " $generation_dir /nixos-version " 2> /dev/null || echo "Unknown" ) "
kernel_dir = " $( dirname " $( realpath " $generation_dir /kernel " ) " ) "
kernel_version = " $( ls " $kernel_dir /lib/modules " || echo "Unknown" ) "
configurationRevision = " $( " $generation_dir /sw/bin/nixos-version " --configuration-revision 2> /dev/null || true ) "
# Old nixos-version output ignored unknown flags and just printed the version
# therefore the following workaround is done not to show the default output
nixos_version_default = " $( " $generation_dir /sw/bin/nixos-version " ) "
if [ " $configurationRevision " = = " $nixos_version_default " ] ; then
configurationRevision = ""
fi
# jq automatically quotes the output => don't try to quote it in output!
build_date = " $( stat " $generation_dir " --format= %W | jq 'todate' ) "
pushd " $generation_dir /specialisation/ " > /dev/null || :
specialisation_list = ( *)
popd > /dev/null || :
specialisations = " $( jq --compact-output --null-input '$ARGS.positional' --args -- " ${ specialisation_list [@] } " ) "
if [ " $( basename " $generation_dir " ) " = " $( readlink " $profile " ) " ] ; then
current_generation_tag = "true"
else
current_generation_tag = "false"
fi
# Escape userdefined strings
nixos_version = " $( jq -aR <<< " $nixos_version " ) "
kernel_version = " $( jq -aR <<< " $kernel_version " ) "
configurationRevision = " $( jq -aR <<< " $configurationRevision " ) "
cat << EOF
{
"generation" : $generation_number ,
"date" : $build_date ,
"nixosVersion" : $nixos_version ,
"kernelVersion" : $kernel_version ,
"configurationRevision" : $configurationRevision ,
"specialisations" : $specialisations ,
"current" : $current_generation_tag
}
EOF
}
find " $( dirname " $profile " ) " -regex " $profile -[0-9]+-link " |
sort -Vr |
while read -r generation_dir; do
describe_generation " $generation_dir "
done |
if [ -z " $json " ] ; then
jq --slurp -r ' .[ ] | [
( [ .generation, ( if .current = = true then "current" else "" end) ] | join( " " ) ) ,
( .date | fromdate | strflocaltime( "%Y-%m-%d %H:%M:%S" ) ) ,
.nixosVersion, .kernelVersion, .configurationRevision,
( .specialisations | join( " " ) )
] | @tsv' |
2024-09-19 14:19:46 +00:00
column --separator $'\t' --table --table-columns "Generation,Build-date,NixOS version,Kernel,Configuration Revision,Specialisation"
2023-10-09 19:29:22 +00:00
else
jq --slurp .
fi
exit 0
fi
2020-04-24 23:36:52 +00:00
# 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
2022-03-30 09:31:56 +00:00
log "building the system configuration..."
2021-12-06 16:07:01 +00:00
if [ [ " $action " = switch || " $action " = boot ] ] ; then
2024-07-27 06:49:29 +00:00
if [ [ -z $buildingAttribute ] ] ; then
pathToConfig = " $( nixBuild $buildFile -A " ${ attr : + $attr . } config.system.build.toplevel " " ${ extraBuildFlags [@] } " ) "
elif [ [ -z $flake ] ] ; then
2020-04-24 23:36:52 +00:00
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 "
2024-01-25 14:12:00 +00:00
targetHostSudoCmd 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
2024-07-27 06:49:29 +00:00
if [ [ -z $buildingAttribute ] ] ; then
pathToConfig = " $( nixBuild $buildFile -A " ${ attr : + $attr . } config.system.build.toplevel " " ${ extraBuildFlags [@] } " ) "
elif [ [ -z $flake ] ] ; then
2020-04-24 23:36:52 +00:00
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
2024-07-27 06:49:29 +00:00
if [ [ -z $buildingAttribute ] ] ; then
pathToConfig = " $( nixBuild $buildFile -A " ${ attr : + $attr . } config.system.build.vm " " ${ extraBuildFlags [@] } " ) "
elif [ [ -z $flake ] ] ; then
2020-04-24 23:36:52 +00:00
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
2024-07-27 06:49:29 +00:00
if [ [ -z $buildingAttribute ] ] ; then
pathToConfig = " $( nixBuild $buildFile -A " ${ attr : + $attr . } config.system.build.vmWithBootLoader " " ${ extraBuildFlags [@] } " ) "
elif [ [ -z $flake ] ] ; then
2020-04-24 23:36:52 +00:00
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
2024-01-25 14:12:00 +00:00
targetHostSudoCmd nix-env --rollback -p " $profile "
2020-04-24 23:36:52 +00:00
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
2023-10-19 13:55:26 +00:00
# Using systemd-run here to protect against PTY failures/network
# disconnections during rebuild.
# See: https://github.com/NixOS/nixpkgs/issues/39118
cmd = (
"systemd-run"
"-E" "LOCALE_ARCHIVE" # Will be set to new value early in switch-to-configuration script, but interpreter starts out with old value
2024-02-29 20:09:43 +00:00
"-E" " NIXOS_INSTALL_BOOTLOADER= $installBootloader "
2023-10-19 13:55:26 +00:00
"--collect"
"--no-ask-password"
2024-04-21 15:54:59 +00:00
"--pipe"
2023-10-19 13:55:26 +00:00
"--quiet"
"--same-dir"
"--service-type=exec"
"--unit=nixos-rebuild-switch-to-configuration"
"--wait"
)
# Check if we have a working systemd-run. In chroot environments we may have
# a non-working systemd, so we fallback to not using systemd-run.
# You may also want to explicitly set NIXOS_SWITCH_USE_DIRTY_ENV environment
# variable, since systemd-run runs inside an isolated environment and
# this may break some post-switch scripts. However keep in mind that this
# may be dangerous in remote access (e.g. SSH).
if [ [ -n " $NIXOS_SWITCH_USE_DIRTY_ENV " ] ] ; then
log "warning: skipping systemd-run since NIXOS_SWITCH_USE_DIRTY_ENV is set. This environment variable will be ignored in the future"
2024-02-29 20:09:43 +00:00
cmd = ( "env" " NIXOS_INSTALL_BOOTLOADER= $installBootloader " )
2024-01-25 14:12:00 +00:00
elif ! targetHostSudoCmd " ${ cmd [@] } " true; then
2023-10-19 13:55:26 +00:00
logVerbose "Skipping systemd-run to switch configuration since it is not working in target host."
2023-11-16 04:20:00 +00:00
cmd = (
"env"
"-i"
" LOCALE_ARCHIVE= $LOCALE_ARCHIVE "
2024-02-29 20:09:43 +00:00
" NIXOS_INSTALL_BOOTLOADER= $installBootloader "
2023-11-16 04:20:00 +00:00
)
2023-10-19 13:55:26 +00:00
else
logVerbose "Using systemd-run to switch configuration."
fi
2023-01-20 10:41:00 +00:00
if [ [ -z " $specialisation " ] ] ; then
2023-10-19 13:55:26 +00:00
cmd += ( " $pathToConfig /bin/switch-to-configuration " )
2023-01-20 10:41:00 +00:00
else
2023-10-19 13:55:26 +00:00
cmd += ( " $pathToConfig /specialisation/ $specialisation /bin/switch-to-configuration " )
2023-01-20 10:41:00 +00:00
2024-04-21 15:54:59 +00:00
if [ -z " $targetHost " ] ; then
specialisationExists = $( test -f " ${ cmd [-1] } " )
else
specialisationExists = $( targetHostCmd test -f " ${ cmd [-1] } " )
fi
if ! $specialisationExists ; then
2023-01-20 10:41:00 +00:00
log " error: specialisation not found: $specialisation "
exit 1
fi
fi
2024-01-25 14:12:00 +00:00
if ! targetHostSudoCmd " ${ cmd [@] } " " $action " ; then
2022-03-30 09:31:56 +00:00
log "warning: error(s) occurred while switching to the new configuration"
2020-04-24 23:36:52 +00:00
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