From db7050bb887b72530d4c65a71af33cb49f710fab Mon Sep 17 00:00:00 2001 From: adisbladis Date: Mon, 14 Jul 2025 18:37:24 +1200 Subject: [PATCH] importNpmLock: Don't create intermediate symlink files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../node/import-npm-lock/hooks/link-node-modules.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pkgs/build-support/node/import-npm-lock/hooks/link-node-modules.js b/pkgs/build-support/node/import-npm-lock/hooks/link-node-modules.js index 79e247eb4acb..b045e4e0918c 100644 --- a/pkgs/build-support/node/import-npm-lock/hooks/link-node-modules.js +++ b/pkgs/build-support/node/import-npm-lock/hooks/link-node-modules.js @@ -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); }) );