From d824d0246bcebbf8863f7a96681bcf85e23ef9f7 Mon Sep 17 00:00:00 2001 From: Vidhan Bhatt Date: Fri, 24 Jul 2026 18:01:43 -0400 Subject: [PATCH 1/2] fix: avoid rewriting flake.nix when its content is unchanged `write-flake` unconditionally `cat`s the freshly-formatted flake.nix over the existing one on every run, bumping its mtime even when the content is byte-identical. Downstream, this makes Nix treat flake.nix as touched on every `nix flake metadata`/`nix flake lock` invocation, which in turn rewrites flake.lock's mtime even though nothing in it actually changed. This defeats mtime-based caching (e.g. nix-direnv) on every `write-flake` run, including via pre-commit hooks that call it on commits that don't touch any flake-file-managed options. Only overwrite flake.nix when the formatted output actually differs. --- modules/write-flake.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/write-flake.nix b/modules/write-flake.nix index 33dc05d..da09c31 100644 --- a/modules/write-flake.nix +++ b/modules/write-flake.nix @@ -110,9 +110,12 @@ let pkgs.writeShellApplication { name = "write-flake"; meta.description = "Generate a flake.nix file"; + runtimeInputs = [ pkgs.diffutils ]; text = '' cd ${config.flake-file.intoPath} - cat ${formatted pkgs} > flake.nix + if ! cmp -s ${formatted pkgs} flake.nix; then + cat ${formatted pkgs} > flake.nix + fi ${hooks} ''; }; From 7eab8209334e71770a93135c2b6bc72ed56bbb3d Mon Sep 17 00:00:00 2001 From: Vidhan Bhatt Date: Fri, 24 Jul 2026 18:35:17 -0400 Subject: [PATCH 2/2] fix: avoid needless flake.lock rewrites in prune-lock-run Same class of bug as the write-flake fix, in two ways: 1. `mv pruned.lock flake.lock` happened unconditionally, even when `prune-lock.program`'s output was byte-identical to what was already there. 2. `nix flake metadata` ran *before* pruning. For inputs that already declare their own `inputs.nixpkgs.follows` (common with home-manager, treefmt-nix, etc.), Nix's own resolution collapses that straight to the direct target node, while a lock-pruning `program` that only sees the flattened lock JSON (not each input's flake.nix) may repoint it at a different, merely content-equal node instead. The two disagree structurally, and *any* subsequent nix invocation re-derives Nix's form -- so running `nix flake metadata` before pruning meant the very next `nix run`/`nix build` would partially undo the prune, which then gets redone on the next `prune-lock` run, forever. Running `nix flake metadata` *after* pruning instead lets Nix have the final say, which converges to a stable fixed point. --- modules/options/prune-lock.nix | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/options/prune-lock.nix b/modules/options/prune-lock.nix index cd92b80..b34735b 100644 --- a/modules/options/prune-lock.nix +++ b/modules/options/prune-lock.nix @@ -30,10 +30,15 @@ let pkgs: pkgs.writeShellApplication { name = "prune-lock"; + runtimeInputs = [ pkgs.diffutils ]; text = '' - nix flake metadata > /dev/null ${prune-cmd pkgs} flake.lock pruned.lock - mv pruned.lock flake.lock + if cmp -s flake.lock pruned.lock; then + rm pruned.lock + else + mv pruned.lock flake.lock + fi + nix flake metadata > /dev/null ''; };