diff options
Diffstat (limited to 'node_modules/cross-spawn/lib')
-rw-r--r-- | node_modules/cross-spawn/lib/enoent.js | 56 | ||||
-rw-r--r-- | node_modules/cross-spawn/lib/hasBrokenSpawn.js | 11 | ||||
-rw-r--r-- | node_modules/cross-spawn/lib/parse.js | 197 | ||||
-rw-r--r-- | node_modules/cross-spawn/lib/resolveCommand.js | 31 |
4 files changed, 112 insertions, 183 deletions
diff --git a/node_modules/cross-spawn/lib/enoent.js b/node_modules/cross-spawn/lib/enoent.js index 74ff06e49..14df9b623 100644 --- a/node_modules/cross-spawn/lib/enoent.js +++ b/node_modules/cross-spawn/lib/enoent.js @@ -1,43 +1,37 @@ '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; +const isWin = process.platform === 'win32'; + +function notFoundError(original, syscall) { + return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), { + code: 'ENOENT', + errno: 'ENOENT', + syscall: `${syscall} ${original.command}`, + path: original.command, + spawnargs: original.args, + }); } function hookChildProcess(cp, parsed) { - var originalEmit; - if (!isWin) { return; } - originalEmit = cp.emit; - cp.emit = function (name, arg1) { - var err; + const originalEmit = cp.emit; + cp.emit = function (name, arg1) { // 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 + // See https://github.com/IndigoUnited/node-cross-spawn/issues/16 if (name === 'exit') { - err = verifyENOENT(arg1, parsed, 'spawn'); + const err = verifyENOENT(arg1, parsed, 'spawn'); if (err) { return originalEmit.call(cp, 'error', err); } } - return originalEmit.apply(cp, arguments); + return originalEmit.apply(cp, arguments); // eslint-disable-line prefer-rest-params }; } @@ -54,20 +48,12 @@ function verifyENOENTSync(status, parsed) { 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; +module.exports = { + hookChildProcess, + verifyENOENT, + verifyENOENTSync, + notFoundError, +}; diff --git a/node_modules/cross-spawn/lib/hasBrokenSpawn.js b/node_modules/cross-spawn/lib/hasBrokenSpawn.js deleted file mode 100644 index e73f906b6..000000000 --- a/node_modules/cross-spawn/lib/hasBrokenSpawn.js +++ /dev/null @@ -1,11 +0,0 @@ -'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 index 77cbb83d2..962827a94 100644 --- a/node_modules/cross-spawn/lib/parse.js +++ b/node_modules/cross-spawn/lib/parse.js @@ -1,140 +1,125 @@ '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); - } +const path = require('path'); +const niceTry = require('nice-try'); +const resolveCommand = require('./util/resolveCommand'); +const escape = require('./util/escape'); +const readShebang = require('./util/readShebang'); +const semver = require('semver'); - // Read the first 150 bytes from the file - buffer = new Buffer(150); +const isWin = process.platform === 'win32'; +const isExecutableRegExp = /\.(?:com|exe)$/i; +const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i; - try { - fd = fs.openSync(command, 'r'); - fs.readSync(fd, buffer, 0, 150, 0); - fs.closeSync(fd); - } catch (e) { /* empty */ } +// `options.shell` is supported in Node ^4.8.0, ^5.7.0 and >= 6.0.0 +const supportsShellOption = niceTry(() => semver.satisfies(process.version, '^4.8.0 || ^5.7.0 || >= 6.0.0', true)) || false; - // Check if it is a shebang - match = buffer.toString().trim().match(/#!(.+)/i); +function detectShebang(parsed) { + parsed.file = resolveCommand(parsed); - if (match) { - shebang = match[1].replace(/\/usr\/bin\/env\s+/i, ''); // Remove /usr/bin/env - } + const shebang = parsed.file && readShebang(parsed.file); - // Store the shebang in the cache - shebangCache.set(command, shebang); + if (shebang) { + parsed.args.unshift(parsed.file); + parsed.command = shebang; + + return resolveCommand(parsed); + } - return shebang; + return parsed.file; } -function escapeArg(arg, quote) { - // Convert to string - arg = '' + arg; +function parseNonShell(parsed) { + if (!isWin) { + return parsed; + } - // 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\\"'); + // Detect & add support for shebangs + const commandFile = detectShebang(parsed); - // 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'); + // We don't need a shell if the command filename is an executable + const needsShell = !isExecutableRegExp.test(commandFile); - // All other backslashes occur literally + // If a shell is required, use cmd.exe and take care of escaping everything correctly + // Note that `forceShell` is an hidden option used only in tests + if (parsed.options.forceShell || needsShell) { + // Need to double escape meta chars if the command is a cmd-shim located in `node_modules/.bin/` + // The cmd-shim simply calls execute the package bin file with NodeJS, proxying any argument + // Because the escape of metachars with ^ gets interpreted when the cmd.exe is first called, + // we need to double escape them + const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile); - // Quote the whole thing: - arg = '"' + arg + '"'; - } + // Normalize posix paths into OS compatible paths (e.g.: foo/bar -> foo\bar) + // This is necessary otherwise it will always fail with ENOENT in those cases + parsed.command = path.normalize(parsed.command); - return arg; -} + // Escape command & arguments + parsed.command = escape.command(parsed.command); + parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars)); -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); -} + const shellCommand = [parsed.command].concat(parsed.args).join(' '); -function requiresShell(command) { - return !/\.(?:com|exe)$/i.test(command); -} + parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`]; + parsed.command = process.env.comspec || 'cmd.exe'; + parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped + } -function parse(command, args, options) { - var shebang; - var applyQuotes; - var file; - var original; - var shell; + return parsed; +} - // Normalize arguments, similar to nodejs - if (args && !Array.isArray(args)) { - options = args; - args = null; +function parseShell(parsed) { + // If node supports the shell option, there's no need to mimic its behavior + if (supportsShellOption) { + return parsed; } - args = args ? args.slice(0) : []; // Clone array to avoid changing the original - options = options || {}; - original = command; + // Mimic node shell option + // See https://github.com/nodejs/node/blob/b9f6a2dc059a1062776133f3d4fd848c4da7d150/lib/child_process.js#L335 + const shellCommand = [parsed.command].concat(parsed.args).join(' '); 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)); + parsed.command = typeof parsed.options.shell === 'string' ? parsed.options.shell : process.env.comspec || 'cmd.exe'; + parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`]; + parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped + } else { + if (typeof parsed.options.shell === 'string') { + parsed.command = parsed.options.shell; + } else if (process.platform === 'android') { + parsed.command = '/system/bin/sh'; } else { - shell = shell || requiresShell(file); + parsed.command = '/bin/sh'; } - 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); - }); + parsed.args = ['-c', shellCommand]; + } - // Use cmd.exe - args = ['/s', '/c', '"' + command + (args.length ? ' ' + args.join(' ') : '') + '"']; - command = process.env.comspec || 'cmd.exe'; + return parsed; +} - // Tell node's spawn that the arguments are already escaped - options.windowsVerbatimArguments = true; - } +function parse(command, args, options) { + // Normalize arguments, similar to nodejs + if (args && !Array.isArray(args)) { + options = args; + args = null; } - return { - command: command, - args: args, - options: options, - file: file, - original: original, + args = args ? args.slice(0) : []; // Clone array to avoid changing the original + options = Object.assign({}, options); // Clone object to avoid changing the original + + // Build our parsed object + const parsed = { + command, + args, + options, + file: undefined, + original: { + command, + args, + }, }; + + // Delegate further parsing to shell or non-shell + return options.shell ? parseShell(parsed) : parseNonShell(parsed); } module.exports = parse; diff --git a/node_modules/cross-spawn/lib/resolveCommand.js b/node_modules/cross-spawn/lib/resolveCommand.js deleted file mode 100644 index b7a949097..000000000 --- a/node_modules/cross-spawn/lib/resolveCommand.js +++ /dev/null @@ -1,31 +0,0 @@ -'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; |