spawn.js 1.6 KB

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