# `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 ]; }; }