# 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)**
```bash
# 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**
```bash
# Enter dev shell manually
nix develop

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

### Quick Start

```bash
# 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

```bash
# 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:
```bash
# 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"
```bash
cd /home/ppetru/projects/alo-cluster
./scripts/diff-configs.sh
```

### "No changes detected"
All changes are already committed. Stage some changes first:
```bash
git add .
```

### Build failures for all hosts
Check flake syntax:
```bash
nix flake check
```

### nvd not found
Install nvd:
```bash
nix profile install nixpkgs#nvd
```
(Already included in workstation-node.nix packages)

## Related Tools

- `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
