spawn.js

import {pump} from './pump'
import childProcess from 'child_process'

class SpawnError extends Error {
  constructor(errorCode, stack) {
    super(`Process exited with code ${errorCode}`)
    this.name = this.constructor.name
    this.message = `Process exited with code ${errorCode}`
    this.stack = stack
  }
}

/**
 * Adapter for the nodejs function `child_process.spawn`.  Mapping the stdout and stderr to an iterable
 *
 * @param {string}    command The command to run
 * @param {Array.<string>=} args The arguments to supply to the command
 * @param {object=}   options Any options to be passed thru to child_process.spawn
 * @return {iteration} An iterable source that contain an object with one of 2 keys (stdout or stderr)
 * @function
 * @memberof module:Generators
 * @name spawn
 */
export function spawn(...args) {

  const stackTrace = {}
  Error.captureStackTrace(stackTrace)

  return pump(async (target, hasStopped) => {
    await target.next()
    const p = childProcess.spawn(...args)
    p.stdout.on('data', stdout => {
      target.next({stdout}).then(() => p.kill('SIGCONT'))
      p.kill('SIGSTOP')
    })
    p.stderr.on('data', stderr => {
      target.next({stderr}).then(() => p.kill('SIGCONT'))
      p.kill('SIGSTOP')
    })
    p.on('close', err => err ? target.throw(new SpawnError(err, stackTrace.stack)) : target.return())

    hasStopped.then(() => p.kill())
  })
}