mirror of
https://github.com/SrIzan10/nodemon.git
synced 2026-05-01 10:55:09 +00:00
165 lines
4.8 KiB
JavaScript
165 lines
4.8 KiB
JavaScript
var utils = require('../utils'),
|
|
bus = utils.bus,
|
|
childProcess = require('child_process'),
|
|
spawn = childProcess.spawn,
|
|
exec = childProcess.exec,
|
|
watch = require('./watch'),
|
|
config = require('../config'),
|
|
child = null, // the actual child process we spawn
|
|
killedAfterChange = false,
|
|
timeout = 1000, // check every 1 second
|
|
restart = null;
|
|
|
|
function run(options) {
|
|
var command = run.command(options),
|
|
nodeMajor = parseInt((process.versions.node.split('.') || [null,null])[1] || 0, 10);
|
|
|
|
utils.log.status('starting `' + command.executable + (command.args.length ? ' ' + command.args.join(' ') : '') + '`');
|
|
|
|
restart = run.bind(this, options);
|
|
run.restart = restart;
|
|
|
|
config.lastStarted = Date.now();
|
|
|
|
if (nodeMajor >= 8) {
|
|
child = spawn(command.executable, command.args, {
|
|
stdio: ['pipe', process.stdout, process.stderr]
|
|
});
|
|
} else {
|
|
child = spawn(command.executable, command.args);
|
|
child.stdout.on('data', function (data) {
|
|
process.stdout.write(data);
|
|
});
|
|
child.stderr.on('data', function (data) {
|
|
process.stderr.write(data);
|
|
});
|
|
}
|
|
|
|
bus.emit('start');
|
|
|
|
utils.log.detail('pid: ' + child.pid);
|
|
|
|
child.on('error', function (error) {
|
|
if (error.code === 'ENOENT') {
|
|
utils.log.error('unable to spawn executable: ' + executable);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
|
|
child.on('exit', function (code, signal) {
|
|
// In case we killed the app ourselves, set the signal thusly
|
|
if (killedAfterChange) {
|
|
killedAfterChange = false;
|
|
signal = 'SIGUSR2';
|
|
}
|
|
// this is nasty, but it gives it windows support
|
|
if (utils.isWindows && signal === 'SIGTERM') {
|
|
signal = 'SIGUSR2';
|
|
}
|
|
|
|
// exit the monitor, but do it gracefully
|
|
if (signal === 'SIGUSR2') {
|
|
// restart
|
|
restart();
|
|
} else if (code === 0) { // clean exit - wait until file change to restart
|
|
utils.log.status('clean exit - waiting for changes before restart');
|
|
child = null;
|
|
} else if (options.exitcrash) {
|
|
utils.log.fail('app crashed');
|
|
process.exit(0);
|
|
} else {
|
|
utils.log.fail('app crashed - waiting for file changes before starting...');
|
|
child = null;
|
|
}
|
|
});
|
|
|
|
process.on('exit', function () {
|
|
if (child) bus.emit('kill');
|
|
});
|
|
|
|
run.kill = function () {
|
|
if (child !== null) {
|
|
// When using CoffeeScript under Windows, child's process is not node.exe
|
|
// Instead coffee.cmd is launched, which launches cmd.exe, which starts
|
|
// node.exe as a child process child.kill() would only kill cmd.exe, not
|
|
// node.exe
|
|
// Therefore we use the Windows taskkill utility to kill the process and all
|
|
// its children (/T for tree)
|
|
if (utils.isWindows) {
|
|
// For the on('exit', ...) handler above the following looks like a crash,
|
|
// so we set the killedAfterChange flag
|
|
killedAfterChange = true;
|
|
// Force kill (/F) the whole child tree (/T) by PID (/PID 123)
|
|
exec('taskkill /pid '+ child.pid + ' /T /F');
|
|
} else {
|
|
child.kill('SIGUSR2');
|
|
}
|
|
} else {
|
|
// if there's no child, then we need to manually start the process
|
|
// this is because as there was no child, the child.on('exit') event
|
|
// handler doesn't exist which would normally trigger the restart.
|
|
restart();
|
|
}
|
|
};
|
|
|
|
// pinched from https://github.com/DTrejo/run.js - pipes stdin to the child process - cheers DTrejo ;-)
|
|
if (options.stdin) {
|
|
process.stdin.resume();
|
|
process.stdin.setEncoding('utf8');
|
|
process.stdin.pipe(child.stdin);
|
|
}
|
|
|
|
watch();
|
|
setTimeout(watch, timeout);
|
|
}
|
|
|
|
run.command = function (options) {
|
|
var executable = options.execOptions.exec,
|
|
args = [];
|
|
|
|
// after "executable" go the exec args (like --debug, etc)
|
|
if (options.execOptions.execArgs) {
|
|
[].push.apply(args, options.execOptions.execArgs);
|
|
}
|
|
|
|
// after the "executable" goes the user's script
|
|
if (options.script) {
|
|
args.push(options.script);
|
|
}
|
|
|
|
// then goes the user's script arguments
|
|
if (options.args) {
|
|
[].push.apply(args, options.args);
|
|
}
|
|
|
|
return {
|
|
executable: executable,
|
|
args: args
|
|
}
|
|
};
|
|
|
|
// stubbed out for now, filled in during run
|
|
run.kill = function () {};
|
|
run.restart = function () {};
|
|
|
|
bus.on('quit', function () {
|
|
// remove event listener
|
|
var exit = function () {
|
|
exit = function () {}; // null out in case of race condition
|
|
process.exit(0);
|
|
};
|
|
|
|
child.removeAllListeners('exit');
|
|
child.on('exit', exit);
|
|
child.kill('SIGINT');
|
|
setTimeout(exit, 10 * 1000); // give up waiting for the kids after 10 seconds
|
|
});
|
|
|
|
bus.on('restart', function () {
|
|
// run.kill will send a SIGINT to the child process, which will cause it
|
|
// to terminate, which in turn uses the 'exit' event handler to restart
|
|
run.kill();
|
|
});
|
|
|
|
|
|
module.exports = run; |