146 lines
4.2 KiB
Bash
146 lines
4.2 KiB
Bash
#! @bash@/bin/sh -e
|
|
|
|
# shellcheck disable=SC3043,SC3044,SC3054
|
|
|
|
shopt -s nullglob
|
|
|
|
export PATH=/empty:@path@
|
|
|
|
# used to track copied generations to decide which are obsolete
|
|
# and need to be removed
|
|
declare -A activeGenerations
|
|
|
|
moveWBackup() {
|
|
local src="$1"
|
|
local dst="$2"
|
|
|
|
# Backup $dst if already exists
|
|
local dstBkp="$dst.bkp.$$"
|
|
if [ -e "$dst" ]; then
|
|
mv "$dst" "$dstBkp"
|
|
fi
|
|
|
|
# Move $src as "new" $dst
|
|
mv "$src" "$dst"
|
|
|
|
# Remove backup directory of the previous $dst
|
|
rm -rf "$dstBkp"
|
|
}
|
|
|
|
# Copy generation's kernel, initrd, cmdline to `gensDir/generationName`.
|
|
addEntry() {
|
|
local generationPath="$1"
|
|
local generationName="$2"
|
|
local gensDir="$3"
|
|
|
|
local dst="$gensDir/$generationName"
|
|
|
|
echo "* nixos generation '$generationName' -> $dst"
|
|
# Don't copy the files if $dst already exists, unless it's the default
|
|
# configuration.
|
|
# This means that we have to create $dst atomically to prevent partially
|
|
# copied generations if this script is ever interrupted.
|
|
#
|
|
# For "default" generation: make backup and then replace with the new
|
|
# "default", minimizing the time when where isn't any "default" generation
|
|
# directory
|
|
if ! [ -e $dst ] || [ "$generationName" = "default" ]; then
|
|
local dstTmp="$dst.tmp.$$"
|
|
mkdir -p "$dstTmp" || true
|
|
|
|
@nixosGenBuilder@ -c "$generationPath" -n "$generationName" -d "$dstTmp"
|
|
|
|
# Move new generation on its place, backing up the previous version
|
|
# if it exists
|
|
# This may only happen when "$generationName" = "default"
|
|
moveWBackup "$dstTmp" "$dst"
|
|
fi
|
|
|
|
activeGenerations["$generationName"]=1
|
|
}
|
|
|
|
removeObsoleteGenerations() {
|
|
local path="$1"
|
|
|
|
echo "removing obsolete generations in $path..."
|
|
for gen in $path/*; do
|
|
if ! [ "${activeGenerations["$(basename "$gen")"]}" = 1 ]; then
|
|
echo "* $gen is obsolete"
|
|
rm -vrf "$gen"
|
|
fi
|
|
done
|
|
}
|
|
|
|
addAllEntries() {
|
|
local defaultGenerationPath="$1"
|
|
local outdir="$2"
|
|
local numGenerations="$3"
|
|
|
|
local gensDir="$outdir/@nixosGenerationsDir@"
|
|
mkdir -p "$gensDir" || true
|
|
|
|
# Add default generation
|
|
addEntry "$defaultGenerationPath" default "$gensDir"
|
|
|
|
if [ "$numGenerations" -gt 0 ]; then
|
|
# Add up to $numGenerations generations of the system profile, in reverse
|
|
# (most recent to least recent) order.
|
|
for generation in $(
|
|
(cd /nix/var/nix/profiles && ls -d system-*-link) \
|
|
| sed 's/system-\([0-9]\+\)-link/\1/' \
|
|
| sort -n -r \
|
|
| head -n "$numGenerations"); do
|
|
link=/nix/var/nix/profiles/system-$generation-link
|
|
addEntry "$link" "${generation}-default" "$gensDir"
|
|
for specialisation in $(
|
|
ls /nix/var/nix/profiles/system-$generation-link/specialisation \
|
|
| sort -n -r); do
|
|
link=/nix/var/nix/profiles/system-$generation-link/specialisation/$specialisation
|
|
addEntry "$link" "${generation}-${specialisation}" "$gensDir"
|
|
done
|
|
done
|
|
fi
|
|
|
|
removeObsoleteGenerations "$gensDir"
|
|
}
|
|
|
|
usage() {
|
|
echo "usage: $0 -c <path-to-default-configuration> [-b <boot-dir>] [-g <num-generations>]" >&2
|
|
exit 1
|
|
}
|
|
|
|
|
|
default= # Default configuration
|
|
numGenerations=0 # Number of other generations to keep (kernel, initrd, DTBs, overlays)
|
|
|
|
echo "$0: $@"
|
|
while getopts "c:b:g:f:" opt; do
|
|
case "$opt" in
|
|
c) default="$OPTARG" ;;
|
|
b) boottarget="$OPTARG" ;;
|
|
g) numGenerations="$OPTARG" ;;
|
|
f) fwtarget="$OPTARG" ;;
|
|
\?) usage ;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$boottarget" ] && [ -z "$fwtarget" ]; then
|
|
echo "Error: at least one of \`-b <boot-dir>\` and \`-f <firmware-dir>\` must be set"
|
|
usage
|
|
fi
|
|
|
|
if [ -n "$fwtarget" ]; then
|
|
echo "installing nixos-generation-independent firmware..."
|
|
@installFirmwareBuilder@ -c "$default" -d "$fwtarget"
|
|
|
|
echo "installing nixos generations..."
|
|
addAllEntries "$default" "$fwtarget" "$numGenerations"
|
|
fi
|
|
|
|
if [ -n "$boottarget" ]; then
|
|
echo "'-b $boottarget' isn't used when loading the kernel directly with \`kernel\`: "\
|
|
"kernels are copied directly to <firmware-dir>"
|
|
exit 0
|
|
fi
|
|
|
|
echo "generational bootloader installed" |