too
Version:
Combine multiple processes' Stdout/Stderr/SIGINT to keep them all foreground
90 lines (89 loc) • 2.79 kB
JavaScript
import { getColorByIndex } from './colors.js';
import { Command } from './command.js';
import { DefaultLogger } from './logger.js';
export class SequentialExecutor {
state;
definition;
env;
logger;
steps = [];
constructor(state, definition = { steps: [] }, env = {}, logger = new DefaultLogger()) {
this.state = state;
this.definition = definition;
this.env = env;
this.logger = logger;
for (let i = 0; i < definition.steps.length; i++) {
const step = definition.steps[i];
const cmd = new Command(step.run, env, getColorByIndex(i), logger, step.label);
this.steps.push(cmd);
}
}
async run() {
if (this.steps.length === 0)
return;
this.logger.stage(this.state);
for (const step of this.steps) {
step.env = { ...step.env, ...this.env };
await step.exec();
}
}
}
export class ParallelExecutor {
state;
definition;
env;
logger;
jobs = [];
procs = [];
constructor(state, definition, env = {}, logger = new DefaultLogger()) {
this.state = state;
this.definition = definition;
this.env = env;
this.logger = logger;
for (let i = 0; i < definition.jobs.length; i++) {
const job = definition.jobs[i];
const cmd = new Command(job.run, env, getColorByIndex(i), logger, job.label);
this.jobs.push(cmd);
}
}
async run() {
this.logger.stage(this.state);
for (const job of this.jobs) {
job.env = { ...job.env, ...this.env };
this.procs.push(await job.start());
}
await this.wait();
}
async cleanup(signal) {
const promises = [];
this.procs.forEach((proc) => {
promises.push(new Promise((resolve) => {
try {
if (proc.pid)
process.kill(-proc.pid, signal);
}
catch (err) {
const error = err;
if (error.code === "ESRCH")
return resolve(true);
console.error(err.message);
resolve(false);
}
proc.on("close", () => resolve(true));
}));
});
return Promise.all(promises);
}
wait() {
return Promise.all(this.procs.map((proc) => {
return new Promise((resolve, reject) => {
proc.on("exit", (code, signal) => {
if (code !== 0)
reject({ code, signal });
else
resolve(code);
});
});
}));
}
}