You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by pu...@apache.org on 2017/05/25 20:38:32 UTC

[12/25] cordova-browser git commit: update shelljs version, prepare is working

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/chmod.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/chmod.js b/node_modules/shelljs/src/chmod.js
index 6c6de10..ce5659e 100644
--- a/node_modules/shelljs/src/chmod.js
+++ b/node_modules/shelljs/src/chmod.js
@@ -4,35 +4,37 @@ var path = require('path');
 
 var PERMS = (function (base) {
   return {
-    OTHER_EXEC  : base.EXEC,
-    OTHER_WRITE : base.WRITE,
-    OTHER_READ  : base.READ,
+    OTHER_EXEC: base.EXEC,
+    OTHER_WRITE: base.WRITE,
+    OTHER_READ: base.READ,
 
-    GROUP_EXEC  : base.EXEC  << 3,
-    GROUP_WRITE : base.WRITE << 3,
-    GROUP_READ  : base.READ << 3,
+    GROUP_EXEC: base.EXEC << 3,
+    GROUP_WRITE: base.WRITE << 3,
+    GROUP_READ: base.READ << 3,
 
-    OWNER_EXEC  : base.EXEC << 6,
-    OWNER_WRITE : base.WRITE << 6,
-    OWNER_READ  : base.READ << 6,
+    OWNER_EXEC: base.EXEC << 6,
+    OWNER_WRITE: base.WRITE << 6,
+    OWNER_READ: base.READ << 6,
 
-    // Literal octal numbers are apparently not allowed in "strict" javascript.  Using parseInt is
-    // the preferred way, else a jshint warning is thrown.
-    STICKY      : parseInt('01000', 8),
-    SETGID      : parseInt('02000', 8),
-    SETUID      : parseInt('04000', 8),
+    // Literal octal numbers are apparently not allowed in "strict" javascript.
+    STICKY: parseInt('01000', 8),
+    SETGID: parseInt('02000', 8),
+    SETUID: parseInt('04000', 8),
 
-    TYPE_MASK   : parseInt('0770000', 8)
+    TYPE_MASK: parseInt('0770000', 8),
   };
-})({
-  EXEC  : 1,
-  WRITE : 2,
-  READ  : 4
+}({
+  EXEC: 1,
+  WRITE: 2,
+  READ: 4,
+}));
+
+common.register('chmod', _chmod, {
 });
 
 //@
-//@ ### chmod(octal_mode || octal_string, file)
-//@ ### chmod(symbolic_mode, file)
+//@ ### chmod([options,] octal_mode || octal_string, file)
+//@ ### chmod([options,] symbolic_mode, file)
 //@
 //@ Available options:
 //@
@@ -46,6 +48,7 @@ var PERMS = (function (base) {
 //@ chmod(755, '/Users/brandon');
 //@ chmod('755', '/Users/brandon'); // same as above
 //@ chmod('u+x', '/Users/brandon');
+//@ chmod('-R', 'a-w', '/Users/brandon');
 //@ ```
 //@
 //@ Alters the permissions of a file or directory by either specifying the
@@ -62,11 +65,8 @@ function _chmod(options, mode, filePattern) {
       // Special case where the specified file permissions started with - to subtract perms, which
       // get picked up by the option parser as command flags.
       // If we are down by one argument and options starts with -, shift everything over.
-      filePattern = mode;
-      mode = options;
-      options = '';
-    }
-    else {
+      [].unshift.call(arguments, '');
+    } else {
       common.error('You must specify a file.');
     }
   }
@@ -74,18 +74,17 @@ function _chmod(options, mode, filePattern) {
   options = common.parseOptions(options, {
     'R': 'recursive',
     'c': 'changes',
-    'v': 'verbose'
+    'v': 'verbose',
   });
 
-  if (typeof filePattern === 'string') {
-    filePattern = [ filePattern ];
-  }
+  filePattern = [].slice.call(arguments, 2);
 
   var files;
 
+  // TODO: replace this with a call to common.expand()
   if (options.recursive) {
     files = [];
-    common.expand(filePattern).forEach(function addFile(expandedFile) {
+    filePattern.forEach(function addFile(expandedFile) {
       var stat = fs.lstatSync(expandedFile);
 
       if (!stat.isSymbolicLink()) {
@@ -98,9 +97,8 @@ function _chmod(options, mode, filePattern) {
         }
       }
     });
-  }
-  else {
-    files = common.expand(filePattern);
+  } else {
+    files = filePattern;
   }
 
   files.forEach(function innerChmod(file) {
@@ -124,7 +122,6 @@ function _chmod(options, mode, filePattern) {
     if (isNaN(parseInt(mode, 8))) {
       // parse options
       mode.split(',').forEach(function (symbolicMode) {
-        /*jshint regexdash:true */
         var pattern = /([ugoa]*)([=\+-])([rwxXst]*)/i;
         var matches = pattern.exec(symbolicMode);
 
@@ -133,19 +130,20 @@ function _chmod(options, mode, filePattern) {
           var operator = matches[2];
           var change = matches[3];
 
-          var changeOwner = applyTo.indexOf('u') != -1 || applyTo === 'a' || applyTo === '';
-          var changeGroup = applyTo.indexOf('g') != -1 || applyTo === 'a' || applyTo === '';
-          var changeOther = applyTo.indexOf('o') != -1 || applyTo === 'a' || applyTo === '';
+          var changeOwner = applyTo.indexOf('u') !== -1 || applyTo === 'a' || applyTo === '';
+          var changeGroup = applyTo.indexOf('g') !== -1 || applyTo === 'a' || applyTo === '';
+          var changeOther = applyTo.indexOf('o') !== -1 || applyTo === 'a' || applyTo === '';
 
-          var changeRead    = change.indexOf('r') != -1;
-          var changeWrite   = change.indexOf('w') != -1;
-          var changeExec    = change.indexOf('x') != -1;
-          var changeExecDir = change.indexOf('X') != -1;
-          var changeSticky  = change.indexOf('t') != -1;
-          var changeSetuid  = change.indexOf('s') != -1;
+          var changeRead = change.indexOf('r') !== -1;
+          var changeWrite = change.indexOf('w') !== -1;
+          var changeExec = change.indexOf('x') !== -1;
+          var changeExecDir = change.indexOf('X') !== -1;
+          var changeSticky = change.indexOf('t') !== -1;
+          var changeSetuid = change.indexOf('s') !== -1;
 
-          if (changeExecDir && isDir)
+          if (changeExecDir && isDir) {
             changeExec = true;
+          }
 
           var mask = 0;
           if (changeOwner) {
@@ -175,35 +173,37 @@ function _chmod(options, mode, filePattern) {
             case '=':
               newPerms = type + mask;
 
-              // According to POSIX, when using = to explicitly set the permissions, setuid and setgid can never be cleared.
+              // According to POSIX, when using = to explicitly set the
+              // permissions, setuid and setgid can never be cleared.
               if (fs.statSync(file).isDirectory()) {
                 newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
               }
               break;
+            default:
+              common.error('Could not recognize operator: `' + operator + '`');
           }
 
           if (options.verbose) {
             console.log(file + ' -> ' + newPerms.toString(8));
           }
 
-          if (perms != newPerms) {
+          if (perms !== newPerms) {
             if (!options.verbose && options.changes) {
               console.log(file + ' -> ' + newPerms.toString(8));
             }
             fs.chmodSync(file, newPerms);
             perms = newPerms; // for the next round of changes!
           }
-        }
-        else {
+        } else {
           common.error('Invalid symbolic mode change: ' + symbolicMode);
         }
       });
-    }
-    else {
+    } else {
       // they gave us a full number
       newPerms = type + parseInt(mode, 8);
 
-      // POSIX rules are that setuid and setgid can only be added using numeric form, but not cleared.
+      // POSIX rules are that setuid and setgid can only be added using numeric
+      // form, but not cleared.
       if (fs.statSync(file).isDirectory()) {
         newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
       }
@@ -211,5 +211,6 @@ function _chmod(options, mode, filePattern) {
       fs.chmodSync(file, newPerms);
     }
   });
+  return '';
 }
 module.exports = _chmod;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/common.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/common.js b/node_modules/shelljs/src/common.js
index 33198bd..f5197d8 100644
--- a/node_modules/shelljs/src/common.js
+++ b/node_modules/shelljs/src/common.js
@@ -1,68 +1,186 @@
+// Ignore warning about 'new String()'
+/* eslint no-new-wrappers: 0 */
+'use strict';
+
 var os = require('os');
 var fs = require('fs');
-var _ls = require('./ls');
+var glob = require('glob');
+var shell = require('..');
 
-// Module globals
-var config = {
-  silent: false,
+var shellMethods = Object.create(shell);
+
+// objectAssign(target_obj, source_obj1 [, source_obj2 ...])
+// "Ponyfill" for Object.assign
+//    objectAssign({A:1}, {b:2}, {c:3}) returns {A:1, b:2, c:3}
+var objectAssign = typeof Object.assign === 'function' ?
+  Object.assign :
+  function objectAssign(target) {
+    var sources = [].slice.call(arguments, 1);
+    sources.forEach(function (source) {
+      Object.keys(source).forEach(function (key) {
+        target[key] = source[key];
+      });
+    });
+
+    return target;
+  };
+exports.extend = objectAssign;
+
+// Check if we're running under electron
+var isElectron = Boolean(process.versions.electron);
+
+// Module globals (assume no execPath by default)
+var DEFAULT_CONFIG = {
   fatal: false,
+  globOptions: {},
+  maxdepth: 255,
+  noglob: false,
+  silent: false,
   verbose: false,
+  execPath: null,
 };
+
+var config = {
+  reset: function () {
+    objectAssign(this, DEFAULT_CONFIG);
+    if (!isElectron) {
+      this.execPath = process.execPath;
+    }
+  },
+  resetForTesting: function () {
+    this.reset();
+    this.silent = true;
+  },
+};
+
+config.reset();
 exports.config = config;
 
 var state = {
   error: null,
+  errorCode: 0,
   currentCmd: 'shell.js',
-  previousDir: null,
-  tempDir: null
+  tempDir: null,
 };
 exports.state = state;
 
+delete process.env.OLDPWD; // initially, there's no previous directory
+
 var platform = os.type().match(/^Win/) ? 'win' : 'unix';
 exports.platform = platform;
 
+// This is populated by calls to commonl.wrap()
+var pipeMethods = [];
+
+// Reliably test if something is any sort of javascript object
+function isObject(a) {
+  return typeof a === 'object' && a !== null;
+}
+exports.isObject = isObject;
+
 function log() {
-  if (!config.silent)
+  /* istanbul ignore next */
+  if (!config.silent) {
     console.error.apply(console, arguments);
+  }
 }
 exports.log = log;
 
-// Shows error message. Throws unless _continue or config.fatal are true
-function error(msg, _continue) {
-  if (state.error === null)
-    state.error = '';
-  var log_entry = state.currentCmd + ': ' + msg;
-  if (state.error === '')
-    state.error = log_entry;
-  else
-    state.error += '\n' + log_entry;
+// Converts strings to be equivalent across all platforms. Primarily responsible
+// for making sure we use '/' instead of '\' as path separators, but this may be
+// expanded in the future if necessary
+function convertErrorOutput(msg) {
+  if (typeof msg !== 'string') {
+    throw new TypeError('input must be a string');
+  }
+  return msg.replace(/\\/g, '/');
+}
+exports.convertErrorOutput = convertErrorOutput;
+
+// Shows error message. Throws if config.fatal is true
+function error(msg, _code, options) {
+  // Validate input
+  if (typeof msg !== 'string') throw new Error('msg must be a string');
+
+  var DEFAULT_OPTIONS = {
+    continue: false,
+    code: 1,
+    prefix: state.currentCmd + ': ',
+    silent: false,
+  };
 
-  if (msg.length > 0)
-    log(log_entry);
+  if (typeof _code === 'number' && isObject(options)) {
+    options.code = _code;
+  } else if (isObject(_code)) { // no 'code'
+    options = _code;
+  } else if (typeof _code === 'number') { // no 'options'
+    options = { code: _code };
+  } else if (typeof _code !== 'number') { // only 'msg'
+    options = {};
+  }
+  options = objectAssign({}, DEFAULT_OPTIONS, options);
+
+  if (!state.errorCode) state.errorCode = options.code;
+
+  var logEntry = convertErrorOutput(options.prefix + msg);
+  state.error = state.error ? state.error + '\n' : '';
+  state.error += logEntry;
 
-  if (config.fatal)
-    process.exit(1);
+  // Throw an error, or log the entry
+  if (config.fatal) throw new Error(logEntry);
+  if (msg.length > 0 && !options.silent) log(logEntry);
 
-  if (!_continue)
-    throw '';
+  if (!options.continue) {
+    throw {
+      msg: 'earlyExit',
+      retValue: (new ShellString('', state.error, state.errorCode)),
+    };
+  }
 }
 exports.error = error;
 
-// In the future, when Proxies are default, we can add methods like `.to()` to primitive strings.
-// For now, this is a dummy function to bookmark places we need such strings
-function ShellString(str) {
-  return str;
+//@
+//@ ### ShellString(str)
+//@
+//@ Examples:
+//@
+//@ ```javascript
+//@ var foo = ShellString('hello world');
+//@ ```
+//@
+//@ Turns a regular string into a string-like object similar to what each
+//@ command returns. This has special methods, like `.to()` and `.toEnd()`
+function ShellString(stdout, stderr, code) {
+  var that;
+  if (stdout instanceof Array) {
+    that = stdout;
+    that.stdout = stdout.join('\n');
+    if (stdout.length > 0) that.stdout += '\n';
+  } else {
+    that = new String(stdout);
+    that.stdout = stdout;
+  }
+  that.stderr = stderr;
+  that.code = code;
+  // A list of all commands that can appear on the right-hand side of a pipe
+  // (populated by calls to common.wrap())
+  pipeMethods.forEach(function (cmd) {
+    that[cmd] = shellMethods[cmd].bind(that);
+  });
+  return that;
 }
+
 exports.ShellString = ShellString;
 
 // Return the home directory in a platform-agnostic way, with consideration for
 // older versions of node
 function getUserHome() {
   var result;
-  if (os.homedir)
+  if (os.homedir) {
     result = os.homedir(); // node 3+
-  else
+  } else {
     result = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
+  }
   return result;
 }
 exports.getUserHome = getUserHome;
@@ -71,52 +189,58 @@ exports.getUserHome = getUserHome;
 //   parseOptions('-a', {'a':'alice', 'b':'bob'});
 // Returns {'reference': 'string-value', 'bob': false} when passed two dictionaries of the form:
 //   parseOptions({'-r': 'string-value'}, {'r':'reference', 'b':'bob'});
-function parseOptions(opt, map) {
-  if (!map)
-    error('parseOptions() internal error: no map given');
+function parseOptions(opt, map, errorOptions) {
+  // Validate input
+  if (typeof opt !== 'string' && !isObject(opt)) {
+    throw new Error('options must be strings or key-value pairs');
+  } else if (!isObject(map)) {
+    throw new Error('parseOptions() internal error: map must be an object');
+  } else if (errorOptions && !isObject(errorOptions)) {
+    throw new Error('parseOptions() internal error: errorOptions must be object');
+  }
 
   // All options are false by default
   var options = {};
-  for (var letter in map) {
-    if (map[letter][0] !== '!')
-      options[map[letter]] = false;
-  }
+  Object.keys(map).forEach(function (letter) {
+    var optName = map[letter];
+    if (optName[0] !== '!') {
+      options[optName] = false;
+    }
+  });
 
-  if (!opt)
-    return options; // defaults
+  if (opt === '') return options; // defaults
 
-  var optionName;
   if (typeof opt === 'string') {
-    if (opt[0] !== '-')
-      return options;
+    if (opt[0] !== '-') {
+      error("Options string must start with a '-'", errorOptions || {});
+    }
 
     // e.g. chars = ['R', 'f']
     var chars = opt.slice(1).split('');
 
-    chars.forEach(function(c) {
+    chars.forEach(function (c) {
       if (c in map) {
-        optionName = map[c];
-        if (optionName[0] === '!')
-          options[optionName.slice(1, optionName.length-1)] = false;
-        else
+        var optionName = map[c];
+        if (optionName[0] === '!') {
+          options[optionName.slice(1)] = false;
+        } else {
           options[optionName] = true;
+        }
       } else {
-        error('option not recognized: '+c);
+        error('option not recognized: ' + c, errorOptions || {});
       }
     });
-  } else if (typeof opt === 'object') {
-    for (var key in opt) {
+  } else { // opt is an Object
+    Object.keys(opt).forEach(function (key) {
       // key is a string of the form '-r', '-d', etc.
       var c = key[1];
       if (c in map) {
-        optionName = map[c];
+        var optionName = map[c];
         options[optionName] = opt[key]; // assign the given value
       } else {
-        error('option not recognized: '+c);
+        error('option not recognized: ' + c, errorOptions || {});
       }
-    }
-  } else {
-    error('options must be strings or key-value pairs');
+    });
   }
   return options;
 }
@@ -127,29 +251,18 @@ exports.parseOptions = parseOptions;
 //   expand(['file*.js']) = ['file1.js', 'file2.js', ...]
 //   (if the files 'file1.js', 'file2.js', etc, exist in the current dir)
 function expand(list) {
+  if (!Array.isArray(list)) {
+    throw new TypeError('must be an array');
+  }
   var expanded = [];
-  list.forEach(function(listEl) {
-    // Wildcard present on directory names ?
-    if(listEl.search(/\*[^\/]*\//) > -1 || listEl.search(/\*\*[^\/]*\//) > -1) {
-      var match = listEl.match(/^([^*]+\/|)(.*)/);
-      var root = match[1];
-      var rest = match[2];
-      var restRegex = rest.replace(/\*\*/g, ".*").replace(/\*/g, "[^\\/]*");
-      restRegex = new RegExp(restRegex);
-
-      _ls('-R', root).filter(function (e) {
-        return restRegex.test(e);
-      }).forEach(function(file) {
-        expanded.push(file);
-      });
-    }
-    // Wildcard present on file names ?
-    else if (listEl.search(/\*/) > -1) {
-      _ls('', listEl).forEach(function(file) {
-        expanded.push(file);
-      });
-    } else {
+  list.forEach(function (listEl) {
+    // Don't expand non-strings
+    if (typeof listEl !== 'string') {
       expanded.push(listEl);
+    } else {
+      var ret = glob.sync(listEl, config.globOptions);
+      // if glob fails, interpret the string literally
+      expanded = expanded.concat(ret.length > 0 ? ret : [listEl]);
     }
   });
   return expanded;
@@ -161,8 +274,9 @@ exports.expand = expand;
 function unlinkSync(file) {
   try {
     fs.unlinkSync(file);
-  } catch(e) {
+  } catch (e) {
     // Try to override file permission
+    /* istanbul ignore next */
     if (e.code === 'EPERM') {
       fs.chmodSync(file, '0666');
       fs.unlinkSync(file);
@@ -176,78 +290,120 @@ exports.unlinkSync = unlinkSync;
 // e.g. 'shelljs_a5f185d0443ca...'
 function randomFileName() {
   function randomHash(count) {
-    if (count === 1)
-      return parseInt(16*Math.random(), 10).toString(16);
-    else {
-      var hash = '';
-      for (var i=0; i<count; i++)
-        hash += randomHash(1);
-      return hash;
+    if (count === 1) {
+      return parseInt(16 * Math.random(), 10).toString(16);
+    }
+    var hash = '';
+    for (var i = 0; i < count; i++) {
+      hash += randomHash(1);
     }
+    return hash;
   }
 
-  return 'shelljs_'+randomHash(20);
+  return 'shelljs_' + randomHash(20);
 }
 exports.randomFileName = randomFileName;
 
-// extend(target_obj, source_obj1 [, source_obj2 ...])
-// Shallow extend, e.g.:
-//    extend({A:1}, {b:2}, {c:3}) returns {A:1, b:2, c:3}
-function extend(target) {
-  var sources = [].slice.call(arguments, 1);
-  sources.forEach(function(source) {
-    for (var key in source)
-      target[key] = source[key];
-  });
-
-  return target;
-}
-exports.extend = extend;
-
-// Common wrapper for all Unix-like commands
+// Common wrapper for all Unix-like commands that performs glob expansion,
+// command-logging, and other nice things
 function wrap(cmd, fn, options) {
-  return function() {
+  options = options || {};
+  if (options.canReceivePipe) {
+    pipeMethods.push(cmd);
+  }
+  return function () {
     var retValue = null;
 
     state.currentCmd = cmd;
     state.error = null;
+    state.errorCode = 0;
 
     try {
       var args = [].slice.call(arguments, 0);
 
+      // Log the command to stderr, if appropriate
       if (config.verbose) {
-        args.unshift(cmd);
-        console.log.apply(console, args);
-        args.shift();
+        console.error.apply(console, [cmd].concat(args));
       }
 
-      if (options && options.notUnix) {
+      // If this is coming from a pipe, let's set the pipedValue (otherwise, set
+      // it to the empty string)
+      state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
+
+      if (options.unix === false) { // this branch is for exec()
         retValue = fn.apply(this, args);
-      } else {
-        if (typeof args[0] === 'object' && args[0].constructor.name === 'Object') {
-          args = args; // object count as options
+      } else { // and this branch is for everything else
+        if (isObject(args[0]) && args[0].constructor.name === 'Object') {
+          // a no-op, allowing the syntax `touch({'-r': file}, ...)`
         } else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
           args.unshift(''); // only add dummy option if '-option' not already present
         }
+
+        // flatten out arrays that are arguments, to make the syntax:
+        //    `cp([file1, file2, file3], dest);`
+        // equivalent to:
+        //    `cp(file1, file2, file3, dest);`
+        args = args.reduce(function (accum, cur) {
+          if (Array.isArray(cur)) {
+            return accum.concat(cur);
+          }
+          accum.push(cur);
+          return accum;
+        }, []);
+
+        // Convert ShellStrings (basically just String objects) to regular strings
+        args = args.map(function (arg) {
+          if (isObject(arg) && arg.constructor.name === 'String') {
+            return arg.toString();
+          }
+          return arg;
+        });
+
         // Expand the '~' if appropriate
         var homeDir = getUserHome();
-        args = args.map(function(arg) {
-          if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~')
+        args = args.map(function (arg) {
+          if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
             return arg.replace(/^~/, homeDir);
-          else
-            return arg;
+          }
+          return arg;
         });
-        retValue = fn.apply(this, args);
+
+        // Perform glob-expansion on all arguments after globStart, but preserve
+        // the arguments before it (like regexes for sed and grep)
+        if (!config.noglob && options.allowGlobbing === true) {
+          args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
+        }
+
+        try {
+          // parse options if options are provided
+          if (isObject(options.cmdOptions)) {
+            args[0] = parseOptions(args[0], options.cmdOptions);
+          }
+
+          retValue = fn.apply(this, args);
+        } catch (e) {
+          /* istanbul ignore else */
+          if (e.msg === 'earlyExit') {
+            retValue = e.retValue;
+          } else {
+            throw e; // this is probably a bug that should be thrown up the call stack
+          }
+        }
       }
     } catch (e) {
+      /* istanbul ignore next */
       if (!state.error) {
         // If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
-        console.log('shell.js: internal error');
-        console.log(e.stack || e);
+        console.error('ShellJS: internal error');
+        console.error(e.stack || e);
         process.exit(1);
       }
-      if (config.fatal)
-        throw e;
+      if (config.fatal) throw e;
+    }
+
+    if (options.wrapOutput &&
+        (typeof retValue === 'string' || Array.isArray(retValue))) {
+      retValue = new ShellString(retValue, state.error, state.errorCode);
     }
 
     state.currentCmd = 'shell.js';
@@ -255,3 +411,40 @@ function wrap(cmd, fn, options) {
   };
 } // wrap
 exports.wrap = wrap;
+
+// This returns all the input that is piped into the current command (or the
+// empty string, if this isn't on the right-hand side of a pipe
+function _readFromPipe() {
+  return state.pipedValue;
+}
+exports.readFromPipe = _readFromPipe;
+
+var DEFAULT_WRAP_OPTIONS = {
+  allowGlobbing: true,
+  canReceivePipe: false,
+  cmdOptions: false,
+  globStart: 1,
+  pipeOnly: false,
+  unix: true,
+  wrapOutput: true,
+  overWrite: false,
+};
+
+// Register a new ShellJS command
+function _register(name, implementation, wrapOptions) {
+  wrapOptions = wrapOptions || {};
+  // If an option isn't specified, use the default
+  wrapOptions = objectAssign({}, DEFAULT_WRAP_OPTIONS, wrapOptions);
+
+  if (shell[name] && !wrapOptions.overWrite) {
+    throw new Error('unable to overwrite `' + name + '` command');
+  }
+
+  if (wrapOptions.pipeOnly) {
+    wrapOptions.canReceivePipe = true;
+    shellMethods[name] = wrap(name, implementation, wrapOptions);
+  } else {
+    shell[name] = wrap(name, implementation, wrapOptions);
+  }
+}
+exports.register = _register;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/cp.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/cp.js b/node_modules/shelljs/src/cp.js
index 54404ef..04c4e57 100644
--- a/node_modules/shelljs/src/cp.js
+++ b/node_modules/shelljs/src/cp.js
@@ -3,42 +3,79 @@ var path = require('path');
 var common = require('./common');
 var os = require('os');
 
+common.register('cp', _cp, {
+  cmdOptions: {
+    'f': '!no_force',
+    'n': 'no_force',
+    'u': 'update',
+    'R': 'recursive',
+    'r': 'recursive',
+    'L': 'followsymlink',
+    'P': 'noFollowsymlink',
+  },
+  wrapOutput: false,
+});
+
 // Buffered file copy, synchronous
 // (Using readFileSync() + writeFileSync() could easily cause a memory overflow
 //  with large files)
-function copyFileSync(srcFile, destFile) {
-  if (!fs.existsSync(srcFile))
+function copyFileSync(srcFile, destFile, options) {
+  if (!fs.existsSync(srcFile)) {
     common.error('copyFileSync: no such file or directory: ' + srcFile);
-
-  var BUF_LENGTH = 64*1024,
-      buf = new Buffer(BUF_LENGTH),
-      bytesRead = BUF_LENGTH,
-      pos = 0,
-      fdr = null,
-      fdw = null;
-
-  try {
-    fdr = fs.openSync(srcFile, 'r');
-  } catch(e) {
-    common.error('copyFileSync: could not read src file ('+srcFile+')');
   }
 
+  // Check the mtimes of the files if the '-u' flag is provided
   try {
-    fdw = fs.openSync(destFile, 'w');
-  } catch(e) {
-    common.error('copyFileSync: could not write to dest file (code='+e.code+'):'+destFile);
+    if (options.update && fs.statSync(srcFile).mtime < fs.statSync(destFile).mtime) {
+      return;
+    }
+  } catch (e) {
+    // If we're here, destFile probably doesn't exist, so just do a normal copy
   }
 
-  while (bytesRead === BUF_LENGTH) {
-    bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos);
-    fs.writeSync(fdw, buf, 0, bytesRead);
-    pos += bytesRead;
-  }
+  if (fs.lstatSync(srcFile).isSymbolicLink() && !options.followsymlink) {
+    try {
+      fs.lstatSync(destFile);
+      common.unlinkSync(destFile); // re-link it
+    } catch (e) {
+      // it doesn't exist, so no work needs to be done
+    }
 
-  fs.closeSync(fdr);
-  fs.closeSync(fdw);
+    var symlinkFull = fs.readlinkSync(srcFile);
+    fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null);
+  } else {
+    var BUF_LENGTH = 64 * 1024;
+    var buf = new Buffer(BUF_LENGTH);
+    var bytesRead = BUF_LENGTH;
+    var pos = 0;
+    var fdr = null;
+    var fdw = null;
 
-  fs.chmodSync(destFile, fs.statSync(srcFile).mode);
+    try {
+      fdr = fs.openSync(srcFile, 'r');
+    } catch (e) {
+      /* istanbul ignore next */
+      common.error('copyFileSync: could not read src file (' + srcFile + ')');
+    }
+
+    try {
+      fdw = fs.openSync(destFile, 'w');
+    } catch (e) {
+      /* istanbul ignore next */
+      common.error('copyFileSync: could not write to dest file (code=' + e.code + '):' + destFile);
+    }
+
+    while (bytesRead === BUF_LENGTH) {
+      bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos);
+      fs.writeSync(fdw, buf, 0, bytesRead);
+      pos += bytesRead;
+    }
+
+    fs.closeSync(fdr);
+    fs.closeSync(fdw);
+
+    fs.chmodSync(destFile, fs.statSync(srcFile).mode);
+  }
 }
 
 // Recursively copies 'sourceDir' into 'destDir'
@@ -49,43 +86,91 @@ function copyFileSync(srcFile, destFile) {
 //
 // Licensed under the MIT License
 // http://www.opensource.org/licenses/mit-license.php
-function cpdirSyncRecursive(sourceDir, destDir, opts) {
+function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) {
   if (!opts) opts = {};
 
-  /* Create the directory where all our junk is moving to; read the mode of the source directory and mirror it */
-  var checkDir = fs.statSync(sourceDir);
+  // Ensure there is not a run away recursive copy
+  if (currentDepth >= common.config.maxdepth) return;
+  currentDepth++;
+
+  // Create the directory where all our junk is moving to; read the mode of the
+  // source directory and mirror it
   try {
+    var checkDir = fs.statSync(sourceDir);
     fs.mkdirSync(destDir, checkDir.mode);
   } catch (e) {
-    //if the directory already exists, that's okay
+    // if the directory already exists, that's okay
     if (e.code !== 'EEXIST') throw e;
   }
 
   var files = fs.readdirSync(sourceDir);
 
   for (var i = 0; i < files.length; i++) {
-    var srcFile = sourceDir + "/" + files[i];
-    var destFile = destDir + "/" + files[i];
+    var srcFile = sourceDir + '/' + files[i];
+    var destFile = destDir + '/' + files[i];
     var srcFileStat = fs.lstatSync(srcFile);
 
+    var symlinkFull;
+    if (opts.followsymlink) {
+      if (cpcheckcycle(sourceDir, srcFile)) {
+        // Cycle link found.
+        console.error('Cycle link found.');
+        symlinkFull = fs.readlinkSync(srcFile);
+        fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null);
+        continue;
+      }
+    }
     if (srcFileStat.isDirectory()) {
       /* recursion this thing right on back. */
-      cpdirSyncRecursive(srcFile, destFile, opts);
-    } else if (srcFileStat.isSymbolicLink()) {
-      var symlinkFull = fs.readlinkSync(srcFile);
-      fs.symlinkSync(symlinkFull, destFile, os.platform() === "win32" ? "junction" : null);
+      cpdirSyncRecursive(srcFile, destFile, currentDepth, opts);
+    } else if (srcFileStat.isSymbolicLink() && !opts.followsymlink) {
+      symlinkFull = fs.readlinkSync(srcFile);
+      try {
+        fs.lstatSync(destFile);
+        common.unlinkSync(destFile); // re-link it
+      } catch (e) {
+        // it doesn't exist, so no work needs to be done
+      }
+      fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null);
+    } else if (srcFileStat.isSymbolicLink() && opts.followsymlink) {
+      srcFileStat = fs.statSync(srcFile);
+      if (srcFileStat.isDirectory()) {
+        cpdirSyncRecursive(srcFile, destFile, currentDepth, opts);
+      } else {
+        copyFileSync(srcFile, destFile, opts);
+      }
     } else {
       /* At this point, we've hit a file actually worth copying... so copy it on over. */
       if (fs.existsSync(destFile) && opts.no_force) {
         common.log('skipping existing file: ' + files[i]);
       } else {
-        copyFileSync(srcFile, destFile);
+        copyFileSync(srcFile, destFile, opts);
       }
     }
-
   } // for files
 } // cpdirSyncRecursive
 
+function cpcheckcycle(sourceDir, srcFile) {
+  var srcFileStat = fs.lstatSync(srcFile);
+  if (srcFileStat.isSymbolicLink()) {
+    // Do cycle check. For example:
+    //   $ mkdir -p 1/2/3/4
+    //   $ cd  1/2/3/4
+    //   $ ln -s ../../3 link
+    //   $ cd ../../../..
+    //   $ cp -RL 1 copy
+    var cyclecheck = fs.statSync(srcFile);
+    if (cyclecheck.isDirectory()) {
+      var sourcerealpath = fs.realpathSync(sourceDir);
+      var symlinkrealpath = fs.realpathSync(srcFile);
+      var re = new RegExp(symlinkrealpath);
+      if (re.test(sourcerealpath)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
 
 //@
 //@ ### cp([options,] source [, source ...], dest)
@@ -94,117 +179,100 @@ function cpdirSyncRecursive(sourceDir, destDir, opts) {
 //@
 //@ + `-f`: force (default behavior)
 //@ + `-n`: no-clobber
-//@ + `-r, -R`: recursive
+//@ + `-u`: only copy if source is newer than dest
+//@ + `-r`, `-R`: recursive
+//@ + `-L`: follow symlinks
+//@ + `-P`: don't follow symlinks
 //@
 //@ Examples:
 //@
 //@ ```javascript
 //@ cp('file1', 'dir1');
+//@ cp('-R', 'path/to/dir/', '~/newCopy/');
 //@ cp('-Rf', '/tmp/*', '/usr/local/*', '/home/tmp');
 //@ cp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above
 //@ ```
 //@
-//@ Copies files. The wildcard `*` is accepted.
+//@ Copies files.
 function _cp(options, sources, dest) {
-  options = common.parseOptions(options, {
-    'f': '!no_force',
-    'n': 'no_force',
-    'R': 'recursive',
-    'r': 'recursive'
-  });
+  // If we're missing -R, it actually implies -L (unless -P is explicit)
+  if (options.followsymlink) {
+    options.noFollowsymlink = false;
+  }
+  if (!options.recursive && !options.noFollowsymlink) {
+    options.followsymlink = true;
+  }
 
   // Get sources, dest
   if (arguments.length < 3) {
     common.error('missing <source> and/or <dest>');
-  } else if (arguments.length > 3) {
+  } else {
     sources = [].slice.call(arguments, 1, arguments.length - 1);
     dest = arguments[arguments.length - 1];
-  } else if (typeof sources === 'string') {
-    sources = [sources];
-  } else if ('length' in sources) {
-    sources = sources; // no-op for array
-  } else {
-    common.error('invalid arguments');
   }
 
-  var exists = fs.existsSync(dest),
-      stats = exists && fs.statSync(dest);
+  var destExists = fs.existsSync(dest);
+  var destStat = destExists && fs.statSync(dest);
 
   // Dest is not existing dir, but multiple sources given
-  if ((!exists || !stats.isDirectory()) && sources.length > 1)
+  if ((!destExists || !destStat.isDirectory()) && sources.length > 1) {
     common.error('dest is not a directory (too many sources)');
-
-  // Dest is an existing file, but no -f given
-  if (exists && stats.isFile() && options.no_force)
-    common.error('dest file already exists: ' + dest);
-
-  if (options.recursive) {
-    // Recursive allows the shortcut syntax "sourcedir/" for "sourcedir/*"
-    // (see Github issue #15)
-    sources.forEach(function(src, i) {
-      if (src[src.length - 1] === '/') {
-        sources[i] += '*';
-      // If src is a directory and dest doesn't exist, 'cp -r src dest' should copy src/* into dest
-      } else if (fs.statSync(src).isDirectory() && !exists) {
-        sources[i] += '/*';
-      }
-    });
-
-    // Create dest
-    try {
-      fs.mkdirSync(dest, parseInt('0777', 8));
-    } catch (e) {
-      // like Unix's cp, keep going even if we can't create dest dir
-    }
   }
 
-  sources = common.expand(sources);
+  // Dest is an existing file, but -n is given
+  if (destExists && destStat.isFile() && options.no_force) {
+    return new common.ShellString('', '', 0);
+  }
 
-  sources.forEach(function(src) {
+  sources.forEach(function (src) {
     if (!fs.existsSync(src)) {
-      common.error('no such file or directory: '+src, true);
+      common.error('no such file or directory: ' + src, { continue: true });
       return; // skip file
     }
-
-    // If here, src exists
-    if (fs.statSync(src).isDirectory()) {
+    var srcStat = fs.statSync(src);
+    if (!options.noFollowsymlink && srcStat.isDirectory()) {
       if (!options.recursive) {
         // Non-Recursive
-        common.log(src + ' is a directory (not copied)');
+        common.error("omitting directory '" + src + "'", { continue: true });
       } else {
         // Recursive
         // 'cp /a/source dest' should create 'source' in 'dest'
-        var newDest = path.join(dest, path.basename(src)),
-            checkDir = fs.statSync(src);
+        var newDest = (destStat && destStat.isDirectory()) ?
+            path.join(dest, path.basename(src)) :
+            dest;
+
         try {
-          fs.mkdirSync(newDest, checkDir.mode);
+          fs.statSync(path.dirname(dest));
+          cpdirSyncRecursive(src, newDest, 0, { no_force: options.no_force, followsymlink: options.followsymlink });
         } catch (e) {
-          //if the directory already exists, that's okay
-          if (e.code !== 'EEXIST') {
-            common.error('dest file no such file or directory: ' + newDest, true);
-            throw e;
-          }
+          /* istanbul ignore next */
+          common.error("cannot create directory '" + dest + "': No such file or directory");
         }
+      }
+    } else {
+      // If here, src is a file
 
-        cpdirSyncRecursive(src, newDest, {no_force: options.no_force});
+      // When copying to '/path/dir':
+      //    thisDest = '/path/dir/file1'
+      var thisDest = dest;
+      if (destStat && destStat.isDirectory()) {
+        thisDest = path.normalize(dest + '/' + path.basename(src));
       }
-      return; // done with dir
-    }
 
-    // If here, src is a file
+      if (fs.existsSync(thisDest) && options.no_force) {
+        return; // skip file
+      }
 
-    // When copying to '/path/dir':
-    //    thisDest = '/path/dir/file1'
-    var thisDest = dest;
-    if (fs.existsSync(dest) && fs.statSync(dest).isDirectory())
-      thisDest = path.normalize(dest + '/' + path.basename(src));
+      if (path.relative(src, thisDest) === '') {
+        // a file cannot be copied to itself, but we want to continue copying other files
+        common.error("'" + thisDest + "' and '" + src + "' are the same file", { continue: true });
+        return;
+      }
 
-    if (fs.existsSync(thisDest) && options.no_force) {
-      common.error('dest file already exists: ' + thisDest, true);
-      return; // skip file
+      copyFileSync(src, thisDest, options);
     }
-
-    copyFileSync(src, thisDest);
   }); // forEach(src)
+
+  return new common.ShellString('', common.state.error, common.state.errorCode);
 }
 module.exports = _cp;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/dirs.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/dirs.js b/node_modules/shelljs/src/dirs.js
index 58fae8b..3806c14 100644
--- a/node_modules/shelljs/src/dirs.js
+++ b/node_modules/shelljs/src/dirs.js
@@ -2,6 +2,16 @@ var common = require('./common');
 var _cd = require('./cd');
 var path = require('path');
 
+common.register('dirs', _dirs, {
+  wrapOutput: false,
+});
+common.register('pushd', _pushd, {
+  wrapOutput: false,
+});
+common.register('popd', _popd, {
+  wrapOutput: false,
+});
+
 // Pushd/popd/dirs internals
 var _dirStack = [];
 
@@ -13,9 +23,8 @@ function _parseStackIndex(index) {
   if (_isStackIndex(index)) {
     if (Math.abs(index) < _dirStack.length + 1) { // +1 for pwd
       return (/^-/).test(index) ? Number(index) - 1 : Number(index);
-    } else {
-      common.error(index + ': directory stack index out of range');
     }
+    common.error(index + ': directory stack index out of range');
   } else {
     common.error(index + ': invalid number');
   }
@@ -54,7 +63,7 @@ function _pushd(options, dir) {
   }
 
   options = common.parseOptions(options, {
-    'n' : 'no-cd'
+    'n': 'no-cd',
   });
 
   var dirs = _actualDirStack();
@@ -120,7 +129,7 @@ function _popd(options, index) {
   }
 
   options = common.parseOptions(options, {
-    'n' : 'no-cd'
+    'n': 'no-cd',
   });
 
   if (!_dirStack.length) {
@@ -163,10 +172,10 @@ function _dirs(options, index) {
   }
 
   options = common.parseOptions(options, {
-    'c' : 'clear'
+    'c': 'clear',
   });
 
-  if (options['clear']) {
+  if (options.clear) {
     _dirStack = [];
     return _dirStack;
   }

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/echo.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/echo.js b/node_modules/shelljs/src/echo.js
index b574adc..2b0e7d9 100644
--- a/node_modules/shelljs/src/echo.js
+++ b/node_modules/shelljs/src/echo.js
@@ -1,7 +1,14 @@
 var common = require('./common');
 
+common.register('echo', _echo, {
+  allowGlobbing: false,
+});
+
+//@
+//@ ### echo([options,] string [, string ...])
+//@ Available options:
 //@
-//@ ### echo(string [, string ...])
+//@ + `-e`: interpret backslash escapes (default)
 //@
 //@ Examples:
 //@
@@ -12,9 +19,16 @@ var common = require('./common');
 //@
 //@ Prints string to stdout, and returns string with additional utility methods
 //@ like `.to()`.
-function _echo() {
-  var messages = [].slice.call(arguments, 0);
+function _echo(opts, messages) {
+  // allow strings starting with '-', see issue #20
+  messages = [].slice.call(arguments, opts ? 0 : 1);
+
+  if (messages[0] === '-e') {
+    // ignore -e
+    messages.shift();
+  }
+
   console.log.apply(console, messages);
-  return common.ShellString(messages.join(' '));
+  return messages.join(' ');
 }
 module.exports = _echo;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/error.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/error.js b/node_modules/shelljs/src/error.js
index 112563d..507c86d 100644
--- a/node_modules/shelljs/src/error.js
+++ b/node_modules/shelljs/src/error.js
@@ -2,8 +2,12 @@ var common = require('./common');
 
 //@
 //@ ### error()
-//@ Tests if error occurred in the last command. Returns `null` if no error occurred,
-//@ otherwise returns string explaining the error
+//@ Tests if error occurred in the last command. Returns a truthy value if an
+//@ error returned and a falsy value otherwise.
+//@
+//@ **Note**: do not rely on the
+//@ return value to be an error message. If you need the last error message, use
+//@ the `.stderr` attribute from the last command's return value instead.
 function error() {
   return common.state.error;
 }

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/exec.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/exec.js b/node_modules/shelljs/src/exec.js
index 4174adb..5d360e8 100644
--- a/node_modules/shelljs/src/exec.js
+++ b/node_modules/shelljs/src/exec.js
@@ -5,85 +5,106 @@ var path = require('path');
 var fs = require('fs');
 var child = require('child_process');
 
-var DEFAULT_MAXBUFFER_SIZE = 20*1024*1024;
+var DEFAULT_MAXBUFFER_SIZE = 20 * 1024 * 1024;
+
+common.register('exec', _exec, {
+  unix: false,
+  canReceivePipe: true,
+  wrapOutput: false,
+});
 
 // Hack to run child_process.exec() synchronously (sync avoids callback hell)
 // Uses a custom wait loop that checks for a flag file, created when the child process is done.
 // (Can't do a wait loop that checks for internal Node variables/messages as
 // Node is single-threaded; callbacks and other internal state changes are done in the
 // event loop).
-function execSync(cmd, opts) {
+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 stdoutFile = path.resolve(tempDir+'/'+common.randomFileName()),
-      stderrFile = path.resolve(tempDir+'/'+common.randomFileName()),
-      codeFile = path.resolve(tempDir+'/'+common.randomFileName()),
-      scriptFile = path.resolve(tempDir+'/'+common.randomFileName()),
-      sleepFile = path.resolve(tempDir+'/'+common.randomFileName());
+  var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName());
+  var stderrFile = path.resolve(tempDir + '/' + common.randomFileName());
+  var codeFile = path.resolve(tempDir + '/' + common.randomFileName());
+  var scriptFile = path.resolve(tempDir + '/' + common.randomFileName());
+  var sleepFile = path.resolve(tempDir + '/' + common.randomFileName());
 
   opts = common.extend({
     silent: common.config.silent,
-    cwd: _pwd(),
+    cwd: _pwd().toString(),
     env: process.env,
-    maxBuffer: DEFAULT_MAXBUFFER_SIZE
+    maxBuffer: DEFAULT_MAXBUFFER_SIZE,
   }, opts);
 
-  var previousStdoutContent = '',
-      previousStderrContent = '';
+  var previousStdoutContent = '';
+  var previousStderrContent = '';
   // Echoes stdout and stderr changes from running process, if not silent
   function updateStream(streamFile) {
-    if (opts.silent || !fs.existsSync(streamFile))
+    if (opts.silent || !fs.existsSync(streamFile)) {
       return;
+    }
 
-    var previousStreamContent,
-        proc_stream;
+    var previousStreamContent;
+    var procStream;
     if (streamFile === stdoutFile) {
       previousStreamContent = previousStdoutContent;
-      proc_stream = process.stdout;
+      procStream = process.stdout;
     } else { // assume stderr
       previousStreamContent = previousStderrContent;
-      proc_stream = process.stderr;
+      procStream = process.stderr;
     }
 
     var streamContent = fs.readFileSync(streamFile, 'utf8');
     // No changes since last time?
-    if (streamContent.length <= previousStreamContent.length)
+    if (streamContent.length <= previousStreamContent.length) {
       return;
+    }
 
-    proc_stream.write(streamContent.substr(previousStreamContent.length));
+    procStream.write(streamContent.substr(previousStreamContent.length));
     previousStreamContent = streamContent;
   }
 
-  function escape(str) {
-    return (str+'').replace(/([\\"'])/g, "\\$1").replace(/\0/g, "\\0");
-  }
-
   if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile);
   if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile);
   if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile);
   if (fs.existsSync(codeFile)) common.unlinkSync(codeFile);
 
-  var execCommand = '"'+process.execPath+'" '+scriptFile;
+  var execCommand = JSON.stringify(common.config.execPath) + ' ' + JSON.stringify(scriptFile);
   var script;
 
+  opts.cwd = path.resolve(opts.cwd);
+  var optString = JSON.stringify(opts);
+
   if (typeof child.execSync === 'function') {
     script = [
       "var child = require('child_process')",
       "  , fs = require('fs');",
-      "var childProcess = child.exec('"+escape(cmd)+"', {env: process.env, maxBuffer: "+opts.maxBuffer+"}, function(err) {",
-      "  fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0');",
-      "});",
-      "var stdoutStream = fs.createWriteStream('"+escape(stdoutFile)+"');",
-      "var stderrStream = fs.createWriteStream('"+escape(stderrFile)+"');",
-      "childProcess.stdout.pipe(stdoutStream, {end: false});",
-      "childProcess.stderr.pipe(stderrStream, {end: false});",
-      "childProcess.stdout.pipe(process.stdout);",
-      "childProcess.stderr.pipe(process.stderr);",
-      "var stdoutEnded = false, stderrEnded = false;",
-      "function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }",
-      "function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }",
-      "childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });",
-      "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });"
-    ].join('\n');
+      'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {',
+      '  var fname = ' + JSON.stringify(codeFile) + ';',
+      '  if (!err) {',
+      '    fs.writeFileSync(fname, "0");',
+      '  } else if (err.code === undefined) {',
+      '    fs.writeFileSync(fname, "1");',
+      '  } else {',
+      '    fs.writeFileSync(fname, err.code.toString());',
+      '  }',
+      '});',
+      'var stdoutStream = fs.createWriteStream(' + JSON.stringify(stdoutFile) + ');',
+      'var stderrStream = fs.createWriteStream(' + JSON.stringify(stderrFile) + ');',
+      'childProcess.stdout.pipe(stdoutStream, {end: false});',
+      'childProcess.stderr.pipe(stderrStream, {end: false});',
+      'childProcess.stdout.pipe(process.stdout);',
+      'childProcess.stderr.pipe(process.stderr);',
+    ].join('\n') +
+      (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n') +
+      [
+        'var stdoutEnded = false, stderrEnded = false;',
+        'function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }',
+        'function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }',
+        "childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });",
+        "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });",
+      ].join('\n');
 
     fs.writeFileSync(scriptFile, script);
 
@@ -94,17 +115,34 @@ function execSync(cmd, opts) {
     }
 
     // Welcome to the future
-    child.execSync(execCommand, opts);
+    try {
+      child.execSync(execCommand, opts);
+    } catch (e) {
+      // Clean up immediately if we have an exception
+      try { common.unlinkSync(scriptFile); } catch (e2) {}
+      try { common.unlinkSync(stdoutFile); } catch (e2) {}
+      try { common.unlinkSync(stderrFile); } catch (e2) {}
+      try { common.unlinkSync(codeFile); } catch (e2) {}
+      throw e;
+    }
   } else {
-    cmd += ' > '+stdoutFile+' 2> '+stderrFile; // works on both win/unix
+    cmd += ' > ' + stdoutFile + ' 2> ' + stderrFile; // works on both win/unix
 
     script = [
       "var child = require('child_process')",
       "  , fs = require('fs');",
-      "var childProcess = child.exec('"+escape(cmd)+"', {env: process.env, maxBuffer: "+opts.maxBuffer+"}, function(err) {",
-      "  fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0');",
-      "});"
-    ].join('\n');
+      'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {',
+      '  var fname = ' + JSON.stringify(codeFile) + ';',
+      '  if (!err) {',
+      '    fs.writeFileSync(fname, "0");',
+      '  } else if (err.code === undefined) {',
+      '    fs.writeFileSync(fname, "1");',
+      '  } else {',
+      '    fs.writeFileSync(fname, err.code.toString());',
+      '  }',
+      '});',
+    ].join('\n') +
+      (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n');
 
     fs.writeFileSync(scriptFile, script);
 
@@ -117,6 +155,7 @@ function execSync(cmd, opts) {
     while (!fs.existsSync(codeFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); }
     while (!fs.existsSync(stdoutFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); }
     while (!fs.existsSync(stderrFile)) { updateStream(stderrFile); fs.writeFileSync(sleepFile, 'a'); }
+    try { common.unlinkSync(sleepFile); } catch (e) {}
   }
 
   // At this point codeFile exists, but it's not necessarily flushed yet.
@@ -130,53 +169,53 @@ function execSync(cmd, opts) {
   var stderr = fs.readFileSync(stderrFile, 'utf8');
 
   // No biggie if we can't erase the files now -- they're in a temp dir anyway
-  try { common.unlinkSync(scriptFile); } catch(e) {}
-  try { common.unlinkSync(stdoutFile); } catch(e) {}
-  try { common.unlinkSync(stderrFile); } catch(e) {}
-  try { common.unlinkSync(codeFile); } catch(e) {}
-  try { common.unlinkSync(sleepFile); } catch(e) {}
-
-  // some shell return codes are defined as errors, per http://tldp.org/LDP/abs/html/exitcodes.html
-  if (code === 1 || code === 2 || code >= 126)  {
-      common.error('', true); // unix/shell doesn't really give an error message after non-zero exit codes
+  try { common.unlinkSync(scriptFile); } catch (e) {}
+  try { common.unlinkSync(stdoutFile); } catch (e) {}
+  try { common.unlinkSync(stderrFile); } catch (e) {}
+  try { common.unlinkSync(codeFile); } catch (e) {}
+
+  if (code !== 0) {
+    common.error('', code, { continue: true });
   }
-  // True if successful, false if not
-  var obj = {
-    code: code,
-    output: stdout, // deprecated
-    stdout: stdout,
-    stderr: stderr
-  };
+  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, callback) {
+function execAsync(cmd, opts, pipe, callback) {
   var stdout = '';
   var stderr = '';
 
   opts = common.extend({
     silent: common.config.silent,
-    cwd: _pwd(),
+    cwd: _pwd().toString(),
     env: process.env,
-    maxBuffer: DEFAULT_MAXBUFFER_SIZE
+    maxBuffer: DEFAULT_MAXBUFFER_SIZE,
   }, opts);
 
-  var c = child.exec(cmd, opts, function(err) {
-    if (callback)
-      callback(err ? err.code : 0, stdout, stderr);
+  var c = child.exec(cmd, opts, function (err) {
+    if (callback) {
+      if (!err) {
+        callback(0, stdout, stderr);
+      } else if (err.code === undefined) {
+        // See issue #536
+        callback(1, stdout, stderr);
+      } else {
+        callback(err.code, stdout, stderr);
+      }
+    }
   });
 
-  c.stdout.on('data', function(data) {
+  if (pipe) c.stdin.end(pipe);
+
+  c.stdout.on('data', function (data) {
     stdout += data;
-    if (!opts.silent)
-      process.stdout.write(data);
+    if (!opts.silent) process.stdout.write(data);
   });
 
-  c.stderr.on('data', function(data) {
+  c.stderr.on('data', function (data) {
     stderr += data;
-    if (!opts.silent)
-      process.stderr.write(data);
+    if (!opts.silent) process.stderr.write(data);
   });
 
   return c;
@@ -189,7 +228,7 @@ function execAsync(cmd, opts, callback) {
 //@ + `async`: Asynchronous execution. If a callback is provided, it will be set to
 //@   `true`, regardless of the passed value.
 //@ + `silent`: Do not echo program output to console.
-//@ + and any option available to NodeJS's
+//@ + 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:
@@ -210,16 +249,22 @@ function execAsync(cmd, opts, callback) {
 //@ ```
 //@
 //@ Executes the given `command` _synchronously_, unless otherwise specified.  When in synchronous
-//@ mode returns the object `{ code:..., stdout:... , stderr:... }`, containing the program's
-//@ `stdout`, `stderr`, and its exit `code`. Otherwise returns the child process object,
-//@ and the `callback` gets the arguments `(code, stdout, stderr)`.
+//@ 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` gets 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.
 //@
 //@ **Note:** For long-lived processes, it's best to run `exec()` asynchronously as
 //@ the current synchronous implementation uses a lot of CPU. This should be getting
 //@ fixed soon.
 function _exec(command, options, callback) {
-  if (!command)
-    common.error('must specify command');
+  options = options || {};
+  if (!command) common.error('must specify command');
+
+  var pipe = common.readFromPipe();
 
   // Callback is defined instead of options.
   if (typeof options === 'function') {
@@ -234,14 +279,15 @@ function _exec(command, options, callback) {
 
   options = common.extend({
     silent: common.config.silent,
-    async: false
+    async: false,
   }, options);
 
   try {
-    if (options.async)
-      return execAsync(command, options, callback);
-    else
-      return execSync(command, options);
+    if (options.async) {
+      return execAsync(command, options, pipe, callback);
+    } else {
+      return execSync(command, options, pipe);
+    }
   } catch (e) {
     common.error('internal error');
   }

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/find.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/find.js b/node_modules/shelljs/src/find.js
index c96fb2f..625aa29 100644
--- a/node_modules/shelljs/src/find.js
+++ b/node_modules/shelljs/src/find.js
@@ -1,7 +1,10 @@
 var fs = require('fs');
+var path = require('path');
 var common = require('./common');
 var _ls = require('./ls');
 
+common.register('find', _find, {});
+
 //@
 //@ ### find(path [, path ...])
 //@ ### find(path_array)
@@ -18,30 +21,37 @@ var _ls = require('./ls');
 //@ The main difference from `ls('-R', path)` is that the resulting file names
 //@ include the base directories, e.g. `lib/resources/file1` instead of just `file1`.
 function _find(options, paths) {
-  if (!paths)
+  if (!paths) {
     common.error('no path specified');
-  else if (typeof paths === 'object')
-    paths = paths; // assume array
-  else if (typeof paths === 'string')
+  } else if (typeof paths === 'string') {
     paths = [].slice.call(arguments, 1);
+  }
 
   var list = [];
 
   function pushFile(file) {
-    if (common.platform === 'win')
+    if (common.platform === 'win') {
       file = file.replace(/\\/g, '/');
+    }
     list.push(file);
   }
 
   // why not simply do ls('-R', paths)? because the output wouldn't give the base dirs
   // to get the base dir in the output, we need instead ls('-R', 'dir/*') for every directory
 
-  paths.forEach(function(file) {
+  paths.forEach(function (file) {
+    var stat;
+    try {
+      stat = fs.statSync(file);
+    } catch (e) {
+      common.error('no such file or directory: ' + file);
+    }
+
     pushFile(file);
 
-    if (fs.statSync(file).isDirectory()) {
-      _ls('-RA', file+'/*').forEach(function(subfile) {
-        pushFile(subfile);
+    if (stat.isDirectory()) {
+      _ls({ recursive: true, all: true }, file).forEach(function (subfile) {
+        pushFile(path.join(file, subfile));
       });
     }
   });

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/grep.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/grep.js b/node_modules/shelljs/src/grep.js
index 78008ce..30842bc 100644
--- a/node_modules/shelljs/src/grep.js
+++ b/node_modules/shelljs/src/grep.js
@@ -1,12 +1,22 @@
 var common = require('./common');
 var fs = require('fs');
 
+common.register('grep', _grep, {
+  globStart: 2, // don't glob-expand the regex
+  canReceivePipe: true,
+  cmdOptions: {
+    'v': 'inverse',
+    'l': 'nameOnly',
+  },
+});
+
 //@
 //@ ### grep([options,] regex_filter, file [, file ...])
 //@ ### grep([options,] regex_filter, file_array)
 //@ Available options:
 //@
 //@ + `-v`: Inverse the sense of the regex and print the lines not matching the criteria.
+//@ + `-l`: Print only filenames of matching files
 //@
 //@ Examples:
 //@
@@ -16,37 +26,42 @@ var fs = require('fs');
 //@ ```
 //@
 //@ Reads input string from given files and returns a string containing all lines of the
-//@ file that match the given `regex_filter`. Wildcard `*` accepted.
+//@ file that match the given `regex_filter`.
 function _grep(options, regex, files) {
-  options = common.parseOptions(options, {
-    'v': 'inverse'
-  });
+  // Check if this is coming from a pipe
+  var pipe = common.readFromPipe();
 
-  if (!files)
-    common.error('no paths given');
+  if (!files && !pipe) common.error('no paths given', 2);
 
-  if (typeof files === 'string')
-    files = [].slice.call(arguments, 2);
-  // if it's array leave it as it is
+  files = [].slice.call(arguments, 2);
 
-  files = common.expand(files);
+  if (pipe) {
+    files.unshift('-');
+  }
 
-  var grep = '';
-  files.forEach(function(file) {
-    if (!fs.existsSync(file)) {
-      common.error('no such file or directory: ' + file, true);
+  var grep = [];
+  files.forEach(function (file) {
+    if (!fs.existsSync(file) && file !== '-') {
+      common.error('no such file or directory: ' + file, 2, { continue: true });
       return;
     }
 
-    var contents = fs.readFileSync(file, 'utf8'),
-        lines = contents.split(/\r*\n/);
-    lines.forEach(function(line) {
-      var matched = line.match(regex);
-      if ((options.inverse && !matched) || (!options.inverse && matched))
-        grep += line + '\n';
-    });
+    var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8');
+    var lines = contents.split(/\r*\n/);
+    if (options.nameOnly) {
+      if (contents.match(regex)) {
+        grep.push(file);
+      }
+    } else {
+      lines.forEach(function (line) {
+        var matched = line.match(regex);
+        if ((options.inverse && !matched) || (!options.inverse && matched)) {
+          grep.push(line);
+        }
+      });
+    }
   });
 
-  return common.ShellString(grep);
+  return grep.join('\n') + '\n';
 }
 module.exports = _grep;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/ln.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/ln.js b/node_modules/shelljs/src/ln.js
index 878fda1..7393d9f 100644
--- a/node_modules/shelljs/src/ln.js
+++ b/node_modules/shelljs/src/ln.js
@@ -2,6 +2,13 @@ var fs = require('fs');
 var path = require('path');
 var common = require('./common');
 
+common.register('ln', _ln, {
+  cmdOptions: {
+    's': 'symlink',
+    'f': 'force',
+  },
+});
+
 //@
 //@ ### ln([options,] source, dest)
 //@ Available options:
@@ -18,11 +25,6 @@ var common = require('./common');
 //@
 //@ Links source to dest. Use -f to force the link, should dest already exist.
 function _ln(options, source, dest) {
-  options = common.parseOptions(options, {
-    's': 'symlink',
-    'f': 'force'
-  });
-
   if (!source || !dest) {
     common.error('Missing <source> and/or <dest>');
   }
@@ -34,7 +36,7 @@ function _ln(options, source, dest) {
 
   if (fs.existsSync(dest)) {
     if (!options.force) {
-      common.error('Destination file exists', true);
+      common.error('Destination file exists', { continue: true });
     }
 
     fs.unlinkSync(dest);
@@ -45,19 +47,19 @@ function _ln(options, source, dest) {
     var linkType = isWindows ? 'file' : null;
     var resolvedSourcePath = isAbsolute ? sourcePath : path.resolve(process.cwd(), path.dirname(dest), source);
     if (!fs.existsSync(resolvedSourcePath)) {
-      common.error('Source file does not exist', true);
+      common.error('Source file does not exist', { continue: true });
     } else if (isWindows && fs.statSync(resolvedSourcePath).isDirectory()) {
-      linkType =  'junction';
+      linkType = 'junction';
     }
 
     try {
-      fs.symlinkSync(linkType === 'junction' ? resolvedSourcePath: source, dest, linkType);
+      fs.symlinkSync(linkType === 'junction' ? resolvedSourcePath : source, dest, linkType);
     } catch (err) {
       common.error(err.message);
     }
   } else {
     if (!fs.existsSync(source)) {
-      common.error('Source file does not exist', true);
+      common.error('Source file does not exist', { continue: true });
     }
     try {
       fs.linkSync(source, dest);
@@ -65,5 +67,6 @@ function _ln(options, source, dest) {
       common.error(err.message);
     }
   }
+  return '';
 }
 module.exports = _ln;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/ls.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/ls.js b/node_modules/shelljs/src/ls.js
index 6a54b3a..bb1b6a7 100644
--- a/node_modules/shelljs/src/ls.js
+++ b/node_modules/shelljs/src/ls.js
@@ -1,8 +1,20 @@
 var path = require('path');
 var fs = require('fs');
 var common = require('./common');
-var _cd = require('./cd');
-var _pwd = require('./pwd');
+var glob = require('glob');
+
+var globPatternRecursive = path.sep + '**';
+
+common.register('ls', _ls, {
+  cmdOptions: {
+    'R': 'recursive',
+    'A': 'all',
+    'L': 'link',
+    'a': 'all_deprecated',
+    'd': 'directory',
+    'l': 'long',
+  },
+});
 
 //@
 //@ ### ls([options,] [path, ...])
@@ -11,6 +23,7 @@ var _pwd = require('./pwd');
 //@
 //@ + `-R`: recursive
 //@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`)
+//@ + `-L`: follow symlinks
 //@ + `-d`: list directories themselves, not their contents
 //@ + `-l`: list objects representing each file, each with fields containing `ls
 //@         -l` output fields. See
@@ -28,14 +41,6 @@ var _pwd = require('./pwd');
 //@
 //@ Returns array of files in the given path, or in current directory if no path provided.
 function _ls(options, paths) {
-  options = common.parseOptions(options, {
-    'R': 'recursive',
-    'A': 'all',
-    'a': 'all_deprecated',
-    'd': 'directory',
-    'l': 'long'
-  });
-
   if (options.all_deprecated) {
     // We won't support the -a option as it's hard to image why it's useful
     // (it includes '.' and '..' in addition to '.*' files)
@@ -44,125 +49,78 @@ function _ls(options, paths) {
     options.all = true;
   }
 
-  if (!paths)
+  if (!paths) {
     paths = ['.'];
-  else if (typeof paths === 'object')
-    paths = paths; // assume array
-  else if (typeof paths === 'string')
+  } else {
     paths = [].slice.call(arguments, 1);
+  }
 
   var list = [];
 
-  // Conditionally pushes file to list - returns true if pushed, false otherwise
-  // (e.g. prevents hidden files to be included unless explicitly told so)
-  function pushFile(file, query) {
-    var name = file.name || file;
-    // hidden file?
-    if (path.basename(name)[0] === '.') {
-      // not explicitly asking for hidden files?
-      if (!options.all && !(path.basename(query)[0] === '.' && path.basename(query).length > 1))
-        return false;
+  function pushFile(abs, relName, stat) {
+    if (process.platform === 'win32') {
+      relName = relName.replace(/\\/g, '/');
     }
-
-    if (common.platform === 'win')
-      name = name.replace(/\\/g, '/');
-
-    if (file.name) {
-      file.name = name;
+    if (options.long) {
+      stat = stat || (options.link ? fs.statSync(abs) : fs.lstatSync(abs));
+      list.push(addLsAttributes(relName, stat));
     } else {
-      file = name;
+      // list.push(path.relative(rel || '.', file));
+      list.push(relName);
     }
-    list.push(file);
-    return true;
   }
 
-  paths.forEach(function(p) {
-    if (fs.existsSync(p)) {
-      var stats = ls_stat(p);
-      // Simple file?
-      if (stats.isFile()) {
-        if (options.long) {
-          pushFile(stats, p);
-        } else {
-          pushFile(p, p);
-        }
-        return; // continue
-      }
+  paths.forEach(function (p) {
+    var stat;
 
-      // Simple dir?
-      if (options.directory) {
-        pushFile(p, p);
-        return;
-      } else if (stats.isDirectory()) {
-        // Iterate over p contents
-        fs.readdirSync(p).forEach(function(file) {
-          var orig_file = file;
-          if (options.long)
-            file = ls_stat(path.join(p, file));
-          if (!pushFile(file, p))
-            return;
+    try {
+      stat = options.link ? fs.statSync(p) : fs.lstatSync(p);
+    } catch (e) {
+      common.error('no such file or directory: ' + p, 2, { continue: true });
+      return;
+    }
 
-          // Recursive?
-          if (options.recursive) {
-            var oldDir = _pwd();
-            _cd('', p);
-            if (fs.statSync(orig_file).isDirectory())
-              list = list.concat(_ls('-R'+(options.all?'A':''), orig_file+'/*'));
-            _cd('', oldDir);
+    // If the stat succeeded
+    if (stat.isDirectory() && !options.directory) {
+      if (options.recursive) {
+        // use glob, because it's simple
+        glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link })
+          .forEach(function (item) {
+            // Glob pattern returns the directory itself and needs to be filtered out.
+            if (path.relative(p, item)) {
+              pushFile(item, path.relative(p, item));
+            }
+          });
+      } else if (options.all) {
+        // use fs.readdirSync, because it's fast
+        fs.readdirSync(p).forEach(function (item) {
+          pushFile(path.join(p, item), item);
+        });
+      } else {
+        // use fs.readdirSync and then filter out secret files
+        fs.readdirSync(p).forEach(function (item) {
+          if (item[0] !== '.') {
+            pushFile(path.join(p, item), item);
           }
         });
-        return; // continue
       }
+    } else {
+      pushFile(p, p, stat);
     }
-
-    // p does not exist - possible wildcard present
-
-    var basename = path.basename(p);
-    var dirname = path.dirname(p);
-    // Wildcard present on an existing dir? (e.g. '/tmp/*.js')
-    if (basename.search(/\*/) > -1 && fs.existsSync(dirname) && fs.statSync(dirname).isDirectory) {
-      // Escape special regular expression chars
-      var regexp = basename.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\.|\+|\?)/g, '\\$1');
-      // Translates wildcard into regex
-      regexp = '^' + regexp.replace(/\*/g, '.*') + '$';
-      // Iterate over directory contents
-      fs.readdirSync(dirname).forEach(function(file) {
-        if (file.match(new RegExp(regexp))) {
-          var file_path = path.join(dirname,  file);
-          file_path = options.long ? ls_stat(file_path) : file_path;
-          if (file_path.name)
-            file_path.name = path.normalize(file_path.name);
-          else
-            file_path = path.normalize(file_path);
-          if (!pushFile(file_path, basename))
-            return;
-
-          // Recursive?
-          if (options.recursive) {
-            var pp = dirname + '/' + file;
-            if (fs.lstatSync(pp).isDirectory())
-              list = list.concat(_ls('-R'+(options.all?'A':''), pp+'/*'));
-          } // recursive
-        } // if file matches
-      }); // forEach
-      return;
-    }
-
-    common.error('no such file or directory: ' + p, true);
   });
 
+  // Add methods, to make this more compatible with ShellStrings
   return list;
 }
-module.exports = _ls;
 
-
-function ls_stat(path) {
-  var stats = fs.statSync(path);
+function addLsAttributes(pathName, stats) {
   // Note: this object will contain more information than .toString() returns
-  stats.name = path;
-  stats.toString = function() {
+  stats.name = pathName;
+  stats.toString = function () {
     // Return a string resembling unix's `ls -l` format
     return [this.mode, this.nlink, this.uid, this.gid, this.size, this.mtime, this.name].join(' ');
   };
   return stats;
 }
+
+module.exports = _ls;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/mkdir.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/mkdir.js b/node_modules/shelljs/src/mkdir.js
index 8b4fd99..115f75c 100644
--- a/node_modules/shelljs/src/mkdir.js
+++ b/node_modules/shelljs/src/mkdir.js
@@ -2,10 +2,23 @@ var common = require('./common');
 var fs = require('fs');
 var path = require('path');
 
+common.register('mkdir', _mkdir, {
+  cmdOptions: {
+    'p': 'fullpath',
+  },
+});
+
 // Recursively creates 'dir'
 function mkdirSyncRecursive(dir) {
   var baseDir = path.dirname(dir);
 
+  // Prevents some potential problems arising from malformed UNCs or
+  // insufficient permissions.
+  /* istanbul ignore next */
+  if (baseDir === dir) {
+    common.error('dirname() failed: [' + dir + ']');
+  }
+
   // Base dir exists, no recursion necessary
   if (fs.existsSync(baseDir)) {
     fs.mkdirSync(dir, parseInt('0777', 8));
@@ -35,34 +48,46 @@ function mkdirSyncRecursive(dir) {
 //@
 //@ Creates directories.
 function _mkdir(options, dirs) {
-  options = common.parseOptions(options, {
-    'p': 'fullpath'
-  });
-  if (!dirs)
-    common.error('no paths given');
+  if (!dirs) common.error('no paths given');
 
-  if (typeof dirs === 'string')
+  if (typeof dirs === 'string') {
     dirs = [].slice.call(arguments, 1);
+  }
   // if it's array leave it as it is
 
-  dirs.forEach(function(dir) {
-    if (fs.existsSync(dir)) {
-      if (!options.fullpath)
-          common.error('path already exists: ' + dir, true);
+  dirs.forEach(function (dir) {
+    try {
+      fs.lstatSync(dir);
+      if (!options.fullpath) {
+        common.error('path already exists: ' + dir, { continue: true });
+      }
       return; // skip dir
+    } catch (e) {
+      // do nothing
     }
 
     // Base dir does not exist, and no -p option given
     var baseDir = path.dirname(dir);
     if (!fs.existsSync(baseDir) && !options.fullpath) {
-      common.error('no such file or directory: ' + baseDir, true);
+      common.error('no such file or directory: ' + baseDir, { continue: true });
       return; // skip dir
     }
 
-    if (options.fullpath)
-      mkdirSyncRecursive(dir);
-    else
-      fs.mkdirSync(dir, parseInt('0777', 8));
+    try {
+      if (options.fullpath) {
+        mkdirSyncRecursive(path.resolve(dir));
+      } else {
+        fs.mkdirSync(dir, parseInt('0777', 8));
+      }
+    } catch (e) {
+      if (e.code === 'EACCES') {
+        common.error('cannot create directory ' + dir + ': Permission denied');
+      } else {
+        /* istanbul ignore next */
+        throw e;
+      }
+    }
   });
+  return '';
 } // mkdir
 module.exports = _mkdir;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/mv.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/mv.js b/node_modules/shelljs/src/mv.js
index 69cc03f..7fc7cf0 100644
--- a/node_modules/shelljs/src/mv.js
+++ b/node_modules/shelljs/src/mv.js
@@ -1,6 +1,15 @@
 var fs = require('fs');
 var path = require('path');
 var common = require('./common');
+var cp = require('./cp');
+var rm = require('./rm');
+
+common.register('mv', _mv, {
+  cmdOptions: {
+    'f': '!no_force',
+    'n': 'no_force',
+  },
+});
 
 //@
 //@ ### mv([options ,] source [, source ...], dest')
@@ -18,13 +27,8 @@ var common = require('./common');
 //@ mv(['file1', 'file2'], 'dir/'); // same as above
 //@ ```
 //@
-//@ Moves files. The wildcard `*` is accepted.
+//@ Moves files.
 function _mv(options, sources, dest) {
-  options = common.parseOptions(options, {
-    'f': '!no_force',
-    'n': 'no_force'
-  });
-
   // Get sources, dest
   if (arguments.length < 3) {
     common.error('missing <source> and/or <dest>');
@@ -33,28 +37,27 @@ function _mv(options, sources, dest) {
     dest = arguments[arguments.length - 1];
   } else if (typeof sources === 'string') {
     sources = [sources];
-  } else if ('length' in sources) {
-    sources = sources; // no-op for array
   } else {
+    // TODO(nate): figure out if we actually need this line
     common.error('invalid arguments');
   }
 
-  sources = common.expand(sources);
-
-  var exists = fs.existsSync(dest),
-      stats = exists && fs.statSync(dest);
+  var exists = fs.existsSync(dest);
+  var stats = exists && fs.statSync(dest);
 
   // Dest is not existing dir, but multiple sources given
-  if ((!exists || !stats.isDirectory()) && sources.length > 1)
+  if ((!exists || !stats.isDirectory()) && sources.length > 1) {
     common.error('dest is not a directory (too many sources)');
+  }
 
   // Dest is an existing file, but no -f given
-  if (exists && stats.isFile() && options.no_force)
+  if (exists && stats.isFile() && options.no_force) {
     common.error('dest file already exists: ' + dest);
+  }
 
-  sources.forEach(function(src) {
+  sources.forEach(function (src) {
     if (!fs.existsSync(src)) {
-      common.error('no such file or directory: '+src, true);
+      common.error('no such file or directory: ' + src, { continue: true });
       return; // skip file
     }
 
@@ -63,20 +66,34 @@ function _mv(options, sources, dest) {
     // When copying to '/path/dir':
     //    thisDest = '/path/dir/file1'
     var thisDest = dest;
-    if (fs.existsSync(dest) && fs.statSync(dest).isDirectory())
+    if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) {
       thisDest = path.normalize(dest + '/' + path.basename(src));
+    }
 
     if (fs.existsSync(thisDest) && options.no_force) {
-      common.error('dest file already exists: ' + thisDest, true);
+      common.error('dest file already exists: ' + thisDest, { continue: true });
       return; // skip file
     }
 
     if (path.resolve(src) === path.dirname(path.resolve(thisDest))) {
-      common.error('cannot move to self: '+src, true);
+      common.error('cannot move to self: ' + src, { continue: true });
       return; // skip file
     }
 
-    fs.renameSync(src, thisDest);
+    try {
+      fs.renameSync(src, thisDest);
+    } catch (e) {
+      /* istanbul ignore next */
+      if (e.code === 'EXDEV') {
+        // If we're trying to `mv` to an external partition, we'll actually need
+        // to perform a copy and then clean up the original file. If either the
+        // copy or the rm fails with an exception, we should allow this
+        // exception to pass up to the top level.
+        cp('-r', src, thisDest);
+        rm('-rf', src);
+      }
+    }
   }); // forEach(src)
+  return '';
 } // mv
 module.exports = _mv;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/popd.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/popd.js b/node_modules/shelljs/src/popd.js
index 11ea24f..d9eac3f 100644
--- a/node_modules/shelljs/src/popd.js
+++ b/node_modules/shelljs/src/popd.js
@@ -1 +1 @@
-// see dirs.js
\ No newline at end of file
+// see dirs.js

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/pushd.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/pushd.js b/node_modules/shelljs/src/pushd.js
index 11ea24f..d9eac3f 100644
--- a/node_modules/shelljs/src/pushd.js
+++ b/node_modules/shelljs/src/pushd.js
@@ -1 +1 @@
-// see dirs.js
\ No newline at end of file
+// see dirs.js

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/pwd.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/pwd.js b/node_modules/shelljs/src/pwd.js
index 26cefe0..3861851 100644
--- a/node_modules/shelljs/src/pwd.js
+++ b/node_modules/shelljs/src/pwd.js
@@ -1,11 +1,15 @@
 var path = require('path');
 var common = require('./common');
 
+common.register('pwd', _pwd, {
+  allowGlobbing: false,
+});
+
 //@
 //@ ### pwd()
 //@ Returns the current directory.
 function _pwd() {
   var pwd = path.resolve(process.cwd());
-  return common.ShellString(pwd);
+  return pwd;
 }
 module.exports = _pwd;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/rm.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/rm.js b/node_modules/shelljs/src/rm.js
index cf2e95b..5953681 100644
--- a/node_modules/shelljs/src/rm.js
+++ b/node_modules/shelljs/src/rm.js
@@ -1,6 +1,14 @@
 var common = require('./common');
 var fs = require('fs');
 
+common.register('rm', _rm, {
+  cmdOptions: {
+    'f': 'force',
+    'r': 'recursive',
+    'R': 'recursive',
+  },
+});
+
 // Recursively removes 'dir'
 // Adapted from https://github.com/ryanmcgrath/wrench-js
 //
@@ -15,32 +23,24 @@ function rmdirSyncRecursive(dir, force) {
   files = fs.readdirSync(dir);
 
   // Loop through and delete everything in the sub-tree after checking it
-  for(var i = 0; i < files.length; i++) {
-    var file = dir + "/" + files[i],
-        currFile = fs.lstatSync(file);
+  for (var i = 0; i < files.length; i++) {
+    var file = dir + '/' + files[i];
+    var currFile = fs.lstatSync(file);
 
-    if(currFile.isDirectory()) { // Recursive function back to the beginning
+    if (currFile.isDirectory()) { // Recursive function back to the beginning
       rmdirSyncRecursive(file, force);
-    }
-
-    else if(currFile.isSymbolicLink()) { // Unlink symlinks
+    } else { // Assume it's a file - perhaps a try/catch belongs here?
       if (force || isWriteable(file)) {
         try {
           common.unlinkSync(file);
         } catch (e) {
-          common.error('could not remove file (code '+e.code+'): ' + file, true);
+          /* istanbul ignore next */
+          common.error('could not remove file (code ' + e.code + '): ' + file, {
+            continue: true,
+          });
         }
       }
     }
-
-    else // Assume it's a file - perhaps a try/catch belongs here?
-      if (force || isWriteable(file)) {
-        try {
-          common.unlinkSync(file);
-        } catch (e) {
-          common.error('could not remove file (code '+e.code+'): ' + file, true);
-        }
-      }
   }
 
   // Now that we know everything in the sub-tree has been deleted, we can delete the main directory.
@@ -50,16 +50,19 @@ function rmdirSyncRecursive(dir, force) {
   try {
     // Retry on windows, sometimes it takes a little time before all the files in the directory are gone
     var start = Date.now();
-    while (true) {
+
+    // TODO: replace this with a finite loop
+    for (;;) {
       try {
         result = fs.rmdirSync(dir);
-        if (fs.existsSync(dir)) throw { code: "EAGAIN" };
+        if (fs.existsSync(dir)) throw { code: 'EAGAIN' };
         break;
-      } catch(er) {
+      } catch (er) {
+        /* istanbul ignore next */
         // In addition to error codes, also check if the directory still exists and loop again if true
-        if (process.platform === "win32" && (er.code === "ENOTEMPTY" || er.code === "EBUSY" || er.code === "EPERM" || er.code === "EAGAIN")) {
+        if (process.platform === 'win32' && (er.code === 'ENOTEMPTY' || er.code === 'EBUSY' || er.code === 'EPERM' || er.code === 'EAGAIN')) {
           if (Date.now() - start > 1000) throw er;
-        } else if (er.code === "ENOENT") {
+        } else if (er.code === 'ENOENT') {
           // Directory did not exist, deletion was successful
           break;
         } else {
@@ -67,8 +70,8 @@ function rmdirSyncRecursive(dir, force) {
         }
       }
     }
-  } catch(e) {
-    common.error('could not remove directory (code '+e.code+'): ' + dir, true);
+  } catch (e) {
+    common.error('could not remove directory (code ' + e.code + '): ' + dir, { continue: true });
   }
 
   return result;
@@ -81,7 +84,7 @@ function isWriteable(file) {
   try {
     var __fd = fs.openSync(file, 'a');
     fs.closeSync(__fd);
-  } catch(e) {
+  } catch (e) {
     writePermission = false;
   }
 
@@ -104,60 +107,44 @@ function isWriteable(file) {
 //@ rm(['some_file.txt', 'another_file.txt']); // same as above
 //@ ```
 //@
-//@ Removes files. The wildcard `*` is accepted.
+//@ Removes files.
 function _rm(options, files) {
-  options = common.parseOptions(options, {
-    'f': 'force',
-    'r': 'recursive',
-    'R': 'recursive'
-  });
-  if (!files)
-    common.error('no paths given');
-
-  if (typeof files === 'string')
-    files = [].slice.call(arguments, 1);
-  // if it's array leave it as it is
+  if (!files) common.error('no paths given');
 
-  files = common.expand(files);
+  // Convert to array
+  files = [].slice.call(arguments, 1);
 
-  files.forEach(function(file) {
-    if (!fs.existsSync(file)) {
+  files.forEach(function (file) {
+    var stats;
+    try {
+      stats = fs.lstatSync(file); // test for existence
+    } catch (e) {
       // Path does not exist, no force flag given
-      if (!options.force)
-        common.error('no such file or directory: '+file, true);
-
+      if (!options.force) {
+        common.error('no such file or directory: ' + file, { continue: true });
+      }
       return; // skip file
     }
 
     // If here, path exists
-
-    var stats = fs.lstatSync(file);
-    if (stats.isFile() || stats.isSymbolicLink()) {
-
-      // Do not check for file writing permissions
-      if (options.force) {
+    if (stats.isFile()) {
+      if (options.force || isWriteable(file)) {
+        // -f was passed, or file is writable, so it can be removed
         common.unlinkSync(file);
-        return;
+      } else {
+        common.error('permission denied: ' + file, { continue: true });
       }
-
-      if (isWriteable(file))
-        common.unlinkSync(file);
-      else
-        common.error('permission denied: '+file, true);
-
-      return;
-    } // simple file
-
-    // Path is an existing directory, but no -r flag given
-    if (stats.isDirectory() && !options.recursive) {
-      common.error('path is a directory', true);
-      return; // skip path
-    }
-
-    // Recursively remove existing directory
-    if (stats.isDirectory() && options.recursive) {
-      rmdirSyncRecursive(file, options.force);
+    } else if (stats.isDirectory()) {
+      if (options.recursive) {
+        // -r was passed, so directory can be removed
+        rmdirSyncRecursive(file, options.force);
+      } else {
+        common.error('path is a directory', { continue: true });
+      }
+    } else if (stats.isSymbolicLink() || stats.isFIFO()) {
+      common.unlinkSync(file);
     }
   }); // forEach(file)
+  return '';
 } // rm
 module.exports = _rm;

http://git-wip-us.apache.org/repos/asf/cordova-browser/blob/c846b473/node_modules/shelljs/src/sed.js
----------------------------------------------------------------------
diff --git a/node_modules/shelljs/src/sed.js b/node_modules/shelljs/src/sed.js
index baa385b..dfdc0a7 100644
--- a/node_modules/shelljs/src/sed.js
+++ b/node_modules/shelljs/src/sed.js
@@ -1,6 +1,14 @@
 var common = require('./common');
 var fs = require('fs');
 
+common.register('sed', _sed, {
+  globStart: 3, // don't glob-expand regexes
+  canReceivePipe: true,
+  cmdOptions: {
+    'i': 'inplace',
+  },
+});
+
 //@
 //@ ### sed([options,] search_regex, replacement, file [, file ...])
 //@ ### sed([options,] search_regex, replacement, file_array)
@@ -17,48 +25,62 @@ var fs = require('fs');
 //@
 //@ Reads an input string from `files` and performs a JavaScript `replace()` on the input
 //@ using the given search regex and replacement string or function. Returns the new string after replacement.
+//@
+//@ Note:
+//@
+//@ Like unix `sed`, ShellJS `sed` supports capture groups. Capture groups are specified
+//@ using the `$n` syntax:
+//@
+//@ ```javascript
+//@ sed(/(\w+)\s(\w+)/, '$2, $1', 'file.txt');
+//@ ```
 function _sed(options, regex, replacement, files) {
-  options = common.parseOptions(options, {
-    'i': 'inplace'
-  });
+  // Check if this is coming from a pipe
+  var pipe = common.readFromPipe();
 
-  if (typeof replacement === 'string' || typeof replacement === 'function')
-    replacement = replacement; // no-op
-  else if (typeof replacement === 'number')
-    replacement = replacement.toString(); // fallback
-  else
-    common.error('invalid replacement string');
+  if (typeof replacement !== 'string' && typeof replacement !== 'function') {
+    if (typeof replacement === 'number') {
+      replacement = replacement.toString(); // fallback
+    } else {
+      common.error('invalid replacement string');
+    }
+  }
 
   // Convert all search strings to RegExp
-  if (typeof regex === 'string')
+  if (typeof regex === 'string') {
     regex = RegExp(regex);
+  }
 
-  if (!files)
+  if (!files && !pipe) {
     common.error('no files given');
+  }
 
-  if (typeof files === 'string')
-    files = [].slice.call(arguments, 3);
-  // if it's array leave it as it is
+  files = [].slice.call(arguments, 3);
 
-  files = common.expand(files);
+  if (pipe) {
+    files.unshift('-');
+  }
 
   var sed = [];
-  files.forEach(function(file) {
-    if (!fs.existsSync(file)) {
-      common.error('no such file or directory: ' + file, true);
+  files.forEach(function (file) {
+    if (!fs.existsSync(file) && file !== '-') {
+      common.error('no such file or directory: ' + file, 2, { continue: true });
       return;
     }
 
-    var result = fs.readFileSync(file, 'utf8').split('\n').map(function (line) {
+    var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8');
+    var lines = contents.split(/\r*\n/);
+    var result = lines.map(function (line) {
       return line.replace(regex, replacement);
     }).join('\n');
 
     sed.push(result);
 
-    if (options.inplace)
+    if (options.inplace) {
       fs.writeFileSync(file, result, 'utf8');
+    }
   });
 
-  return common.ShellString(sed.join('\n'));
+  return sed.join('\n');
 }
 module.exports = _sed;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org