Skip to content

Instantly share code, notes, and snippets.

@andreyctkn
Created January 29, 2019 05:30
Show Gist options
  • Save andreyctkn/d25b63229fde7c8d1adb7e8fdc805d32 to your computer and use it in GitHub Desktop.
Save andreyctkn/d25b63229fde7c8d1adb7e8fdc805d32 to your computer and use it in GitHub Desktop.
NodeShellExecutor
const { watch } = require("chokidar");
const { spawn } = require("child_process");
const { NodeShellExecutor } = require("./shell-executor");
const { OUTPUTS, INPUTS, DIRS } = require("./constants");
const waitForTsBuild = () => {
return new Promise((resolve) => {
const watcher = watch(INPUTS.jsDev).once("add", (path) => {
console.log("waitForTsBuild");
watcher.close();
resolve();
});
});
};
new NodeShellExecutor()
.addExecCommand({ command: `rm -rf ${DIRS.tmp} && mkdir -p ${DIRS.tmp}` })
.addSpawnCommand({ command: "tsc -p config/tsconfig.dev.json --watch", runNextAfter: waitForTsBuild })
.addSpawnCommand({ command: "webpack --config scripts/webpack/webpack.config.js --watch" })
.start();
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 };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment