feat(nixos): add nixos-diff rebuild diff + reboot/re-login helper

This commit is contained in:
2026-08-06 14:55:06 +02:00
parent 5d0a33d09f
commit b9e8641bbf
2 changed files with 84 additions and 1 deletions
+83
View File
@@ -0,0 +1,83 @@
# `nixos-diff`: after a rebuild, report (1) what packages changed and (2) whether the
# change needs a reboot, a re-login, or nothing. NixOS keeps two markers —
# /run/booted-system (what you booted) and /run/current-system (what the last `switch`
# activated). A switch applies userland live, but:
# - the kernel, initrd, and kernel modules are frozen until the next BOOT — detected
# exactly, by comparing those store paths between the two systems;
# - session-mapped components (the Wayland compositor, GL stack, portals) a running
# graphical session keeps until you log out and back in — detected HEURISTICALLY,
# by matching changed package names against `local.rebuildDiff.reloginPackages`.
# Generic and topology-free, so it rides in the baseline; disable with
# `local.rebuildDiff.enable = false`.
{ config, lib, pkgs, ... }:
let
cfg = config.local.rebuildDiff;
reloginPattern = lib.concatStringsSep "|" cfg.reloginPackages;
nixos-diff = pkgs.writeShellApplication {
name = "nixos-diff";
runtimeInputs = [ pkgs.nvd pkgs.coreutils pkgs.gnugrep ];
text = ''
booted=/run/booted-system
current=/run/current-system
# Package-level diff of the running system vs the activated one. Force colour
# (nvd auto-disables it when captured); only version parts are coloured, so the
# package-name grep below is unaffected.
diff=$(nvd --color always diff "$booted" "$current")
printf '%s\n' "$diff"
# Reboot (exact): kernel/initrd/modules only take effect on the next boot.
reboot=0
for c in kernel initrd kernel-modules; do
[ "$(readlink -f "$booted/$c" 2>/dev/null)" = "$(readlink -f "$current/$c" 2>/dev/null)" ] \
|| reboot=1
done
# Re-login (heuristic): session-mapped components a running Wayland session
# keeps until you log out and back in.
relogin_hits=""
${lib.optionalString (reloginPattern != "") ''
relogin_hits=$(printf '%s\n' "$diff" | grep -Ew "${reloginPattern}" || true)
''}
echo
if [ "$reboot" -eq 1 ]; then
printf '>>> REBOOT needed (kernel/initrd/modules changed).\n'
elif [ -n "$relogin_hits" ]; then
printf '>>> RE-LOGIN recommended session components changed:\n'
printf '%s\n' "$relogin_hits"
else
printf '>>> No reboot/re-login needed.\n'
fi
'';
};
in
{
options.local.rebuildDiff = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Install `nixos-diff`: after a `nixos-rebuild switch`, print an `nvd` closure
diff of the running vs activated system plus a reboot / re-login / live verdict.
'';
};
reloginPackages = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "mesa" "wayland" "hyprland" "xdg-desktop-portal" ];
description = ''
Whole-word package-name patterns matched against the diff; a match means a
running Wayland session should be restarted (re-login) to pick the change up
the compositor, GL stack, and portals. Extend per host (e.g. a specific GPU
driver). Empty disables the re-login heuristic.
'';
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ nixos-diff pkgs.nvd ];
};
}