text: var common = require('./common');
  var _tempDir = require('./tempdir');
  var _pwd = require('./pwd');
  var path = require('path');
  var fs = require('fs');
  var child = require('child_process');
  
  var DEFAULT_MAXBUFFER_SIZE = 20 * 1024 * 1024;
  var DEFAULT_ERROR_CODE = 1;
  
  common.register('exec', _exec, {
    unix: false,
    canReceivePipe: true,
    wrapOutput: false,
  });
  
  // We use this function to run `exec` synchronously while also providing realtime
  // output.
  function execSync(cmd, opts, pipe) {
    if (!common.config.execPath) {
      common.error('Unable to find a path to the node binary. Please manually set config.execPath');
    }
  
    var tempDir = _tempDir();
    var paramsFile = path.resolve(tempDir + '/' + common.randomFileName());
    var stderrFile = path.resolve(tempDir + '/' + common.randomFileName());
    var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName());
  
    opts = common.extend({
      silent: common.config.silent,
      cwd: _pwd().toString(),
      env: process.env,
      maxBuffer: DEFAULT_MAXBUFFER_SIZE,
      encoding: 'utf8',
    }, opts);
  
    if (fs.existsSync(paramsFile)) common.unlinkSync(paramsFile);
    if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile);
    if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile);
  
    opts.cwd = path.resolve(opts.cwd);
  
    var paramsToSerialize = {
      command: cmd,
      execOptions: opts,
      pipe: pipe,
      stdoutFile: stdoutFile,
      stderrFile: stderrFile,
    };
  
    fs.writeFileSync(paramsFile, JSON.stringify(paramsToSerialize), 'utf8');
  
    var execArgs = [
      path.join(__dirname, 'exec-child.js'),
      paramsFile,
    ];
  
    /* istanbul ignore else */
    if (opts.silent) {
      opts.stdio = 'ignore';
    } else {
      opts.stdio = [0, 1, 2];
    }
  
    var code = 0;
  
    // Welcome to the future
    try {
      // Bad things if we pass in a `shell` option to child_process.execFileSync,
      // so we need to explicitly remove it here.
      delete opts.shell;
  
      child.execFileSync(common.config.execPath, execArgs, opts);
    } catch (e) {
      // Commands with non-zero exit code raise an exception.
      code = e.status || DEFAULT_ERROR_CODE;
    }
  
    // fs.readFileSync uses buffer encoding by default, so call
    // it without the encoding option if the encoding is 'buffer'.
    // Also, if the exec timeout is too short for node to start up,
    // the files will not be created, so these calls will throw.
    var stdout = '';
    var stderr = '';
    if (opts.encoding === 'buffer') {
      stdout = fs.readFileSync(stdoutFile);
      stderr = fs.readFileSync(stderrFile);
    } else {
      stdout = fs.readFileSync(stdoutFile, opts.encoding);
      stderr = fs.readFileSync(stderrFile, opts.encoding);
    }
  
    // No biggie if we can't erase the files now -- they're in a temp dir anyway
    try { common.unlinkSync(paramsFile); } catch (e) {}
    try { common.unlinkSync(stderrFile); } catch (e) {}
    try { common.unlinkSync(stdoutFile); } catch (e) {}
  
    if (code !== 0) {
      common.error(stderr, code, { continue: true });
    }
    var obj = common.ShellString(stdout, stderr, code);
    return obj;
  } // execSync()
  
  // Wrapper around exec() to enable echoing output to console in real time
  function execAsync(cmd, opts, pipe, callback) {
    opts = common.extend({
      silent: common.config.silent,
      cwd: _pwd().toString(),
      env: process.env,
      maxBuffer: DEFAULT_MAXBUFFER_SIZE,
      encoding: 'utf8',
    }, opts);
  
    var c = child.exec(cmd, opts, function (err, stdout, stderr) {
      if (callback) {
        if (!err) {
          callback(0, stdout, stderr);
        } else if (err.code === undefined) {
          // See issue #536
          /* istanbul ignore next */
          callback(1, stdout, stderr);
        } else {
          callback(err.code, stdout, stderr);
        }
      }
    });
  
    if (pipe) c.stdin.end(pipe);
  
    if (!opts.silent) {
      c.stdout.pipe(process.stdout);
      c.stderr.pipe(process.stderr);
    }
  
    return c;
  }
  
  //@
  //@ ### exec(command [, options] [, callback])
  //@
  //@ Available options:
  //@
  //@ + `async`: Asynchronous execution. If a callback is provided, it will be set to
  //@   `true`, regardless of the passed value (default: `false`).
  //@ + `silent`: Do not echo program output to console (default: `false`).
  //@ + `encoding`: Character encoding to use. Affects the values returned to stdout and stderr, and
  //@   what is written to stdout and stderr when not in silent mode (default: `'utf8'`).
  //@ + and any option available to Node.js's
  //@   [`child_process.exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)
  //@
  //@ Examples:
  //@
  //@ ```javascript
  //@ var version = exec('node --version', {silent:true}).stdout;
  //@
  //@ var child = exec('some_long_running_process', {async:true});
  //@ child.stdout.on('data', function(data) {
  //@   /* ... do something with data ... */
  //@ });
  //@
  //@ exec('some_long_running_process', function(code, stdout, stderr) {
  //@   console.log('Exit code:', code);
  //@   console.log('Program output:', stdout);
  //@   console.log('Program stderr:', stderr);
  //@ });
  //@ ```
  //@
  //@ Executes the given `command` _synchronously_, unless otherwise specified.  When in synchronous
  //@ mode, this returns a `ShellString` (compatible with ShellJS v0.6.x, which returns an object
  //@ of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process
  //@ object, and the `callback` receives the arguments `(code, stdout, stderr)`.
  //@
  //@ Not seeing the behavior you want? `exec()` runs everything through `sh`
  //@ by default (or `cmd.exe` on Windows), which differs from `bash`. If you
  //@ need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option.
  function _exec(command, options, callback) {
    options = options || {};
    if (!command) common.error('must specify command');
  
    var pipe = common.readFromPipe();
  
    // Callback is defined instead of options.
    if (typeof options === 'function') {
      callback = options;
      options = { async: true };
    }
  
    // Callback is defined with options.
    if (typeof options === 'object' && typeof callback === 'function') {
      options.async = true;
    }
  
    options = common.extend({
      silent: common.config.silent,
      async: false,
    }, options);
  
    if (options.async) {
      return execAsync(command, options, pipe, callback);
    } else {
      return execSync(command, options, pipe);
    }
  }
  module.exports = _exec;
  