1'use strict' 2 3module.exports = spawn 4 5const _spawn = require('child_process').spawn 6const EventEmitter = require('events').EventEmitter 7 8let progressEnabled 9let running = 0 10 11function startRunning (log) { 12 if (progressEnabled == null) progressEnabled = log.progressEnabled 13 if (progressEnabled) log.disableProgress() 14 ++running 15} 16 17function stopRunning (log) { 18 --running 19 if (progressEnabled && running === 0) log.enableProgress() 20} 21 22function willCmdOutput (stdio) { 23 if (stdio === 'inherit') return true 24 if (!Array.isArray(stdio)) return false 25 for (let fh = 1; fh <= 2; ++fh) { 26 if (stdio[fh] === 'inherit') return true 27 if (stdio[fh] === 1 || stdio[fh] === 2) return true 28 } 29 return false 30} 31 32function spawn (cmd, args, options, log) { 33 const cmdWillOutput = willCmdOutput(options && options.stdio) 34 35 if (cmdWillOutput) startRunning(log) 36 const raw = _spawn(cmd, args, options) 37 const cooked = new EventEmitter() 38 39 raw.on('error', function (er) { 40 if (cmdWillOutput) stopRunning(log) 41 er.file = cmd 42 cooked.emit('error', er) 43 }).on('close', function (code, signal) { 44 if (cmdWillOutput) stopRunning(log) 45 // Create ENOENT error because Node.js v8.0 will not emit 46 // an `error` event if the command could not be found. 47 if (code === 127) { 48 const er = new Error('spawn ENOENT') 49 er.code = 'ENOENT' 50 er.errno = 'ENOENT' 51 er.syscall = 'spawn' 52 er.file = cmd 53 cooked.emit('error', er) 54 } else { 55 cooked.emit('close', code, signal) 56 } 57 }) 58 59 cooked.stdin = raw.stdin 60 cooked.stdout = raw.stdout 61 cooked.stderr = raw.stderr 62 cooked.kill = function (sig) { return raw.kill(sig) } 63 64 return cooked 65} 66