• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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