"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const logger_1 = require("@pnpm/logger");
const find_packages_1 = require("find-packages");
const graphSequencer = require("graph-sequencer");
const pLimit = require("p-limit");
const pkgs_graph_1 = require("pkgs-graph");
const supi_1 = require("supi");
const createStoreController_1 = require("../createStoreController");
const requireHooks_1 = require("../requireHooks");
exports.default = (input, opts) => __awaiter(this, void 0, void 0, function* () {
    let concurrency = 4;
    if (!isNaN(parseInt(input[0], 10))) {
        concurrency = parseInt(input.shift(), 10);
    }
    if (concurrency < 1) {
        throw new Error('Concurrency should be at least 1');
    }
    const cmd = input.shift();
    if (cmd && ['install', 'i', 'update', 'up', 'upgrade'].indexOf(cmd) === -1) {
        throw new Error('Unsupported recursive command');
    }
    logger_1.default.warn('The recursive command is an experimental feature. Breaking changes may happen in non-major versions.');
    if (cmd === 'update' || cmd === 'up' || cmd === 'upgrade') {
        opts = Object.assign({}, opts, { update: true });
    }
    const pkgs = yield find_packages_1.default(process.cwd(), {
        ignore: [
            '**/node_modules/**',
            '**/bower_components/**',
        ],
    });
    const pkgGraphResult = pkgs_graph_1.default(pkgs);
    const graph = new Map(Object.keys(pkgGraphResult.graph).map((pkgPath) => [pkgPath, pkgGraphResult.graph[pkgPath].dependencies]));
    const graphSequencerResult = graphSequencer({
        graph,
        groups: [Object.keys(pkgGraphResult.graph)],
    });
    const chunks = graphSequencerResult.chunks;
    const store = yield createStoreController_1.default(opts);
    // It is enough to save the store.json file once,
    // once all installations are done.
    // That's why saveState that is passed to the install engine
    // does nothing.
    const saveState = store.ctrl.saveState;
    const storeController = Object.assign({}, store.ctrl, { saveState: () => __awaiter(this, void 0, void 0, function* () { return undefined; }) });
    const installOpts = Object.assign(opts, {
        store: store.path,
        storeController,
    });
    const limitInstallation = pLimit(concurrency);
    for (const chunk of chunks) {
        yield chunk.map((prefix) => limitInstallation(() => {
            const hooks = opts.ignorePnpmfile ? {} : requireHooks_1.default(prefix);
            return supi_1.install(Object.assign({}, installOpts, { hooks, storeController, prefix }));
        }));
    }
    yield saveState();
});
//# sourceMappingURL=recursive.js.map