Skip to content
This repository was archived by the owner on Apr 7, 2021. It is now read-only.

Commit cba97bb

Browse files
jdaltonzkat
authored andcommittedApr 13, 2018
fix(spawn): spawn child processes with node without relying on the shebang. (#174)
1 parent 11d9fe0 commit cba97bb

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed
 

‎index.js

+16-11
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ function installPackages (specs, prefix, opts) {
253253
module.exports._execCommand = execCommand
254254
function execCommand (_existing, argv) {
255255
return findNodeScript(_existing, argv).then(existing => {
256+
const argvCmdOpts = argv.cmdOpts || []
256257
if (existing && !argv.alwaysSpawn && !argv.nodeArg && !argv.shell && existing !== process.argv[1]) {
257258
const Module = require('module')
258259
// let it take over the process. This means we can skip node startup!
@@ -263,31 +264,35 @@ function execCommand (_existing, argv) {
263264
process.argv = [
264265
process.argv[0], // Current node binary
265266
existing // node script path. `runMain()` will set this as the new main
266-
].concat(argv.cmdOpts) // options for the cmd itself
267+
].concat(argvCmdOpts) // options for the cmd itself
267268
Module.runMain() // ✨MAGIC✨. Sorry-not-sorry
268269
} else if (!existing && argv.nodeArg && argv.nodeArg.length) {
269270
throw new Error(Y()`ERROR: --node-arg/-n can only be used on packages with node scripts.`)
270271
} else {
271272
let cmd = existing
272-
let opts = argv
273-
if (existing && argv.nodeArg && argv.nodeArg.length) {
273+
let cmdOpts = argvCmdOpts
274+
if (existing) {
275+
cmd = process.argv[0]
276+
if (process.platform === 'win32') {
277+
cmd = child.escapeArg(cmd, true)
278+
}
274279
// If we know we're running a run script and we got a --node-arg,
275280
// we need to fudge things a bit to get them working right.
276-
let nargs = argv.nodeArg
277-
if (typeof nargs === 'string') {
278-
nargs = [nargs]
281+
cmdOpts = argv.nodeArg
282+
if (cmdOpts) {
283+
cmdOpts = Array.isArray(cmdOpts) ? cmdOpts : [cmdOpts]
284+
} else {
285+
cmdOpts = []
279286
}
280287
// It's valid for a single arg to be a string of multiple
281288
// space-separated node args.
282289
// Example: `$ npx -n '--inspect --harmony --debug' ...`
283-
nargs = nargs.reduce((acc, arg) => {
290+
cmdOpts = cmdOpts.reduce((acc, arg) => {
284291
return acc.concat(arg.split(/\s+/))
285292
}, [])
286-
cmd = child.escapeArg(process.argv[0], true)
287-
opts = Object.assign({}, argv, {
288-
cmdOpts: nargs.concat([existing], argv.cmdOpts || [])
289-
})
293+
cmdOpts = cmdOpts.concat(existing, argvCmdOpts)
290294
}
295+
const opts = Object.assign({}, argv, { cmdOpts })
291296
return child.runCommand(cmd, opts).catch(err => {
292297
if (err.isOperational && err.exitCode) {
293298
// At this point, we want to treat errors from the child as if

‎test/index.js

+33
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,39 @@ const NPM_PATH = path.resolve(__dirname, '..', 'node_modules', 'npm', 'bin', 'np
1616

1717
const NPX_ESC = isWindows ? child.escapeArg(NPX_PATH) : NPX_PATH
1818

19+
test('npx --always-spawn', t => {
20+
return child.spawn('node', [
21+
NPX_ESC, '--always-spawn', 'echo-cli', 'hewwo'
22+
], {stdio: 'pipe'}).then(res => {
23+
t.equal(res.stdout.trim(), 'hewwo')
24+
})
25+
})
26+
27+
test('npx --always-spawn resolves promise after command is executed', t => {
28+
const _runCommand = child.runCommand
29+
const parsed = main.parseArgs([
30+
process.argv[0],
31+
'[fake arg]',
32+
'--always-spawn',
33+
'echo-cli',
34+
'hewwo'
35+
], NPM_PATH)
36+
child.runCommand = (command, opts) => {
37+
child.runCommand = _runCommand
38+
return Promise.resolve([command, opts])
39+
}
40+
return main(parsed)
41+
.then(args => {
42+
const command = args[0]
43+
const opts = args[1]
44+
t.ok(command.includes('node'), 'node executes the command')
45+
t.equal(opts.alwaysSpawn, true, 'set opts.alwaysSpawn')
46+
t.equal(opts.command, 'echo-cli', 'set opts.command')
47+
t.ok(opts.cmdOpts[0].includes('echo-cli'), 'set opts.cmdOpts[0]')
48+
t.equal(opts.cmdOpts[1], 'hewwo', 'set opts.cmdOpts[1]')
49+
})
50+
})
51+
1952
test('npx --shell-auto-fallback', t => {
2053
return child.spawn('node', [
2154
NPX_ESC, '--shell-auto-fallback', 'zsh'

0 commit comments

Comments
 (0)
This repository has been archived.