"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.batchRunnerPath = void 0;
exports.default = gradleBatch;
exports.getGradlewTasksToRun = getGradlewTasksToRun;
const devkit_1 = require("@nx/devkit");
const run_commands_impl_1 = require("nx/src/executors/run-commands/run-commands.impl");
const exec_gradle_1 = require("../../utils/exec-gradle");
const path_1 = require("path");
const child_process_1 = require("child_process");
const pseudo_terminal_1 = require("nx/src/tasks-runner/pseudo-terminal");
const get_exclude_task_1 = require("./get-exclude-task");
exports.batchRunnerPath = (0, path_1.join)(__dirname, '../../../batch-runner/build/libs/batch-runner-all.jar');
async function gradleBatch(taskGraph, inputs, overrides, context) {
    try {
        const projectName = taskGraph.tasks[taskGraph.roots[0]]?.target?.project;
        let projectRoot = context.projectGraph.nodes[projectName]?.data?.root ?? '';
        const customGradleExecutableDirectory = (0, exec_gradle_1.getCustomGradleExecutableDirectoryFromPlugin)(context.nxJsonConfiguration);
        let gradlewPath = (0, exec_gradle_1.findGradlewFile)((0, path_1.join)(projectRoot, 'project.json'), devkit_1.workspaceRoot, customGradleExecutableDirectory); // find gradlew near project root
        gradlewPath = (0, path_1.join)(context.root, gradlewPath);
        const root = (0, path_1.dirname)(gradlewPath);
        // set args with passed in args and overrides in command line
        const input = inputs[taskGraph.roots[0]];
        let args = typeof input.args === 'string'
            ? input.args.trim().split(' ')
            : Array.isArray(input.args)
                ? input.args
                : [];
        if (overrides.__overrides_unparsed__.length) {
            args.push(...overrides.__overrides_unparsed__);
        }
        const taskIds = Object.keys(taskGraph.tasks);
        const { gradlewTasksToRun, excludeTasks, excludeTestTasks } = getGradlewTasksToRun(taskIds, taskGraph, inputs, context.projectGraph.nodes);
        const batchResults = await runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root);
        taskIds.forEach((taskId) => {
            if (!batchResults[taskId]) {
                batchResults[taskId] = {
                    success: false,
                    terminalOutput: `Gradlew batch failed`,
                };
            }
        });
        return batchResults;
    }
    catch (e) {
        devkit_1.output.error({
            title: `Gradlew batch failed`,
            bodyLines: [e.toString()],
        });
        return taskGraph.roots.reduce((acc, key) => {
            acc[key] = { success: false, terminalOutput: e.toString() };
            return acc;
        }, {});
    }
}
/**
 * Get the gradlew task ids to run
 */
function getGradlewTasksToRun(taskIds, taskGraph, inputs, nodes) {
    const taskIdsWithExclude = new Set([]);
    const testTaskIdsWithExclude = new Set([]);
    const taskIdsWithoutExclude = new Set([]);
    const gradlewTasksToRun = {};
    const includeDependsOnTasks = new Set();
    for (const taskId of taskIds) {
        const task = taskGraph.tasks[taskId];
        const input = inputs[task.id];
        gradlewTasksToRun[taskId] = input;
        // Collect tasks that should be included (not excluded) - typically provider-based dependencies
        if (input.includeDependsOnTasks) {
            for (const task of input.includeDependsOnTasks) {
                includeDependsOnTasks.add(task);
            }
        }
        if (input.excludeDependsOn) {
            if (input.testClassName) {
                testTaskIdsWithExclude.add(taskId);
            }
            else {
                taskIdsWithExclude.add(taskId);
            }
        }
        else {
            taskIdsWithoutExclude.add(taskId);
        }
    }
    const allDependsOn = new Set(taskIds);
    for (const taskId of taskIdsWithoutExclude) {
        const [projectName, targetName] = taskId.split(':');
        const dependencies = (0, get_exclude_task_1.getAllDependsOn)(nodes, projectName, targetName);
        dependencies.forEach((dep) => allDependsOn.add(dep));
    }
    const excludeTasks = (0, get_exclude_task_1.getExcludeTasks)(taskIdsWithExclude, nodes, allDependsOn, includeDependsOnTasks);
    const allTestsDependsOn = new Set();
    for (const taskId of testTaskIdsWithExclude) {
        const [projectName, targetName] = taskId.split(':');
        const taskDependsOn = (0, get_exclude_task_1.getAllDependsOn)(nodes, projectName, targetName);
        taskDependsOn.forEach((dep) => allTestsDependsOn.add(dep));
    }
    const excludeTestTasks = new Set();
    for (let taskId of allTestsDependsOn) {
        const gradleTaskName = (0, get_exclude_task_1.getGradleTaskNameWithNxTaskId)(taskId, nodes);
        if (gradleTaskName) {
            excludeTestTasks.add(gradleTaskName);
        }
    }
    return {
        gradlewTasksToRun,
        excludeTasks,
        excludeTestTasks,
    };
}
async function runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root) {
    const gradlewBatchStart = performance.mark(`gradlew-batch:start`);
    const usePseudoTerminal = process.env.NX_NATIVE_COMMAND_RUNNER !== 'false' &&
        pseudo_terminal_1.PseudoTerminal.isSupported();
    const debugOptions = ' ' + (process.env.NX_GRADLE_BATCH_DEBUG ?? '');
    const command = `java${debugOptions} -jar ${exports.batchRunnerPath} --tasks='${JSON.stringify(gradlewTasksToRun)}' --workspaceRoot=${root} --args='${args
        .join(' ')
        .replaceAll("'", '"')}' --excludeTasks='${Array.from(excludeTasks).join(',')}' --excludeTestTasks='${Array.from(excludeTestTasks).join(',')}' ${process.env.NX_VERBOSE_LOGGING === 'true' ? '' : '--quiet'}`;
    let batchResults;
    if (usePseudoTerminal && process.env.NX_VERBOSE_LOGGING !== 'true') {
        const terminal = (0, pseudo_terminal_1.createPseudoTerminal)();
        await terminal.init();
        const cp = terminal.runCommand(command, {
            cwd: devkit_1.workspaceRoot,
            jsEnv: process.env,
            quiet: true,
        });
        const results = await cp.getResults();
        terminal.shutdown(0);
        batchResults = results.terminalOutput;
        batchResults = batchResults.replace(command, '');
        const startIndex = batchResults.indexOf('{');
        const endIndex = batchResults.lastIndexOf('}');
        // only keep the json part
        batchResults = batchResults.substring(startIndex, endIndex + 1);
    }
    else {
        batchResults = (0, child_process_1.execSync)(command, {
            cwd: devkit_1.workspaceRoot,
            windowsHide: true,
            env: process.env,
            maxBuffer: run_commands_impl_1.LARGE_BUFFER,
        }).toString();
    }
    const gradlewBatchEnd = performance.mark(`gradlew-batch:end`);
    performance.measure(`gradlew-batch`, gradlewBatchStart.name, gradlewBatchEnd.name);
    const gradlewBatchResults = JSON.parse(batchResults);
    return gradlewBatchResults;
}
