[Pkg-javascript-commits] [node-cross-spawn] 01/04: Imported Upstream version 2.0.0

Ross Gammon ross-guest at moszumanska.debian.org
Sat Aug 15 20:18:24 UTC 2015


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

ross-guest pushed a commit to branch master
in repository node-cross-spawn.

commit 416d88045f5813ccd8a9a7f3df4a94012744bed3
Author: Ross Gammon <rossgammon at mail.dk>
Date:   Sat Aug 15 21:33:30 2015 +0200

    Imported Upstream version 2.0.0
---
 .editorconfig                                      |   3 +
 .gitignore                                         |   1 +
 .jshintrc                                          |   2 +-
 README.md                                          |  19 +-
 appveyor.yml                                       |  28 ++
 index.js                                           | 130 ++----
 package.json                                       |  13 +-
 test/fixtures/{()%!^&|;, .bat => ()%!^&;, .bat}    |   0
 test/fixtures/bar space.bat                        |   0
 test/fixtures/echo.js                              |   0
 test/fixtures/exit.js                              |   0
 test/fixtures/{()%!^&|;,  => exit1}                |   2 +-
 test/fixtures/exit1.bat                            |   1 +
 test/fixtures/foo.bat                              |   0
 test/fixtures/{()%!^&|;,  => prepare_()%!^&;, .sh} |   0
 test/fixtures/shebang_enoent                       |   3 +
 test/prepare.js                                    |  14 +
 test/test.js                                       | 519 ++++++++++++++-------
 test/util/buffered.js                              |  31 +-
 19 files changed, 486 insertions(+), 280 deletions(-)

diff --git a/.editorconfig b/.editorconfig
index 779f99a..fe988fc 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,5 +8,8 @@ charset = utf-8
 trim_trailing_whitespace = true
 insert_final_newline = true
 
+[.gitignore]
+trim_trailing_whitespace = false
+
 [*.md]
 trim_trailing_whitespace = false
diff --git a/.gitignore b/.gitignore
index c755054..fc48699 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 node_modules/
 npm-debug.*
+test/fixtures/(*
diff --git a/.jshintrc b/.jshintrc
index 2d3e748..5595ed2 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -39,7 +39,7 @@
     "es5": false,
     "esnext": false,
     "evil": false,
-    "expr": false,
+    "expr": true,
     "funcscope": false,
     "globalstrict": false,
     "iterator": false,
diff --git a/README.md b/README.md
index 55c0b1f..f94b6a6 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,14 @@
-# cross-spawn [![Build Status](https://travis-ci.org/IndigoUnited/node-cross-spawn.svg?branch=master)](https://travis-ci.org/IndigoUnited/node-cross-spawn)
+# cross-spawn [![Build Status](https://travis-ci.org/IndigoUnited/node-cross-spawn.svg?branch=master)](https://travis-ci.org/IndigoUnited/node-cross-spawn) [![Build status](https://ci.appveyor.com/api/projects/status/ckt1qfvke6mc6pe5/branch/master?svg=true)](https://ci.appveyor.com/project/satazor/node-cross-spawn/branch/master)
 
-A cross platform solution to node's spawn.
+A cross platform solution to node's spawn and spawnSync.
 
 
 ## Installation
 
 `$ 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)
+
 
 ## Why
 
@@ -15,6 +17,7 @@ Node has issues when using spawn on Windows:
 - It ignores [PATHEXT](https://github.com/joyent/node/issues/2318)
 - It does not support [shebangs](http://pt.wikipedia.org/wiki/Shebang)
 - It does not allow you to run `del` or `dir`
+- It does not properly escape arguments with spaces or special characters
 
 All these issues are handled correctly by `cross-spawn`.
 There are some known modules, such as [win-spawn](https://github.com/ForbesLindesay/win-spawn), that try to solve this but they are either broken or provide faulty escaping of shell arguments.
@@ -22,7 +25,17 @@ There are some known modules, such as [win-spawn](https://github.com/ForbesLinde
 
 ## Usage
 
-Exactly the same way as node's spawn, so it's a drop in replacement.
+Exactly the same way as node's [`spawn`](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) or [`spawnSync`](https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options), so it's a drop in replacement.
+
+```javascript
+var spawn = require('cross-spawn');
+
+// Spawn NPM asynchronously
+var process = spawn('npm', ['list', '-g', '-depth' '0'], { stdio: 'inherit' });
+
+// Spawn NPM synchronously
+var results = spawn.sync('npm', ['list', '-g', '-depth' '0'], { stdio: 'inherit' });
+```
 
 
 ## Tests
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..22c6f43
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,28 @@
+# appveyor file
+# http://www.appveyor.com/docs/appveyor-yml
+
+# build version format
+version: "{build}"
+
+# fix lineendings in Windows
+init:
+  - git config --global core.autocrlf input
+
+# what combinations to test
+environment:
+  matrix:
+    - nodejs_version: 0.10
+    - nodejs_version: 0.12
+
+# get the latest stable version of Node 0.STABLE.latest
+install:
+  - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)
+  - npm install
+
+build: off
+
+test_script:
+  - node --version
+  - npm --version
+  - ps: npm test --no-color  # PowerShell
+  - cmd: npm test --no-color
diff --git a/index.js b/index.js
index cfadaee..07b1ba4 100644
--- a/index.js
+++ b/index.js
@@ -1,115 +1,55 @@
-var fs = require('fs');
-var path = require('path');
-var cp = require('child_process');
-var LRU = require('lru-cache');
+'use strict';
 
-var isWin = process.platform === 'win32';
-var shebangCache = LRU({ max: 50, maxAge: 30 * 1000 });
+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');
 
-function readShebang(command) {
-    var buffer;
-    var fd;
-    var match;
-    var shebang;
+var isWin    = process.platform === 'win32';
+var isNode10 = process.version.indexOf('v0.10.') === 0;
 
-    // Resolve command to an absolute path if it contains /
-    if (command.indexOf(path.sep) !== -1) {
-        command = path.resolve(command);
-    }
+function verifySyncENOENT(status, parsed) {
+    // First check against the standard enoent.verifyENOENT
+    var err = enoent.verifyENOENT(status, parsed, 'spawnSync');
 
-    // Check if its resolved in the cache
-    shebang = shebangCache.get(command);
-    if (shebang) {
-        return shebang;
+    if (err) {
+        return err;
     }
 
-    // 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);
-    } catch (e) {}
-
-    // Check if it is a shebang
-    match = buffer.toString().trim().match(/\#\!\/usr\/bin\/env ([^\r\n]+)/i);
-    shebang = match && match[1];
-
-    // 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(/([\(\)%!\^<>&|;,"' ])/g, '^$1');
-    } else {
-        // Sequence of backslashes followed by a double quote:
-        // double up all the backslashes and escape the double quote
-        arg = arg.replace(/(\\*)"/gi, '$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');
+    // 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);
 
-        // All other backslashes occur literally
-
-        // Quote the whole thing:
-        arg = '"' + arg + '"';
+        if (!parsed.file) {
+            err = enoent.notFoundError(parsed.original, 'spawnSync');
+        }
     }
 
-    return arg;
-}
-
-function escapeCommand(command) {
-    // Escape shell metacharacters:
-    command = command.replace(/([\(\)%!\^<>&|;, ])/g, '^$1');
-
-    return command;
+    return err;
 }
 
 function spawn(command, args, options) {
-    var applyQuotes;
-    var shebang;
-
-    args = args || [];
-    options = options || {};
-
-    // Use node's spawn if not on windows
-    if (!isWin) {
-        return cp.spawn(command, args, options);
-    }
+    return crossSpawn.spawn(command, args, options);
+}
 
-    // Detect & add support for shebangs
-    shebang = readShebang(command);
-    if (shebang) {
-        args.unshift(command);
-        command = shebang;
-    }
+function spawnSync(command, args, options) {
+    var parsed;
+    var result;
 
-    // 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);
-    });
+    // Parse the arguments
+    parsed = parse(command, args, options);
 
-    // Use cmd.exe
-    args = ['/s', '/c', '"' + command + (args.length ? ' ' + args.join(' ') : '') + '"'];
-    command = process.env.comspec || 'cmd.exe';
+    // Spawn the child process
+    result = sync(parsed.command, parsed.args, parsed.options);
 
-    // Tell node's spawn that the arguments are already escaped
-    options.windowsVerbatimArguments = true;
+    // 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);
 
-    return cp.spawn(command, args, options);
+    return result;
 }
 
-module.exports = spawn;
+module.exports       = spawn;
 module.exports.spawn = spawn;
+module.exports.sync  = spawnSync;
diff --git a/package.json b/package.json
index ff17098..b1f2eaa 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,10 @@
 {
   "name": "cross-spawn",
-  "version": "0.2.6",
-  "description": "Cross platform child_process#spawn",
+  "version": "2.0.0",
+  "description": "Cross platform child_process#spawn and child_process#spawnSync",
   "main": "index.js",
   "scripts": {
-    "test": "mocha --bail -R spec"
+    "test": "node test/prepare && mocha --bail -R spec test/test"
   },
   "bugs": {
     "url": "https://github.com/IndigoUnited/node-cross-spawn/issues/"
@@ -15,6 +15,7 @@
   },
   "keywords": [
     "spawn",
+    "spawnSync",
     "windows",
     "cross",
     "platform",
@@ -30,10 +31,12 @@
   "author": "IndigoUnited <hello at indigounited.com> (http://indigounited.com)",
   "license": "MIT",
   "dependencies": {
-    "lru-cache": "^2.5.0"
+    "cross-spawn-async": "^2.0.0",
+    "spawn-sync": "^1.0.13"
   },
   "devDependencies": {
     "expect.js": "^0.3.0",
-    "mocha": "^1.20.1"
+    "glob": "^5.0.12",
+    "mocha": "^2.2.5"
   }
 }
diff --git a/test/fixtures/()%!^&|;, .bat b/test/fixtures/()%!^&;, .bat
old mode 100644
new mode 100755
similarity index 100%
rename from test/fixtures/()%!^&|;, .bat
rename to test/fixtures/()%!^&;, .bat
diff --git a/test/fixtures/bar space.bat b/test/fixtures/bar space.bat
old mode 100644
new mode 100755
diff --git a/test/fixtures/echo.js b/test/fixtures/echo.js
old mode 100644
new mode 100755
diff --git a/test/fixtures/exit.js b/test/fixtures/exit.js
old mode 100644
new mode 100755
diff --git a/test/fixtures/()%!^&|;,  b/test/fixtures/exit1
similarity index 50%
copy from test/fixtures/()%!^&|;, 
copy to test/fixtures/exit1
index 051009c..d87f29e 100755
--- a/test/fixtures/()%!^&|;, 	
+++ b/test/fixtures/exit1
@@ -1,3 +1,3 @@
 #!/bin/bash
 
-echo special
+exit 1
diff --git a/test/fixtures/exit1.bat b/test/fixtures/exit1.bat
new file mode 100755
index 0000000..379a4c9
--- /dev/null
+++ b/test/fixtures/exit1.bat
@@ -0,0 +1 @@
+exit 1
diff --git a/test/fixtures/foo.bat b/test/fixtures/foo.bat
old mode 100644
new mode 100755
diff --git a/test/fixtures/()%!^&|;,  b/test/fixtures/prepare_()%!^&;, .sh
similarity index 100%
rename from test/fixtures/()%!^&|;, 
rename to test/fixtures/prepare_()%!^&;, .sh
diff --git a/test/fixtures/shebang_enoent b/test/fixtures/shebang_enoent
new file mode 100755
index 0000000..bd86265
--- /dev/null
+++ b/test/fixtures/shebang_enoent
@@ -0,0 +1,3 @@
+#!/usr/bin/env somecommandthatwillneverexist
+
+echo foo
diff --git a/test/prepare.js b/test/prepare.js
new file mode 100644
index 0000000..addb078
--- /dev/null
+++ b/test/prepare.js
@@ -0,0 +1,14 @@
+var glob = require('glob');
+var fs   = require('fs');
+
+var fixturesDir = __dirname + '/fixtures';
+
+glob.sync('prepare_*', { cwd: __dirname + '/fixtures' }).forEach(function (file) {
+    var contents = fs.readFileSync(fixturesDir + '/' + file);
+    var finalFile = file.replace(/^prepare_/, '').replace(/\.sh$/, '');
+
+    fs.writeFileSync(fixturesDir + '/' + finalFile, contents);
+    fs.chmodSync(fixturesDir + '/' + finalFile, 0777);
+
+    process.stdout.write('Copied "' + file + '" to "' + finalFile + '"\n');
+});
diff --git a/test/test.js b/test/test.js
index b8260b7..819f894 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,192 +1,381 @@
 'use strict';
 
+var path     = require('path');
+var expect   = require('expect.js');
 var buffered = require('./util/buffered');
-var expect = require('expect.js');
+var spawn    = require('../');
+
+var isWin    = process.platform === 'win32';
 
 describe('cross-spawn', function () {
-    it('should support shebang in executables', function (next) {
-        buffered(__dirname + '/fixtures/shebang', function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data).to.equal('shebang works!');
+    var methods = ['spawn', 'sync'];
 
-            next();
-        });
-    });
+    methods.forEach(function (method) {
+        describe(method, function() {
+            it('should support shebang in executables', function (next) {
+                buffered(method, __dirname + '/fixtures/shebang', function (err, data, code) {
+                    var envPath;
 
-    it('should expand using PATHEXT properly', function (next) {
-        buffered(__dirname + '/fixtures/foo', function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data.trim()).to.equal('foo');
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('shebang works!');
 
-            next();
-        });
-    });
+                    // Test if the actual shebang file is resolved against the PATH
+                    envPath = process.env.PATH;
+                    process.env.PATH = path.normalize(__dirname + '/fixtures/') + path.delimiter + process.env.PATH;
 
-    it('should handle commands with spaces', function (next) {
-        buffered(__dirname + '/fixtures/bar space', function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data.trim()).to.equal('bar');
+                    buffered(method, 'shebang', function (err, data, code) {
+                        process.env.PATH = envPath;
 
-            next();
-        });
-    });
+                        expect(err).to.not.be.ok();
+                        expect(code).to.be(0);
+                        expect(data).to.equal('shebang works!');
 
-    it('should handle commands with special shell chars', function (next) {
-        buffered(__dirname + '/fixtures/()%!^&|;, ', function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data.trim()).to.equal('special');
+                        next();
+                    });
+                });
+            });
 
-            next();
-        });
-    });
+            it('should expand using PATHEXT properly', function (next) {
+                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data.trim()).to.equal('foo');
 
-    it('should handle empty arguments', function (next) {
-        buffered('node', [
-            __dirname + '/fixtures/echo',
-            'foo',
-            '',
-            'bar'
-        ], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data).to.equal('foo\n\nbar');
-
-            buffered('echo', [
-                'foo',
-                '',
-                'bar'
-            ], function (err, data, code) {
-                expect(err).to.not.be.ok();
-                expect(code).to.be(0);
-                expect(data.trim()).to.equal('foo  bar');
-
-                next();
+                    next();
+                });
             });
-        });
-    });
 
-    it('should handle non-string arguments', function (next) {
-        buffered('node', [
-            __dirname + '/fixtures/echo',
-            1234
-        ], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data).to.equal('1234');
+            it('should handle commands with spaces', function (next) {
+                buffered(method, __dirname + '/fixtures/bar space', function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data.trim()).to.equal('bar');
 
-            next();
-        });
-    });
+                    next();
+                });
+            });
 
-    it('should handle arguments with spaces', function (next) {
-        buffered('node', [
-            __dirname + '/fixtures/echo',
-            'I am',
-            'André Cruz'
-        ], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data).to.equal('I am\nAndré Cruz');
-
-            next();
-        });
-    });
+            it('should handle commands with special shell chars', function (next) {
+                buffered(method, __dirname + '/fixtures/()%!^&;, ', function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data.trim()).to.equal('special');
 
-    it('should handle arguments with \\"', function (next) {
-        buffered('node', [
-            __dirname + '/fixtures/echo',
-            'foo',
-            '\\"',
-            'bar'
-        ], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data).to.equal('foo\n\\"\nbar');
-
-            next();
-        });
-    });
+                    next();
+                });
+            });
 
-    it('should handle arguments that end with \\', function (next) {
-        buffered('node', [
-            __dirname + '/fixtures/echo',
-            'foo',
-            'bar\\',
-            'baz'
-        ], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data).to.equal('foo\nbar\\\nbaz');
-
-            next();
-        });
-    });
+            it('should handle empty arguments', function (next) {
+                buffered(method, 'node', [
+                    __dirname + '/fixtures/echo',
+                    'foo',
+                    '',
+                    'bar'
+                ], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('foo\n\nbar');
 
-    it('should handle arguments that contain shell special chars', function (next) {
-        buffered('node', [
-            __dirname + '/fixtures/echo',
-            'foo',
-            '()',
-            'foo',
-            '%!',
-            'foo',
-            '^<',
-            'foo',
-            '>&',
-            'foo',
-            '|;',
-            'foo',
-            ', ',
-            'foo'
-        ], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data).to.equal('foo\n()\nfoo\n%!\nfoo\n^<\nfoo\n>&\nfoo\n|;\nfoo\n, \nfoo');
-
-            next();
-        });
-    });
+                    buffered(method, 'echo', [
+                        'foo',
+                        '',
+                        'bar'
+                    ], function (err, data, code) {
+                        expect(err).to.not.be.ok();
+                        expect(code).to.be(0);
+                        expect(data.trim()).to.equal('foo  bar');
 
-    it('should handle special arguments when using echo', function (next) {
-        buffered('echo', ['foo\\"foo\\foo&bar"foo\'bar'], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(0);
-            expect(data.trim()).to.equal('foo\\"foo\\foo&bar"foo\'bar');
-
-            buffered('echo', [
-                'foo',
-                '()',
-                'foo',
-                '%!',
-                'foo',
-                '^<',
-                'foo',
-                '>&',
-                'foo',
-                '|;',
-                'foo',
-                ', ',
-                'foo'
-            ], function (err, data, code) {
-                expect(err).to.not.be.ok();
-                expect(code).to.be(0);
-                expect(data.trim()).to.equal('foo () foo %! foo ^< foo >& foo |; foo ,  foo');
-
-                next();
+                        next();
+                    });
+                });
             });
-        });
-    });
 
-    it('should give correct exit code', function (next) {
-        buffered('node', [ __dirname + '/fixtures/exit'], function (err, data, code) {
-            expect(err).to.not.be.ok();
-            expect(code).to.be(25);
+            it('should handle non-string arguments', function (next) {
+                buffered(method, 'node', [
+                    __dirname + '/fixtures/echo',
+                    1234
+                ], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('1234');
+
+                    next();
+                });
+            });
+
+            it('should handle arguments with spaces', function (next) {
+                buffered(method, 'node', [
+                    __dirname + '/fixtures/echo',
+                    'I am',
+                    'André Cruz'
+                ], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('I am\nAndré Cruz');
+
+                    next();
+                });
+            });
+
+            it('should handle arguments with \\"', function (next) {
+                buffered(method, 'node', [
+                    __dirname + '/fixtures/echo',
+                    'foo',
+                    '\\"',
+                    'bar'
+                ], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('foo\n\\"\nbar');
+
+                    next();
+                });
+            });
+
+            it('should handle arguments that end with \\', function (next) {
+                buffered(method, 'node', [
+                    __dirname + '/fixtures/echo',
+                    'foo',
+                    'bar\\',
+                    'baz'
+                ], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('foo\nbar\\\nbaz');
+
+                    next();
+                });
+            });
+
+            it('should handle arguments that contain shell special chars', function (next) {
+                buffered(method, 'node', [
+                    __dirname + '/fixtures/echo',
+                    'foo',
+                    '()',
+                    'foo',
+                    '%!',
+                    'foo',
+                    '^<',
+                    'foo',
+                    '>&',
+                    'foo',
+                    '|;',
+                    'foo',
+                    ', ',
+                    'foo'
+                ], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data).to.equal('foo\n()\nfoo\n%!\nfoo\n^<\nfoo\n>&\nfoo\n|;\nfoo\n, \nfoo');
+
+                    next();
+                });
+            });
+
+            it('should handle special arguments when using echo', function (next) {
+                buffered(method, 'echo', ['foo\\"foo\\foo&bar"foo\'bar'], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data.trim()).to.equal('foo\\"foo\\foo&bar"foo\'bar');
+
+                    buffered(method, 'echo', [
+                        'foo',
+                        '()',
+                        'foo',
+                        '%!',
+                        'foo',
+                        '^<',
+                        'foo',
+                        '>&',
+                        'foo',
+                        '|;',
+                        'foo',
+                        ', ',
+                        'foo'
+                    ], function (err, data, code) {
+                        expect(err).to.not.be.ok();
+                        expect(code).to.be(0);
+                        expect(data.trim()).to.equal('foo () foo %! foo ^< foo >& foo |; foo ,  foo');
+
+                        next();
+                    });
+                });
+            });
+
+            it('should handle optional args correctly', function (next) {
+                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+
+                    buffered(method, __dirname + '/fixtures/foo', {
+                        stdio: ['pipe', 'pipe', 'pipe'],
+                    }, function (err, data, code) {
+                        expect(err).to.not.be.ok();
+                        expect(code).to.be(0);
+
+                        buffered(method, __dirname + '/fixtures/foo', null, {
+                            stdio: ['pipe', 'pipe', 'pipe'],
+                        }, function (err, data, code) {
+                            expect(err).to.not.be.ok();
+                            expect(code).to.be(0);
+
+                            next();
+                        });
+                    });
+                });
+            });
+
+            it('should not mutate args nor options', function (next) {
+                var args = [];
+                var options = {};
+
+                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+
+                    expect(args).to.have.length(0);
+                    expect(Object.keys(options)).to.have.length(0);
+
+                    next();
+                });
+            });
+
+            it('should give correct exit code', function (next) {
+                buffered(method, 'node', [__dirname + '/fixtures/exit'], function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(25);
+
+                    next();
+                });
+            });
+
+            it('should work with a relative command', function (next) {
+                buffered(method, path.relative(process.cwd(), __dirname + '/fixtures/foo'), function (err, data, code) {
+                    expect(err).to.not.be.ok();
+                    expect(code).to.be(0);
+                    expect(data.trim()).to.equal('foo');
+
+                    if (!isWin) {
+                        return next();
+                    }
+
+                    buffered(method, path.relative(process.cwd(), __dirname + '/fixtures/foo.bat'), function (err, data, code) {
+                        expect(err).to.not.be.ok();
+                        expect(code).to.be(0);
+                        expect(data.trim()).to.equal('foo');
 
-            next();
+                        next();
+                    });
+                });
+            });
+
+            it('should emit "error" and "close" if command does not exist', function (next) {
+                var errors;
+                var spawned = spawn[method]('somecommandthatwillneverexist');
+
+                this.timeout(5000);
+
+                function assertError(err) {
+                    var syscall = method === 'sync' ? 'spawnSync' : 'spawn';
+
+                    expect(err).to.be.an(Error);
+                    expect(err.message).to.contain(syscall);
+                    expect(err.message).to.contain('ENOENT');
+                    expect(err.message).to.not.contain('undefined');
+                    expect(err.code).to.be('ENOENT');
+                    expect(err.errno).to.be('ENOENT');
+                    expect(err.syscall).to.contain(syscall);
+                    expect(err.syscall).to.not.contain('undefined');
+                }
+
+                if (method === 'spawn') {
+                    errors = [];
+
+                    spawned
+                    .on('error', function (err) {
+                        errors.push(err);
+                    })
+                    .on('exit', function () {
+                        spawned.removeAllListeners();
+                        next(new Error('Should not emit exit'));
+                    })
+                    .on('close', function (code, signal) {
+                        expect(code).to.not.be(0);
+                        expect(signal).to.be(null);
+
+                        setTimeout(function () {
+                            expect(errors).to.have.length(1);
+                            assertError(errors[0]);
+
+                            next();
+                        }, 1000);
+                    });
+                } else {
+                    assertError(spawned.error);
+                    next();
+                }
+            });
+
+            it('should NOT emit "error" if shebang command does not exist', function (next) {
+                var spawned = spawn[method](__dirname + '/fixtures/shebang_enoent');
+                var exited;
+                var timeout;
+
+                this.timeout(5000);
+
+                if (method === 'spawn') {
+                    spawned
+                    .on('error', function (err) {
+                        spawned.removeAllListeners();
+                        clearTimeout(timeout);
+                        next(new Error('Should not emit error'));
+                    })
+                    .on('exit', function () {
+                        exited = true;
+                    })
+                    .on('close', function (code, signal) {
+                        expect(code).to.not.be(0);
+                        expect(signal).to.be(null);
+                        expect(exited).to.be(true);
+
+                        timeout = setTimeout(next, 1000);
+                    });
+                } else {
+                    expect(spawned.error).to.not.be.ok();
+                    next();
+                }
+            });
+
+            it('should NOT emit "error" if the command actual exists but exited with 1', function (next) {
+                var spawned = spawn[method](__dirname + '/fixtures/exit1');
+                var exited;
+                var timeout;
+
+                this.timeout(5000);
+
+                if (method === 'spawn') {
+                    spawned
+                    .on('error', function (err) {
+                        spawned.removeAllListeners();
+                        clearTimeout(timeout);
+                        next(new Error('Should not emit error'));
+                    })
+                    .on('exit', function () {
+                        exited = true;
+                    })
+                    .on('close', function (code, signal) {
+                        expect(code).to.not.be(0);
+                        expect(signal).to.be(null);
+                        expect(exited).to.be(true);
+
+                        timeout = setTimeout(next, 1000);
+                    });
+                } else {
+                    expect(spawned.error).to.not.be.ok();
+                    next();
+                }
+            });
         });
     });
 });
diff --git a/test/util/buffered.js b/test/util/buffered.js
index 4659849..37cd15e 100644
--- a/test/util/buffered.js
+++ b/test/util/buffered.js
@@ -2,7 +2,11 @@
 
 var spawn = require('../../index');
 
-function buffered(command, args, options, callback) {
+function buffered(method, command, args, options, callback) {
+    var cp;
+    var data;
+    var results;
+
     if (typeof options === 'function') {
         callback = options;
         options = null;
@@ -13,18 +17,25 @@ function buffered(command, args, options, callback) {
         args = options = null;
     }
 
-    var cp = spawn(command, args, options);
-    var data = '';
+    if (method === 'sync') {
+        results = spawn.sync(command, args, options);
+        callback(results.error, results.stdout ? results.stdout.toString() : null, results.status);
+    }
+    else {
+        cp = spawn(command, args, options);
+        data = null;
 
-    cp.stdout.on('data', function (buffer) {
-        data += buffer.toString();
-    });
+        cp.stdout && cp.stdout.on('data', function(buffer) {
+            data = data || '';
+            data += buffer.toString();
+        });
 
-    cp.on('error', callback);
+        cp.on('error', callback);
 
-    cp.on('close', function (code) {
-        callback(null, data, code);
-    });
+        cp.on('close', function(code) {
+            callback(null, data, code);
+        });
+    }
 }
 
 module.exports = buffered;

-- 
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