| var signalExit = require('signal-exit') |
| var spawn = require('child_process').spawn |
| if (process.platform === 'win32') { |
| spawn = require('cross-spawn') |
| } |
| |
| module.exports = function (program, args, cb) { |
| var arrayIndex = arguments.length |
| |
| if (typeof args === 'function') { |
| cb = args |
| args = undefined |
| } else { |
| cb = Array.prototype.slice.call(arguments).filter(function (arg, i) { |
| if (typeof arg === 'function') { |
| arrayIndex = i |
| return true |
| } |
| })[0] |
| } |
| |
| cb = cb || function (done) { |
| return done() |
| } |
| |
| if (Array.isArray(program)) { |
| args = program.slice(1) |
| program = program[0] |
| } else if (!Array.isArray(args)) { |
| args = [].slice.call(arguments, 1, arrayIndex) |
| } |
| |
| var spawnOpts = { stdio: [0, 1, 2] } |
| |
| if (process.send) { |
| spawnOpts.stdio.push('ipc') |
| } |
| |
| var child = spawn(program, args, spawnOpts) |
| |
| var childExited = false |
| var unproxySignals = proxySignals(child) |
| process.on('exit', childHangup) |
| function childHangup () { |
| child.kill('SIGHUP') |
| } |
| |
| child.on('close', function (code, signal) { |
| // Allow the callback to inspect the child’s exit code and/or modify it. |
| process.exitCode = signal ? 128 + signal : code |
| |
| cb(function () { |
| unproxySignals() |
| process.removeListener('exit', childHangup) |
| childExited = true |
| if (signal) { |
| // If there is nothing else keeping the event loop alive, |
| // then there's a race between a graceful exit and getting |
| // the signal to this process. Put this timeout here to |
| // make sure we're still alive to get the signal, and thus |
| // exit with the intended signal code. |
| setTimeout(function () {}, 200) |
| process.kill(process.pid, signal) |
| } else { |
| // Equivalent to process.exit() on Node.js >= 0.11.8 |
| process.exit(process.exitCode) |
| } |
| }) |
| }) |
| |
| if (process.send) { |
| process.removeAllListeners('message') |
| |
| child.on('message', function (message, sendHandle) { |
| process.send(message, sendHandle) |
| }) |
| |
| process.on('message', function (message, sendHandle) { |
| child.send(message, sendHandle) |
| }) |
| } |
| |
| return child |
| } |
| |
| function proxySignals (child) { |
| var listeners = {} |
| signalExit.signals().forEach(function (sig) { |
| listeners[sig] = function () { |
| child.kill(sig) |
| } |
| process.on(sig, listeners[sig]) |
| }) |
| |
| return unproxySignals |
| |
| function unproxySignals () { |
| for (var sig in listeners) { |
| process.removeListener(sig, listeners[sig]) |
| } |
| } |
| } |