"use strict";
// TODO: move to separate package. It is used in supi/lib/install.ts as well
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("@pnpm/constants");
const core_loggers_1 = require("@pnpm/core-loggers");
const lifecycle_1 = require("@pnpm/lifecycle");
const logger_1 = require("@pnpm/logger");
const read_package_json_1 = require("@pnpm/read-package-json");
const graphSequencer = require("graph-sequencer");
const path = require("path");
const R = require("ramda");
const run_groups_1 = require("run-groups");
exports.default = async (depGraph, rootDepPaths, opts) => {
    // postinstall hooks
    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;
    const groups = chunks.map((chunk) => chunk.filter((depPath) => depGraph[depPath].requiresBuild && !depGraph[depPath].isBuilt).map((depPath) => async () => {
        const depNode = depGraph[depPath];
        try {
            const hasSideEffects = await lifecycle_1.runPostinstallHooks({
                depPath,
                optional: depNode.optional,
                pkgRoot: depNode.peripheralLocation,
                prepare: depNode.prepare,
                rawNpmConfig: opts.rawNpmConfig,
                rootNodeModulesDir: opts.rootNodeModulesDir,
                unsafePerm: opts.unsafePerm || false,
            });
            if (hasSideEffects && opts.sideEffectsCacheWrite) {
                try {
                    await opts.storeController.upload(depNode.peripheralLocation, {
                        engine: constants_1.ENGINE_NAME,
                        packageId: 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 = await read_package_json_1.fromDir(path.join(depNode.peripheralLocation));
                core_loggers_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;
        }
    }));
    await run_groups_1.default(opts.childConcurrency || 4, groups);
};
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