importNpmLock: Don't create intermediate symlink files

It's currently possible to run into a race condition when entering the same development environment concurrently:
```
❯ git fetch; jj rebase -b 'all:mutable() & mine()' -d main@origin --skip-emptied
Rebased 4 commits onto destination
Abandoned 1 newly emptied commits
Working copy  (@) now at: tnyknvqt 93e36def (empty) (no description set)
Parent commit (@-)      : wnqxqyyl e0983a05 main@origin | Increase limit of max number of words
Added 0 files, modified 8 files, removed 0 files
direnv: loading ~/dev/REDACTED/.envrc
direnv: loading https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc (sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4=)
Executing linkNodeModulesHook
node:internal/fs/promises:782
  return await PromisePrototypeThen(
         ^

Error: ENOENT: no such file or directory, rename 'node_modules/.bin-nix-hook-temp' -> 'node_modules/.bin'
    at async Object.rename (node:internal/fs/promises:782:10)
    at async /nix/store/ps9ivjjxzi0fks67j6vd4gbw5dcnhp0w-link-node-modules.js:84:7
    at async Promise.all (index 0)
    at async main (/nix/store/ps9ivjjxzi0fks67j6vd4gbw5dcnhp0w-link-node-modules.js:58:3) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'rename',
  path: 'node_modules/.bin-nix-hook-temp',
  dest: 'node_modules/.bin'
}

Node.js v20.17.0
Finished executing linkNodeModulesShellHook
```

This change removes the intermediate file creation and simply tries to create a symlink directly.
If the target `node_modules/foo` already exists we unlink it and try to create the symlink again.
This commit is contained in:
adisbladis 2025-07-14 18:37:24 +12:00
parent a9904e09a1
commit db7050bb88

View File

@ -69,19 +69,17 @@ async function main() {
// Don't unlink this file, we just wrote it.
managed.delete(file);
// Link to a temporary dummy path and rename.
// This is to get some degree of atomicity.
// Link file
try {
await fs.promises.symlink(sourcePath, targetPath + "-nix-hook-temp");
await fs.promises.symlink(sourcePath, targetPath);
} catch (err) {
// If the target file already exists remove it and try again
if (err.code !== "EEXIST") {
throw err;
}
await fs.promises.unlink(targetPath + "-nix-hook-temp");
await fs.promises.symlink(sourcePath, targetPath + "-nix-hook-temp");
await fs.promises.unlink(targetPath);
await fs.promises.symlink(sourcePath, targetPath);
}
await fs.promises.rename(targetPath + "-nix-hook-temp", targetPath);
})
);