File: /var/www/web.enelar.com.co/node_modules/nx/src/tasks-runner/forked-process-task-runner.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ForkedProcessTaskRunner = void 0;
const fs_1 = require("fs");
const child_process_1 = require("child_process");
const chalk = require("chalk");
const logTransformer = require("strong-log-transformer");
const output_1 = require("../utils/output");
const utils_1 = require("./utils");
const path_1 = require("path");
const batch_messages_1 = require("./batch/batch-messages");
const strip_indents_1 = require("../utils/strip-indents");
const stream_1 = require("stream");
const workerPath = (0, path_1.join)(__dirname, './batch/run-batch.js');
class ForkedProcessTaskRunner {
constructor(options) {
this.options = options;
this.cliPath = (0, utils_1.getCliPath)();
this.verbose = process.env.NX_VERBOSE_LOGGING === 'true';
this.processes = new Set();
this.setupProcessEventListeners();
}
// TODO: vsavkin delegate terminal output printing
forkProcessForBatch({ executorName, taskGraph: batchTaskGraph }, fullTaskGraph, env) {
return new Promise((res, rej) => {
try {
const count = Object.keys(batchTaskGraph.tasks).length;
if (count > 1) {
output_1.output.logSingleLine(`Running ${output_1.output.bold(count)} ${output_1.output.bold('tasks')} with ${output_1.output.bold(executorName)}`);
}
else {
const args = (0, utils_1.getPrintableCommandArgsForTask)(Object.values(batchTaskGraph.tasks)[0]);
output_1.output.logCommand(args.join(' '));
output_1.output.addNewline();
}
const p = (0, child_process_1.fork)(workerPath, {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
env,
});
this.processes.add(p);
p.once('exit', (code, signal) => {
this.processes.delete(p);
if (code === null)
code = this.signalToCode(signal);
if (code !== 0) {
const results = {};
for (const rootTaskId of batchTaskGraph.roots) {
results[rootTaskId] = {
success: false,
terminalOutput: '',
};
}
rej(new Error(`"${executorName}" exited unexpectedly with code: ${code}`));
}
});
p.on('message', (message) => {
switch (message.type) {
case batch_messages_1.BatchMessageType.CompleteBatchExecution: {
res(message.results);
break;
}
case batch_messages_1.BatchMessageType.RunTasks: {
break;
}
default: {
// Re-emit any non-batch messages from the task process
if (process.send) {
process.send(message);
}
}
}
});
// Start the tasks
p.send({
type: batch_messages_1.BatchMessageType.RunTasks,
executorName,
batchTaskGraph,
fullTaskGraph,
});
}
catch (e) {
rej(e);
}
});
}
forkProcessPipeOutputCapture(task, { streamOutput, temporaryOutputPath, taskGraph, env, }) {
return new Promise((res, rej) => {
try {
const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
if (streamOutput) {
output_1.output.logCommand(args.join(' '));
output_1.output.addNewline();
}
const p = (0, child_process_1.fork)(this.cliPath, {
stdio: ['inherit', 'pipe', 'pipe', 'ipc'],
env,
});
this.processes.add(p);
// Re-emit any messages from the task process
p.on('message', (message) => {
if (process.send) {
process.send(message);
}
});
// Send message to run the executor
p.send({
targetDescription: task.target,
overrides: task.overrides,
taskGraph,
isVerbose: this.verbose,
});
if (streamOutput) {
if (process.env.NX_PREFIX_OUTPUT === 'true') {
const color = getColor(task.target.project);
const prefixText = `${task.target.project}:`;
p.stdout
.pipe(logClearLineToPrefixTransformer(color.bold(prefixText) + ' '))
.pipe(logTransformer({ tag: color.bold(prefixText) }))
.pipe(process.stdout);
p.stderr
.pipe(logClearLineToPrefixTransformer(color(prefixText) + ' '))
.pipe(logTransformer({ tag: color(prefixText) }))
.pipe(process.stderr);
}
else {
p.stdout.pipe(logTransformer()).pipe(process.stdout);
p.stderr.pipe(logTransformer()).pipe(process.stderr);
}
}
let outWithErr = [];
p.stdout.on('data', (chunk) => {
outWithErr.push(chunk.toString());
});
p.stderr.on('data', (chunk) => {
outWithErr.push(chunk.toString());
});
p.on('exit', (code, signal) => {
this.processes.delete(p);
if (code === null)
code = this.signalToCode(signal);
// we didn't print any output as we were running the command
// print all the collected output|
const terminalOutput = outWithErr.join('');
if (!streamOutput) {
this.options.lifeCycle.printTaskTerminalOutput(task, code === 0 ? 'success' : 'failure', terminalOutput);
}
this.writeTerminalOutput(temporaryOutputPath, terminalOutput);
res({ code, terminalOutput });
});
}
catch (e) {
console.error(e);
rej(e);
}
});
}
forkProcessDirectOutputCapture(task, { streamOutput, temporaryOutputPath, taskGraph, env, }) {
return new Promise((res, rej) => {
try {
const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
if (streamOutput) {
output_1.output.logCommand(args.join(' '));
output_1.output.addNewline();
}
const p = (0, child_process_1.fork)(this.cliPath, {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
env,
});
this.processes.add(p);
// Re-emit any messages from the task process
p.on('message', (message) => {
if (process.send) {
process.send(message);
}
});
// Send message to run the executor
p.send({
targetDescription: task.target,
overrides: task.overrides,
taskGraph,
isVerbose: this.verbose,
});
p.on('exit', (code, signal) => {
if (code === null)
code = this.signalToCode(signal);
// we didn't print any output as we were running the command
// print all the collected output
let terminalOutput = '';
try {
terminalOutput = this.readTerminalOutput(temporaryOutputPath);
if (!streamOutput) {
this.options.lifeCycle.printTaskTerminalOutput(task, code === 0 ? 'success' : 'failure', terminalOutput);
}
}
catch (e) {
console.log((0, strip_indents_1.stripIndents) `
Unable to print terminal output for Task "${task.id}".
Task failed with Exit Code ${code} and Signal "${signal}".
Received error message:
${e.message}
`);
}
res({
code,
terminalOutput,
});
});
}
catch (e) {
console.error(e);
rej(e);
}
});
}
readTerminalOutput(outputPath) {
return (0, fs_1.readFileSync)(outputPath).toString();
}
writeTerminalOutput(outputPath, content) {
(0, fs_1.writeFileSync)(outputPath, content);
}
signalToCode(signal) {
if (signal === 'SIGHUP')
return 128 + 1;
if (signal === 'SIGINT')
return 128 + 2;
if (signal === 'SIGTERM')
return 128 + 15;
return 128;
}
setupProcessEventListeners() {
// When the nx process gets a message, it will be sent into the task's process
process.on('message', (message) => {
this.processes.forEach((p) => {
if (p.connected) {
p.send(message);
}
});
});
// Terminate any task processes on exit
process.on('exit', () => {
this.processes.forEach((p) => {
if (p.connected) {
p.kill();
}
});
});
process.on('SIGINT', () => {
this.processes.forEach((p) => {
if (p.connected) {
p.kill('SIGTERM');
}
});
// we exit here because we don't need to write anything to cache.
process.exit();
});
process.on('SIGTERM', () => {
this.processes.forEach((p) => {
if (p.connected) {
p.kill('SIGTERM');
}
});
// no exit here because we expect child processes to terminate which
// will store results to the cache and will terminate this process
});
process.on('SIGHUP', () => {
this.processes.forEach((p) => {
if (p.connected) {
p.kill('SIGTERM');
}
});
// no exit here because we expect child processes to terminate which
// will store results to the cache and will terminate this process
});
}
}
exports.ForkedProcessTaskRunner = ForkedProcessTaskRunner;
const colors = [
chalk.green,
chalk.greenBright,
chalk.red,
chalk.redBright,
chalk.cyan,
chalk.cyanBright,
chalk.yellow,
chalk.yellowBright,
chalk.magenta,
chalk.magentaBright,
];
function getColor(projectName) {
let code = 0;
for (let i = 0; i < projectName.length; ++i) {
code += projectName.charCodeAt(i);
}
const colorIndex = code % colors.length;
return colors[colorIndex];
}
/**
* Prevents terminal escape sequence from clearing line prefix.
*/
function logClearLineToPrefixTransformer(prefix) {
let prevChunk = null;
return new stream_1.Transform({
transform(chunk, _encoding, callback) {
if (prevChunk && prevChunk.toString() === '\x1b[2K') {
chunk = chunk.toString().replace(/\x1b\[1G/g, (m) => m + prefix);
}
this.push(chunk);
prevChunk = chunk;
callback();
},
});
}