You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
2.8 KiB
JavaScript
114 lines
2.8 KiB
JavaScript
"use strict";
|
|
|
|
const Promise = require("bluebird");
|
|
const execa = require("execa");
|
|
const chalk = require("chalk");
|
|
|
|
const isExecaError = require("./is-execa-error");
|
|
|
|
// TODO: Eventually turn this into a generic restartableProcess abstraction?
|
|
|
|
module.exports = function createProcessManager(processPath, processArguments, { onOutput, onError, onStart }) {
|
|
let running = false;
|
|
let queuedRestart = false;
|
|
let currentProcess;
|
|
|
|
function reportEnded() {
|
|
currentProcess = null;
|
|
running = false;
|
|
|
|
if (queuedRestart === true) {
|
|
console.log(chalk.blue.bold(`Restarting process...`));
|
|
return startProcess();
|
|
}
|
|
}
|
|
|
|
function killProcess() {
|
|
if (currentProcess != null) {
|
|
currentProcess.cancel();
|
|
}
|
|
}
|
|
|
|
function startProcess() {
|
|
return Promise.try(() => {
|
|
if (!running) {
|
|
running = true;
|
|
onStart();
|
|
|
|
let process = execa("node", [ processPath, ... processArguments ]);
|
|
|
|
currentProcess = process;
|
|
return process;
|
|
} else {
|
|
throw new Error(`Tried to start already-running process; this is a bug and should never happen`);
|
|
}
|
|
}).then(({ stdout, stderr }) => {
|
|
console.error(stderr); // TODO: Think about whether to keep this
|
|
|
|
console.log(chalk.blue.bold(`Process exited normally; it will be restarted upon changes`));
|
|
|
|
try {
|
|
onOutput(JSON.parse(stdout));
|
|
} catch (error) {
|
|
if (error instanceof SyntaxError) {
|
|
// Show the original unparseable output, for debugging purposes
|
|
console.error(chalk.bold("Process output:\n"), stdout);
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
|
|
return reportEnded();
|
|
}).catch(isExecaError, (error) => {
|
|
let { stdout, stderr, exitCode, isCanceled } = error;
|
|
|
|
if (exitCode != null && exitCode !== 0) {
|
|
onError({
|
|
reason: `Process exited with exit code ${exitCode}`,
|
|
output: (error.stderr + error.stdout).trim()
|
|
});
|
|
|
|
console.error(stdout);
|
|
console.error(stderr);
|
|
console.log(chalk.red.bold(`Process exited with exit code ${exitCode}; it will be restarted upon changes`));
|
|
} else if (isCanceled === true) {
|
|
// Ignore
|
|
} else {
|
|
throw error;
|
|
}
|
|
|
|
return reportEnded();
|
|
}).catch(SyntaxError, (error) => {
|
|
onError({
|
|
reason: "Failed to parse process output",
|
|
output: error.stack
|
|
});
|
|
|
|
console.error(error.stack);
|
|
console.log(chalk.red.bold(`Failed to parse output of the process; it will be restarted upon changes`));
|
|
|
|
return reportEnded();
|
|
});
|
|
}
|
|
|
|
return {
|
|
kill: killProcess,
|
|
restart: function (reason) {
|
|
console.log(chalk.green.bold(`Change detected in ${reason}; running ${processPath}...`));
|
|
|
|
if (running === true) {
|
|
queuedRestart = true;
|
|
return this.kill();
|
|
} else {
|
|
return this.start();
|
|
}
|
|
},
|
|
start: function () {
|
|
if (!running) {
|
|
return startProcess();
|
|
}
|
|
// TODO: Make this a possible error condition, rather than silently ignored?
|
|
}
|
|
};
|
|
};
|