#! @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 [-b ] [-g ]" >&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 \` and \`-f \` 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 " exit 0 fi echo "generational bootloader installed"