diff --git a/sources/commands/Hydrate.ts b/sources/commands/Hydrate.ts index 8318baf2b..c1ceb31f7 100644 --- a/sources/commands/Hydrate.ts +++ b/sources/commands/Hydrate.ts @@ -1,4 +1,5 @@ import {Command, Option, UsageError} from 'clipanion'; +import {mkdir} from 'fs/promises'; import path from 'path'; import * as folderUtils from '../folderUtils'; @@ -63,6 +64,9 @@ export class HydrateCommand extends Command { else this.context.stdout.write(`Hydrating ${name}@${reference}...\n`); + // Recreate the folder in case it was deleted somewhere else: + await mkdir(installFolder, {recursive: true}); + await tar.x({file: fileName, cwd: installFolder}, [`${name}/${reference}`]); if (this.activate) { diff --git a/sources/commands/Prepare.ts b/sources/commands/Prepare.ts index 7a867d2d3..3911e5323 100644 --- a/sources/commands/Prepare.ts +++ b/sources/commands/Prepare.ts @@ -1,4 +1,5 @@ import {Command, Option, UsageError} from 'clipanion'; +import {mkdir} from 'fs/promises'; import path from 'path'; import * as folderUtils from '../folderUtils'; @@ -117,6 +118,8 @@ export class PrepareCommand extends Command { this.context.stdout.write(`Packing the selected tools in ${path.basename(outputPath)}...\n`); const {default: tar} = await import(/* webpackMode: 'eager' */ `tar`); + // Recreate the folder in case it was deleted somewhere else: + await mkdir(baseInstallFolder, {recursive: true}); await tar.c({gzip: true, cwd: baseInstallFolder, file: path.resolve(outputPath)}, installLocations.map(location => { return path.relative(baseInstallFolder, location); })); diff --git a/tests/main.test.ts b/tests/main.test.ts index 9a505b24c..67cc90669 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -404,6 +404,44 @@ it(`should support hydrating package managers from cached archives`, async () => }); }); +it(`should support hydrating package managers if cache folder was removed`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`prepare`, `yarn@2.2.2`, `-o`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + + // Use a new cache + process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); + + // Simulate cache removal + await xfs.removePromise(npath.toPortablePath(process.env.COREPACK_HOME)); + + // Disable the network to make sure we don't succeed by accident + process.env.COREPACK_ENABLE_NETWORK = `0`; + + try { + await expect(runCli(cwd, [`hydrate`, `corepack.tgz`])).resolves.toMatchObject({ + stdout: `Hydrating yarn@2.2.2...\nAll done!\n`, + stderr: ``, + exitCode: 0, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }); + } finally { + delete process.env.COREPACK_ENABLE_NETWORK; + } + }); +}); + it(`should support hydrating multiple package managers from cached archives`, async () => { await xfs.mktempPromise(async cwd => { await expect(runCli(cwd, [`prepare`, `yarn@2.2.2`, `pnpm@5.8.0`, `-o`])).resolves.toMatchObject({ diff --git a/tests/nock/ToUs5E5EzXCAwMv31KqJGA-1.dat b/tests/nock/ToUs5E5EzXCAwMv31KqJGA-1.dat index f64f73d54..4ffa8f5b6 100644 Binary files a/tests/nock/ToUs5E5EzXCAwMv31KqJGA-1.dat and b/tests/nock/ToUs5E5EzXCAwMv31KqJGA-1.dat differ diff --git a/tests/nock/_2yNDOq6UlHEKY9lwBEOig-1.dat b/tests/nock/_2yNDOq6UlHEKY9lwBEOig-1.dat new file mode 100644 index 000000000..86de4928b Binary files /dev/null and b/tests/nock/_2yNDOq6UlHEKY9lwBEOig-1.dat differ diff --git a/tests/nock/_2yNDOq6UlHEKY9lwBEOig-2.dat b/tests/nock/_2yNDOq6UlHEKY9lwBEOig-2.dat new file mode 100644 index 000000000..5403d9e58 Binary files /dev/null and b/tests/nock/_2yNDOq6UlHEKY9lwBEOig-2.dat differ diff --git a/tests/nock/_2yNDOq6UlHEKY9lwBEOig-3.dat b/tests/nock/_2yNDOq6UlHEKY9lwBEOig-3.dat new file mode 100644 index 000000000..5403d9e58 Binary files /dev/null and b/tests/nock/_2yNDOq6UlHEKY9lwBEOig-3.dat differ