{...}: { # `nix run .#sync-hardware` # # Refreshes the calling host's generated hardware module in-repo, replacing the # old habit of importing /etc/nixos/hardware-configuration.nix by absolute path. # # Why bother: that absolute import left the flake impure (every eval needed # --impure, since the file lives outside the store) and — worse — meant *both* # hosts resolved to whichever machine's hardware file was on disk at build # time. Building t480 from shadow silently baked in shadow's disk UUIDs. # # Run this on a host after changing its hardware, then commit the result. perSystem = {pkgs, ...}: let script = pkgs.writeShellApplication { name = "sync-hardware"; runtimeInputs = [pkgs.nixos-install-tools pkgs.git pkgs.coreutils pkgs.nettools]; text = '' set -euo pipefail host="''${1:-$(hostname)}" root=$(git rev-parse --show-toplevel 2>/dev/null || true) if [ -z "$root" ]; then echo "sync-hardware: run this from inside the config repo." >&2 exit 1 fi dir="$root/modules/hosts/$host" if [ ! -d "$dir" ]; then echo "sync-hardware: no host directory at $dir" >&2 echo " known hosts: $(cd "$root/modules/hosts" && echo *)" >&2 echo " pass an explicit name with: nix run .#sync-hardware -- " >&2 exit 1 fi out="$dir/_hardware.nix" # --no-filesystems is load-bearing: fileSystems/swapDevices are declared # by hand in the host's disks.nix. Without the flag this would emit # entries for whatever is mounted right now, duplicating (and conflicting # with) those definitions. header=$(cat <<'EOF' # GENERATED FILE — do not edit by hand. # # Regenerate on the host itself with: nix run .#sync-hardware # # Produced by `nixos-generate-config --show-hardware-config --no-filesystems`. # The --no-filesystems flag is deliberate: fileSystems and swapDevices are # declared by hand in ./disks.nix, so regenerating this file can never clobber # them or emit duplicates for whatever happened to be mounted at the time. # # Leading underscore keeps import-tree from auto-importing this as a # flake-parts module (its filter drops any path containing "/_"); it is # imported explicitly from ./default.nix instead. EOF ) tmp=$(mktemp) trap 'rm -f "$tmp"' EXIT # Strip the upstream 3-line "Do not modify" banner; ours replaces it. { printf '%s\n' "$header" | sed 's/^ //' nixos-generate-config --show-hardware-config --no-filesystems | tail -n +4 } > "$tmp" if [ -f "$out" ] && cmp -s "$tmp" "$out"; then echo "sync-hardware: $out already up to date." exit 0 fi cp "$tmp" "$out" echo "sync-hardware: wrote $out" echo " review with: git diff -- $out" ''; }; in { apps.sync-hardware = { type = "app"; program = "${script}/bin/sync-hardware"; meta.description = "Regenerate modules/hosts//_hardware.nix from the running machine"; }; }; }