Source: CLI/helpers/dockerLib.js

var child_process = require('child_process');
var spawn = child_process.spawn;
var exec = child_process.exec;



/**
* Function that takes in an array of tasks that will be individually
*   passed to the spawn function, then runs each task in series. At the 
*   end of all the tasks, a final callback will be invoked.
* @function
* @memberof module:helpers
* EXAMPLE
*   spawnSeries([
*    ['ls', ['-lh', '/usr']],
*    ['ls', ['-la']]
*   ], function() { console.log('all done!'); });
*/
var spawnSeries = function(tasks, callback) {
  var sendBuildRegEx = /Sending build context to Docker daemon.*B/;
  callback = callback || function() {};
  var completed = 0;
  var iterate = function() {
    if (++completed < tasks.length) {
      run();
    } else {
      callback();
    }
  }
  var run = function() {
    var task = tasks[completed];

    // If there is explanation text, log it out for user
    if (task[2] !== undefined) {
      var text = task.splice(2).join('');
      console.log(text);
    }

    var commandText = "docker ";
      for(var i = 6; i < task[1].length; i++) {
        commandText += task[1][i] + " ";
      }
    console.log("RUNNING:", commandText);

    var proc = spawn.apply(null, task);
    proc.stdout.on('data', function(data) {
      console.log(data.toString());
    });
    proc.stderr.on('data', function(data) {
      var output = data.toString();
      if (sendBuildRegEx.test(output)) {
        // write progress on same line if sending build context
        process.stdout.write(output+'\r');
      } else {
        console.log(data.toString());
      }
    });
    proc.on('exit', function(code) {
      // show error code if error
      if (code !== 0) {
        console.log('DOCKER COMMAND FAILED:');
        console.log(commandText);
        console.log('EXITED WITH CODE:', code);
      }

      iterate();
    });
  }
  run();
}

// EXAMPLE
// dockerExec('exec app ls');
var dockerExec = function(command, callback) {
  getDockerDefaults(function(defaults) {
    defaults = defaults.join(' ');
    console.log(defaults+' '+command);

    exec('docker ' + defaults+' '+command, function(err, stdout, stderr) {
      callback(err, stdout, stderr);
    });
  });
}

/**
* Function that takes in an array of docker commands that will be  
*   have docker default parameters mapped to them, so they can 
*   properly communicate with the boot2docker VM, then runs each 
*   task in series. 
*   At the end of all the tasks, a final callback will be invoked.
* @function
* @memberof module:helpers
*/
// EXAMPLE
// dockerSpawnSeries([
//   ['docker', ['pull', 'ubuntu:latest']],
//   ['docker', ['-v']]
// ]);
var dockerSpawnSeries = function(commands, callback) {
  callback = callback || function() {};
  getDockerDefaults(function(defaults) {
    commands.map(function(command) {
      command[1] = defaults.concat(command[1]);
    });
    spawnSeries(commands, callback);
  })
}

// EXAMPLE
// dockerSpawn(['docker', ['pull', 'ubuntu:latest']]);
var dockerSpawn = function(command, callback) {
  var arr = [];
  arr.push(command);
  dockerSpawnSeries(arr, callback);
}

var getDockerDefaults = function(callback) {
  exec('boot2docker shellinit', function(err, stdout, stderr) {
    parseDefaults(stdout.split('\n'), callback);
  });
}

var parseDefaults = function(arr, callback) {
  var defaults = ['--tlsverify'];
  arr.forEach(function(val) {
    var param = val.trim().split('=');
    if (param[0] === 'export DOCKER_HOST') {
      defaults.push('-H');
      defaults.push(param[1]);
    } else if (param[0] === 'export DOCKER_CERT_PATH') {
      defaults.push('--tlscacert="' + param[1] + '/ca.pem"');
      defaults.push('--tlscert="' + param[1] + '/cert.pem"');
      defaults.push('--tlskey="' + param[1] + '/key.pem"');
    }
  });
  callback(defaults);
}

module.exports = {
  spawnSeries: dockerSpawnSeries,
  spawn: dockerSpawn,
  exec: dockerExec
}