diff --git a/sources/corepackUtils.ts b/sources/corepackUtils.ts index d38df1c7b..65ba18419 100644 --- a/sources/corepackUtils.ts +++ b/sources/corepackUtils.ts @@ -218,13 +218,24 @@ export async function installVersion(installTarget: string, locator: Locator, {s const corepackData = JSON.parse(corepackContent); - debugUtils.log(`Reusing ${locator.name}@${locator.reference} found in ${installFolder}`); + // An older Corepack may have recorded bin paths that the package doesn't + // ship (e.g. `bin/pnpm.cjs` for pnpm 12). Reinstall instead of running them. + const recordedBin: unknown = corepackData.bin; + const isStale = isValidBinSpec(recordedBin) && + Object.values(recordedBin).every(dest => !fs.existsSync(path.join(installFolder, dest))); + + if (!isStale) { + debugUtils.log(`Reusing ${locator.name}@${locator.reference} found in ${installFolder}`); + + return { + hash: corepackData.hash as string, + location: installFolder, + bin: corepackData.bin, + }; + } - return { - hash: corepackData.hash as string, - location: installFolder, - bin: corepackData.bin, - }; + debugUtils.log(`Reinstalling ${locator.name}@${locator.reference}: none of its bins exist in ${installFolder}`); + await fs.promises.rm(installFolder, {recursive: true, force: true}); } catch (err) { if (nodeUtils.isNodeError(err) && err.code !== `ENOENT`) { throw err; diff --git a/tests/main.test.ts b/tests/main.test.ts index 4bb7f40f4..c4ad7eeb7 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1235,6 +1235,33 @@ it(`should handle parallel installs`, async () => { }); }); +it(`should reinstall a cached package manager whose recorded bin is missing`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `pnpm@6.6.2+sha224.eb5c0acad3b0f40ecdaa2db9aa5a73134ad256e17e22d1419a2ab073`, + }); + + await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `6.6.2\n`, + }); + + // Simulate a record written by an older Corepack that pointed to a file the package doesn't ship. + const corepackFile = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `pnpm/6.6.2/.corepack` as PortablePath); + const record = await xfs.readJsonPromise(corepackFile); + await xfs.writeJsonPromise(corepackFile, {...record, bin: {pnpm: `./bin/missing.cjs`, pnpx: `./bin/missing.cjs`}}); + + await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `6.6.2\n`, + }); + + await expect(xfs.readJsonPromise(corepackFile)).resolves.toMatchObject({bin: record.bin}); + }); +}); + it(`should not override the package manager exit code`, async () => { await xfs.mktempPromise(async cwd => { await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {