fix: don't create broken symlinks during hoisting

ref #2916
PR #3062
This commit is contained in:
Zoltan Kochan
2021-01-10 18:12:25 +02:00
committed by GitHub
parent d5ef7958ab
commit 672c27cfe6
3 changed files with 24 additions and 13 deletions

View File

@@ -0,0 +1,5 @@
---
"supi": patch
---
Don't create broken symlinks to skipped optional dependencies, when hoisting. This issue was already fixed in pnpm v5.13.7 for the case when the lockfile is up-to-date. This fixes the same issue for cases when the lockfile need updates. For instance, when adding a new package.

View File

@@ -231,8 +231,15 @@ export default async function linkPackages (
let newHoistedDependencies!: HoistedDependencies
if ((opts.hoistPattern != null || opts.publicHoistPattern != null) && (newDepPaths.length > 0 || removedDepPaths.size > 0)) {
// It is important to keep the skipped packages in the lockfile which will be saved as the "current lockfile".
// pnpm is comparing the current lockfile to the wanted one and they should much.
// But for hoisting, we need a version of the lockfile w/o the skipped packages, so we're making a copy.
const hoistLockfile = {
...currentLockfile,
packages: R.omit(Array.from(opts.skipped), currentLockfile.packages),
}
newHoistedDependencies = await hoist({
lockfile: currentLockfile,
lockfile: hoistLockfile,
lockfileDir: opts.lockfileDir,
privateHoistedModulesDir: opts.hoistedModulesDir,
privateHoistPattern: opts.hoistPattern ?? [],

View File

@@ -502,28 +502,27 @@ test('should recreate node_modules with hoisting', async () => {
test('hoisting should not create a broken symlink to a skipped optional dependency', async () => {
const project = prepareEmpty()
const rootModules = assertProject(process.cwd())
await install({
const manifest = {
dependencies: {
'is-positive': '1.0.0',
},
optionalDependencies: {
'not-compatible-with-any-os': '*',
},
}, await testDefaults({ publicHoistPattern: '*' }))
}
await install(manifest, await testDefaults({ publicHoistPattern: '*' }))
await project.hasNot('dep-of-optional-pkg')
expect(await rootModules.readCurrentLockfile()).toStrictEqual(await rootModules.readLockfile())
// Verifying the same with headless installation
await rimraf('node_modules')
await install({
optionalDependencies: {
'not-compatible-with-any-os': '*',
},
}, await testDefaults({ publicHoistPattern: '*' }))
await install(manifest, await testDefaults({ publicHoistPattern: '*' }))
await project.hasNot('dep-of-optional-pkg')
const rootModules = assertProject(process.cwd())
const currentLockfile = await rootModules.readCurrentLockfile()
const wantedLockfile = await rootModules.readLockfile()
expect(currentLockfile).toStrictEqual(wantedLockfile)
expect(await rootModules.readCurrentLockfile()).toStrictEqual(await rootModules.readLockfile())
})