"use strict";
// TODO: move to separate package. It is used in supi/lib/install.ts as well
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 lifecycle_1 = require("@pnpm/lifecycle");
const logger_1 = require("@pnpm/logger");
const read_package_json_1 = require("@pnpm/read-package-json");
const utils_1 = require("@pnpm/utils");
const graphSequencer = require("graph-sequencer");
const pLimit = require("p-limit");
const path = require("path");
const R = require("ramda");
const constants_1 = require("./constants");
exports.default = (depGraph, rootDepPaths, opts) => __awaiter(this, void 0, void 0, function* () {
    // postinstall hooks
    const limitChild = pLimit(opts.childConcurrency || 4);
    const depPaths = Object.keys(depGraph);
    const nodesToBuild = new Set();
    getSubgraphToBuild(depGraph, rootDepPaths, nodesToBuild, new Set());
    const onlyFromBuildGraph = R.filter((depPath) => nodesToBuild.has(depPath));
    const nodesToBuildArray = Array.from(nodesToBuild);
    const graph = new Map(nodesToBuildArray
        .map((depPath) => [depPath, onlyFromBuildGraph(R.values(depGraph[depPath].children))]));
    const graphSequencerResult = graphSequencer({
        graph,
        groups: [nodesToBuildArray],
    });
    const chunks = graphSequencerResult.chunks;
    for (const chunk of chunks) {
        yield Promise.all(chunk
            .filter((depPath) => depGraph[depPath].requiresBuild && !depGraph[depPath].isBuilt)
            .map((depPath) => limitChild(() => __awaiter(this, void 0, void 0, function* () {
            const depNode = depGraph[depPath];
            try {
                const hasSideEffects = yield lifecycle_1.runPostinstallHooks({
                    depPath,
                    pkgRoot: depNode.peripheralLocation,
                    prepare: depNode.prepare,
                    rawNpmConfig: opts.rawNpmConfig,
                    rootNodeModulesDir: opts.nodeModulesDir,
                    unsafePerm: opts.unsafePerm || false,
                });
                if (hasSideEffects && opts.sideEffectsCache && !opts.sideEffectsCacheReadonly) {
                    try {
                        yield opts.storeController.upload(depNode.peripheralLocation, {
                            engine: constants_1.ENGINE_NAME,
                            pkgId: depNode.pkgId,
                        });
                    }
                    catch (err) {
                        if (err && err.statusCode === 403) {
                            logger_1.default.warn({
                                message: `The store server disabled upload requests, could not upload ${depNode.pkgId}`,
                                prefix: opts.prefix,
                            });
                        }
                        else {
                            logger_1.default.warn({
                                error: err,
                                message: `An error occurred while uploading ${depNode.pkgId}`,
                                prefix: opts.prefix,
                            });
                        }
                    }
                }
            }
            catch (err) {
                if (depNode.optional) {
                    // TODO: add parents field to the log
                    const pkg = yield read_package_json_1.fromDir(path.join(depNode.peripheralLocation));
                    utils_1.skippedOptionalDependencyLogger.debug({
                        details: err.toString(),
                        package: {
                            id: depNode.pkgId,
                            name: pkg.name,
                            version: pkg.version,
                        },
                        prefix: opts.prefix,
                        reason: 'build_failure',
                    });
                    return;
                }
                throw err;
            }
        }))));
    }
});
function getSubgraphToBuild(graph, entryNodes, nodesToBuild, walked) {
    let currentShouldBeBuilt = false;
    for (const depPath of entryNodes) {
        if (!graph[depPath])
            return; // packages that are already in node_modules are skipped
        if (nodesToBuild.has(depPath)) {
            currentShouldBeBuilt = true;
        }
        if (walked.has(depPath))
            continue;
        walked.add(depPath);
        const childShouldBeBuilt = getSubgraphToBuild(graph, R.values(graph[depPath].children), nodesToBuild, walked)
            || graph[depPath].requiresBuild;
        if (childShouldBeBuilt) {
            nodesToBuild.add(depPath);
            currentShouldBeBuilt = true;
        }
    }
    return currentShouldBeBuilt;
}
//# sourceMappingURL=runDependenciesScripts.js.map