diff options
Diffstat (limited to 'deps/npm/node_modules/libnpx/node_modules/yargs/node_modules/os-locale/node_modules/execa/node_modules/cross-spawn/lib/parse.js')
-rw-r--r-- | deps/npm/node_modules/libnpx/node_modules/yargs/node_modules/os-locale/node_modules/execa/node_modules/cross-spawn/lib/parse.js | 169 |
1 files changed, 71 insertions, 98 deletions
diff --git a/deps/npm/node_modules/libnpx/node_modules/yargs/node_modules/os-locale/node_modules/execa/node_modules/cross-spawn/lib/parse.js b/deps/npm/node_modules/libnpx/node_modules/yargs/node_modules/os-locale/node_modules/execa/node_modules/cross-spawn/lib/parse.js index 77cbb83d2d..10a013625b 100644 --- a/deps/npm/node_modules/libnpx/node_modules/yargs/node_modules/os-locale/node_modules/execa/node_modules/cross-spawn/lib/parse.js +++ b/deps/npm/node_modules/libnpx/node_modules/yargs/node_modules/os-locale/node_modules/execa/node_modules/cross-spawn/lib/parse.js @@ -1,90 +1,92 @@ 'use strict'; -var fs = require('fs'); -var LRU = require('lru-cache'); -var resolveCommand = require('./resolveCommand'); -var hasBrokenSpawn = require('./hasBrokenSpawn'); +var resolveCommand = require('./util/resolveCommand'); +var hasEmptyArgumentBug = require('./util/hasEmptyArgumentBug'); +var escapeArgument = require('./util/escapeArgument'); +var escapeCommand = require('./util/escapeCommand'); +var readShebang = require('./util/readShebang'); var isWin = process.platform === 'win32'; -var shebangCache = new LRU({ max: 50, maxAge: 30 * 1000 }); // Cache just for 30sec +var skipShellRegExp = /\.(?:com|exe)$/i; -function readShebang(command) { - var buffer; - var fd; - var match; +// Supported in Node >= 6 and >= 4.8 +var supportsShellOption = parseInt(process.version.substr(1).split('.')[0], 10) >= 6 || + parseInt(process.version.substr(1).split('.')[0], 10) === 4 && parseInt(process.version.substr(1).split('.')[1], 10) >= 8; + +function parseNonShell(parsed) { var shebang; + var needsShell; + var applyQuotes; - // Check if it is in the cache first - if (shebangCache.has(command)) { - return shebangCache.get(command); + if (!isWin) { + return parsed; } - // 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); + // Detect & add support for shebangs + parsed.file = resolveCommand(parsed.command); + parsed.file = parsed.file || resolveCommand(parsed.command, true); + shebang = parsed.file && readShebang(parsed.file); - if (match) { - shebang = match[1].replace(/\/usr\/bin\/env\s+/i, ''); // Remove /usr/bin/env + if (shebang) { + parsed.args.unshift(parsed.file); + parsed.command = shebang; + needsShell = hasEmptyArgumentBug || !skipShellRegExp.test(resolveCommand(shebang) || resolveCommand(shebang, true)); + } else { + needsShell = hasEmptyArgumentBug || !skipShellRegExp.test(parsed.file); } - // Store the shebang in the cache - shebangCache.set(command, shebang); + // If a shell is required, use cmd.exe and take care of escaping everything correctly + if (needsShell) { + // Escape command & arguments + applyQuotes = (parsed.command !== 'echo'); // Do not quote arguments for the special "echo" command + parsed.command = escapeCommand(parsed.command); + parsed.args = parsed.args.map(function (arg) { + return escapeArgument(arg, applyQuotes); + }); + + // Make use of cmd.exe + parsed.args = ['/d', '/s', '/c', '"' + parsed.command + (parsed.args.length ? ' ' + parsed.args.join(' ') : '') + '"']; + parsed.command = process.env.comspec || 'cmd.exe'; + parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped + } - return shebang; + return parsed; } -function escapeArg(arg, quote) { - // Convert to string - arg = '' + arg; +function parseShell(parsed) { + var shellCommand; - // 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\\"'); + // If node supports the shell option, there's no need to mimic its behavior + if (supportsShellOption) { + return 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'); + // Mimic node shell option, see: https://github.com/nodejs/node/blob/b9f6a2dc059a1062776133f3d4fd848c4da7d150/lib/child_process.js#L335 + shellCommand = [parsed.command].concat(parsed.args).join(' '); - // All other backslashes occur literally + if (isWin) { + 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 { + parsed.command = '/bin/sh'; + } - // Quote the whole thing: - arg = '"' + arg + '"'; + parsed.args = ['-c', shellCommand]; } - return arg; + return parsed; } -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; + var parsed; // Normalize arguments, similar to nodejs if (args && !Array.isArray(args)) { @@ -94,47 +96,18 @@ function parse(command, args, options) { 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 { + // Build our parsed object + parsed = { command: command, args: args, options: options, - file: file, - original: original, + file: undefined, + original: command, }; + + // Delegate further parsing to shell or non-shell + return options.shell ? parseShell(parsed) : parseNonShell(parsed); } module.exports = parse; |