"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const error_1 = require("@pnpm/error");
const utils_1 = require("@pnpm/utils");
const supi_1 = require("supi");
const createStoreController_1 = require("../createStoreController");
const findWorkspacePackages_1 = require("../findWorkspacePackages");
const getPinnedVersion_1 = require("../getPinnedVersion");
const readImporterManifest_1 = require("../readImporterManifest");
const requireHooks_1 = require("../requireHooks");
const updateToLatestSpecsFromManifest_1 = require("../updateToLatestSpecsFromManifest");
const recursive_1 = require("./recursive");
const OVERWRITE_UPDATE_OPTIONS = {
    allowNew: true,
    update: false,
};
/**
 * Perform installation.
 * @example
 *     installCmd([ 'lodash', 'foo' ], { silent: true })
 */
async function installCmd(input, opts, invocation) {
    // `pnpm install ""` is going to be just `pnpm install`
    input = input.filter(Boolean);
    const prefix = opts.prefix || process.cwd();
    const localPackages = opts.linkWorkspacePackages && opts.workspacePrefix
        ? findWorkspacePackages_1.arrayOfLocalPackagesToMap(await findWorkspacePackages_1.default(opts.workspacePrefix, opts))
        : undefined;
    if (!opts.ignorePnpmfile) {
        opts.hooks = requireHooks_1.default(opts.lockfileDirectory || prefix, opts);
    }
    const store = await createStoreController_1.default(opts);
    const installOpts = Object.assign(Object.assign({}, opts), { 
        // In case installation is done in a multi-package repository
        // The dependencies should be built first,
        // so ignoring scripts for now
        ignoreScripts: !!localPackages || opts.ignoreScripts, localPackages, store: store.path, storeController: store.ctrl, forceHoistPattern: typeof opts.localConfig['hoist-pattern'] !== 'undefined' || typeof opts.localConfig['hoist'] !== 'undefined', forceIndependentLeaves: typeof opts.localConfig['independent-leaves'] !== 'undefined', forceShamefullyHoist: typeof opts.localConfig['shamefully-hoist'] !== 'undefined' });
    let { manifest, writeImporterManifest } = await readImporterManifest_1.tryReadImporterManifest(opts.prefix, opts);
    if (manifest === null) {
        if (opts.update) {
            throw new error_1.default('NO_IMPORTER_MANIFEST', 'No package.json found');
        }
        manifest = {};
    }
    if (opts.update && opts.latest) {
        if (!input || !input.length) {
            input = updateToLatestSpecsFromManifest_1.default(manifest, opts.include);
        }
        else {
            input = updateToLatestSpecsFromManifest_1.createLatestSpecs(input, manifest);
        }
        delete installOpts.include;
    }
    if (!input || !input.length) {
        if (invocation === 'add') {
            throw new error_1.default('MISSING_PACKAGE_NAME', '`pnpm add` requires the package name');
        }
        await supi_1.install(manifest, installOpts);
    }
    else {
        const [updatedImporter] = await supi_1.mutateModules([
            {
                allowNew: opts.allowNew,
                bin: installOpts.bin,
                dependencySelectors: input,
                manifest,
                mutation: 'installSome',
                peer: opts.savePeer,
                pinnedVersion: getPinnedVersion_1.default(opts),
                prefix: installOpts.prefix,
                targetDependenciesField: utils_1.getSaveType(installOpts),
            },
        ], installOpts);
        await writeImporterManifest(updatedImporter.manifest);
    }
    if (opts.linkWorkspacePackages && opts.workspacePrefix) {
        // TODO: reuse somehow the previous read of packages
        // this is not optimal
        const allWorkspacePkgs = await findWorkspacePackages_1.default(opts.workspacePrefix, opts);
        await recursive_1.recursive(allWorkspacePkgs, [], Object.assign(Object.assign(Object.assign({}, opts), OVERWRITE_UPDATE_OPTIONS), { ignoredPackages: new Set([prefix]), packageSelectors: [
                {
                    pattern: prefix,
                    scope: 'dependencies',
                    selectBy: 'location',
                },
            ] }), 'install', 'install');
        if (opts.ignoreScripts)
            return;
        await supi_1.rebuild([
            {
                buildIndex: 0,
                manifest: await readImporterManifest_1.readImporterManifestOnly(opts.prefix, opts),
                prefix: opts.prefix,
            },
        ], Object.assign(Object.assign({}, opts), { pending: true, store: store.path, storeController: store.ctrl }));
    }
}
exports.default = installCmd;
