diff --git a/__tests__/commands/install/integration-deduping.js b/__tests__/commands/install/integration-deduping.js index b822194188..d08757fd20 100644 --- a/__tests__/commands/install/integration-deduping.js +++ b/__tests__/commands/install/integration-deduping.js @@ -220,3 +220,21 @@ test.concurrent('install should not hardlink repeated dependencies if linkDuplic expect(b_a.ino).not.toEqual(c_a.ino); }); }); + +test.concurrent('install should not copy node_modules when hardlinking', (): Promise => { + // https://github.com/yarnpkg/yarn/issues/2734 + // A@1 -> B@1 -> C@1 + // -> C@2 + // B@2 + // C@2 + // D@1 -> B@1 (hardlink) -> C@1 (hardlink) + // -> C@2 + return runInstall({linkDuplicates: true}, 'hardlink-collision', async config => { + let a_1 = await fs.stat(path.join(config.cwd, 'node_modules/a/node_modules/b/package.json')); + let d_1 = await fs.stat(path.join(config.cwd, 'node_modules/d/node_modules/b/package.json')); + expect(a_1.ino).toEqual(d_1.ino); + a_1 = await fs.stat(path.join(config.cwd, 'node_modules/a/node_modules/b/node_modules/c/package.json')); + d_1 = await fs.stat(path.join(config.cwd, 'node_modules/d/node_modules/b/node_modules/c/package.json')); + expect(a_1.ino).toEqual(d_1.ino); + }); +}); diff --git a/__tests__/fixtures/install/hardlink-collision/deps/a-1/package.json b/__tests__/fixtures/install/hardlink-collision/deps/a-1/package.json new file mode 100644 index 0000000000..c2c8651d69 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/deps/a-1/package.json @@ -0,0 +1,8 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "b": "file:../b-1", + "c": "file:../c-2" + } +} diff --git a/__tests__/fixtures/install/hardlink-collision/deps/b-1/package.json b/__tests__/fixtures/install/hardlink-collision/deps/b-1/package.json new file mode 100644 index 0000000000..ad3074b214 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/deps/b-1/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "1.0.0", + "dependencies": { + "c": "file:../c-1" + } +} diff --git a/__tests__/fixtures/install/hardlink-collision/deps/b-2/package.json b/__tests__/fixtures/install/hardlink-collision/deps/b-2/package.json new file mode 100644 index 0000000000..57549744f3 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/deps/b-2/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "2.0.0" +} diff --git a/__tests__/fixtures/install/hardlink-collision/deps/c-1/package.json b/__tests__/fixtures/install/hardlink-collision/deps/c-1/package.json new file mode 100644 index 0000000000..abd3384930 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/deps/c-1/package.json @@ -0,0 +1,4 @@ +{ + "name": "c", + "version": "1.0.0" +} diff --git a/__tests__/fixtures/install/hardlink-collision/deps/c-2/package.json b/__tests__/fixtures/install/hardlink-collision/deps/c-2/package.json new file mode 100644 index 0000000000..eede1fcd97 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/deps/c-2/package.json @@ -0,0 +1,4 @@ +{ + "name": "c", + "version": "2.0.0" +} diff --git a/__tests__/fixtures/install/hardlink-collision/deps/c-3/package.json b/__tests__/fixtures/install/hardlink-collision/deps/c-3/package.json new file mode 100644 index 0000000000..6915ecb021 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/deps/c-3/package.json @@ -0,0 +1,4 @@ +{ + "name": "c", + "version": "3.0.0" +} diff --git a/__tests__/fixtures/install/hardlink-collision/deps/d-1/package.json b/__tests__/fixtures/install/hardlink-collision/deps/d-1/package.json new file mode 100644 index 0000000000..eae1f73732 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/deps/d-1/package.json @@ -0,0 +1,8 @@ +{ + "name": "a", + "version": "2.0.0", + "dependencies": { + "b": "file:../b-1", + "c": "file:../c-2" + } +} diff --git a/__tests__/fixtures/install/hardlink-collision/package.json b/__tests__/fixtures/install/hardlink-collision/package.json new file mode 100644 index 0000000000..9b49885a10 --- /dev/null +++ b/__tests__/fixtures/install/hardlink-collision/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "a": "file:deps/a-1", + "b": "file:deps/b-2", + "c": "file:deps/c-3", + "d": "file:deps/d-1" + } +} diff --git a/src/util/fs.js b/src/util/fs.js index 9adfe91261..da9bc53320 100644 --- a/src/util/fs.js +++ b/src/util/fs.js @@ -450,6 +450,8 @@ async function buildActionsForHardlink( // push all files to queue invariant(srcFiles, 'src files not initialised'); + // hardlinking is per package, not going into sub packages + srcFiles = srcFiles.filter(f => f !== 'node_modules'); let remaining = srcFiles.length; if (!remaining) { onDone();