mirror of
https://github.com/nix-community/home-manager.git
synced 2026-10-02 19:49:18 +00:00
The merge overwrote the target in place with `cat "$tmp" > path`, so a crash mid-write could leave a truncated file, and an application that saved its config while activation ran had that change silently overwritten. Snapshot the existing file, write the merged result to a temporary file next to the resolved target, copy the existing mode (or apply `mode` or the umask for a new file), and rename it into place. The snapshot keeps the configured file name inside a temporary directory, so a reader that detects the format from the extension still recognizes it, even through a symlink to a differently named file. Symlinked targets are written through and stay symlinks; a dangling symlink creates its target, as the hand-written mergers this helper replaced did. Activation fails without writing if the content, the mode, or the symlink target changed since the snapshot, and refuses targets inside the Nix store. A target that cannot be renamed over, such as a file bind-mounted by impermanence, is written in place instead. Temporary files are cleaned up by a trap scoped to a subshell, since activation owns the top-level EXIT trap; this also keeps the merge's shell variables out of the activation script. The change check is not a lock: a write between the final check and the rename is still lost. The documentation says so, along with the attributes a rename does not preserve. This follows the approach programs.vscode uses for its mutable user settings.