Clean up the oopsie. Rebuild the blank exercises.

This commit is contained in:
Michael Frank
2021-05-09 00:39:21 +12:00
parent b984cb4c6f
commit d28d80c46f
1565 changed files with 27186 additions and 199003 deletions
+99 -5
View File
@@ -1,6 +1,100 @@
## 5.0.0 - 2016-10-30
# Change Log
- Add support for `options.shell`
- Improve parsing of shebangs by using [`shebang-command`](https://github.com/kevva/shebang-command) module
- Refactor some code to make it more clear
- Update README caveats
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
<a name="6.0.5"></a>
## [6.0.5](https://github.com/moxystudio/node-cross-spawn/compare/v6.0.4...v6.0.5) (2018-03-02)
### Bug Fixes
* avoid using deprecated Buffer constructor ([#94](https://github.com/moxystudio/node-cross-spawn/issues/94)) ([d5770df](https://github.com/moxystudio/node-cross-spawn/commit/d5770df)), closes [/nodejs.org/api/deprecations.html#deprecations_dep0005](https://github.com//nodejs.org/api/deprecations.html/issues/deprecations_dep0005)
<a name="6.0.4"></a>
## [6.0.4](https://github.com/moxystudio/node-cross-spawn/compare/v6.0.3...v6.0.4) (2018-01-31)
### Bug Fixes
* fix paths being incorrectly normalized on unix ([06ee3c6](https://github.com/moxystudio/node-cross-spawn/commit/06ee3c6)), closes [#90](https://github.com/moxystudio/node-cross-spawn/issues/90)
<a name="6.0.3"></a>
## [6.0.3](https://github.com/moxystudio/node-cross-spawn/compare/v6.0.2...v6.0.3) (2018-01-23)
<a name="6.0.2"></a>
## [6.0.2](https://github.com/moxystudio/node-cross-spawn/compare/v6.0.1...v6.0.2) (2018-01-23)
<a name="6.0.1"></a>
## [6.0.1](https://github.com/moxystudio/node-cross-spawn/compare/v6.0.0...v6.0.1) (2018-01-23)
<a name="6.0.0"></a>
# [6.0.0](https://github.com/moxystudio/node-cross-spawn/compare/5.1.0...6.0.0) (2018-01-23)
### Bug Fixes
* fix certain arguments not being correctly escaped or causing batch syntax error ([900cf10](https://github.com/moxystudio/node-cross-spawn/commit/900cf10)), closes [#82](https://github.com/moxystudio/node-cross-spawn/issues/82) [#51](https://github.com/moxystudio/node-cross-spawn/issues/51)
* fix commands as posix relatixe paths not working correctly, e.g.: `./my-command` ([900cf10](https://github.com/moxystudio/node-cross-spawn/commit/900cf10))
* fix `options` argument being mutated ([900cf10](https://github.com/moxystudio/node-cross-spawn/commit/900cf10))
* fix commands resolution when PATH was actually Path ([900cf10](https://github.com/moxystudio/node-cross-spawn/commit/900cf10))
### Features
* improve compliance with node's ENOENT errors ([900cf10](https://github.com/moxystudio/node-cross-spawn/commit/900cf10))
* improve detection of node's shell option support ([900cf10](https://github.com/moxystudio/node-cross-spawn/commit/900cf10))
### Chores
* upgrade tooling
* upgrate project to es6 (node v4)
### BREAKING CHANGES
* remove support for older nodejs versions, only `node >= 4` is supported
<a name="5.1.0"></a>
## [5.1.0](https://github.com/moxystudio/node-cross-spawn/compare/5.0.1...5.1.0) (2017-02-26)
### Bug Fixes
* fix `options.shell` support for NodeJS [v4.8](https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V4.md#4.8.0)
<a name="5.0.1"></a>
## [5.0.1](https://github.com/moxystudio/node-cross-spawn/compare/5.0.0...5.0.1) (2016-11-04)
### Bug Fixes
* fix `options.shell` support for NodeJS v7
<a name="5.0.0"></a>
# [5.0.0](https://github.com/moxystudio/node-cross-spawn/compare/4.0.2...5.0.0) (2016-10-30)
## Features
* add support for `options.shell`
* improve parsing of shebangs by using [`shebang-command`](https://github.com/kevva/shebang-command) module
## Chores
* refactor some code to make it more clear
* update README caveats
+7 -5
View File
@@ -1,14 +1,16 @@
Copyright (c) 2014 IndigoUnited
The MIT License (MIT)
Copyright (c) 2018 Made With MOXY Lda <hello@moxy.studio>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+34 -25
View File
@@ -1,18 +1,22 @@
# cross-spawn
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Build status][appveyor-image]][appveyor-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url]
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Build status][appveyor-image]][appveyor-url] [![Coverage Status][codecov-image]][codecov-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url] [![Greenkeeper badge][greenkeeper-image]][greenkeeper-url]
[npm-url]:https://npmjs.org/package/cross-spawn
[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/master.svg
[travis-url]:https://travis-ci.org/moxystudio/node-cross-spawn
[travis-image]:http://img.shields.io/travis/moxystudio/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/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
[david-dm-dev-image]:https://img.shields.io/david/dev/IndigoUnited/node-cross-spawn.svg
[codecov-url]:https://codecov.io/gh/moxystudio/node-cross-spawn
[codecov-image]:https://img.shields.io/codecov/c/github/moxystudio/node-cross-spawn/master.svg
[david-dm-url]:https://david-dm.org/moxystudio/node-cross-spawn
[david-dm-image]:https://img.shields.io/david/moxystudio/node-cross-spawn.svg
[david-dm-dev-url]:https://david-dm.org/moxystudio/node-cross-spawn?type=dev
[david-dm-dev-image]:https://img.shields.io/david/dev/moxystudio/node-cross-spawn.svg
[greenkeeper-image]:https://badges.greenkeeper.io/moxystudio/node-cross-spawn.svg
[greenkeeper-url]:https://greenkeeper.io/
A cross platform solution to node's spawn and spawnSync.
@@ -21,19 +25,17 @@ A cross platform solution to node's spawn and spawnSync.
`$ npm install cross-spawn`
If you are using `spawnSync` on node 0.10 or older, you will also need to install `spawn-sync`:
`$ npm install spawn-sync`
## Why
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)
- No `options.shell` support on node < v6
- It does not allow you to run `del` or `dir`
- It does not support [shebangs](https://en.wikipedia.org/wiki/Shebang_(Unix))
- Has problems running commands with [spaces](https://github.com/nodejs/node/issues/7367)
- Has problems running commands with posix relative paths (e.g.: `./my-folder/my-executable`)
- Has an [issue](https://github.com/moxystudio/node-cross-spawn/issues/82) with command shims (files in `node_modules/.bin/`), where arguments with quotes and parenthesis would result in [invalid syntax error](https://github.com/moxystudio/node-cross-spawn/blob/e77b8f22a416db46b6196767bcd35601d7e11d54/test/index.test.js#L149)
- No `options.shell` support on node `<v4.8`
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.
@@ -45,40 +47,47 @@ Exactly the same way as node's [`spawn`](https://nodejs.org/api/child_process.ht
```js
var spawn = require('cross-spawn');
const spawn = require('cross-spawn');
// Spawn NPM asynchronously
var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
const child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
// Spawn NPM synchronously
var results = spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
const result = spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
```
## Caveats
#### `options.shell` as an alternative to `cross-spawn`
### Using `options.shell` as an alternative to `cross-spawn`
Starting from node v6, `spawn` has a `shell` option that allows you run commands from within a shell. This new option solves most of the problems that `cross-spawn` attempts to solve, but:
Starting from node `v4.8`, `spawn` has a `shell` option that allows you run commands from within a shell. This new option solves
the [PATHEXT](https://github.com/joyent/node/issues/2318) issue but:
- It's not supported in node < v6
- It has no support for shebangs on Windows
- It's not supported in node `<v4.8`
- You must manually escape the command and arguments which is very error prone, specially when passing user input
- There are a lot of other unresolved issues from the [Why](#why) section that you must take into account
If you are using the `shell` option to spawn a command in a cross platform way, consider using `cross-spawn` instead. You have been warned.
### `options.shell` support
#### Shebangs
While `cross-spawn` adds support for `options.shell` in node `<v4.8`, all of its enhancements are disabled.
While `cross-spawn` handles shebangs on Windows, its support is limited: e.g.: it doesn't handle arguments after the path, e.g.: `#!/bin/bash -e`.
This mimics the Node.js behavior. More specifically, the command and its arguments will not be automatically escaped nor shebang support will be offered. This is by design because if you are using `options.shell` you are probably targeting a specific platform anyway and you don't want things to get into your way.
### Shebangs support
While `cross-spawn` handles shebangs on Windows, its support is limited. More specifically, it just supports `#!/usr/bin/env <program>` where `<program>` must not contain any arguments.
If you would like to have the shebang support improved, feel free to contribute via a pull-request.
Remember to always test your code on Windows!
## Tests
`$ npm test`
`$ npm test`
`$ npm test -- --watch` during development
## License
+8 -28
View File
@@ -1,20 +1,15 @@
'use strict';
var cp = require('child_process');
var parse = require('./lib/parse');
var enoent = require('./lib/enoent');
var cpSpawnSync = cp.spawnSync;
const cp = require('child_process');
const parse = require('./lib/parse');
const enoent = require('./lib/enoent');
function spawn(command, args, options) {
var parsed;
var spawned;
// Parse the arguments
parsed = parse(command, args, options);
const parsed = parse(command, args, options);
// Spawn the child process
spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
// 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
@@ -24,28 +19,13 @@ function spawn(command, args, options) {
}
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);
const parsed = parse(command, args, options);
// Spawn the child process
result = cpSpawnSync(parsed.command, parsed.args, parsed.options);
const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
// Analyze if the command does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
// Analyze if the command does not exist, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
return result;
+20 -34
View File
@@ -1,43 +1,37 @@
'use strict';
var isWin = process.platform === 'win32';
var resolveCommand = require('./util/resolveCommand');
const isWin = process.platform === 'win32';
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 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,
};
+63 -51
View File
@@ -1,73 +1,86 @@
'use strict';
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');
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');
var isWin = process.platform === 'win32';
var skipShellRegExp = /\.(?:com|exe)$/i;
const isWin = process.platform === 'win32';
const isExecutableRegExp = /\.(?:com|exe)$/i;
const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
// 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;
// `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;
function detectShebang(parsed) {
parsed.file = resolveCommand(parsed);
const shebang = parsed.file && readShebang(parsed.file);
if (shebang) {
parsed.args.unshift(parsed.file);
parsed.command = shebang;
return resolveCommand(parsed);
}
return parsed.file;
}
function parseNonShell(parsed) {
var shebang;
var needsShell;
var applyQuotes;
if (!isWin) {
return parsed;
}
// Detect & add support for shebangs
parsed.file = resolveCommand(parsed.command);
parsed.file = parsed.file || resolveCommand(parsed.command, true);
shebang = parsed.file && readShebang(parsed.file);
const commandFile = detectShebang(parsed);
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);
}
// We don't need a shell if the command filename is an executable
const needsShell = !isExecutableRegExp.test(commandFile);
// 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);
});
// 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);
// Make use of cmd.exe
parsed.args = ['/d', '/s', '/c', '"' + parsed.command + (parsed.args.length ? ' ' + parsed.args.join(' ') : '') + '"'];
// 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);
// Escape command & arguments
parsed.command = escape.command(parsed.command);
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
const shellCommand = [parsed.command].concat(parsed.args).join(' ');
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
parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped
}
return parsed;
}
function parseShell(parsed) {
var shellCommand;
// If node supports the shell option, there's no need to mimic its behavior
if (supportsShellOption) {
return parsed;
}
// Mimic node shell option, see: https://github.com/nodejs/node/blob/b9f6a2dc059a1062776133f3d4fd848c4da7d150/lib/child_process.js#L335
shellCommand = [parsed.command].concat(parsed.args).join(' ');
// 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) {
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
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;
@@ -83,27 +96,26 @@ function parseShell(parsed) {
return parsed;
}
// ------------------------------------------------
function parse(command, args, options) {
var parsed;
// 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 || {};
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
parsed = {
command: command,
args: args,
options: options,
const parsed = {
command,
args,
options,
file: undefined,
original: command,
original: {
command,
args,
},
};
// Delegate further parsing to shell or non-shell
-30
View File
@@ -1,30 +0,0 @@
'use strict';
function escapeArgument(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;
}
module.exports = escapeArgument;
-12
View File
@@ -1,12 +0,0 @@
'use strict';
var escapeArgument = require('./escapeArgument');
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 : escapeArgument(command, true);
}
module.exports = escapeCommand;
-18
View File
@@ -1,18 +0,0 @@
'use strict';
// See: https://github.com/IndigoUnited/node-cross-spawn/pull/34#issuecomment-221623455
function hasEmptyArgumentBug() {
var nodeVer;
if (process.platform !== 'win32') {
return false;
}
nodeVer = process.version.substr(1).split('.').map(function (num) {
return parseInt(num, 10);
});
return (nodeVer[0] === 0 && nodeVer[1] < 12);
}
module.exports = hasEmptyArgumentBug();
+16 -21
View File
@@ -1,37 +1,32 @@
'use strict';
var fs = require('fs');
var LRU = require('lru-cache');
var shebangCommand = require('shebang-command');
var shebangCache = new LRU({ max: 50, maxAge: 30 * 1000 }); // Cache just for 30sec
const fs = require('fs');
const shebangCommand = require('shebang-command');
function readShebang(command) {
var buffer;
var fd;
var shebang;
// Read the first 150 bytes from the file
const size = 150;
let buffer;
// Check if it is in the cache first
if (shebangCache.has(command)) {
return shebangCache.get(command);
if (Buffer.alloc) {
// Node.js v4.5+ / v5.10+
buffer = Buffer.alloc(size);
} else {
// Old Node.js API
buffer = new Buffer(size);
buffer.fill(0); // zero-fill
}
// Read the first 150 bytes from the file
buffer = new Buffer(150);
let fd;
try {
fd = fs.openSync(command, 'r');
fs.readSync(fd, buffer, 0, 150, 0);
fs.readSync(fd, buffer, 0, size, 0);
fs.closeSync(fd);
} catch (e) { /* empty */ }
} catch (e) { /* Empty */ }
// Attempt to extract shebang (null is returned if not a shebang)
shebang = shebangCommand(buffer.toString());
// Store the shebang in the cache
shebangCache.set(command, shebang);
return shebang;
return shebangCommand(buffer.toString());
}
module.exports = readShebang;
+35 -19
View File
@@ -1,31 +1,47 @@
'use strict';
var path = require('path');
var which = require('which');
var LRU = require('lru-cache');
const path = require('path');
const which = require('which');
const pathKey = require('path-key')();
var commandCache = new LRU({ max: 50, maxAge: 30 * 1000 }); // Cache just for 30sec
function resolveCommandAttempt(parsed, withoutPathExt) {
const cwd = process.cwd();
const hasCustomCwd = parsed.options.cwd != null;
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);
// If a custom `cwd` was specified, we need to change the process cwd
// because `which` will do stat calls but does not support a custom cwd
if (hasCustomCwd) {
try {
process.chdir(parsed.options.cwd);
} catch (err) {
/* Empty */
}
}
try {
resolved = !noExtension ?
which.sync(command) :
which.sync(command, { pathExt: path.delimiter + (process.env.PATHEXT || '') });
} catch (e) { /* empty */ }
let resolved;
commandCache.set(command + '!' + noExtension, resolved);
try {
resolved = which.sync(parsed.command, {
path: (parsed.options.env || process.env)[pathKey],
pathExt: withoutPathExt ? path.delimiter : undefined,
});
} catch (e) {
/* Empty */
} finally {
process.chdir(cwd);
}
// If we successfully resolved, ensure that an absolute path is returned
// Note that when a custom `cwd` was used, we need to resolve to an absolute path based on it
if (resolved) {
resolved = path.resolve(hasCustomCwd ? parsed.options.cwd : '', resolved);
}
return resolved;
}
function resolveCommand(parsed) {
return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
}
module.exports = resolveCommand;
+59 -35
View File
@@ -1,83 +1,107 @@
{
"_from": "cross-spawn@^5.1.0",
"_id": "cross-spawn@5.1.0",
"_from": "cross-spawn@^6.0.0",
"_id": "cross-spawn@6.0.5",
"_inBundle": false,
"_integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"_integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"_location": "/cross-spawn",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "cross-spawn@^5.1.0",
"raw": "cross-spawn@^6.0.0",
"name": "cross-spawn",
"escapedName": "cross-spawn",
"rawSpec": "^5.1.0",
"rawSpec": "^6.0.0",
"saveSpec": null,
"fetchSpec": "^5.1.0"
"fetchSpec": "^6.0.0"
},
"_requiredBy": [
"/eslint"
"/execa"
],
"_resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"_shasum": "e8bd0efee58fcff6f8f94510a0a554bbfa235449",
"_spec": "cross-spawn@^5.1.0",
"_where": "/Users/cloyd/coderrr/odin/javascript-exercises/node_modules/eslint",
"_resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"_shasum": "4a5ec7c64dfae22c3a14124dbacdee846d80cbc4",
"_spec": "cross-spawn@^6.0.0",
"_where": "/home/michael/projects/javascript-exercises/node_modules/execa",
"author": {
"name": "IndigoUnited",
"email": "hello@indigounited.com",
"url": "http://indigounited.com"
"name": "André Cruz",
"email": "andre@moxy.studio"
},
"bugs": {
"url": "https://github.com/IndigoUnited/node-cross-spawn/issues/"
"url": "https://github.com/moxystudio/node-cross-spawn/issues"
},
"bundleDependencies": false,
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"dependencies": {
"lru-cache": "^4.0.1",
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
},
"deprecated": false,
"description": "Cross platform child_process#spawn and child_process#spawnSync",
"devDependencies": {
"@satazor/eslint-config": "^3.0.0",
"eslint": "^3.0.0",
"expect.js": "^0.3.0",
"glob": "^7.0.0",
"@commitlint/cli": "^6.0.0",
"@commitlint/config-conventional": "^6.0.2",
"babel-core": "^6.26.0",
"babel-jest": "^22.1.0",
"babel-preset-moxy": "^2.2.1",
"eslint": "^4.3.0",
"eslint-config-moxy": "^5.0.0",
"husky": "^0.14.3",
"jest": "^22.0.0",
"lint-staged": "^7.0.0",
"mkdirp": "^0.5.1",
"mocha": "^3.0.2",
"once": "^1.4.0",
"rimraf": "^2.5.0"
"regenerator-runtime": "^0.11.1",
"rimraf": "^2.6.2",
"standard-version": "^4.2.0"
},
"engines": {
"node": ">=4.8"
},
"files": [
"index.js",
"lib"
],
"homepage": "https://github.com/IndigoUnited/node-cross-spawn#readme",
"homepage": "https://github.com/moxystudio/node-cross-spawn",
"keywords": [
"spawn",
"spawnSync",
"windows",
"cross",
"platform",
"path",
"ext",
"cross-platform",
"path-ext",
"path_ext",
"shebang",
"hashbang",
"cmd",
"execute"
],
"license": "MIT",
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
},
"main": "index.js",
"name": "cross-spawn",
"repository": {
"type": "git",
"url": "git://github.com/IndigoUnited/node-cross-spawn.git"
"url": "git+ssh://git@github.com/moxystudio/node-cross-spawn.git"
},
"scripts": {
"lint": "eslint '{*.js,lib/**/*.js,test/**/*.js}'",
"test": "node test/prepare && mocha --bail test/test"
"commitmsg": "commitlint -e $GIT_PARAMS",
"lint": "eslint .",
"precommit": "lint-staged",
"prerelease": "npm t && npm run lint",
"release": "standard-version",
"test": "jest --env node --coverage"
},
"version": "5.1.0"
"standard-version": {
"scripts": {
"posttag": "git push --follow-tags origin master && npm publish"
}
},
"version": "6.0.5"
}