From b9e8641bbf5cd92445ac33304a22ce25454a6437 Mon Sep 17 00:00:00 2001 From: Daniel Fainberg Date: Thu, 6 Aug 2026 14:55:06 +0200 Subject: [PATCH] feat(nixos): add `nixos-diff` rebuild diff + reboot/re-login helper --- modules/nixos.nix | 2 +- modules/rebuild-diff.nix | 83 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 modules/rebuild-diff.nix diff --git a/modules/nixos.nix b/modules/nixos.nix index 87fab4e..c007bfc 100644 --- a/modules/nixos.nix +++ b/modules/nixos.nix @@ -5,7 +5,7 @@ { config, lib, pkgs, ... }: { - imports = [ ./shutdown-debug.nix ./printing-scanning.nix ]; + imports = [ ./shutdown-debug.nix ./printing-scanning.nix ./rebuild-diff.nix ]; nix.settings.experimental-features = [ "nix-command" "flakes" ]; # Deduplicate identical store paths via hardlinks. diff --git a/modules/rebuild-diff.nix b/modules/rebuild-diff.nix new file mode 100644 index 0000000..49bf412 --- /dev/null +++ b/modules/rebuild-diff.nix @@ -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 ]; + }; +}