Cleanup
This commit is contained in:
154
node_modules/nodemon/lib/monitor/run.js
generated
vendored
154
node_modules/nodemon/lib/monitor/run.js
generated
vendored
@@ -5,6 +5,7 @@ var bus = utils.bus;
|
||||
var childProcess = require('child_process');
|
||||
var spawn = childProcess.spawn;
|
||||
var exec = childProcess.exec;
|
||||
var execSync = childProcess.execSync;
|
||||
var fork = childProcess.fork;
|
||||
var watch = require('./watch').watch;
|
||||
var config = require('../config');
|
||||
@@ -15,6 +16,7 @@ var restart = null;
|
||||
var psTree = require('pstree.remy');
|
||||
var path = require('path');
|
||||
var signals = require('./signals');
|
||||
const osRelease = parseInt(require('os').release().split('.')[0], 10);
|
||||
|
||||
function run(options) {
|
||||
var cmd = config.command.raw;
|
||||
@@ -62,10 +64,10 @@ function run(options) {
|
||||
|
||||
const spawnOptions = {
|
||||
env: Object.assign({}, process.env, options.execOptions.env, {
|
||||
PATH: binPath + ':' + process.env.PATH,
|
||||
PATH: binPath + path.delimiter + process.env.PATH,
|
||||
}),
|
||||
stdio: stdio,
|
||||
}
|
||||
};
|
||||
|
||||
var executable = cmd.executable;
|
||||
|
||||
@@ -74,17 +76,21 @@ function run(options) {
|
||||
// but *only* apply to the first command, and none of the arguments.
|
||||
// ref #1251 and #1236
|
||||
if (executable.indexOf('/') !== -1) {
|
||||
executable = executable.split(' ').map((e, i) => {
|
||||
if (i === 0) {
|
||||
return path.normalize(e);
|
||||
}
|
||||
return e;
|
||||
}).join(' ');
|
||||
executable = executable
|
||||
.split(' ')
|
||||
.map((e, i) => {
|
||||
if (i === 0) {
|
||||
return path.normalize(e);
|
||||
}
|
||||
return e;
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
// taken from npm's cli: https://git.io/vNFD4
|
||||
sh = process.env.comspec || 'cmd';
|
||||
shFlag = '/d /s /c';
|
||||
spawnOptions.windowsVerbatimArguments = true;
|
||||
spawnOptions.windowsHide = true;
|
||||
}
|
||||
|
||||
var args = runCmd ? utils.stringify(executable, cmd.args) : ':';
|
||||
@@ -109,7 +115,7 @@ function run(options) {
|
||||
!(firstArg.indexOf('-') === 0) && // don't fork if there's a node exec arg
|
||||
firstArg !== 'inspect' && // don't fork it's `inspect` debugger
|
||||
executable === 'node' && // only fork if node
|
||||
utils.version.major > 4 // only fork if node version > 4
|
||||
utils.version.major > 4; // only fork if node version > 4
|
||||
|
||||
if (shouldFork) {
|
||||
// this assumes the first argument is the script and slices it out, since
|
||||
@@ -117,13 +123,17 @@ function run(options) {
|
||||
var forkArgs = cmd.args.slice(1);
|
||||
var env = utils.merge(options.execOptions.env, process.env);
|
||||
stdio.push('ipc');
|
||||
child = fork(options.execOptions.script, forkArgs, {
|
||||
const forkOptions = {
|
||||
env: env,
|
||||
stdio: stdio,
|
||||
silent: !hasStdio,
|
||||
});
|
||||
};
|
||||
if (utils.isWindows) {
|
||||
forkOptions.windowsHide = true;
|
||||
}
|
||||
child = fork(options.execOptions.script, forkArgs, forkOptions);
|
||||
utils.log.detail('forking');
|
||||
debug('fork', sh, shFlag, args)
|
||||
debug('fork', sh, shFlag, args);
|
||||
} else {
|
||||
utils.log.detail('spawning');
|
||||
child = spawn.apply(null, spawnArgs);
|
||||
@@ -179,8 +189,9 @@ function run(options) {
|
||||
}
|
||||
|
||||
if (code === 127) {
|
||||
utils.log.error('failed to start process, "' + cmd.executable +
|
||||
'" exec not found');
|
||||
utils.log.error(
|
||||
'failed to start process, "' + cmd.executable + '" exec not found'
|
||||
);
|
||||
bus.emit('error', code);
|
||||
process.exit();
|
||||
}
|
||||
@@ -225,7 +236,8 @@ function run(options) {
|
||||
return restart();
|
||||
}
|
||||
|
||||
if (code === 0) { // clean exit - wait until file change to restart
|
||||
if (code === 0) {
|
||||
// clean exit - wait until file change to restart
|
||||
if (runCmd) {
|
||||
utils.log.status('clean exit - waiting for changes before restart');
|
||||
}
|
||||
@@ -239,8 +251,9 @@ function run(options) {
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
utils.log.fail('app crashed - waiting for file changes before' +
|
||||
' starting...');
|
||||
utils.log.fail(
|
||||
'app crashed - waiting for file changes before' + ' starting...'
|
||||
);
|
||||
child = null;
|
||||
}
|
||||
}
|
||||
@@ -265,21 +278,25 @@ function run(options) {
|
||||
// swallow the stdin error if it happens
|
||||
// ref: https://github.com/remy/nodemon/issues/1195
|
||||
if (hasStdio) {
|
||||
child.stdin.on('error', () => { });
|
||||
child.stdin.on('error', () => {});
|
||||
process.stdin.pipe(child.stdin);
|
||||
} else {
|
||||
if (child.stdout) {
|
||||
child.stdout.pipe(process.stdout);
|
||||
} else {
|
||||
utils.log.error('running an unsupported version of node ' +
|
||||
process.version);
|
||||
utils.log.error('nodemon may not work as expected - ' +
|
||||
'please consider upgrading to LTS');
|
||||
utils.log.error(
|
||||
'running an unsupported version of node ' + process.version
|
||||
);
|
||||
utils.log.error(
|
||||
'nodemon may not work as expected - ' +
|
||||
'please consider upgrading to LTS'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bus.once('exit', function () {
|
||||
if (child && process.stdin.unpipe) { // node > 0.8
|
||||
if (child && process.stdin.unpipe) {
|
||||
// node > 0.8
|
||||
process.stdin.unpipe(child.stdin);
|
||||
}
|
||||
});
|
||||
@@ -298,26 +315,80 @@ function waitForSubProcesses(pid, callback) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
utils.log.status(`still waiting for ${pids.length} sub-process${
|
||||
pids.length > 2 ? 'es' : ''} to finish...`);
|
||||
utils.log.status(
|
||||
`still waiting for ${pids.length} sub-process${
|
||||
pids.length > 2 ? 'es' : ''
|
||||
} to finish...`
|
||||
);
|
||||
setTimeout(() => waitForSubProcesses(pid, callback), 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function kill(child, signal, callback) {
|
||||
if (!callback) {
|
||||
callback = function () { };
|
||||
callback = noop;
|
||||
}
|
||||
|
||||
if (utils.isWindows) {
|
||||
// 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).
|
||||
// Force kill (/F) the whole child tree (/T) by PID (/PID 123)
|
||||
exec('taskkill /pid ' + child.pid + ' /T /F');
|
||||
const taskKill = () => {
|
||||
try {
|
||||
exec('taskkill /pid ' + child.pid + ' /T /F');
|
||||
} catch (e) {
|
||||
utils.log.error('Could not shutdown sub process cleanly');
|
||||
}
|
||||
};
|
||||
|
||||
// We are handling a 'SIGKILL' , 'SIGUSR2' and 'SIGUSR1' POSIX signal under Windows the
|
||||
// same way it is handled on a UNIX system: We are performing
|
||||
// a hard shutdown without waiting for the process to clean-up.
|
||||
if (signal === 'SIGKILL' || osRelease < 10 || signal === 'SIGUSR2' || signal==="SIGUSR1" ) {
|
||||
debug('terminating process group by force: %s', child.pid);
|
||||
|
||||
// We are using the taskkill utility to terminate the whole
|
||||
// process group ('/t') of the child ('/pid') by force ('/f').
|
||||
// We need to end all sub processes, because the 'child'
|
||||
// process in this context is actually a cmd.exe wrapper.
|
||||
taskKill();
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// We are using the Windows Management Instrumentation Command-line
|
||||
// (wmic.exe) to resolve the sub-child process identifier, because the
|
||||
// 'child' process in this context is actually a cmd.exe wrapper.
|
||||
// We want to send the termination signal directly to the node process.
|
||||
// The '2> nul' silences the no process found error message.
|
||||
const resultBuffer = execSync(
|
||||
`wmic process where (ParentProcessId=${child.pid}) get ProcessId 2> nul`
|
||||
);
|
||||
const result = resultBuffer.toString().match(/^[0-9]+/m);
|
||||
|
||||
// If there is no sub-child process we fall back to the child process.
|
||||
const processId = Array.isArray(result) ? result[0] : child.pid;
|
||||
|
||||
debug('sending kill signal SIGINT to process: %s', processId);
|
||||
|
||||
// We are using the standalone 'windows-kill' executable to send the
|
||||
// standard POSIX signal 'SIGINT' to the node process. This fixes #1720.
|
||||
const windowsKill = path.normalize(
|
||||
`${__dirname}/../../bin/windows-kill.exe`
|
||||
);
|
||||
|
||||
// We have to detach the 'windows-kill' execution completely from this
|
||||
// process group to avoid terminating the nodemon process itself.
|
||||
// See: https://github.com/alirdn/windows-kill#how-it-works--limitations
|
||||
//
|
||||
// Therefore we are using 'start' to create a new cmd.exe context.
|
||||
// The '/min' option hides the new terminal window and the '/wait'
|
||||
// option lets the process wait for the command to finish.
|
||||
|
||||
execSync(
|
||||
`start "windows-kill" /min /wait "${windowsKill}" -SIGINT ${processId}`
|
||||
);
|
||||
} catch (e) {
|
||||
taskKill();
|
||||
}
|
||||
callback();
|
||||
} else {
|
||||
// we use psTree to kill the full subtree of nodemon, because when
|
||||
@@ -340,15 +411,13 @@ function kill(child, signal, callback) {
|
||||
|
||||
child.kill(signal);
|
||||
|
||||
pids.sort().forEach(pid => exec(`kill -${sig} ${pid}`, noop));
|
||||
pids.sort().forEach((pid) => exec(`kill -${sig} ${pid}`, noop));
|
||||
|
||||
waitForSubProcesses(child.pid, () => {
|
||||
// finally kill the main user process
|
||||
exec(`kill -${sig} ${child.pid}`, callback);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,7 +524,9 @@ bus.on('restart', function () {
|
||||
// remove the child file on exit
|
||||
process.on('exit', function () {
|
||||
utils.log.detail('exiting');
|
||||
if (child) { child.kill(); }
|
||||
if (child) {
|
||||
child.kill();
|
||||
}
|
||||
});
|
||||
|
||||
// because windows borks when listening for the SIG* events
|
||||
@@ -465,10 +536,11 @@ if (!utils.isWindows) {
|
||||
process.once('SIGINT', () => bus.emit('quit', 130));
|
||||
process.once('SIGTERM', () => {
|
||||
bus.emit('quit', 143);
|
||||
if (child) { child.kill('SIGTERM'); }
|
||||
if (child) {
|
||||
child.kill('SIGTERM');
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
module.exports = run;
|
||||
|
||||
Reference in New Issue
Block a user