Files
alo-cluster/docs/DIFF_CONFIGS.md

7.2 KiB

Configuration Diff Tool

Tool to compare all NixOS host configurations between current working tree and HEAD commit.

Purpose

Before committing changes (especially refactors), verify that you haven't accidentally broken existing host configurations. This tool:

  • Builds all host configurations in current state (with uncommitted changes)
  • Builds all host configurations at HEAD (last commit)
  • Uses nvd to show readable diffs for each host
  • Highlights which hosts changed and which didn't

Usage

Prerequisites

The script requires nvd to be in PATH. Use either:

Option 1: direnv (recommended)

# Allow direnv in the repository (one-time setup)
direnv allow

# direnv will automatically load the dev shell when you cd into the directory
cd /home/ppetru/projects/alo-cluster
# nvd is now in PATH

Option 2: nix develop

# Enter dev shell manually
nix develop

# Now run the script
./scripts/diff-configs.sh

Quick Start

# Compare all hosts (summary)
./scripts/diff-configs.sh

# Compare with detailed path listing
./scripts/diff-configs.sh -v c1

# Compare with content diffs of changed files (deep mode)
./scripts/diff-configs.sh --deep c1

# Compare only x86_64 hosts (avoid slow ARM cross-compilation)
./scripts/diff-configs.sh c1 c2 c3 zippy chilly sparky

# Verbose mode with multiple hosts
./scripts/diff-configs.sh --verbose c1 c2 c3

# Via flake app
nix run .#diff-configs

# Show help
./scripts/diff-configs.sh --help

Typical Workflow

# 1. Make changes to configurations
vim common/impermanence.nix

# 2. Stage changes (required for flake to see them)
git add common/impermanence.nix

# 3. Check what would change if you committed now
# For quick feedback, compare only x86_64 hosts first:
./scripts/diff-configs.sh c1 c2 c3 zippy chilly sparky

# 4. Review output, make adjustments if needed

# 5. If changes look good and affect ARM hosts, check those too:
./scripts/diff-configs.sh stinky alo-cloud-1

# 6. Commit when satisfied
git commit -m "Refactor impermanence config"

Output Explanation

No Changes

━━━ c1 ━━━
  Building current... done
  Building HEAD...    done
  ✓ No changes

This host's configuration is identical between current and HEAD.

Changes Detected

━━━ stinky ━━━
  Building current... done
  Building HEAD...    done
  ⚠ Configuration changed

<<< /nix/store/abc-nixos-system-stinky-25.05 (HEAD)
>>> /nix/store/xyz-nixos-system-stinky-25.05 (current)

Version changes:
[C]  octoprint: 1.9.3 -> 1.10.0
[A+] libcamera: ∅ -> 0.1.0
Closure size: 1500 -> 1520 (5 paths added, 2 paths removed, +3, +15.2 MB)

Legend:

  • [C] - Changed package version
  • [A+] - Added package
  • [R-] - Removed package
  • [U.] - Updated (same version, rebuilt)

Verbose Mode (--verbose)

With -v or --verbose, also shows the actual store paths that changed:

━━━ c1 ━━━
  Building current... done
  Building HEAD...    done
  ⚠ Configuration changed

[nvd summary as above]

  Changed store paths:
    Removed (17 paths):
    - config.fish
    - system-units
    - home-manager-generation
    - etc-fuse.conf
    ... and 13 more

    Added (17 paths):
    - config.fish
    - system-units
    - home-manager-generation
    - etc-fuse.conf
    ... and 13 more

This is useful when nvd shows "No version changes" but paths still changed (e.g., refactors that rebuild config files).

Deep Mode (--deep)

With -d or --deep, shows actual content diffs of changed files within store paths (implies verbose):

━━━ c1 ━━━
  Building current... done
  Building HEAD...    done
  ⚠ Configuration changed

[nvd summary and path listing as above]

  Content diffs of changed files:

    ▸ etc-fuse.conf
      @@ -1,2 +1,2 @@
      -user_allow_other
      +#user_allow_other
       mount_max = 1000

    ▸ nixos-system-c1-25.05
      activate:
        @@ -108,7 +108,7 @@
         echo "setting up /etc..."
        -/nix/store/...-perl/bin/perl /nix/store/...-setup-etc.pl /nix/store/abc-etc/etc
        +/nix/store/...-perl/bin/perl /nix/store/...-setup-etc.pl /nix/store/xyz-etc/etc

    ▸ unit-dbus.service
      dbus.service:
        @@ -1,5 +1,5 @@
         [Service]
        +Environment="LD_LIBRARY_PATH=/nix/store/.../systemd/lib"
         Environment="LOCALE_ARCHIVE=..."

What it shows:

  • Matches changed paths by basename (e.g., both have "config.fish")
  • Diffs important files: activate scripts, etc/*, *.conf, *.fish, *.service, *.nix
  • Shows unified diff format (lines added/removed)
  • Limits to first 50 lines per file

When to use:

  • When you need to know what exactly changed in config files
  • Debugging unexpected configuration changes
  • Reviewing refactors that don't change package versions
  • Understanding why a host rebuilt despite "No version changes"

Build Failures

━━━ broken-host ━━━
  Building current... FAILED
  Error: attribute 'foo' missing

If a host fails to build, the error is shown and the script continues with other hosts.

How It Works

  1. Discovers hosts: Queries deploy.nodes from flake to get all configured hosts
  2. Creates worktree: Uses git worktree to check out HEAD in a temporary directory
  3. Builds configurations: Builds config.system.build.toplevel for each host in both locations
  4. Compares with nvd: Runs nvd diff to show package-level changes
  5. Cleans up: Removes temporary worktree automatically

Important Notes

Git Staging Required

Flakes only evaluate files that are tracked by git. To make changes visible:

# Stage new files
git add new-file.nix

# Stage changes to existing files
git add modified-file.nix

# Or stage everything
git add .

Unstaged changes to tracked files are visible (flake uses working tree content).

Performance

  • First run may be slow (building all configurations)
  • Subsequent runs benefit from Nix evaluation cache
  • Typical runtime: 1-5 minutes depending on changes
  • ARM cross-compilation is slow: Use host filtering to avoid building ARM hosts when not needed
    • Example: ./scripts/diff-configs.sh c1 c2 c3 (x86_64 only, fast)
    • vs ./scripts/diff-configs.sh (includes stinky/alo-cloud-1, slow)

When to Use

Good use cases:

  • Refactoring shared modules (like impermanence)
  • Updating common configurations
  • Before committing significant changes
  • Verifying deploy target consistency

Not needed for:

  • Adding a single new host
  • Trivial one-host changes
  • Documentation updates

Troubleshooting

"Not in a git repository"

cd /home/ppetru/projects/alo-cluster
./scripts/diff-configs.sh

"No changes detected"

All changes are already committed. Stage some changes first:

git add .

Build failures for all hosts

Check flake syntax:

nix flake check

nvd not found

Install nvd:

nix profile install nixpkgs#nvd

(Already included in workstation-node.nix packages)

  • nvd - Package diff tool (used internally)
  • nix diff-closures - Low-level closure diff
  • nix store diff-closures - Alternative diff command
  • deploy-rs - Actual deployment tool

See Also

  • common/global/show-changelog.nix - Shows changes during system activation
  • docs/RASPBERRY_PI_SD_IMAGE.md - SD image building process