Files
nixconfig/update-system.sh
T

61 lines
2.3 KiB
Bash

# Run as dev; privileged activation uses the already declared scoped sudo rule.
repo=${NIXOS_CONFIG_REPO:-/etc/nixos}
state=${CACHE_DIRECTORY:-/var/cache/nixos-update}
mkdir -p "$state"
exec 9>"$state/lock"
flock -n 9 || exit 0
cd "$repo"
if [ -n "$(git status --porcelain)" ]; then
echo 'Skipping automatic update: the configuration has local changes.'
exit 0
fi
baseline=$(git rev-parse HEAD)
branch=$(git symbolic-ref HEAD)
work=$(mktemp -d "$state/work.XXXXXXXX")
cleanup() {
git -C "$repo" worktree remove --force "$work" >/dev/null 2>&1 || true
rm -rf -- "$work"
}
trap cleanup EXIT
git worktree add --detach "$work" "$baseline"
cd "$work"
# Only these stable release inputs advance. Neovim's source stays pinned.
nix flake update nixpkgs home-manager
if git diff --quiet -- flake.lock; then
echo 'Stable inputs are already current.'
exit 0
fi
nix flake check --no-build --no-update-lock-file
nix build .#checks.x86_64-linux.updates .#checks.x86_64-linux.desktop-config \
--no-update-lock-file --no-link
git add flake.lock
git -c user.name='NixOS Updater' -c user.email='nixos-updater@localhost' \
commit -m 'chore: update stable NixOS and Home Manager inputs'
built=$(nix build .#nixosConfigurations.dev.config.system.build.toplevel \
--no-update-lock-file --no-link --print-out-paths)
candidate=$(git rev-parse HEAD)
# Never overwrite work started while the candidate was building.
cd "$repo"
if [ "$(git rev-parse HEAD)" != "$baseline" ] || \
[ "$(git symbolic-ref HEAD)" != "$branch" ] || \
[ -n "$(git status --porcelain)" ]; then
echo 'Configuration changed during the build; leaving it untouched.'
exit 0
fi
previous=$(readlink -f /run/current-system)
sudo "$built/sw/bin/nixos-rebuild" dry-activate --no-reexec --store-path "$built"
git merge --ff-only "$candidate"
if ! sudo "$built/sw/bin/nixos-rebuild" switch --no-reexec --store-path "$built"; then
echo 'Activation failed; restoring the previous system. See the journal.' >&2
sudo "$previous/sw/bin/nixos-rebuild" switch --no-reexec --store-path "$previous"
if [ "$(git rev-parse HEAD)" = "$candidate" ] && [ -z "$(git status --porcelain)" ]; then
git -c user.name='NixOS Updater' -c user.email='nixos-updater@localhost' \
revert --no-edit "$candidate"
fi
exit 1
fi
# No forced reboot or garbage collection: recovery generations are retained.