import {Command, UsageError} from 'clipanion'; import path from 'path'; import tar from 'tar'; import * as folderUtils from '../folderUtils'; import {Context} from '../main'; import {SupportedPackageManagerSet, SupportedPackageManagers} from '../types'; export class HydrateCommand extends Command { static usage = Command.Usage({ description: `Import a package manager into the cache`, details: ` This command unpacks a package manager archive into the cache. The archive must have been generated by the \`corepack pack\` command - no other will work. `, examples: [[ `Import a package manager in the cache`, `$0 hydrate corepack-yarn-2.2.2.tgz`, ]], }); @Command.String() fileName!: string; @Command.Boolean(`--activate`) activate: boolean = false; @Command.Path(`hydrate`) async execute() { const installFolder = folderUtils.getInstallFolder(); const fileName = path.resolve(this.context.cwd, this.fileName); const firstLevel = new Set(); const secondLevel = new Set(); let hasShortEntries = false; await tar.t({file: fileName, onentry: entry => { const segments = entry.header.path.split(/\//g); if (segments.length < 3) { hasShortEntries = true; } else { firstLevel.add(segments[0]); secondLevel.add(segments[1]); } }}); if (hasShortEntries || firstLevel.size !== 1 || secondLevel.size !== 1) throw new UsageError(`Invalid archive format; did it get generated by 'corepack prepare'?`); const name = [...firstLevel][0] as SupportedPackageManagers; const reference = [...secondLevel][0] as string; if (!SupportedPackageManagerSet.has(name)) throw new UsageError(`Unsupported package manager '${name}'`); await tar.x({file: fileName, cwd: installFolder}); if (this.activate) await this.context.engine.activatePackageManager({name, reference}); this.context.stdout.write(`Hydrated ${name}@${reference}\n`); } }