[Pkg-javascript-commits] [node-cross-spawn] 01/02: Manually import version 4.0.2 to upstream branch

Sruthi Chandran srud-guest at moszumanska.debian.org
Mon Nov 7 06:42:17 UTC 2016


This is an automated email from the git hooks/post-receive script.

srud-guest pushed a commit to branch upstream
in repository node-cross-spawn.

commit e7146ebe2cee2370eeae9db912955fd9ebd60ef8
Author: Sruthi <srud at disroot.org>
Date:   Mon Nov 7 11:40:02 2016 +0530

    Manually import version 4.0.2 to upstream branch
---
 README.md                   |  19 ++++--
 appveyor.yml                |   4 +-
 index.js                    |  64 ++++++++++----------
 lib/enoent.js               |  73 +++++++++++++++++++++++
 lib/hasBrokenSpawn.js       |  11 ++++
 lib/parse.js                | 140 ++++++++++++++++++++++++++++++++++++++++++++
 lib/resolveCommand.js       |  31 ++++++++++
 package.json                |  22 ++++---
 test/.eslintrc              |  10 ++++
 test/fixtures/echo.js       |   2 +
 test/fixtures/exit.js       |   2 +
 test/fixtures/shebang       |   2 +
 test/fixtures/shebang_noenv |   3 -
 test/fixtures/win-ppid.js   |  12 ++++
 test/prepare.js             |  18 +++++-
 test/test.js                | 101 ++++++++++++++++++++++++--------
 test/util/buffered.js       |   3 +-
 17 files changed, 441 insertions(+), 76 deletions(-)

diff --git a/README.md b/README.md
index 6e518e6..18cc2b8 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,9 @@
 [downloads-image]:http://img.shields.io/npm/dm/cross-spawn.svg
 [npm-image]:http://img.shields.io/npm/v/cross-spawn.svg
 [travis-url]:https://travis-ci.org/IndigoUnited/node-cross-spawn
-[travis-image]:http://img.shields.io/travis/IndigoUnited/node-cross-spawn.svg
+[travis-image]:http://img.shields.io/travis/IndigoUnited/node-cross-spawn/master.svg
 [appveyor-url]:https://ci.appveyor.com/project/satazor/node-cross-spawn
-[appveyor-image]:https://img.shields.io/appveyor/ci/satazor/node-cross-spawn.svg
+[appveyor-image]:https://img.shields.io/appveyor/ci/satazor/node-cross-spawn/master.svg
 [david-dm-url]:https://david-dm.org/IndigoUnited/node-cross-spawn
 [david-dm-image]:https://img.shields.io/david/IndigoUnited/node-cross-spawn.svg
 [david-dm-dev-url]:https://david-dm.org/IndigoUnited/node-cross-spawn#info=devDependencies
@@ -21,7 +21,9 @@ A cross platform solution to node's spawn and spawnSync.
 
 `$ npm install cross-spawn`
 
-If you're not using the `spawnSync`, you can use [cross-spawn-async](http://github.com/IndigoUnited/node-cross-spawn-async) which doesn't require a build toolchain, see [#18](https://github.com/IndigoUnited/node-cross-spawn/pull/18)
+If you are using `spawnSync` on node 0.10 or older, you will also need to install `spawn-sync`:
+
+`$ npm install spawn-sync`
 
 
 ## Why
@@ -45,12 +47,19 @@ Exactly the same way as node's [`spawn`](https://nodejs.org/api/child_process.ht
 var spawn = require('cross-spawn');
 
 // Spawn NPM asynchronously
-var process = spawn('npm', ['list', '-g', '-depth' '0'], { stdio: 'inherit' });
+var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
 
 // Spawn NPM synchronously
-var results = spawn.sync('npm', ['list', '-g', '-depth' '0'], { stdio: 'inherit' });
+var results = spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
 ```
 
+## Caveat
+
+On Windows, cross-spawn will only spawn `cmd.exe` if necessary. If the extension
+of the executable is `.exe` or `.com`, it will spawn it directly. If you wish
+to override this behavior and *always* spawn a shell, pass the `{shell: true}`
+option.
+
 
 ## Tests
 
diff --git a/appveyor.yml b/appveyor.yml
index 02aad11..f8c4e7a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -13,10 +13,8 @@ environment:
   matrix:
     - nodejs_version: 0.10
     - nodejs_version: 0.12
-    - nodejs_version: 1
-    - nodejs_version: 2
-    - nodejs_version: 3
     - nodejs_version: 4
+    - nodejs_version: 6
 
 # get the latest stable version of Node 0.STABLE.latest
 install:
diff --git a/index.js b/index.js
index 07b1ba4..7814a96 100644
--- a/index.js
+++ b/index.js
@@ -1,55 +1,59 @@
 'use strict';
 
-var sync           = require('spawn-sync');
-var crossSpawn     = require('cross-spawn-async');
-var parse          = require('cross-spawn-async/lib/parse');
-var enoent         = require('cross-spawn-async/lib/enoent');
-var resolveCommand = require('cross-spawn-async/lib/resolveCommand');
+var cp = require('child_process');
+var parse = require('./lib/parse');
+var enoent = require('./lib/enoent');
 
-var isWin    = process.platform === 'win32';
-var isNode10 = process.version.indexOf('v0.10.') === 0;
+var cpSpawnSync = cp.spawnSync;
 
-function verifySyncENOENT(status, parsed) {
-    // First check against the standard enoent.verifyENOENT
-    var err = enoent.verifyENOENT(status, parsed, 'spawnSync');
-
-    if (err) {
-        return err;
-    }
+function spawn(command, args, options) {
+    var parsed;
+    var spawned;
 
-    // If we are in node 10, then we are using spawn-sync; if it exited
-    // with -1 it probably means that the command does not exist
-    if (isNode10 && status === -1) {
-        parsed.file = isWin ? parsed.file : resolveCommand(parsed.original);
+    // Parse the arguments
+    parsed = parse(command, args, options);
 
-        if (!parsed.file) {
-            err = enoent.notFoundError(parsed.original, 'spawnSync');
-        }
-    }
+    // Spawn the child process
+    spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
 
-    return err;
-}
+    // Hook into child process "exit" event to emit an error if the command
+    // does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
+    enoent.hookChildProcess(spawned, parsed);
 
-function spawn(command, args, options) {
-    return crossSpawn.spawn(command, args, options);
+    return spawned;
 }
 
 function spawnSync(command, args, options) {
     var parsed;
     var result;
 
+    if (!cpSpawnSync) {
+        try {
+            cpSpawnSync = require('spawn-sync');  // eslint-disable-line global-require
+        } catch (ex) {
+            throw new Error(
+                'In order to use spawnSync on node 0.10 or older, you must ' +
+                'install spawn-sync:\n\n' +
+                '  npm install spawn-sync --save'
+            );
+        }
+    }
+
     // Parse the arguments
     parsed = parse(command, args, options);
 
     // Spawn the child process
-    result = sync(parsed.command, parsed.args, parsed.options);
+    result = cpSpawnSync(parsed.command, parsed.args, parsed.options);
 
     // Analyze if the command does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
-    result.error = result.error || verifySyncENOENT(result.status, parsed);
+    result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
 
     return result;
 }
 
-module.exports       = spawn;
+module.exports = spawn;
 module.exports.spawn = spawn;
-module.exports.sync  = spawnSync;
+module.exports.sync = spawnSync;
+
+module.exports._parse = parse;
+module.exports._enoent = enoent;
diff --git a/lib/enoent.js b/lib/enoent.js
new file mode 100644
index 0000000..74ff06e
--- /dev/null
+++ b/lib/enoent.js
@@ -0,0 +1,73 @@
+'use strict';
+
+var isWin = process.platform === 'win32';
+var resolveCommand = require('./resolveCommand');
+
+var isNode10 = process.version.indexOf('v0.10.') === 0;
+
+function notFoundError(command, syscall) {
+    var err;
+
+    err = new Error(syscall + ' ' + command + ' ENOENT');
+    err.code = err.errno = 'ENOENT';
+    err.syscall = syscall + ' ' + command;
+
+    return err;
+}
+
+function hookChildProcess(cp, parsed) {
+    var originalEmit;
+
+    if (!isWin) {
+        return;
+    }
+
+    originalEmit = cp.emit;
+    cp.emit = function (name, arg1) {
+        var err;
+
+        // If emitting "exit" event and exit code is 1, we need to check if
+        // the command exists and emit an "error" instead
+        // See: https://github.com/IndigoUnited/node-cross-spawn/issues/16
+        if (name === 'exit') {
+            err = verifyENOENT(arg1, parsed, 'spawn');
+
+            if (err) {
+                return originalEmit.call(cp, 'error', err);
+            }
+        }
+
+        return originalEmit.apply(cp, arguments);
+    };
+}
+
+function verifyENOENT(status, parsed) {
+    if (isWin && status === 1 && !parsed.file) {
+        return notFoundError(parsed.original, 'spawn');
+    }
+
+    return null;
+}
+
+function verifyENOENTSync(status, parsed) {
+    if (isWin && status === 1 && !parsed.file) {
+        return notFoundError(parsed.original, 'spawnSync');
+    }
+
+    // If we are in node 10, then we are using spawn-sync; if it exited
+    // with -1 it probably means that the command does not exist
+    if (isNode10 && status === -1) {
+        parsed.file = isWin ? parsed.file : resolveCommand(parsed.original);
+
+        if (!parsed.file) {
+            return notFoundError(parsed.original, 'spawnSync');
+        }
+    }
+
+    return null;
+}
+
+module.exports.hookChildProcess = hookChildProcess;
+module.exports.verifyENOENT = verifyENOENT;
+module.exports.verifyENOENTSync = verifyENOENTSync;
+module.exports.notFoundError = notFoundError;
diff --git a/lib/hasBrokenSpawn.js b/lib/hasBrokenSpawn.js
new file mode 100644
index 0000000..e73f906
--- /dev/null
+++ b/lib/hasBrokenSpawn.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = (function () {
+    if (process.platform !== 'win32') {
+        return false;
+    }
+    var nodeVer = process.version.substr(1).split('.').map(function (num) {
+        return parseInt(num, 10);
+    });
+    return (nodeVer[0] === 0 && nodeVer[1] < 12);
+})();
diff --git a/lib/parse.js b/lib/parse.js
new file mode 100644
index 0000000..77cbb83
--- /dev/null
+++ b/lib/parse.js
@@ -0,0 +1,140 @@
+'use strict';
+
+var fs = require('fs');
+var LRU = require('lru-cache');
+var resolveCommand = require('./resolveCommand');
+var hasBrokenSpawn = require('./hasBrokenSpawn');
+
+var isWin = process.platform === 'win32';
+var shebangCache = new LRU({ max: 50, maxAge: 30 * 1000 });  // Cache just for 30sec
+
+function readShebang(command) {
+    var buffer;
+    var fd;
+    var match;
+    var shebang;
+
+    // Check if it is in the cache first
+    if (shebangCache.has(command)) {
+        return shebangCache.get(command);
+    }
+
+    // Read the first 150 bytes from the file
+    buffer = new Buffer(150);
+
+    try {
+        fd = fs.openSync(command, 'r');
+        fs.readSync(fd, buffer, 0, 150, 0);
+        fs.closeSync(fd);
+    } catch (e) { /* empty */ }
+
+    // Check if it is a shebang
+    match = buffer.toString().trim().match(/#!(.+)/i);
+
+    if (match) {
+        shebang = match[1].replace(/\/usr\/bin\/env\s+/i, '');   // Remove /usr/bin/env
+    }
+
+    // Store the shebang in the cache
+    shebangCache.set(command, shebang);
+
+    return shebang;
+}
+
+function escapeArg(arg, quote) {
+    // Convert to string
+    arg = '' + arg;
+
+    // If we are not going to quote the argument,
+    // escape shell metacharacters, including double and single quotes:
+    if (!quote) {
+        arg = arg.replace(/([\(\)%!\^<>&|;,"'\s])/g, '^$1');
+    } else {
+        // Sequence of backslashes followed by a double quote:
+        // double up all the backslashes and escape the double quote
+        arg = arg.replace(/(\\*)"/g, '$1$1\\"');
+
+        // Sequence of backslashes followed by the end of the string
+        // (which will become a double quote later):
+        // double up all the backslashes
+        arg = arg.replace(/(\\*)$/, '$1$1');
+
+        // All other backslashes occur literally
+
+        // Quote the whole thing:
+        arg = '"' + arg + '"';
+    }
+
+    return arg;
+}
+
+function escapeCommand(command) {
+    // Do not escape if this command is not dangerous..
+    // We do this so that commands like "echo" or "ifconfig" work
+    // Quoting them, will make them unaccessible
+    return /^[a-z0-9_-]+$/i.test(command) ? command : escapeArg(command, true);
+}
+
+function requiresShell(command) {
+    return !/\.(?:com|exe)$/i.test(command);
+}
+
+function parse(command, args, options) {
+    var shebang;
+    var applyQuotes;
+    var file;
+    var original;
+    var shell;
+
+    // Normalize arguments, similar to nodejs
+    if (args && !Array.isArray(args)) {
+        options = args;
+        args = null;
+    }
+
+    args = args ? args.slice(0) : [];  // Clone array to avoid changing the original
+    options = options || {};
+    original = command;
+
+    if (isWin) {
+        // Detect & add support for shebangs
+        file = resolveCommand(command);
+        file = file || resolveCommand(command, true);
+        shebang = file && readShebang(file);
+        shell = options.shell || hasBrokenSpawn;
+
+        if (shebang) {
+            args.unshift(file);
+            command = shebang;
+            shell = shell || requiresShell(resolveCommand(shebang) || resolveCommand(shebang, true));
+        } else {
+            shell = shell || requiresShell(file);
+        }
+
+        if (shell) {
+            // Escape command & arguments
+            applyQuotes = (command !== 'echo');  // Do not quote arguments for the special "echo" command
+            command = escapeCommand(command);
+            args = args.map(function (arg) {
+                return escapeArg(arg, applyQuotes);
+            });
+
+            // Use cmd.exe
+            args = ['/s', '/c', '"' + command + (args.length ? ' ' + args.join(' ') : '') + '"'];
+            command = process.env.comspec || 'cmd.exe';
+
+            // Tell node's spawn that the arguments are already escaped
+            options.windowsVerbatimArguments = true;
+        }
+    }
+
+    return {
+        command: command,
+        args: args,
+        options: options,
+        file: file,
+        original: original,
+    };
+}
+
+module.exports = parse;
diff --git a/lib/resolveCommand.js b/lib/resolveCommand.js
new file mode 100644
index 0000000..b7a9490
--- /dev/null
+++ b/lib/resolveCommand.js
@@ -0,0 +1,31 @@
+'use strict';
+
+var path = require('path');
+var which = require('which');
+var LRU = require('lru-cache');
+
+var commandCache = new LRU({ max: 50, maxAge: 30 * 1000 });  // Cache just for 30sec
+
+function resolveCommand(command, noExtension) {
+    var resolved;
+
+    noExtension = !!noExtension;
+    resolved = commandCache.get(command + '!' + noExtension);
+
+    // Check if its resolved in the cache
+    if (commandCache.has(command)) {
+        return commandCache.get(command);
+    }
+
+    try {
+        resolved = !noExtension ?
+            which.sync(command) :
+            which.sync(command, { pathExt: path.delimiter + (process.env.PATHEXT || '') });
+    } catch (e) { /* empty */ }
+
+    commandCache.set(command + '!' + noExtension, resolved);
+
+    return resolved;
+}
+
+module.exports = resolveCommand;
diff --git a/package.json b/package.json
index 7305dc5..7d7bb88 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,11 @@
 {
   "name": "cross-spawn",
-  "version": "2.1.5",
+  "version": "4.0.2",
   "description": "Cross platform child_process#spawn and child_process#spawnSync",
   "main": "index.js",
   "scripts": {
-    "test": "node test/prepare && mocha --bail test/test"
+    "test": "node test/prepare && mocha --bail test/test",
+    "lint": "eslint '{*.js,lib/**/*.js,test/**/*.js}'"
   },
   "bugs": {
     "url": "https://github.com/IndigoUnited/node-cross-spawn/issues/"
@@ -13,6 +14,10 @@
     "type": "git",
     "url": "git://github.com/IndigoUnited/node-cross-spawn.git"
   },
+  "files": [
+    "index.js",
+    "lib"
+  ],
   "keywords": [
     "spawn",
     "spawnSync",
@@ -31,15 +36,16 @@
   "author": "IndigoUnited <hello at indigounited.com> (http://indigounited.com)",
   "license": "MIT",
   "dependencies": {
-    "cross-spawn-async": "^2.0.0",
-    "spawn-sync": "^1.0.15"
+    "lru-cache": "^4.0.1",
+    "which": "^1.2.9"
   },
   "devDependencies": {
+    "@satazor/eslint-config": "^3.0.0",
+    "eslint": "^3.0.0",
     "expect.js": "^0.3.0",
-    "glob": "^6.0.3",
+    "glob": "^7.0.0",
     "mkdirp": "^0.5.1",
-    "mocha": "^2.2.5",
-    "rimraf": "^2.5.0",
-    "which": "^1.2.4"
+    "mocha": "^3.0.2",
+    "rimraf": "^2.5.0"
   }
 }
diff --git a/test/.eslintrc b/test/.eslintrc
new file mode 100644
index 0000000..32a5d9a
--- /dev/null
+++ b/test/.eslintrc
@@ -0,0 +1,10 @@
+{
+    "env": {
+        "mocha": true
+    },
+    "rules": {
+        "no-invalid-this": 0,
+        "max-nested-callbacks": 0,
+        "callback-return": 0
+    }
+}
\ No newline at end of file
diff --git a/test/fixtures/echo.js b/test/fixtures/echo.js
index 430da7a..133540b 100755
--- a/test/fixtures/echo.js
+++ b/test/fixtures/echo.js
@@ -1,3 +1,5 @@
+'use strict';
+
 var args = process.argv.slice(2);
 
 args.forEach(function (arg, index) {
diff --git a/test/fixtures/exit.js b/test/fixtures/exit.js
index ea1a66f..9b1890e 100755
--- a/test/fixtures/exit.js
+++ b/test/fixtures/exit.js
@@ -1 +1,3 @@
+'use strict';
+
 process.exit(25);
diff --git a/test/fixtures/shebang b/test/fixtures/shebang
index 5650cbd..373d191 100755
--- a/test/fixtures/shebang
+++ b/test/fixtures/shebang
@@ -1,3 +1,5 @@
 #!/usr/bin/env node
 
+'use strict';
+
 process.stdout.write('shebang works!');
diff --git a/test/fixtures/shebang_noenv b/test/fixtures/shebang_noenv
deleted file mode 100755
index f119f91..0000000
--- a/test/fixtures/shebang_noenv
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/local/bin/node
-
-process.stdout.write('shebang works!');
\ No newline at end of file
diff --git a/test/fixtures/win-ppid.js b/test/fixtures/win-ppid.js
new file mode 100644
index 0000000..e9d03ff
--- /dev/null
+++ b/test/fixtures/win-ppid.js
@@ -0,0 +1,12 @@
+#!/usr/bin/env node
+
+var spawnSync = require('child_process').spawnSync || require('spawn-sync');
+
+function ppidSync() {
+    var res = spawnSync('wmic',
+        ['process', 'where', '(processid=' + process.pid + ')', 'get', 'parentprocessid']);
+    var lines = res.stdout.toString().split(/\r?\n/);
+    return parseInt(lines[1].trim(), 10);
+}
+
+console.log(ppidSync());
diff --git a/test/prepare.js b/test/prepare.js
index addb078..e82c7b6 100644
--- a/test/prepare.js
+++ b/test/prepare.js
@@ -1,5 +1,8 @@
+'use strict';
+
 var glob = require('glob');
-var fs   = require('fs');
+var fs = require('fs');
+var buffered = require('./util/buffered');
 
 var fixturesDir = __dirname + '/fixtures';
 
@@ -8,7 +11,18 @@ glob.sync('prepare_*', { cwd: __dirname + '/fixtures' }).forEach(function (file)
     var finalFile = file.replace(/^prepare_/, '').replace(/\.sh$/, '');
 
     fs.writeFileSync(fixturesDir + '/' + finalFile, contents);
-    fs.chmodSync(fixturesDir + '/' + finalFile, 0777);
+    fs.chmodSync(fixturesDir + '/' + finalFile, parseInt('0777', 8));
 
     process.stdout.write('Copied "' + file + '" to "' + finalFile + '"\n');
 });
+
+if (/^v0\.10\./.test(process.version)) {
+    process.stdout.write('Installing spawn-sync..\n');
+    buffered('spawn', 'npm', ['install', 'spawn-sync'], { stdio: 'inherit' }, function (err) {
+        if (err) {
+            throw err;
+        }
+
+        process.exit();
+    });
+}
diff --git a/test/test.js b/test/test.js
index 5a2bd80..76647a1 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,15 +1,16 @@
 'use strict';
 
-var fs       = require('fs');
-var path     = require('path');
-var expect   = require('expect.js');
-var rimraf   = require('rimraf');
-var mkdirp   = require('mkdirp');
-var which    = require('which');
+var fs = require('fs');
+var path = require('path');
+var expect = require('expect.js');
+var rimraf = require('rimraf');
+var mkdirp = require('mkdirp');
+var which = require('which');
 var buffered = require('./util/buffered');
-var spawn    = require('../');
+var hasBrokenSpawn = require('../lib/hasBrokenSpawn');
+var spawn = require('../');
 
-var isWin    = process.platform === 'win32';
+var isWin = process.platform === 'win32';
 
 // Fix AppVeyor tests because Git bin folder is in PATH and it has a "echo" program there
 if (isWin) {
@@ -25,7 +26,7 @@ describe('cross-spawn', function () {
     var methods = ['spawn', 'sync'];
 
     methods.forEach(function (method) {
-        describe(method, function() {
+        describe(method, function () {
             var originalPath = process.env.PATH;
 
             before(function () {
@@ -36,7 +37,7 @@ describe('cross-spawn', function () {
                 // Give it some time, RIMRAF was giving problems on windows
                 this.timeout(10000);
 
-                rimraf(__dirname + '/tmp', function (err) {
+                rimraf(__dirname + '/tmp', function () {
                     // Ignore errors, RIMRAF was giving problems on windows
                     next(null);
                 });
@@ -70,7 +71,7 @@ describe('cross-spawn', function () {
                 var file = __dirname + '/fixtures/shebang_noenv';
 
                 fs.writeFileSync(file, '#!' + nodejs + '\n\nprocess.stdout.write(\'shebang works!\');', {
-                    mode: parseInt('0777', 8)
+                    mode: parseInt('0777', 8),
                 });
 
                 buffered(method, file, function (err, data, code) {
@@ -94,7 +95,24 @@ describe('cross-spawn', function () {
             it('should support shebang in executables with relative path', function (next) {
                 var executable = './' + path.relative(process.cwd(), __dirname + '/fixtures/shebang');
 
-                fs.writeFileSync(__dirname + '/tmp/shebang', '#!/usr/bin/env node\n\nprocess.stdout.write(\'yeah\');', { mode: parseInt('0777', 8) });
+                fs.writeFileSync(__dirname + '/tmp/shebang', '#!/usr/bin/env node\n\nprocess.stdout.write(\'yeah\');',
+                    { mode: parseInt('0777', 8) });
+                process.env.PATH = path.normalize(__dirname + '/tmp/') + path.delimiter + process.env.PATH;
+
+                buffered(method, executable, function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('shebang works!');
+
+                    next();
+                });
+            });
+
+            it('should support shebang in executables with relative path that starts with `..`', function (next) {
+                var executable = '../' + path.basename(process.cwd()) + '/' + path.relative(process.cwd(), __dirname + '/fixtures/shebang');
+
+                fs.writeFileSync(__dirname + '/tmp/shebang', '#!/usr/bin/env node\n\nprocess.stdout.write(\'yeah\');',
+                    { mode: parseInt('0777', 8) });
                 process.env.PATH = path.normalize(__dirname + '/tmp/') + path.delimiter + process.env.PATH;
 
                 buffered(method, executable, function (err, data, code) {
@@ -107,7 +125,8 @@ describe('cross-spawn', function () {
             });
 
             it('should support shebang in executables with extensions', function (next) {
-                fs.writeFileSync(__dirname + '/tmp/shebang_' + method + '.js', '#!/usr/bin/env node\n\nprocess.stdout.write(\'shebang with extension\');', { mode: parseInt('0777', 8) });
+                fs.writeFileSync(__dirname + '/tmp/shebang_' + method + '.js', '#!/usr/bin/env node\n\nprocess.stdout.write(\'shebang with \
+extension\');', { mode: parseInt('0777', 8) });
                 process.env.PATH = path.normalize(__dirname + '/tmp/') + path.delimiter + process.env.PATH;
 
                 buffered(method, __dirname + '/tmp/shebang_' + method + '.js', function (err, data, code) {
@@ -158,12 +177,26 @@ describe('cross-spawn', function () {
                 });
             });
 
+            it('should handle arguments with quotes', function (next) {
+                buffered(method, 'node', [
+                    __dirname + '/fixtures/echo',
+                    '"foo"',
+                    'foo"bar"foo',
+                ], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('"foo"\nfoo"bar"foo');
+
+                    next();
+                });
+            });
+
             it('should handle empty arguments', function (next) {
                 buffered(method, 'node', [
                     __dirname + '/fixtures/echo',
                     'foo',
                     '',
-                    'bar'
+                    'bar',
                 ], function (err, data, code) {
                     expect(err).to.not.be.ok();
                     expect(code).to.be(0);
@@ -172,7 +205,7 @@ describe('cross-spawn', function () {
                     buffered(method, 'echo', [
                         'foo',
                         '',
-                        'bar'
+                        'bar',
                     ], function (err, data, code) {
                         expect(err).to.not.be.ok();
                         expect(code).to.be(0);
@@ -186,7 +219,7 @@ describe('cross-spawn', function () {
             it('should handle non-string arguments', function (next) {
                 buffered(method, 'node', [
                     __dirname + '/fixtures/echo',
-                    1234
+                    1234,
                 ], function (err, data, code) {
                     expect(err).to.not.be.ok();
                     expect(code).to.be(0);
@@ -200,7 +233,7 @@ describe('cross-spawn', function () {
                 buffered(method, 'node', [
                     __dirname + '/fixtures/echo',
                     'I am',
-                    'André Cruz'
+                    'André Cruz',
                 ], function (err, data, code) {
                     expect(err).to.not.be.ok();
                     expect(code).to.be(0);
@@ -215,7 +248,7 @@ describe('cross-spawn', function () {
                     __dirname + '/fixtures/echo',
                     'foo',
                     '\\"',
-                    'bar'
+                    'bar',
                 ], function (err, data, code) {
                     expect(err).to.not.be.ok();
                     expect(code).to.be(0);
@@ -230,7 +263,7 @@ describe('cross-spawn', function () {
                     __dirname + '/fixtures/echo',
                     'foo',
                     'bar\\',
-                    'baz'
+                    'baz',
                 ], function (err, data, code) {
                     expect(err).to.not.be.ok();
                     expect(code).to.be(0);
@@ -255,7 +288,7 @@ describe('cross-spawn', function () {
                     '|;',
                     'foo',
                     ', ',
-                    'foo'
+                    'foo',
                 ], function (err, data, code) {
                     expect(err).to.not.be.ok();
                     expect(code).to.be(0);
@@ -284,7 +317,7 @@ describe('cross-spawn', function () {
                         '|;',
                         'foo',
                         ', ',
-                        'foo'
+                        'foo',
                     ], function (err, data, code) {
                         expect(err).to.not.be.ok();
                         expect(code).to.be(0);
@@ -418,7 +451,7 @@ describe('cross-spawn', function () {
 
                 if (method === 'spawn') {
                     spawned
-                    .on('error', function (err) {
+                    .on('error', function () {
                         spawned.removeAllListeners();
                         clearTimeout(timeout);
                         next(new Error('Should not emit error'));
@@ -448,7 +481,7 @@ describe('cross-spawn', function () {
 
                 if (method === 'spawn') {
                     spawned
-                    .on('error', function (err) {
+                    .on('error', function () {
                         spawned.removeAllListeners();
                         clearTimeout(timeout);
                         next(new Error('Should not emit error'));
@@ -468,6 +501,28 @@ describe('cross-spawn', function () {
                     next();
                 }
             });
+
+            if (isWin) {
+                if (hasBrokenSpawn) {
+                    it('should spawn a shell for a .exe on old Node', function (next) {
+                        buffered(method, __dirname + '/fixtures/win-ppid.js', function (err, data, code) {
+                            expect(err).to.not.be.ok();
+                            expect(code).to.be(0);
+                            expect(data.trim()).to.not.equal('' + process.pid);
+                            next();
+                        });
+                    });
+                } else {
+                    it('should NOT spawn a shell for a .exe', function (next) {
+                        buffered(method, __dirname + '/fixtures/win-ppid.js', function (err, data, code) {
+                            expect(err).to.not.be.ok();
+                            expect(code).to.be(0);
+                            expect(data.trim()).to.equal('' + process.pid);
+                            next();
+                        });
+                    });
+                }
+            }
         });
     });
 });
diff --git a/test/util/buffered.js b/test/util/buffered.js
index f2a45d3..7c2f713 100644
--- a/test/util/buffered.js
+++ b/test/util/buffered.js
@@ -21,8 +21,7 @@ function buffered(method, command, args, options, callback) {
     if (method === 'sync') {
         results = spawn.sync(command, args, options);
         callback(results.error, results.stdout ? results.stdout.toString() : null, results.status);
-    }
-    else {
+    } else {
         cp = spawn(command, args, options);
         stdout = stderr = null;
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-cross-spawn.git



More information about the Pkg-javascript-commits mailing list