const { execSync, spawn } = require("child_process"); class NodeShellExecutor { constructor() { this.shellCommands = []; this.childProcesses = []; process.on("SIGINT", () => this.onExit()); } onExit() { console.log("\nGracefully shutting down from SIGINT (Ctrl+C)"); this.childProcesses.forEach((childProc) => { childProc.kill(); }); process.exit(); } /** * @callback RunNextAfter * @returns {Promise} */ /** * @param {Object} args - The employee who is responsible for the project. * @param {string} args.command - The name of the employee. * @param {(function: Promise)} [args.runNextAfter] - The employee's department. * @returns {NodeShellExecutor} */ addExecCommand(args) { this.shellCommands.push({ type: "exec", ...args }); return this; } /** * @param {Object} args - The employee who is responsible for the project. * @param {string} args.command - The name of the employee. * @param {(function: Promise)} [args.runNextAfter] - The employee's department. * @returns {NodeShellExecutor} */ addSpawnCommand(args) { this.shellCommands.push({ type: "spawn", ...args }); return this; } start() { this.recursiveExecuteTasks(); } recursiveExecuteTasks() { const shellCommand = this.shellCommands.shift(); if (!shellCommand) { return; } const { runNextAfter = () => Promise.resolve(), ...args } = shellCommand; Promise.all([runNextAfter(), this.executeShellCommand(args)]) .then(() => this.recursiveExecuteTasks()) .catch(() => this.onExit()); } /** * Returns the average of two numbers. * @returns {Promise} Promise object represents the sum of a and b */ executeShellCommand({ type, command: commandWithParams }) { switch (type) { case "exec": return this.executeExecCommand(commandWithParams); case "spawn": return this.executeSpawnCommand(commandWithParams); } } /* * @returns {Promise} */ executeSpawnCommand(commandWithParams) { console.log(commandWithParams); const [command, ...params] = commandWithParams.split(" "); const childProcess = spawn(command, params, { stdio: "inherit", shell: true, }); this.childProcesses.push(childProcess); return Promise.resolve(); } /* * @returns {Promise} */ executeExecCommand(commandWithParams) { console.log(commandWithParams); try { execSync(commandWithParams, { stdio: "inherit", shell: true }); } catch (error) { return Promise.reject(error); } return Promise.resolve(); } } module.exports = { NodeShellExecutor };