exec-sh.js
  1  var cp = require('child_process')
  2  
  3  var defSpawnOptions = { stdio: 'inherit' }
  4  
  5  /**
  6   * @summary Get shell program meta for current platform
  7   * @private
  8   * @returns {Object}
  9   */
 10  function getShell () {
 11    if (process.platform === 'win32') {
 12      return { cmd: 'cmd', arg: '/C' }
 13    } else {
 14      return { cmd: 'sh', arg: '-c' }
 15    }
 16  }
 17  
 18  /**
 19   * Callback is called with the output when the process terminates. Output is
 20   * available when true is passed as options argument or stdio: null set
 21   * within given options.
 22   *
 23   * @summary Execute shell command forwarding all stdio
 24   * @param {String|Array} command
 25   * @param {Object|TRUE} [options] spawn() options or TRUE to set stdio: null
 26   * @param {Function} [callback]
 27   * @returns {ChildProcess}
 28   */
 29  function execSh (command, options, callback) {
 30    if (Array.isArray(command)) {
 31      command = command.join(';')
 32    }
 33  
 34    if (options === true) {
 35      options = { stdio: null }
 36    }
 37  
 38    if (typeof options === 'function') {
 39      callback = options
 40      options = defSpawnOptions
 41    } else {
 42      options = options || {}
 43      options = Object.assign({}, defSpawnOptions, options)
 44      callback = callback || function () {}
 45    }
 46  
 47    var child
 48    var stdout = ''
 49    var stderr = ''
 50    var shell = getShell()
 51  
 52    try {
 53      child = cp.spawn(shell.cmd, [shell.arg, command], options)
 54    } catch (e) {
 55      callback(e, stdout, stderr)
 56      return
 57    }
 58  
 59    if (child.stdout) {
 60      child.stdout.on('data', function (data) {
 61        stdout += data
 62      })
 63    }
 64  
 65    if (child.stderr) {
 66      child.stderr.on('data', function (data) {
 67        stderr += data
 68      })
 69    }
 70  
 71    child.on('close', function (code) {
 72      if (code) {
 73        var e = new Error('Shell command exit with non zero code: ' + code)
 74        e.code = code
 75        callback(e, stdout, stderr)
 76      } else {
 77        callback(null, stdout, stderr)
 78      }
 79    })
 80  
 81    return child
 82  }
 83  
 84  execSh.promise = function (command, options) {
 85    return new Promise(function (resolve, reject) {
 86      execSh(command, options, function (err, stdout, stderr) {
 87        if (err) {
 88          err.stdout = stdout
 89          err.stderr = stderr
 90          return reject(err)
 91        }
 92  
 93        resolve({
 94          stderr: stderr,
 95          stdout: stdout
 96        })
 97      })
 98    })
 99  }
100  
101  module.exports = execSh