diff options
Diffstat (limited to 'node_modules/cross-spawn/lib')
-rw-r--r-- | node_modules/cross-spawn/lib/enoent.js | 73 | ||||
-rw-r--r-- | node_modules/cross-spawn/lib/hasBrokenSpawn.js | 11 | ||||
-rw-r--r-- | node_modules/cross-spawn/lib/parse.js | 140 | ||||
-rw-r--r-- | node_modules/cross-spawn/lib/resolveCommand.js | 31 |
4 files changed, 255 insertions, 0 deletions
diff --git a/node_modules/cross-spawn/lib/enoent.js b/node_modules/cross-spawn/lib/enoent.js new file mode 100644 index 000000000..74ff06e49 --- /dev/null +++ b/node_modules/cross-spawn/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/node_modules/cross-spawn/lib/hasBrokenSpawn.js b/node_modules/cross-spawn/lib/hasBrokenSpawn.js new file mode 100644 index 000000000..e73f906b6 --- /dev/null +++ b/node_modules/cross-spawn/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/node_modules/cross-spawn/lib/parse.js b/node_modules/cross-spawn/lib/parse.js new file mode 100644 index 000000000..77cbb83d2 --- /dev/null +++ b/node_modules/cross-spawn/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/node_modules/cross-spawn/lib/resolveCommand.js b/node_modules/cross-spawn/lib/resolveCommand.js new file mode 100644 index 000000000..b7a949097 --- /dev/null +++ b/node_modules/cross-spawn/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; |