diff --git a/sources/commands/Hydrate.ts b/sources/commands/Hydrate.ts index 88cc0fe..196d8ba 100644 --- a/sources/commands/Hydrate.ts +++ b/sources/commands/Hydrate.ts @@ -23,8 +23,8 @@ export class HydrateCommand extends Command { @Command.Path(`hydrate`) async execute() { const installFolder = folderUtils.getInstallFolder(); - const fileName = path.resolve(this.context.cwd); + const fileName = path.resolve(this.context.cwd, this.fileName); - await tar.x({file: fileName, strip: 1, cwd: installFolder}); + await tar.x({file: fileName, cwd: installFolder}); } } diff --git a/sources/folderUtils.ts b/sources/folderUtils.ts index 8040522..786a6a6 100644 --- a/sources/folderUtils.ts +++ b/sources/folderUtils.ts @@ -3,7 +3,7 @@ import {homedir, tmpdir} from 'os'; import {join} from 'path'; export function getInstallFolder() { - return join(homedir(), `.node/pmm`); + return process.env.PMM_HOME ?? join(homedir(), `.node/pmm`); } export function getTemporaryFolder(target: string = tmpdir()) { diff --git a/sources/httpUtils.ts b/sources/httpUtils.ts index 5adfdbd..d403edd 100644 --- a/sources/httpUtils.ts +++ b/sources/httpUtils.ts @@ -1,7 +1,11 @@ +import {UsageError} from 'clipanion'; import https, {RequestOptions} from 'https'; import {IncomingMessage} from 'http'; export function fetchUrlStream(url: string, options: RequestOptions = {}) { + if (process.env.PMM_ENABLE_NETWORK === `0`) + throw new UsageError(`Network access disabled by the environment; can't reach ${url}`); + return new Promise((resolve, reject) => { const request = https.get(url, options, response => { const statusCode = response.statusCode ?? 500; diff --git a/tests/_runCli.ts b/tests/_runCli.ts index 3a505d2..c98943e 100644 --- a/tests/_runCli.ts +++ b/tests/_runCli.ts @@ -1,6 +1,7 @@ import {PortablePath, npath} from '@yarnpkg/fslib'; import {PassThrough} from 'stream'; +import {Engine} from '../sources/Engine'; import {main} from '../sources/main'; export async function runCli(cwd: PortablePath, argv: string[]) { @@ -21,6 +22,7 @@ export async function runCli(cwd: PortablePath, argv: string[]) { const exitCode = await main(argv, { cwd: npath.fromPortablePath(cwd), + engine: new Engine(), stdin, stdout, stderr, diff --git a/tests/main.test.ts b/tests/main.test.ts index dfa7b2e..8e41336 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1,9 +1,13 @@ -import {Filename, ppath, xfs} from '@yarnpkg/fslib'; +import {Filename, ppath, xfs, PortablePath} from '@yarnpkg/fslib'; import Enquirer from 'enquirer'; import config from '../config.json'; import {runCli} from './_runCli'; +beforeEach(async () => { + process.env.PMM_HOME = await xfs.mktempPromise(); +}); + for (const [name, version] of [[`yarn`, `1.22.4`], [`yarn`, `2.0.0-rc.30`], [`pnpm`, `4.11.6`], [`npm`, `6.14.2`]]) { it(`should use the right package manager version for a given project (${name}@${version})`, async () => { await xfs.mktempPromise(async cwd => { @@ -76,3 +80,54 @@ it(`should use the pinned version when local projects don't list any spec`, asyn }); }); }); + +it(`should support disabling the network accesses from the environment`, async () => { + process.env.PMM_ENABLE_NETWORK = `0`; + + try { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarn`, `yarn`, `--version`])).resolves.toMatchObject({ + stdout: expect.stringContaining(`Network access disabled by the environment`), + exitCode: 1, + }); + }); + } finally { + delete process.env.PMM_ENABLE_NETWORK; + } +}); + +it(`should support hydrating package managers from cached archives`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ + exitCode: 0, + }); + + // Use a new cache + process.env.PMM_HOME = await xfs.mktempPromise(); + + // Disable the network to make sure we don't succeed by accident + process.env.PMM_ENABLE_NETWORK = `0`; + + try { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`hydrate`, `pmm-yarn-2.2.2.tgz`])).resolves.toMatchObject({ + stdout: ``, + exitCode: 0, + }); + + await expect(runCli(cwd, [`yarn`, `yarn`, `--version`])).resolves.toMatchObject({ + stdout: `2.2.2\n`, + exitCode: 0, + }); + } finally { + delete process.env.PMM_ENABLE_NETWORK; + } + }); +});