"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Map SIGINT & SIGTERM to process exit
// so that lockfiles are removed automatically
process
    .once('SIGINT', () => process.exit(0))
    .once('SIGTERM', () => process.exit(0));
// Patch the global fs module here at the app level
const chalk = require("chalk");
const fs = require("fs");
const gfs = require("graceful-fs");
gfs.gracefulify(fs);
const loud_rejection_1 = require("loud-rejection");
loud_rejection_1.default();
const cli_utils_1 = require("@pnpm/cli-utils");
const core_loggers_1 = require("@pnpm/core-loggers");
const filter_workspace_packages_1 = require("@pnpm/filter-workspace-packages");
const find_workspace_packages_1 = require("@pnpm/find-workspace-packages");
const logger_1 = require("@pnpm/logger");
const isCI = require("is-ci");
const R = require("ramda");
const checkForUpdates_1 = require("./checkForUpdates");
const cmd_1 = require("./cmd");
require("./logging/fileLogger");
const parseCliArgs_1 = require("./parseCliArgs");
const reporter_1 = require("./reporter");
async function run(inputArgv) {
    var _a;
    const { argv, cliArgs, cliConf, cmd, subCmd, isKnownCommand, unknownOptions, workspaceDir } = await parseCliArgs_1.default(inputArgv);
    if (!isKnownCommand && cmd !== null) {
        console.error(`${chalk.bgRed.black('\u2009ERROR\u2009')} ${chalk.red(`Unknown command '${cmd}'`)}`);
        console.log(`For help, run: pnpm help`);
        process.exit(1);
    }
    if (unknownOptions.length > 0) {
        let errorMsg = `${chalk.bgRed.black('\u2009ERROR\u2009')}`;
        if (unknownOptions.length === 1) {
            errorMsg += ` ${chalk.red(`Unknown option '${unknownOptions[0]}'`)}`;
        }
        else {
            errorMsg += ` ${chalk.red(`Unknown options ${unknownOptions.map(unknownOption => `'${unknownOption}'`).join(', ')}`)}`;
        }
        console.error(errorMsg);
        console.log(`For help, run: pnpm help${cmd ? ` ${cmd}` : ''}`);
        process.exit(1);
    }
    process.env['npm_config_argv'] = JSON.stringify(argv);
    let config;
    try {
        config = await cli_utils_1.getConfig(cliConf, {
            excludeReporter: false,
            rcOptionsTypes: cmd_1.getRCOptionsTypes(cmd),
            workspaceDir,
        });
        config.forceSharedLockfile = typeof config.workspaceDir === 'string' && config.sharedWorkspaceLockfile === true;
        config.argv = argv;
    }
    catch (err) {
        // Reporting is not initialized at this point, so just printing the error
        console.error(`${chalk.bgRed.black('\u2009ERROR\u2009')} ${chalk.red(err.message)}`);
        console.log(`For help, run: pnpm help${cmd ? ` ${cmd}` : ''}`);
        process.exit(1);
        return;
    }
    // chalk reads the FORCE_COLOR env variable
    if (config.color === 'always') {
        process.env['FORCE_COLOR'] = '1';
    }
    else if (config.color === 'never') {
        process.env['FORCE_COLOR'] = '0';
    }
    if (config.useBetaCli && cmd === 'remove' && config.argv.remain[0] === 'r') {
        // Reporting is not initialized at this point, so just printing the error
        console.error(`${chalk.bgRed.black('\u2009ERROR\u2009')} ${chalk.red("The 'r' alias for 'pnpm remove' is deprecated.")}`);
        console.log(`For help, run: pnpm help ${cmd}`);
        process.exit(1);
        return;
    }
    const selfUpdate = config.global && (cmd === 'add' || cmd === 'update') && argv.remain.includes(cli_utils_1.packageManager.name);
    // Don't check for updates
    //   1. on CI environments
    //   2. when in the middle of an actual update
    if (!isCI && !selfUpdate) {
        checkForUpdates_1.default();
    }
    const reporterType = (() => {
        if (config.loglevel === 'silent')
            return 'silent';
        if (config.reporter)
            return config.reporter;
        if (isCI || !process.stdout.isTTY)
            return 'append-only';
        return 'default';
    })();
    reporter_1.default(reporterType, {
        cmd,
        config,
        subCmd,
    });
    global['reporterInitialized'] = true;
    delete config.reporter; // This is a silly workaround because supi expects a function as config.reporter
    if (selfUpdate) {
        await cmd_1.default.server(['stop'], config); // tslint:disable-line:no-any
    }
    if (cliConf['recursive']) {
        const wsDir = workspaceDir !== null && workspaceDir !== void 0 ? workspaceDir : process.cwd();
        const allProjects = await find_workspace_packages_1.default(wsDir, config);
        if (!allProjects.length) {
            if (!config['parseable']) {
                console.log(`No projects found in "${wsDir}"`);
            }
            process.exit(0);
            return;
        }
        const filterResults = await filter_workspace_packages_1.filterPackages(allProjects, (_a = config.filter) !== null && _a !== void 0 ? _a : [], {
            prefix: process.cwd(),
            workspaceDir: wsDir,
        });
        config.selectedProjectsGraph = filterResults.selectedProjectsGraph;
        if (R.isEmpty(config.selectedProjectsGraph)) {
            if (!config['parseable']) {
                console.log(`No projects matched the filters in "${wsDir}"`);
            }
            process.exit(0);
            return;
        }
        if (filterResults.unmatchedFilters.length !== 0 && !config['parseable']) {
            console.log(`No projects matched the filters "${filterResults.unmatchedFilters.join(', ')}" in "${wsDir}"`);
        }
        config.allProjects = allProjects;
        config.workspaceDir = wsDir;
    }
    // NOTE: we defer the next stage, otherwise reporter might not catch all the logs
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            if (config.force === true) {
                logger_1.default.warn({
                    message: 'using --force I sure hope you know what you are doing',
                    prefix: config.dir,
                });
            }
            core_loggers_1.scopeLogger.debug({
                ...(!cliConf['recursive']
                    ? { selected: 1 }
                    : {
                        selected: Object.keys(config.selectedProjectsGraph).length,
                        total: config.allProjects.length,
                    }),
                ...(workspaceDir ? { workspacePrefix: workspaceDir } : {}),
            });
            try {
                const result = cmd_1.default[cmd || 'help'](cliArgs, 
                // TypeScript doesn't currently infer that the type of config
                // is `Omit<typeof config, 'reporter'>` after the `delete config.reporter` statement
                config);
                if (result instanceof Promise) {
                    result
                        .then((output) => {
                        if (typeof output === 'string') {
                            process.stdout.write(output);
                        }
                        resolve();
                    })
                        .catch(reject);
                }
                else {
                    if (typeof result === 'string') {
                        process.stdout.write(result);
                    }
                    resolve();
                }
            }
            catch (err) {
                reject(err);
            }
        }, 0);
    });
    if (!cmd) {
        process.exit(1);
    }
}
exports.default = run;
