From ec492d8656446b46419f90fd99824f2f3242c4f2 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Wed, 3 Apr 2019 18:46:41 +0200 Subject: [PATCH 01/41] Add fork method Fix #65 --- index.js | 9 +++++++++ lib/stdio.js | 2 +- test.js | 6 ++++++ test/stdio.js | 38 ++++++++++++++++++++------------------ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index 92bfc6afc..65c0e284e 100644 --- a/index.js +++ b/index.js @@ -427,3 +427,12 @@ module.exports.sync = (command, args, options) => { }; module.exports.shellSync = (command, options) => handleShell(execa.sync, command, options); + +module.exports.fork = (filePath, args, options) =>{ + return execa('node', [filePath, ...(args || [])], { + ...options, + ipc: 'pipe', + execPath: path.resolve(filePath), + shell: false, + }); +}; diff --git a/lib/stdio.js b/lib/stdio.js index 5b4cb9e57..8f74e9614 100644 --- a/lib/stdio.js +++ b/lib/stdio.js @@ -1,5 +1,5 @@ 'use strict'; -const alias = ['stdin', 'stdout', 'stderr']; +const alias = ['stdin', 'stdout', 'stderr', 'ipc']; const hasAlias = opts => alias.some(x => Boolean(opts[x])); diff --git a/test.js b/test.js index eba24b6a1..735348c8b 100644 --- a/test.js +++ b/test.js @@ -640,3 +640,9 @@ test('calling cancel method on a process which has been killed does not make err const error = await t.throwsAsync(subprocess); t.false(error.isCanceled); }); + +test.only('fork', async t => { + const result = await execa.fork('./fixtures/simple-log.js'); + + t.is(result.stdout, 'ok'); +}); diff --git a/test/stdio.js b/test/stdio.js index e51fc7d8e..8bce06723 100644 --- a/test/stdio.js +++ b/test/stdio.js @@ -27,24 +27,26 @@ test(macro, null, undefined); test(macro, {stdio: 'inherit'}, 'inherit'); test(macro, {stdio: 'pipe'}, 'pipe'); test(macro, {stdio: 'ignore'}, 'ignore'); -test(macro, {stdio: [0, 1, 2]}, [0, 1, 2]); - -test(macro, {}, [undefined, undefined, undefined]); -test(macro, {stdio: []}, [undefined, undefined, undefined]); -test(macro, {stdin: 'pipe'}, ['pipe', undefined, undefined]); -test(macro, {stdout: 'ignore'}, [undefined, 'ignore', undefined]); -test(macro, {stderr: 'inherit'}, [undefined, undefined, 'inherit']); -test(macro, {stdin: 'pipe', stdout: 'ignore', stderr: 'inherit'}, ['pipe', 'ignore', 'inherit']); -test(macro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', undefined]); -test(macro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', undefined, 'inherit']); -test(macro, {stdout: 'ignore', stderr: 'inherit'}, [undefined, 'ignore', 'inherit']); -test(macro, {stdin: 0, stdout: 1, stderr: 2}, [0, 1, 2]); -test(macro, {stdin: 0, stdout: 1}, [0, 1, undefined]); -test(macro, {stdin: 0, stderr: 2}, [0, undefined, 2]); -test(macro, {stdout: 1, stderr: 2}, [undefined, 1, 2]); +test(macro, {stdio: [0, 1, 2, 3]}, [0, 1, 2, 3]); + +test(macro, {}, [undefined, undefined, undefined, undefined]); +test(macro, {stdio: []}, [undefined, undefined, undefined, undefined]); +test(macro, {stdin: 'pipe'}, ['pipe', undefined, undefined, undefined]); +test(macro, {stdout: 'ignore'}, [undefined, 'ignore', undefined, undefined]); +test(macro, {stderr: 'inherit'}, [undefined, undefined, 'inherit', undefined]); +test(macro, {ipc: 'pipe'}, [undefined, undefined, undefined, 'pipe']); +test(macro, {stdin: 'pipe', stdout: 'ignore', stderr: 'inherit'}, ['pipe', 'ignore', 'inherit', undefined]); +test(macro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', undefined, undefined]); +test(macro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', undefined, 'inherit', undefined]); +test(macro, {stdout: 'ignore', stderr: 'inherit'}, [undefined, 'ignore', 'inherit', undefined]); +test(macro, {stdin: 0, stdout: 1, stderr: 2}, [0, 1, 2, undefined]); +test(macro, {stdin: 0, stdout: 1}, [0, 1, undefined, undefined]); +test(macro, {stdin: 0, stderr: 2}, [0, undefined, 2, undefined]); +test(macro, {stdout: 1, stderr: 2}, [undefined, 1, 2, undefined]); +test(macro, {ipc: 3, stderr: 2}, [undefined, undefined, 2, 3]); test(macro, {stdio: {foo: 'bar'}}, new TypeError('Expected `stdio` to be of type `string` or `Array`, got `object`')); -test(macro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); -test(macro, {stdin: 'inherit', stdio: ['pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); -test(macro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); +test(macro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`, `ipc`')); +test(macro, {stdin: 'inherit', stdio: ['pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`, `ipc`')); +test(macro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`, `ipc`')); From f844651505b3f794f404139f5a8cbcddae7f4601 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Wed, 3 Apr 2019 23:29:49 +0200 Subject: [PATCH 02/41] Revert changes of stdio --- lib/stdio.js | 2 +- test/stdio.js | 38 ++++++++++++++++++-------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/lib/stdio.js b/lib/stdio.js index 8f74e9614..5b4cb9e57 100644 --- a/lib/stdio.js +++ b/lib/stdio.js @@ -1,5 +1,5 @@ 'use strict'; -const alias = ['stdin', 'stdout', 'stderr', 'ipc']; +const alias = ['stdin', 'stdout', 'stderr']; const hasAlias = opts => alias.some(x => Boolean(opts[x])); diff --git a/test/stdio.js b/test/stdio.js index 8bce06723..e51fc7d8e 100644 --- a/test/stdio.js +++ b/test/stdio.js @@ -27,26 +27,24 @@ test(macro, null, undefined); test(macro, {stdio: 'inherit'}, 'inherit'); test(macro, {stdio: 'pipe'}, 'pipe'); test(macro, {stdio: 'ignore'}, 'ignore'); -test(macro, {stdio: [0, 1, 2, 3]}, [0, 1, 2, 3]); - -test(macro, {}, [undefined, undefined, undefined, undefined]); -test(macro, {stdio: []}, [undefined, undefined, undefined, undefined]); -test(macro, {stdin: 'pipe'}, ['pipe', undefined, undefined, undefined]); -test(macro, {stdout: 'ignore'}, [undefined, 'ignore', undefined, undefined]); -test(macro, {stderr: 'inherit'}, [undefined, undefined, 'inherit', undefined]); -test(macro, {ipc: 'pipe'}, [undefined, undefined, undefined, 'pipe']); -test(macro, {stdin: 'pipe', stdout: 'ignore', stderr: 'inherit'}, ['pipe', 'ignore', 'inherit', undefined]); -test(macro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', undefined, undefined]); -test(macro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', undefined, 'inherit', undefined]); -test(macro, {stdout: 'ignore', stderr: 'inherit'}, [undefined, 'ignore', 'inherit', undefined]); -test(macro, {stdin: 0, stdout: 1, stderr: 2}, [0, 1, 2, undefined]); -test(macro, {stdin: 0, stdout: 1}, [0, 1, undefined, undefined]); -test(macro, {stdin: 0, stderr: 2}, [0, undefined, 2, undefined]); -test(macro, {stdout: 1, stderr: 2}, [undefined, 1, 2, undefined]); -test(macro, {ipc: 3, stderr: 2}, [undefined, undefined, 2, 3]); +test(macro, {stdio: [0, 1, 2]}, [0, 1, 2]); + +test(macro, {}, [undefined, undefined, undefined]); +test(macro, {stdio: []}, [undefined, undefined, undefined]); +test(macro, {stdin: 'pipe'}, ['pipe', undefined, undefined]); +test(macro, {stdout: 'ignore'}, [undefined, 'ignore', undefined]); +test(macro, {stderr: 'inherit'}, [undefined, undefined, 'inherit']); +test(macro, {stdin: 'pipe', stdout: 'ignore', stderr: 'inherit'}, ['pipe', 'ignore', 'inherit']); +test(macro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', undefined]); +test(macro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', undefined, 'inherit']); +test(macro, {stdout: 'ignore', stderr: 'inherit'}, [undefined, 'ignore', 'inherit']); +test(macro, {stdin: 0, stdout: 1, stderr: 2}, [0, 1, 2]); +test(macro, {stdin: 0, stdout: 1}, [0, 1, undefined]); +test(macro, {stdin: 0, stderr: 2}, [0, undefined, 2]); +test(macro, {stdout: 1, stderr: 2}, [undefined, 1, 2]); test(macro, {stdio: {foo: 'bar'}}, new TypeError('Expected `stdio` to be of type `string` or `Array`, got `object`')); -test(macro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`, `ipc`')); -test(macro, {stdin: 'inherit', stdio: ['pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`, `ipc`')); -test(macro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`, `ipc`')); +test(macro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); +test(macro, {stdin: 'inherit', stdio: ['pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); +test(macro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); From 1a15ee771fcd3115cda45fd88002ada7dd6fe3c6 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 4 Apr 2019 00:57:35 +0200 Subject: [PATCH 03/41] Cover execArgv and compute stdio --- index.js | 9 ++++++--- lib/stdio.js | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 65c0e284e..d59719171 100644 --- a/index.js +++ b/index.js @@ -429,10 +429,13 @@ module.exports.sync = (command, args, options) => { module.exports.shellSync = (command, options) => handleShell(execa.sync, command, options); module.exports.fork = (filePath, args, options) =>{ - return execa('node', [filePath, ...(args || [])], { + const absolutePath = path.resolve(filePath); + + return execa(absolutePath, args, { ...options, - ipc: 'pipe', - execPath: path.resolve(filePath), + stdio: stdio.fork(options), + execPath: absolutePath, + execArgv: options.execArgv || process.execArgv, shell: false, }); }; diff --git a/lib/stdio.js b/lib/stdio.js index 5b4cb9e57..0473cff93 100644 --- a/lib/stdio.js +++ b/lib/stdio.js @@ -3,7 +3,7 @@ const alias = ['stdin', 'stdout', 'stderr']; const hasAlias = opts => alias.some(x => Boolean(opts[x])); -module.exports = opts => { +const stdio = opts => { if (!opts) { return; } @@ -39,3 +39,17 @@ module.exports = opts => { return result; }; + +module.exports = stdio; + +module.exports.fork = opts => { + let stdioOption = options.silent ? stdio(opts || {}) : 'pipe'; + if (typeof stdioOption === "string") { + stdioOption = [...new Array(3)].fill(stdioOption); + } + if (!stdioOption.includes('ipc')) { + stdioOption.push('ipc'); + } + + return stdioOption; +}; From 5f4978415a401893694df513d5cc3545314db5e2 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 4 Apr 2019 16:27:29 +0200 Subject: [PATCH 04/41] Add tests for fork's stdio option --- test/stdio.js | 104 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/test/stdio.js b/test/stdio.js index e51fc7d8e..611aacc76 100644 --- a/test/stdio.js +++ b/test/stdio.js @@ -4,47 +4,67 @@ import stdio from '../lib/stdio'; util.inspect.styles.name = 'magenta'; -function macro(t, input, expected) { - if (expected instanceof Error) { - t.throws(() => stdio(input), expected.message); - return; - } - - const result = stdio(input); - - if (typeof expected === 'object' && expected !== null) { - t.deepEqual(result, expected); - } else { - t.is(result, expected); - } +function createMacro(func) { + const macro = (t, input, expected) => { + if (expected instanceof Error) { + t.throws(() => stdio(input), expected.message); + return; + } + + const result = func(input); + + if (typeof expected === 'object' && expected !== null) { + t.deepEqual(result, expected); + } else { + t.is(result, expected); + } + }; + + macro.title = (providedTitle, input) => `${func.name} ${(providedTitle || util.inspect(input, {colors: true}))}`; + + return macro; } -macro.title = (providedTitle, input) => providedTitle || util.inspect(input, {colors: true}); - -test(macro, undefined, undefined); -test(macro, null, undefined); - -test(macro, {stdio: 'inherit'}, 'inherit'); -test(macro, {stdio: 'pipe'}, 'pipe'); -test(macro, {stdio: 'ignore'}, 'ignore'); -test(macro, {stdio: [0, 1, 2]}, [0, 1, 2]); - -test(macro, {}, [undefined, undefined, undefined]); -test(macro, {stdio: []}, [undefined, undefined, undefined]); -test(macro, {stdin: 'pipe'}, ['pipe', undefined, undefined]); -test(macro, {stdout: 'ignore'}, [undefined, 'ignore', undefined]); -test(macro, {stderr: 'inherit'}, [undefined, undefined, 'inherit']); -test(macro, {stdin: 'pipe', stdout: 'ignore', stderr: 'inherit'}, ['pipe', 'ignore', 'inherit']); -test(macro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', undefined]); -test(macro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', undefined, 'inherit']); -test(macro, {stdout: 'ignore', stderr: 'inherit'}, [undefined, 'ignore', 'inherit']); -test(macro, {stdin: 0, stdout: 1, stderr: 2}, [0, 1, 2]); -test(macro, {stdin: 0, stdout: 1}, [0, 1, undefined]); -test(macro, {stdin: 0, stderr: 2}, [0, undefined, 2]); -test(macro, {stdout: 1, stderr: 2}, [undefined, 1, 2]); - -test(macro, {stdio: {foo: 'bar'}}, new TypeError('Expected `stdio` to be of type `string` or `Array`, got `object`')); - -test(macro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); -test(macro, {stdin: 'inherit', stdio: ['pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); -test(macro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); +const stdioMacro = createMacro(stdio); + +test(stdioMacro, undefined, undefined); +test(stdioMacro, null, undefined); + +test(stdioMacro, {stdio: 'inherit'}, 'inherit'); +test(stdioMacro, {stdio: 'pipe'}, 'pipe'); +test(stdioMacro, {stdio: 'ignore'}, 'ignore'); +test(stdioMacro, {stdio: [0, 1, 2]}, [0, 1, 2]); + +test(stdioMacro, {}, [undefined, undefined, undefined]); +test(stdioMacro, {stdio: []}, [undefined, undefined, undefined]); +test(stdioMacro, {stdin: 'pipe'}, ['pipe', undefined, undefined]); +test(stdioMacro, {stdout: 'ignore'}, [undefined, 'ignore', undefined]); +test(stdioMacro, {stderr: 'inherit'}, [undefined, undefined, 'inherit']); +test(stdioMacro, {stdin: 'pipe', stdout: 'ignore', stderr: 'inherit'}, ['pipe', 'ignore', 'inherit']); +test(stdioMacro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', undefined]); +test(stdioMacro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', undefined, 'inherit']); +test(stdioMacro, {stdout: 'ignore', stderr: 'inherit'}, [undefined, 'ignore', 'inherit']); +test(stdioMacro, {stdin: 0, stdout: 1, stderr: 2}, [0, 1, 2]); +test(stdioMacro, {stdin: 0, stdout: 1}, [0, 1, undefined]); +test(stdioMacro, {stdin: 0, stderr: 2}, [0, undefined, 2]); +test(stdioMacro, {stdout: 1, stderr: 2}, [undefined, 1, 2]); + +test(stdioMacro, {stdio: {foo: 'bar'}}, new TypeError('Expected `stdio` to be of type `string` or `Array`, got `object`')); + +test(stdioMacro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); +test(stdioMacro, {stdin: 'inherit', stdio: ['pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); +test(stdioMacro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); + +const forkMacro = createMacro(stdio.fork); + +test(forkMacro, undefined, ['pipe', 'pipe', 'pipe', 'ipc']); +test(forkMacro, {stdio: 'ignore'}, ['ignore', 'ignore', 'ignore', 'ipc']); +test(forkMacro, {stdio: [0, 1, 2]}, [0, 1, 2, 'ipc']); +test(forkMacro, {stdio: [0, 1, 2, 3]}, [0, 1, 2, 3, 'ipc']); + +test(forkMacro, {stdout: 'ignore'}, ['pipe', 'ignore', 'pipe', 'ipc']); +test(forkMacro, {stdout: 'ignore', stderr: 'ignore'}, ['pipe', 'ignore', 'ignore', 'ipc']); + +test(forkMacro, {silent: true, stdio: 'ignore'}, ['pipe', 'pipe', 'pipe', 'ipc']); +test(forkMacro, {silent: true, stdio: [0, 1, 2, 42, 5]}, ['pipe', 'pipe', 'pipe', 'ipc']); +test(forkMacro, {silent: true, stdout: 'ignore'}, ['pipe', 'pipe', 'pipe', 'ipc']); From 360f07c18b15b6c5a55ecc80ee3404c61daa87d2 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 4 Apr 2019 17:42:26 +0200 Subject: [PATCH 05/41] Fix stdio fork tests --- test/stdio.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/stdio.js b/test/stdio.js index 611aacc76..7bbbf2831 100644 --- a/test/stdio.js +++ b/test/stdio.js @@ -57,14 +57,16 @@ test(stdioMacro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\' const forkMacro = createMacro(stdio.fork); -test(forkMacro, undefined, ['pipe', 'pipe', 'pipe', 'ipc']); +test(forkMacro, undefined, ['inherit', 'inherit', 'inherit', 'ipc']); test(forkMacro, {stdio: 'ignore'}, ['ignore', 'ignore', 'ignore', 'ipc']); test(forkMacro, {stdio: [0, 1, 2]}, [0, 1, 2, 'ipc']); test(forkMacro, {stdio: [0, 1, 2, 3]}, [0, 1, 2, 3, 'ipc']); +test(forkMacro, {stdio: [0, 1, 2, 'ipc']}, [0, 1, 2, 'ipc']); -test(forkMacro, {stdout: 'ignore'}, ['pipe', 'ignore', 'pipe', 'ipc']); -test(forkMacro, {stdout: 'ignore', stderr: 'ignore'}, ['pipe', 'ignore', 'ignore', 'ipc']); +test(forkMacro, {stdout: 'ignore'}, ['inherit', 'ignore', 'inherit', 'ipc']); +test(forkMacro, {stdout: 'ignore', stderr: 'ignore'}, ['inherit', 'ignore', 'ignore', 'ipc']); -test(forkMacro, {silent: true, stdio: 'ignore'}, ['pipe', 'pipe', 'pipe', 'ipc']); -test(forkMacro, {silent: true, stdio: [0, 1, 2, 42, 5]}, ['pipe', 'pipe', 'pipe', 'ipc']); -test(forkMacro, {silent: true, stdout: 'ignore'}, ['pipe', 'pipe', 'pipe', 'ipc']); +test(forkMacro, {silent: true}, ['pipe', 'pipe', 'pipe', 'ipc']); +test(forkMacro, {silent: true, stdio: 'ignore'}, ['ignore', 'ignore', 'ignore', 'ipc']); +test(forkMacro, {silent: true, stdio: [0, 1, 2]}, [0, 1, 2, 'ipc']); +test(forkMacro, {silent: true, stdout: 'ignore'}, ['pipe', 'ignore', 'pipe', 'ipc']); From dbc42744989d46be1870e44e53fb59fdc9360be6 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 4 Apr 2019 18:43:19 +0200 Subject: [PATCH 06/41] Fix stdio fork function --- lib/stdio.js | 10 ++++++++-- test/stdio.js | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/stdio.js b/lib/stdio.js index 0473cff93..f8fe0eb8e 100644 --- a/lib/stdio.js +++ b/lib/stdio.js @@ -43,10 +43,16 @@ const stdio = opts => { module.exports = stdio; module.exports.fork = opts => { - let stdioOption = options.silent ? stdio(opts || {}) : 'pipe'; - if (typeof stdioOption === "string") { + const defaultOption = (opts && opts.silent && !opts.stdio) ? 'pipe' : 'inherit'; + + let stdioOption = stdio(opts || {stdio: defaultOption}); + + if (typeof stdioOption === 'string') { stdioOption = [...new Array(3)].fill(stdioOption); + } else if (Array.isArray(stdioOption)) { + stdioOption = stdioOption.map(channel => channel === undefined ? defaultOption : channel); } + if (!stdioOption.includes('ipc')) { stdioOption.push('ipc'); } diff --git a/test/stdio.js b/test/stdio.js index 7bbbf2831..c7dc65a66 100644 --- a/test/stdio.js +++ b/test/stdio.js @@ -70,3 +70,6 @@ test(forkMacro, {silent: true}, ['pipe', 'pipe', 'pipe', 'ipc']); test(forkMacro, {silent: true, stdio: 'ignore'}, ['ignore', 'ignore', 'ignore', 'ipc']); test(forkMacro, {silent: true, stdio: [0, 1, 2]}, [0, 1, 2, 'ipc']); test(forkMacro, {silent: true, stdout: 'ignore'}, ['pipe', 'ignore', 'pipe', 'ipc']); + +test(forkMacro, {stdio: {foo: 'bar'}}, new TypeError('Expected `stdio` to be of type `string` or `Array`, got `object`')); +test(forkMacro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); From b03baf6d52fa24522657cc5660bbdc4a6e19c693 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 4 Apr 2019 18:56:42 +0200 Subject: [PATCH 07/41] Add test for fork --- fixtures/exec-path.js | 2 ++ index.js | 18 +++++++++++------- test.js | 10 ++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) create mode 100755 fixtures/exec-path.js diff --git a/fixtures/exec-path.js b/fixtures/exec-path.js new file mode 100755 index 000000000..f2ed079fb --- /dev/null +++ b/fixtures/exec-path.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log(process.execPath); diff --git a/index.js b/index.js index d59719171..b493144a5 100644 --- a/index.js +++ b/index.js @@ -428,14 +428,18 @@ module.exports.sync = (command, args, options) => { module.exports.shellSync = (command, options) => handleShell(execa.sync, command, options); -module.exports.fork = (filePath, args, options) =>{ - const absolutePath = path.resolve(filePath); +module.exports.fork = (filePath, args, options) => { + const stdioOption = stdio.fork(options); + delete options.stdin; + delete options.stdout; + delete options.stderr; - return execa(absolutePath, args, { + return execa(filePath, args, { ...options, - stdio: stdio.fork(options), - execPath: absolutePath, - execArgv: options.execArgv || process.execArgv, - shell: false, + code: 0, + stdio: stdioOption, + execPath: filePath, + execArgv: (options && options.execArgv) || process.execArgv, + shell: false }); }; diff --git a/test.js b/test.js index 735348c8b..4bebaec9f 100644 --- a/test.js +++ b/test.js @@ -627,7 +627,7 @@ test('calling cancel method twice should show the same behaviour as calling it o t.true(subprocess.killed); }); -test('calling cancel method on a successfuly completed process does not make result.isCanceled true', async t => { +test('calling cancel method on a successfully completed process does not make result.isCanceled true', async t => { const subprocess = execa('noop'); const result = await subprocess; subprocess.cancel(); @@ -641,8 +641,10 @@ test('calling cancel method on a process which has been killed does not make err t.false(error.isCanceled); }); -test.only('fork', async t => { - const result = await execa.fork('./fixtures/simple-log.js'); +test('fork correctly set execPath', async t => { + const result = await execa.fork('exec-path.js', [], { + stdout: 'pipe' + }); - t.is(result.stdout, 'ok'); + t.is(result.stdout, path.resolve('fixtures/exec-path.js')); }); From 0a116f84a01b10e1f627facb2ee4b2b891485457 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 5 Apr 2019 15:34:14 +0200 Subject: [PATCH 08/41] Avoid mutating arguments to fork --- index.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index b493144a5..cdbe559f6 100644 --- a/index.js +++ b/index.js @@ -428,17 +428,16 @@ module.exports.sync = (command, args, options) => { module.exports.shellSync = (command, options) => handleShell(execa.sync, command, options); -module.exports.fork = (filePath, args, options) => { +module.exports.fork = (command, args, options) => { const stdioOption = stdio.fork(options); - delete options.stdin; - delete options.stdout; - delete options.stderr; - return execa(filePath, args, { + return execa(command, args, { ...options, - code: 0, + stdin: undefined, + stdout: undefined, + stderr: undefined, stdio: stdioOption, - execPath: filePath, + execPath: (options && options.execPath) || process.execPath, execArgv: (options && options.execArgv) || process.execArgv, shell: false }); From 2e83f030b4d061640e16135da24d806813673935 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 5 Apr 2019 17:02:32 +0200 Subject: [PATCH 09/41] Use execPath and execArgv --- index.js | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index cdbe559f6..f4b43de09 100644 --- a/index.js +++ b/index.js @@ -428,17 +428,23 @@ module.exports.sync = (command, args, options) => { module.exports.shellSync = (command, options) => handleShell(execa.sync, command, options); -module.exports.fork = (command, args, options) => { +module.exports.fork = (filePath, args = [], options = {}) => { const stdioOption = stdio.fork(options); - return execa(command, args, { - ...options, - stdin: undefined, - stdout: undefined, - stderr: undefined, - stdio: stdioOption, - execPath: (options && options.execPath) || process.execPath, - execArgv: (options && options.execArgv) || process.execArgv, - shell: false - }); + return execa( + options.execPath || process.execPath, + [ + filePath, + ...(options.execArgv || process.execArgv), + ...args + ], + { + ...options, + stdin: undefined, + stdout: undefined, + stderr: undefined, + stdio: stdioOption, + shell: false + } + ); }; From 35e8167a8daa825e04f8b3821823d644ffb44db4 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 5 Apr 2019 17:03:01 +0200 Subject: [PATCH 10/41] Add more tests to the fork function --- fixtures/exec-path.js | 2 -- fixtures/hello.sh | 1 + fixtures/plain.js | 1 + fixtures/send.js | 7 +++++++ test.js | 44 ++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 50 insertions(+), 5 deletions(-) delete mode 100755 fixtures/exec-path.js create mode 100755 fixtures/hello.sh create mode 100755 fixtures/plain.js create mode 100755 fixtures/send.js diff --git a/fixtures/exec-path.js b/fixtures/exec-path.js deleted file mode 100755 index f2ed079fb..000000000 --- a/fixtures/exec-path.js +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -console.log(process.execPath); diff --git a/fixtures/hello.sh b/fixtures/hello.sh new file mode 100755 index 000000000..ff0e12ec6 --- /dev/null +++ b/fixtures/hello.sh @@ -0,0 +1 @@ +echo Hello World diff --git a/fixtures/plain.js b/fixtures/plain.js new file mode 100755 index 000000000..2210e5bf8 --- /dev/null +++ b/fixtures/plain.js @@ -0,0 +1 @@ +console.log('Javascript'); diff --git a/fixtures/send.js b/fixtures/send.js new file mode 100755 index 000000000..22fc2dbed --- /dev/null +++ b/fixtures/send.js @@ -0,0 +1,7 @@ +process.on('message', message => { + if (message === 'ping') { + process.send('pong'); + } else { + throw new Error('Receive wrong message'); + } +}); diff --git a/test.js b/test.js index 4bebaec9f..977bd342d 100644 --- a/test.js +++ b/test.js @@ -641,10 +641,48 @@ test('calling cancel method on a process which has been killed does not make err t.false(error.isCanceled); }); -test('fork correctly set execPath', async t => { - const result = await execa.fork('exec-path.js', [], { +test.cb('fork()', t => { + const fork = execa.fork('fixtures/plain.js'); + + fork.on('close', code => { + t.is(code, 0); + t.end(); + }); +}); + +test('fork pipe stdout', async t => { + const result = await execa.fork('fixtures/plain.js', [], { stdout: 'pipe' }); - t.is(result.stdout, path.resolve('fixtures/exec-path.js')); + t.is(result.stdout, 'Javascript'); +}); + +test('fork correctly use execPath', async t => { + const result = await execa.fork(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', [], { + stdout: 'pipe', + execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash' + }); + + t.is(result.stdout, 'Hello World'); +}); + +test('fork pass on execArgv', async t => { + const result = await execa.fork('fixtures/noop', [], { + stdout: 'pipe', + execArgv: ['foo'] + }); + + t.is(result.stdout, 'foo'); +}); + +test.cb('forked script have a communication channel', t => { + const subprocess = execa.fork('fixtures/send.js'); + + subprocess.on('message', message => { + t.is(message, 'pong'); + t.end(); + }); + + subprocess.send('ping'); }); From eb2f47a48c4833ed8778fa20080768cbe1853b80 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Mon, 8 Apr 2019 13:11:45 +0200 Subject: [PATCH 11/41] Remove duplicate fixture file --- fixtures/plain.js | 1 - test.js | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100755 fixtures/plain.js diff --git a/fixtures/plain.js b/fixtures/plain.js deleted file mode 100755 index 2210e5bf8..000000000 --- a/fixtures/plain.js +++ /dev/null @@ -1 +0,0 @@ -console.log('Javascript'); diff --git a/test.js b/test.js index 977bd342d..977ccb1a8 100644 --- a/test.js +++ b/test.js @@ -642,7 +642,7 @@ test('calling cancel method on a process which has been killed does not make err }); test.cb('fork()', t => { - const fork = execa.fork('fixtures/plain.js'); + const fork = execa.fork('fixtures/noop'); fork.on('close', code => { t.is(code, 0); @@ -651,11 +651,11 @@ test.cb('fork()', t => { }); test('fork pipe stdout', async t => { - const result = await execa.fork('fixtures/plain.js', [], { + const {stdout} = await execa.fork('fixtures/noop', ['foo'], { stdout: 'pipe' }); - t.is(result.stdout, 'Javascript'); + t.is(stdout, 'foo'); }); test('fork correctly use execPath', async t => { From be63122828098ef83615c484a330855294d9b1a4 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Mon, 8 Apr 2019 14:22:43 +0200 Subject: [PATCH 12/41] normalize --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index f4b43de09..88a890448 100644 --- a/index.js +++ b/index.js @@ -434,7 +434,7 @@ module.exports.fork = (filePath, args = [], options = {}) => { return execa( options.execPath || process.execPath, [ - filePath, + path.normalize(filePath), ...(options.execArgv || process.execArgv), ...args ], From 483aa5cf5c7e72c69aab333e684f08a5d64cf95e Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Tue, 7 May 2019 15:25:41 +0200 Subject: [PATCH 13/41] Unshift unique args to windows OS cmd --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 88a890448..22f117098 100644 --- a/index.js +++ b/index.js @@ -62,7 +62,7 @@ function handleArgs(command, args, options) { if (process.platform === 'win32' && path.basename(command) === 'cmd.exe') { // #116 - args.unshift('/q'); + args = [...new Set(['/q', '/d', '/s', '/c', ...args])]; } return {command, args, options, parsed}; From e5783d04892d2f7c0eebe004bfe2da37a537de8e Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 10 May 2019 11:48:48 +0200 Subject: [PATCH 14/41] Update readme, types and types tests --- index.d.ts | 45 +++++++++++++++++++++++++++++++++++++++++++-- index.test-d.ts | 13 +++++++++++++ readme.md | 29 +++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index da9dc5af7..1d59fccd7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -178,14 +178,35 @@ declare namespace execa { readonly input?: string | Buffer | ReadableStream; } - interface SyncOptions - extends CommonOptions { + interface SyncOptions extends CommonOptions { /** Write some input to the `stdin` of your binary. */ readonly input?: string | Buffer; } + interface ForkOptions extends CommonOptions { + + /** + Define the sub-process executable binary + + @default process.execPath + */ + readonly execPath?: string; + + /** + Define the sub-process arguments + + @default process.execArgv + */ + readonly execArgv?: string[]; + + /** + If `true`, set all stdio channel to `'pipe'` + */ + readonly silent?: boolean; + } + interface ExecaReturnBase { /** The numeric exit code of the process that was run. @@ -496,6 +517,26 @@ declare const execa: { command: string, options?: execa.Options ): execa.ExecaSyncReturnValue; + + /** + Run a file through a fork of the current process. + + @param file - The program/script to execute. + @param arguments - Arguments to pass to `file` on execution. + @returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties. + */ + fork( + file: string, + arguments?: readonly string[], + options?: execa.Options + ): execa.ExecaChildProcess; + fork( + file: string, + arguments?: readonly string[], + options?: execa.Options + ): execa.ExecaChildProcess; + fork(file: string, options?: execa.Options): execa.ExecaChildProcess; + fork(file: string, options?: execa.Options): execa.ExecaChildProcess; }; export = execa; diff --git a/index.test-d.ts b/index.test-d.ts index e89d9661d..8b4df89a0 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -158,3 +158,16 @@ expectType>( expectType>( execa.shellSync('unicorns', {encoding: null}) ); + +expectType>(execa.fork('unicorns')); +expectType>(await execa.fork('unicorns')); +expectType>( + await execa.fork('unicorns', {encoding: 'utf8'}) +); +expectType>(await execa.fork('unicorns', {encoding: null})); +expectType>( + await execa.fork('unicorns', ['foo'], {encoding: 'utf8'}) +); +expectType>( + await execa.fork('unicorns', ['foo'], {encoding: null}) +); diff --git a/readme.md b/readme.md index 971fa6d9a..cb55d59b5 100644 --- a/readme.md +++ b/readme.md @@ -173,6 +173,15 @@ Execute a command synchronously through the system shell. Returns the same result object as [`child_process.spawnSync`](https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options). +### execa.fork(file, [arguments], [options]) + +Run a file through a forked process. The default sub-process is the current (node). + +It introduce a communication channel (IPC) that allows messages to be passed back and forth between the parent and child.
+Note that the `shell` option will be ignored. + +Returns a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess). + ### options Type: `object` @@ -342,6 +351,26 @@ Default: `false` If `true`, no quoting or escaping of arguments is done on Windows. Ignored on other platforms. This is set to `true` automatically when the `shell` option is `true`. +#### execPath (for `fork` only) + +Type: `string`
+Default: `process.execPath` + +Define the sub-process executable binary. + +#### execArgv (for `fork` only) + +Type: `string[]`
+Default: `process.execArgv` + +Define the sub-process arguments. + +#### silent (for `fork` only) + +Type: `boolean`
+Default: `false` + +If `true`, set all stdio channel to `'pipe'`. ## Tips From cf79301db34d4fb44cf7baac25ae4ae2734b428c Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 10 May 2019 13:22:53 +0200 Subject: [PATCH 15/41] Remove unnecessary normalize --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index f5e55b4c2..f0455000a 100644 --- a/index.js +++ b/index.js @@ -480,7 +480,7 @@ module.exports.fork = (filePath, args = [], options = {}) => { return execa( options.execPath || process.execPath, [ - path.normalize(filePath), + filePath, ...(options.execArgv || process.execArgv), ...args ], From 2c2d7271b9326d09d677a90406e88cbdc7319c35 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 10 May 2019 17:02:01 +0200 Subject: [PATCH 16/41] Revert "Unshift unique args to windows OS cmd" This reverts commit 483aa5cf --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index f0455000a..df4623fb6 100644 --- a/index.js +++ b/index.js @@ -95,7 +95,7 @@ function handleArgs(command, args, options = {}) { if (process.platform === 'win32' && path.basename(command, '.exe') === 'cmd') { // #116 - args = [...new Set(['/q', '/d', '/s', '/c', ...args])]; + args.unshift('/q'); } return {command, args, options, parsed}; From 0ed7fd6829b486ff6d757f72eb739fa1c1690148 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Tue, 21 May 2019 12:02:33 +0200 Subject: [PATCH 17/41] Fix tests on windows --- test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.js b/test.js index f1dfdcc60..093a6358c 100644 --- a/test.js +++ b/test.js @@ -725,7 +725,7 @@ test('fork pipe stdout', async t => { }); test('fork correctly use execPath', async t => { - const result = await execa.fork(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', [], { + const result = await execa.fork(process.platform === 'win32' ? '/c hello.cmd' : 'hello.sh', [], { stdout: 'pipe', execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash' }); From 76428060000158f561e7a1b763ee37f649db8169 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Tue, 21 May 2019 18:21:30 +0200 Subject: [PATCH 18/41] Reword on readme --- readme.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index 57ceeb3fe..dd5c4dce8 100644 --- a/readme.md +++ b/readme.md @@ -150,8 +150,10 @@ Stream combining/interleaving [`stdout`](https://nodejs.org/api/child_process.ht Run a file through a forked process. The default sub-process is the current (node). -It introduce a communication channel (IPC) that allows messages to be passed back and forth between the parent and child.
-Note that the `shell` option will be ignored. +Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): + - the `execPath`, `execArgv` and `silent` options can be used + - the [`shell`](#shell) option cannot be used + - the [`stdio`](#stdio)-related options defaults to `inherit` instead of `pipe` Returns the same object as [execa](#execafile-arguments-options). @@ -419,21 +421,21 @@ If `true`, no quoting or escaping of arguments is done on Windows. Ignored on ot Type: `string`
Default: `process.execPath` -Define the sub-process executable binary. +Executable used to create the child process. #### execArgv (for `fork` only) Type: `string[]`
Default: `process.execArgv` -Define the sub-process arguments. +List of string arguments passed to the executable. #### silent (for `fork` only) Type: `boolean`
Default: `false` -If `true`, set all stdio channel to `'pipe'`. +If `true`, set all stdio channels to `'pipe'`. ## Tips From e82b43a201cdddf6b336be60370ba44a91a90283 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Tue, 21 May 2019 18:41:46 +0200 Subject: [PATCH 19/41] Minor fixes --- index.d.ts | 2 ++ index.js | 7 ++++--- lib/stdio.js | 2 +- test.js | 21 +++++++++------------ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/index.d.ts b/index.d.ts index 5bda2ee4b..b53a7cffa 100644 --- a/index.d.ts +++ b/index.d.ts @@ -210,6 +210,8 @@ declare namespace execa { /** If `true`, set all stdio channel to `'pipe'` + + @default false */ readonly silent?: boolean; } diff --git a/index.js b/index.js index e2acfa016..44e9cf2cb 100644 --- a/index.js +++ b/index.js @@ -462,15 +462,16 @@ module.exports.sync = (command, args, options) => { }; }; -module.exports.fork = (filePath, args = [], options = {}) => { +module.exports.fork = (filePath, args, options) => { const stdioOption = stdio.fork(options); + options = options || {}; return execa( options.execPath || process.execPath, [ - filePath, ...(options.execArgv || process.execArgv), - ...args + filePath, + ...(Array.isArray(args) ? args : []) ], { ...options, diff --git a/lib/stdio.js b/lib/stdio.js index f8fe0eb8e..5988821f7 100644 --- a/lib/stdio.js +++ b/lib/stdio.js @@ -50,7 +50,7 @@ module.exports.fork = opts => { if (typeof stdioOption === 'string') { stdioOption = [...new Array(3)].fill(stdioOption); } else if (Array.isArray(stdioOption)) { - stdioOption = stdioOption.map(channel => channel === undefined ? defaultOption : channel); + stdioOption = stdioOption.map((channel = defaultOption) => channel); } if (!stdioOption.includes('ipc')) { diff --git a/test.js b/test.js index 093a6358c..242c2907c 100644 --- a/test.js +++ b/test.js @@ -707,13 +707,9 @@ test('calling cancel method on a process which has been killed does not make err t.false(isCanceled); }); -test.cb('fork()', t => { - const fork = execa.fork('fixtures/noop'); - - fork.on('close', code => { - t.is(code, 0); - t.end(); - }); +test('fork()', async t => { + const {exitCode} = await execa.fork('fixtures/noop'); + t.is(exitCode, 0); }); test('fork pipe stdout', async t => { @@ -725,21 +721,22 @@ test('fork pipe stdout', async t => { }); test('fork correctly use execPath', async t => { - const result = await execa.fork(process.platform === 'win32' ? '/c hello.cmd' : 'hello.sh', [], { + const {stdout} = await execa.fork(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', [], { stdout: 'pipe', - execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash' + execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash', + execArgv: ['/c'] }); - t.is(result.stdout, 'Hello World'); + t.is(stdout, 'Hello World'); }); test('fork pass on execArgv', async t => { - const result = await execa.fork('fixtures/noop', [], { + const {stdout} = await execa.fork('fixtures/noop', [], { stdout: 'pipe', execArgv: ['foo'] }); - t.is(result.stdout, 'foo'); + t.is(stdout, 'foo'); }); test.cb('forked script have a communication channel', t => { From 054b49b77ec5c18977a4ce976d9950b090f89cc6 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Wed, 22 May 2019 00:49:40 +0200 Subject: [PATCH 20/41] Fix tests on windows --- test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test.js b/test.js index 242c2907c..cb49660d1 100644 --- a/test.js +++ b/test.js @@ -724,16 +724,16 @@ test('fork correctly use execPath', async t => { const {stdout} = await execa.fork(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', [], { stdout: 'pipe', execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash', - execArgv: ['/c'] + execArgv: process.platform === 'win32' ? ['/c'] : [] }); t.is(stdout, 'Hello World'); }); test('fork pass on execArgv', async t => { - const {stdout} = await execa.fork('fixtures/noop', [], { + const {stdout} = await execa.fork('console.log("foo")', [], { stdout: 'pipe', - execArgv: ['foo'] + execArgv: ['-e'] }); t.is(stdout, 'foo'); From ac12a9f1bab696717982c624f74fdb7c66baa0fc Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Wed, 22 May 2019 00:50:07 +0200 Subject: [PATCH 21/41] Sync readme and type definition --- index.d.ts | 8 ++++---- media/logo.sketch | Bin 9975 -> 9974 bytes readme.md | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/index.d.ts b/index.d.ts index b53a7cffa..f685b71c2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -195,21 +195,21 @@ declare namespace execa { interface ForkOptions extends CommonOptions { /** - Define the sub-process executable binary + Executable used to create the child process. @default process.execPath */ readonly execPath?: string; /** - Define the sub-process arguments + List of string arguments passed to the executable. @default process.execArgv */ readonly execArgv?: string[]; /** - If `true`, set all stdio channel to `'pipe'` + If `true`, set all stdio channels to `'pipe'`. @default false */ @@ -393,7 +393,7 @@ declare const execa: { ): execa.ExecaSyncReturnValue; /** - Run a file through a fork of the current process. + Run a file through a forked process. @param file - The program/script to execute. @param arguments - Arguments to pass to `file` on execution. diff --git a/media/logo.sketch b/media/logo.sketch index 077e5e9f6f9cb5109d310b2c1a7429156b0323a4..4b2f8cb0df07c245e37ff78961cfaf18921ca1c2 100644 GIT binary patch delta 12 TcmezF`^|TQD&J-`zKaq7C=vxb delta 14 Vcmez7``vegDjy^7W>vn65&$nZ1xNq@ diff --git a/readme.md b/readme.md index dd5c4dce8..84bc91347 100644 --- a/readme.md +++ b/readme.md @@ -154,8 +154,7 @@ Same as `execa('node', [file, ...arguments], options)` except (like [`child_proc - the `execPath`, `execArgv` and `silent` options can be used - the [`shell`](#shell) option cannot be used - the [`stdio`](#stdio)-related options defaults to `inherit` instead of `pipe` - -Returns the same object as [execa](#execafile-arguments-options). + - an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio) ### execa.sync(file, [arguments], [options]) ### execa.sync(command, [options]) From fe687c231d6f4e24b4a27002f34d9cc7308eda7c Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Wed, 22 May 2019 11:45:19 +0200 Subject: [PATCH 22/41] Readme fine tune --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 84bc91347..d28e2a1ca 100644 --- a/readme.md +++ b/readme.md @@ -148,7 +148,7 @@ Stream combining/interleaving [`stdout`](https://nodejs.org/api/child_process.ht ### execa.fork(file, [arguments], [options]) -Run a file through a forked process. The default sub-process is the current (node). +Run a file through a forked process. Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): - the `execPath`, `execArgv` and `silent` options can be used From 497b23f8b51afebb22e01741063d56a9d3fdbb89 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Wed, 22 May 2019 13:35:35 +0200 Subject: [PATCH 23/41] Allow for user to omit args on fork --- index.js | 5 +++++ test.js | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 44e9cf2cb..824bca73a 100644 --- a/index.js +++ b/index.js @@ -463,6 +463,11 @@ module.exports.sync = (command, args, options) => { }; module.exports.fork = (filePath, args, options) => { + if (args && !Array.isArray(args) && typeof args === 'object') { + options = args; + args = [] + } + const stdioOption = stdio.fork(options); options = options || {}; diff --git a/test.js b/test.js index cb49660d1..b161e3dea 100644 --- a/test.js +++ b/test.js @@ -721,7 +721,7 @@ test('fork pipe stdout', async t => { }); test('fork correctly use execPath', async t => { - const {stdout} = await execa.fork(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', [], { + const {stdout} = await execa.fork(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', { stdout: 'pipe', execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash', execArgv: process.platform === 'win32' ? ['/c'] : [] @@ -731,7 +731,7 @@ test('fork correctly use execPath', async t => { }); test('fork pass on execArgv', async t => { - const {stdout} = await execa.fork('console.log("foo")', [], { + const {stdout} = await execa.fork('console.log("foo")', { stdout: 'pipe', execArgv: ['-e'] }); From 737e1184a134d82f944f8d467ce04949847d7ecb Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Wed, 22 May 2019 13:40:45 +0200 Subject: [PATCH 24/41] Add missing semicolon --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 824bca73a..eb4fc9a1e 100644 --- a/index.js +++ b/index.js @@ -465,7 +465,7 @@ module.exports.sync = (command, args, options) => { module.exports.fork = (filePath, args, options) => { if (args && !Array.isArray(args) && typeof args === 'object') { options = args; - args = [] + args = []; } const stdioOption = stdio.fork(options); From 0f90a2275014c29c87d06287c3eafa6b7719a2ca Mon Sep 17 00:00:00 2001 From: GMartigny Date: Thu, 6 Jun 2019 12:48:59 +0200 Subject: [PATCH 25/41] revert change to logo.sketch --- media/logo.sketch | Bin 9974 -> 9975 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/media/logo.sketch b/media/logo.sketch index 4b2f8cb0df07c245e37ff78961cfaf18921ca1c2..077e5e9f6f9cb5109d310b2c1a7429156b0323a4 100644 GIT binary patch delta 14 Vcmez7``vegDjy^7W>vn65&$nZ1xNq@ delta 12 TcmezF`^|TQD&J-`zKaq7C=vxb From 0fa394180f443257fd89842be54b57f85f4ca469 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 6 Jun 2019 14:19:21 +0200 Subject: [PATCH 26/41] Move all tests to `test` directory --- fixtures/echo | 3 - {fixtures => test/fixtures}/delay | 0 {fixtures => test/fixtures}/detach | 2 +- test/fixtures/echo | 3 + {fixtures => test/fixtures}/environment | 0 {fixtures => test/fixtures}/exit | 0 {fixtures => test/fixtures}/fail | 0 {fixtures => test/fixtures}/fast-exit-darwin | Bin {fixtures => test/fixtures}/fast-exit-linux | Bin {fixtures => test/fixtures}/forever | 0 {fixtures => test/fixtures}/hello.cmd | 0 {fixtures => test/fixtures}/hello.sh | 0 {fixtures => test/fixtures}/max-buffer | 0 {fixtures => test/fixtures}/non-executable | 0 {fixtures => test/fixtures}/noop | 0 {fixtures => test/fixtures}/noop-132 | 0 {fixtures => test/fixtures}/noop-err | 0 {fixtures => test/fixtures}/noop-throw | 0 {fixtures => test/fixtures}/send.js | 0 {fixtures => test/fixtures}/stdin | 0 {fixtures => test/fixtures}/sub-process | 2 +- {fixtures => test/fixtures}/sub-process-exit | 2 +- test/node.js | 47 +++++++++++++ test/stdio.js | 13 ++-- test.js => test/test.js | 67 ++++--------------- 25 files changed, 69 insertions(+), 70 deletions(-) delete mode 100755 fixtures/echo rename {fixtures => test/fixtures}/delay (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/detach (82%) mode change 100755 => 100644 create mode 100644 test/fixtures/echo rename {fixtures => test/fixtures}/environment (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/exit (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/fail (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/fast-exit-darwin (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/fast-exit-linux (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/forever (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/hello.cmd (100%) rename {fixtures => test/fixtures}/hello.sh (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/max-buffer (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/non-executable (100%) rename {fixtures => test/fixtures}/noop (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/noop-132 (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/noop-err (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/noop-throw (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/send.js (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/stdin (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/sub-process (87%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/sub-process-exit (84%) mode change 100755 => 100644 create mode 100644 test/node.js rename test.js => test/test.js (92%) diff --git a/fixtures/echo b/fixtures/echo deleted file mode 100755 index cdfa972df..000000000 --- a/fixtures/echo +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node -'use strict'; -console.log(process.argv.slice(2).join('\n')) diff --git a/fixtures/delay b/test/fixtures/delay old mode 100755 new mode 100644 similarity index 100% rename from fixtures/delay rename to test/fixtures/delay diff --git a/fixtures/detach b/test/fixtures/detach old mode 100755 new mode 100644 similarity index 82% rename from fixtures/detach rename to test/fixtures/detach index 7da1f8fd6..64983a4a0 --- a/fixtures/detach +++ b/test/fixtures/detach @@ -1,7 +1,7 @@ #!/usr/bin/env node 'use strict'; -const execa = require('..'); +const execa = require('../../'); const subprocess = execa('node', ['./fixtures/forever'], {detached: true}); console.log(subprocess.pid); diff --git a/test/fixtures/echo b/test/fixtures/echo new file mode 100644 index 000000000..e9baf7ef6 --- /dev/null +++ b/test/fixtures/echo @@ -0,0 +1,3 @@ +#!/usr/bin/env node +'use strict'; +console.log(process.argv.slice(2).join('\n')); diff --git a/fixtures/environment b/test/fixtures/environment old mode 100755 new mode 100644 similarity index 100% rename from fixtures/environment rename to test/fixtures/environment diff --git a/fixtures/exit b/test/fixtures/exit old mode 100755 new mode 100644 similarity index 100% rename from fixtures/exit rename to test/fixtures/exit diff --git a/fixtures/fail b/test/fixtures/fail old mode 100755 new mode 100644 similarity index 100% rename from fixtures/fail rename to test/fixtures/fail diff --git a/fixtures/fast-exit-darwin b/test/fixtures/fast-exit-darwin old mode 100755 new mode 100644 similarity index 100% rename from fixtures/fast-exit-darwin rename to test/fixtures/fast-exit-darwin diff --git a/fixtures/fast-exit-linux b/test/fixtures/fast-exit-linux old mode 100755 new mode 100644 similarity index 100% rename from fixtures/fast-exit-linux rename to test/fixtures/fast-exit-linux diff --git a/fixtures/forever b/test/fixtures/forever old mode 100755 new mode 100644 similarity index 100% rename from fixtures/forever rename to test/fixtures/forever diff --git a/fixtures/hello.cmd b/test/fixtures/hello.cmd similarity index 100% rename from fixtures/hello.cmd rename to test/fixtures/hello.cmd diff --git a/fixtures/hello.sh b/test/fixtures/hello.sh old mode 100755 new mode 100644 similarity index 100% rename from fixtures/hello.sh rename to test/fixtures/hello.sh diff --git a/fixtures/max-buffer b/test/fixtures/max-buffer old mode 100755 new mode 100644 similarity index 100% rename from fixtures/max-buffer rename to test/fixtures/max-buffer diff --git a/fixtures/non-executable b/test/fixtures/non-executable similarity index 100% rename from fixtures/non-executable rename to test/fixtures/non-executable diff --git a/fixtures/noop b/test/fixtures/noop old mode 100755 new mode 100644 similarity index 100% rename from fixtures/noop rename to test/fixtures/noop diff --git a/fixtures/noop-132 b/test/fixtures/noop-132 old mode 100755 new mode 100644 similarity index 100% rename from fixtures/noop-132 rename to test/fixtures/noop-132 diff --git a/fixtures/noop-err b/test/fixtures/noop-err old mode 100755 new mode 100644 similarity index 100% rename from fixtures/noop-err rename to test/fixtures/noop-err diff --git a/fixtures/noop-throw b/test/fixtures/noop-throw old mode 100755 new mode 100644 similarity index 100% rename from fixtures/noop-throw rename to test/fixtures/noop-throw diff --git a/fixtures/send.js b/test/fixtures/send.js old mode 100755 new mode 100644 similarity index 100% rename from fixtures/send.js rename to test/fixtures/send.js diff --git a/fixtures/stdin b/test/fixtures/stdin old mode 100755 new mode 100644 similarity index 100% rename from fixtures/stdin rename to test/fixtures/stdin diff --git a/fixtures/sub-process b/test/fixtures/sub-process old mode 100755 new mode 100644 similarity index 87% rename from fixtures/sub-process rename to test/fixtures/sub-process index 727aa0019..410e984ed --- a/fixtures/sub-process +++ b/test/fixtures/sub-process @@ -1,6 +1,6 @@ #!/usr/bin/env node 'use strict'; -const execa = require('..'); +const execa = require('../../'); const cleanup = process.argv[2] === 'true'; const detached = process.argv[3] === 'true'; diff --git a/fixtures/sub-process-exit b/test/fixtures/sub-process-exit old mode 100755 new mode 100644 similarity index 84% rename from fixtures/sub-process-exit rename to test/fixtures/sub-process-exit index 3ea8173ff..2378d8f91 --- a/fixtures/sub-process-exit +++ b/test/fixtures/sub-process-exit @@ -1,6 +1,6 @@ #!/usr/bin/env node 'use strict'; -const execa = require('..'); +const execa = require('../../'); const cleanup = process.argv[2] === 'true'; const detached = process.argv[3] === 'true'; diff --git a/test/node.js b/test/node.js new file mode 100644 index 000000000..03944fd13 --- /dev/null +++ b/test/node.js @@ -0,0 +1,47 @@ +import test from "ava"; +import pEvent from 'p-event'; +import execa from ".."; +import path from "path"; + +process.env.PATH = path.join(__dirname, 'fixtures') + path.delimiter + process.env.PATH; + +test('node()', async t => { + const {exitCode} = await execa.node('fixtures/noop'); + t.is(exitCode, 0); +}); + +test('node pipe stdout', async t => { + const {stdout} = await execa.node('fixtures/noop', ['foo'], { + stdout: 'pipe' + }); + + t.is(stdout, 'foo'); +}); + +test('node correctly use execPath', async t => { + const {stdout} = await execa.node(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', { + stdout: 'pipe', + execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash', + execArgv: process.platform === 'win32' ? ['/c'] : [] + }); + + t.is(stdout, 'Hello World'); +}); + +test('node pass on execArgv', async t => { + const {stdout} = await execa.node('console.log("foo")', { + stdout: 'pipe', + execArgv: ['-e'] + }); + + t.is(stdout, 'foo'); +}); + +test('node\'s forked script has a communication channel', async t => { + const subprocess = execa.node('fixtures/send.js'); + + const message = await pEvent(subprocess, 'message'); + t.is(message, 'pong'); + + subprocess.send('ping'); +}); diff --git a/test/stdio.js b/test/stdio.js index c7dc65a66..09a339a9f 100644 --- a/test/stdio.js +++ b/test/stdio.js @@ -55,21 +55,16 @@ test(stdioMacro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possibl test(stdioMacro, {stdin: 'inherit', stdio: ['pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); test(stdioMacro, {stdin: 'inherit', stdio: [undefined, 'pipe']}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); -const forkMacro = createMacro(stdio.fork); +const forkMacro = createMacro(stdio.node); -test(forkMacro, undefined, ['inherit', 'inherit', 'inherit', 'ipc']); +test(forkMacro, undefined, ['pipe', 'pipe', 'pipe', 'ipc']); test(forkMacro, {stdio: 'ignore'}, ['ignore', 'ignore', 'ignore', 'ipc']); test(forkMacro, {stdio: [0, 1, 2]}, [0, 1, 2, 'ipc']); test(forkMacro, {stdio: [0, 1, 2, 3]}, [0, 1, 2, 3, 'ipc']); test(forkMacro, {stdio: [0, 1, 2, 'ipc']}, [0, 1, 2, 'ipc']); -test(forkMacro, {stdout: 'ignore'}, ['inherit', 'ignore', 'inherit', 'ipc']); -test(forkMacro, {stdout: 'ignore', stderr: 'ignore'}, ['inherit', 'ignore', 'ignore', 'ipc']); - -test(forkMacro, {silent: true}, ['pipe', 'pipe', 'pipe', 'ipc']); -test(forkMacro, {silent: true, stdio: 'ignore'}, ['ignore', 'ignore', 'ignore', 'ipc']); -test(forkMacro, {silent: true, stdio: [0, 1, 2]}, [0, 1, 2, 'ipc']); -test(forkMacro, {silent: true, stdout: 'ignore'}, ['pipe', 'ignore', 'pipe', 'ipc']); +test(forkMacro, {stdout: 'ignore'}, ['pipe', 'ignore', 'pipe', 'ipc']); +test(forkMacro, {stdout: 'ignore', stderr: 'ignore'}, ['pipe', 'ignore', 'ignore', 'ipc']); test(forkMacro, {stdio: {foo: 'bar'}}, new TypeError('Expected `stdio` to be of type `string` or `Array`, got `object`')); test(forkMacro, {stdin: 'inherit', stdio: 'pipe'}, new Error('It\'s not possible to provide `stdio` in combination with one of `stdin`, `stdout`, `stderr`')); diff --git a/test.js b/test/test.js similarity index 92% rename from test.js rename to test/test.js index b161e3dea..de07fbf31 100644 --- a/test.js +++ b/test/test.js @@ -7,7 +7,7 @@ import getStream from 'get-stream'; import isRunning from 'is-running'; import tempfile from 'tempfile'; import pEvent from 'p-event'; -import execa from '.'; +import execa from '..'; process.env.PATH = path.join(__dirname, 'fixtures') + path.delimiter + process.env.PATH; process.env.FOO = 'foo'; @@ -87,49 +87,49 @@ test('stdout/stderr/all on process errors, in sync mode', t => { test('pass `stdout` to a file descriptor', async t => { const file = tempfile('.txt'); - await execa('fixtures/noop', ['foo bar'], {stdout: fs.openSync(file, 'w')}); + await execa('test/fixtures/noop', ['foo bar'], {stdout: fs.openSync(file, 'w')}); t.is(fs.readFileSync(file, 'utf8'), 'foo bar\n'); }); test('pass `stderr` to a file descriptor', async t => { const file = tempfile('.txt'); - await execa('fixtures/noop-err', ['foo bar'], {stderr: fs.openSync(file, 'w')}); + await execa('test/fixtures/noop-err', ['foo bar'], {stderr: fs.openSync(file, 'w')}); t.is(fs.readFileSync(file, 'utf8'), 'foo bar\n'); }); test('allow string arguments', async t => { - const {stdout} = await execa('node fixtures/echo foo bar'); + const {stdout} = await execa('node test/fixtures/echo foo bar'); t.is(stdout, 'foo\nbar'); }); test('allow string arguments in synchronous mode', t => { - const {stdout} = execa.sync('node fixtures/echo foo bar'); + const {stdout} = execa.sync('node test/fixtures/echo foo bar'); t.is(stdout, 'foo\nbar'); }); test('forbid string arguments together with array arguments', t => { t.throws(() => { - execa('node fixtures/echo foo bar', ['foo', 'bar']); + execa('node test/fixtures/echo foo bar', ['foo', 'bar']); }, /Arguments cannot be inside/); }); test('ignore consecutive spaces in string arguments', async t => { - const {stdout} = await execa('node fixtures/echo foo bar'); + const {stdout} = await execa('node test/fixtures/echo foo bar'); t.is(stdout, 'foo\nbar'); }); test('escape other whitespaces in string arguments', async t => { - const {stdout} = await execa('node fixtures/echo foo\tbar'); + const {stdout} = await execa('node test/fixtures/echo foo\tbar'); t.is(stdout, 'foo\tbar'); }); test('allow escaping spaces in string arguments', async t => { - const {stdout} = await execa('node fixtures/echo foo\\ bar'); + const {stdout} = await execa('node test/fixtures/echo foo\\ bar'); t.is(stdout, 'foo bar'); }); test('trim string arguments', async t => { - const {stdout} = await execa(' node fixtures/echo foo bar '); + const {stdout} = await execa(' node test/fixtures/echo foo bar '); t.is(stdout, 'foo\nbar'); }); @@ -550,13 +550,13 @@ test('do not extend environment with `extendEnv: false`', async t => { }); test('can use `options.shell: true`', async t => { - const {stdout} = await execa('node fixtures/noop foo', {shell: true}); + const {stdout} = await execa('node test/fixtures/noop foo', {shell: true}); t.is(stdout, 'foo'); }); test('can use `options.shell: string`', async t => { const shell = process.platform === 'win32' ? 'cmd.exe' : '/bin/bash'; - const {stdout} = await execa('node fixtures/noop foo', {shell}); + const {stdout} = await execa('node test/fixtures/noop foo', {shell}); t.is(stdout, 'foo'); }); @@ -706,46 +706,3 @@ test('calling cancel method on a process which has been killed does not make err const {isCanceled} = await t.throwsAsync(subprocess); t.false(isCanceled); }); - -test('fork()', async t => { - const {exitCode} = await execa.fork('fixtures/noop'); - t.is(exitCode, 0); -}); - -test('fork pipe stdout', async t => { - const {stdout} = await execa.fork('fixtures/noop', ['foo'], { - stdout: 'pipe' - }); - - t.is(stdout, 'foo'); -}); - -test('fork correctly use execPath', async t => { - const {stdout} = await execa.fork(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', { - stdout: 'pipe', - execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash', - execArgv: process.platform === 'win32' ? ['/c'] : [] - }); - - t.is(stdout, 'Hello World'); -}); - -test('fork pass on execArgv', async t => { - const {stdout} = await execa.fork('console.log("foo")', { - stdout: 'pipe', - execArgv: ['-e'] - }); - - t.is(stdout, 'foo'); -}); - -test.cb('forked script have a communication channel', t => { - const subprocess = execa.fork('fixtures/send.js'); - - subprocess.on('message', message => { - t.is(message, 'pong'); - t.end(); - }); - - subprocess.send('ping'); -}); From b02d6f4ce262dc0be29f8068bd6ef9816de58821 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 6 Jun 2019 14:20:29 +0200 Subject: [PATCH 27/41] Rename `fork` to `node` and remove `silent` option --- index.d.ts | 22 +++++++--------------- index.js | 4 ++-- index.test-d.ts | 12 ++++++------ lib/stdio.js | 4 ++-- readme.md | 19 ++++++------------- 5 files changed, 23 insertions(+), 38 deletions(-) diff --git a/index.d.ts b/index.d.ts index f685b71c2..ce65cb478 100644 --- a/index.d.ts +++ b/index.d.ts @@ -192,28 +192,20 @@ declare namespace execa { readonly input?: string | Buffer; } - interface ForkOptions extends CommonOptions { - + interface NodeOptions extends CommonOptions { /** Executable used to create the child process. - @default process.execPath + @default process.execPath */ readonly execPath?: string; /** List of string arguments passed to the executable. - @default process.execArgv + @default process.execArgv */ readonly execArgv?: string[]; - - /** - If `true`, set all stdio channels to `'pipe'`. - - @default false - */ - readonly silent?: boolean; } interface ExecaReturnBase { @@ -399,18 +391,18 @@ declare const execa: { @param arguments - Arguments to pass to `file` on execution. @returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties. */ - fork( + node( file: string, arguments?: readonly string[], options?: execa.Options ): execa.ExecaChildProcess; - fork( + node( file: string, arguments?: readonly string[], options?: execa.Options ): execa.ExecaChildProcess; - fork(file: string, options?: execa.Options): execa.ExecaChildProcess; - fork(file: string, options?: execa.Options): execa.ExecaChildProcess; + node(file: string, options?: execa.Options): execa.ExecaChildProcess; + node(file: string, options?: execa.Options): execa.ExecaChildProcess; }; export = execa; diff --git a/index.js b/index.js index eb4fc9a1e..6d9c76d4b 100644 --- a/index.js +++ b/index.js @@ -462,13 +462,13 @@ module.exports.sync = (command, args, options) => { }; }; -module.exports.fork = (filePath, args, options) => { +module.exports.node = (filePath, args, options) => { if (args && !Array.isArray(args) && typeof args === 'object') { options = args; args = []; } - const stdioOption = stdio.fork(options); + const stdioOption = stdio.node(options); options = options || {}; return execa( diff --git a/index.test-d.ts b/index.test-d.ts index c68646115..1863db63e 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -147,15 +147,15 @@ expectType>( execa.sync('unicorns', ['foo'], {encoding: null}) ); -expectType>(execa.fork('unicorns')); -expectType>(await execa.fork('unicorns')); +expectType>(execa.node('unicorns')); +expectType>(await execa.node('unicorns')); expectType>( - await execa.fork('unicorns', {encoding: 'utf8'}) + await execa.node('unicorns', {encoding: 'utf8'}) ); -expectType>(await execa.fork('unicorns', {encoding: null})); +expectType>(await execa.node('unicorns', {encoding: null})); expectType>( - await execa.fork('unicorns', ['foo'], {encoding: 'utf8'}) + await execa.node('unicorns', ['foo'], {encoding: 'utf8'}) ); expectType>( - await execa.fork('unicorns', ['foo'], {encoding: null}) + await execa.node('unicorns', ['foo'], {encoding: null}) ); diff --git a/lib/stdio.js b/lib/stdio.js index 5988821f7..d9f5458b4 100644 --- a/lib/stdio.js +++ b/lib/stdio.js @@ -42,8 +42,8 @@ const stdio = opts => { module.exports = stdio; -module.exports.fork = opts => { - const defaultOption = (opts && opts.silent && !opts.stdio) ? 'pipe' : 'inherit'; +module.exports.node = opts => { + const defaultOption = 'pipe'; let stdioOption = stdio(opts || {stdio: defaultOption}); diff --git a/readme.md b/readme.md index d28e2a1ca..8172aa68f 100644 --- a/readme.md +++ b/readme.md @@ -146,12 +146,12 @@ Similar to [`childProcess.kill()`](https://nodejs.org/api/child_process.html#chi Stream combining/interleaving [`stdout`](https://nodejs.org/api/child_process.html#child_process_subprocess_stdout) and [`stderr`](https://nodejs.org/api/child_process.html#child_process_subprocess_stderr). -### execa.fork(file, [arguments], [options]) +### execa.node(file, [arguments], [options]) Run a file through a forked process. Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): - - the `execPath`, `execArgv` and `silent` options can be used + - the `execPath` and `execArgv` options can be used - the [`shell`](#shell) option cannot be used - the [`stdio`](#stdio)-related options defaults to `inherit` instead of `pipe` - an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio) @@ -415,27 +415,20 @@ Default: `false` If `true`, no quoting or escaping of arguments is done on Windows. Ignored on other platforms. This is set to `true` automatically when the `shell` option is `true`. -#### execPath (for `fork` only) +#### execPath *(for `.node()` only)* Type: `string`
-Default: `process.execPath` +Default: [`process.execPath`](https://nodejs.org/api/process.html#process_process_execpath) Executable used to create the child process. -#### execArgv (for `fork` only) +#### execArgv *(for `.node()` only)* Type: `string[]`
-Default: `process.execArgv` +Default: [`process.execArgv`](https://nodejs.org/api/process.html#process_process_execargv) List of string arguments passed to the executable. -#### silent (for `fork` only) - -Type: `boolean`
-Default: `false` - -If `true`, set all stdio channels to `'pipe'`. - ## Tips ### Save and pipe output from a child process From 56807946aa0594b9124500fecc02cd1f45e23910 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 6 Jun 2019 14:49:10 +0200 Subject: [PATCH 28/41] Fix `.node()` tests --- test/node.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/node.js b/test/node.js index 03944fd13..7d5aafc4c 100644 --- a/test/node.js +++ b/test/node.js @@ -6,12 +6,12 @@ import path from "path"; process.env.PATH = path.join(__dirname, 'fixtures') + path.delimiter + process.env.PATH; test('node()', async t => { - const {exitCode} = await execa.node('fixtures/noop'); + const {exitCode} = await execa.node('test/fixtures/noop'); t.is(exitCode, 0); }); test('node pipe stdout', async t => { - const {stdout} = await execa.node('fixtures/noop', ['foo'], { + const {stdout} = await execa.node('test/fixtures/noop', ['foo'], { stdout: 'pipe' }); @@ -37,11 +37,10 @@ test('node pass on execArgv', async t => { t.is(stdout, 'foo'); }); -test('node\'s forked script has a communication channel', async t => { - const subprocess = execa.node('fixtures/send.js'); +test.only('node\'s forked script has a communication channel', async t => { + const subprocess = execa.node('test/fixtures/send.js'); + subprocess.send('ping'); const message = await pEvent(subprocess, 'message'); t.is(message, 'pong'); - - subprocess.send('ping'); }); From d93cb698d3b3d5de0cd67b3f7068d47fcb2a4a3d Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 6 Jun 2019 14:55:59 +0200 Subject: [PATCH 29/41] Minor tweak to syntax --- readme.md | 23 +++++++++++------------ test/stdio.js | 4 +++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/readme.md b/readme.md index 2df563740..f16564fbf 100644 --- a/readme.md +++ b/readme.md @@ -162,16 +162,6 @@ Similar to [`childProcess.kill()`](https://nodejs.org/api/child_process.html#chi Stream combining/interleaving [`stdout`](https://nodejs.org/api/child_process.html#child_process_subprocess_stdout) and [`stderr`](https://nodejs.org/api/child_process.html#child_process_subprocess_stderr). -### execa.node(file, [arguments], [options]) - -Run a file through a forked process. - -Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): - - the `execPath` and `execArgv` options can be used - - the [`shell`](#shell) option cannot be used - - the [`stdio`](#stdio)-related options defaults to `inherit` instead of `pipe` - - an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio) - ### execa.sync(file, [arguments], [options]) Execute a file synchronously. @@ -190,6 +180,15 @@ Same as [`execa.command()`](#execacommand-command-options) but synchronous. Returns or throws a [`childProcessResult`](#childProcessResult). +### execa.node(file, [arguments], [options]) + +Run a file through a forked process. + +Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): + - the `execPath` and `execArgv` options can be used + - the [`shell`](#shell) option cannot be used + - an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio) + ### childProcessResult Type: `object` @@ -447,14 +446,14 @@ If `true`, no quoting or escaping of arguments is done on Windows. Ignored on ot Type: `string`
Default: [`process.execPath`](https://nodejs.org/api/process.html#process_process_execpath) -Executable used to create the child process. +Node.js executable used to create the child process. #### execArgv *(for `.node()` only)* Type: `string[]`
Default: [`process.execArgv`](https://nodejs.org/api/process.html#process_process_execargv) -List of string arguments passed to the executable. +List of string arguments passed to the node.js executable. ## Tips diff --git a/test/stdio.js b/test/stdio.js index 09a339a9f..a9ccb0325 100644 --- a/test/stdio.js +++ b/test/stdio.js @@ -7,7 +7,9 @@ util.inspect.styles.name = 'magenta'; function createMacro(func) { const macro = (t, input, expected) => { if (expected instanceof Error) { - t.throws(() => stdio(input), expected.message); + t.throws(() => { + stdio(input); + }, expected.message); return; } From f302e7841dac534b5cf28c7f9ecda2cad2f64be6 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 6 Jun 2019 15:01:15 +0200 Subject: [PATCH 30/41] Remove linter warning --- test/node.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/node.js b/test/node.js index 7d5aafc4c..141c1b017 100644 --- a/test/node.js +++ b/test/node.js @@ -1,7 +1,7 @@ -import test from "ava"; +import test from 'ava'; import pEvent from 'p-event'; -import execa from ".."; -import path from "path"; +import path from 'path'; +import execa from '..'; process.env.PATH = path.join(__dirname, 'fixtures') + path.delimiter + process.env.PATH; @@ -37,7 +37,7 @@ test('node pass on execArgv', async t => { t.is(stdout, 'foo'); }); -test.only('node\'s forked script has a communication channel', async t => { +test('node\'s forked script has a communication channel', async t => { const subprocess = execa.node('test/fixtures/send.js'); subprocess.send('ping'); From 7746b01fe1fb0fec8459e5a40cb96d01f9f675f8 Mon Sep 17 00:00:00 2001 From: GMartigny Date: Thu, 6 Jun 2019 15:26:20 +0200 Subject: [PATCH 31/41] Add execution right to fixtures files --- test/fixtures/delay | 0 test/fixtures/detach | 0 test/fixtures/echo | 0 test/fixtures/environment | 0 test/fixtures/exit | 0 test/fixtures/fail | 0 test/fixtures/fast-exit-darwin | Bin test/fixtures/fast-exit-linux | Bin test/fixtures/forever | 0 test/fixtures/hello.cmd | 0 test/fixtures/hello.sh | 0 test/fixtures/max-buffer | 0 test/fixtures/noop | 0 test/fixtures/noop-132 | 0 test/fixtures/noop-err | 0 test/fixtures/noop-throw | 0 test/fixtures/send.js | 0 test/fixtures/stdin | 0 test/fixtures/sub-process | 0 test/fixtures/sub-process-exit | 0 20 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/fixtures/delay mode change 100644 => 100755 test/fixtures/detach mode change 100644 => 100755 test/fixtures/echo mode change 100644 => 100755 test/fixtures/environment mode change 100644 => 100755 test/fixtures/exit mode change 100644 => 100755 test/fixtures/fail mode change 100644 => 100755 test/fixtures/fast-exit-darwin mode change 100644 => 100755 test/fixtures/fast-exit-linux mode change 100644 => 100755 test/fixtures/forever mode change 100644 => 100755 test/fixtures/hello.cmd mode change 100644 => 100755 test/fixtures/hello.sh mode change 100644 => 100755 test/fixtures/max-buffer mode change 100644 => 100755 test/fixtures/noop mode change 100644 => 100755 test/fixtures/noop-132 mode change 100644 => 100755 test/fixtures/noop-err mode change 100644 => 100755 test/fixtures/noop-throw mode change 100644 => 100755 test/fixtures/send.js mode change 100644 => 100755 test/fixtures/stdin mode change 100644 => 100755 test/fixtures/sub-process mode change 100644 => 100755 test/fixtures/sub-process-exit diff --git a/test/fixtures/delay b/test/fixtures/delay old mode 100644 new mode 100755 diff --git a/test/fixtures/detach b/test/fixtures/detach old mode 100644 new mode 100755 diff --git a/test/fixtures/echo b/test/fixtures/echo old mode 100644 new mode 100755 diff --git a/test/fixtures/environment b/test/fixtures/environment old mode 100644 new mode 100755 diff --git a/test/fixtures/exit b/test/fixtures/exit old mode 100644 new mode 100755 diff --git a/test/fixtures/fail b/test/fixtures/fail old mode 100644 new mode 100755 diff --git a/test/fixtures/fast-exit-darwin b/test/fixtures/fast-exit-darwin old mode 100644 new mode 100755 diff --git a/test/fixtures/fast-exit-linux b/test/fixtures/fast-exit-linux old mode 100644 new mode 100755 diff --git a/test/fixtures/forever b/test/fixtures/forever old mode 100644 new mode 100755 diff --git a/test/fixtures/hello.cmd b/test/fixtures/hello.cmd old mode 100644 new mode 100755 diff --git a/test/fixtures/hello.sh b/test/fixtures/hello.sh old mode 100644 new mode 100755 diff --git a/test/fixtures/max-buffer b/test/fixtures/max-buffer old mode 100644 new mode 100755 diff --git a/test/fixtures/noop b/test/fixtures/noop old mode 100644 new mode 100755 diff --git a/test/fixtures/noop-132 b/test/fixtures/noop-132 old mode 100644 new mode 100755 diff --git a/test/fixtures/noop-err b/test/fixtures/noop-err old mode 100644 new mode 100755 diff --git a/test/fixtures/noop-throw b/test/fixtures/noop-throw old mode 100644 new mode 100755 diff --git a/test/fixtures/send.js b/test/fixtures/send.js old mode 100644 new mode 100755 diff --git a/test/fixtures/stdin b/test/fixtures/stdin old mode 100644 new mode 100755 diff --git a/test/fixtures/sub-process b/test/fixtures/sub-process old mode 100644 new mode 100755 diff --git a/test/fixtures/sub-process-exit b/test/fixtures/sub-process-exit old mode 100644 new mode 100755 From 9a65cc546c9277e8fd0a87242d315e2d4e6e9e9a Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 6 Jun 2019 16:22:05 +0200 Subject: [PATCH 32/41] Fix path in fixtures --- test/fixtures/detach | 2 +- test/fixtures/sub-process | 2 +- test/fixtures/sub-process-exit | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/fixtures/detach b/test/fixtures/detach index 64983a4a0..101b30167 100755 --- a/test/fixtures/detach +++ b/test/fixtures/detach @@ -3,6 +3,6 @@ const execa = require('../../'); -const subprocess = execa('node', ['./fixtures/forever'], {detached: true}); +const subprocess = execa('node', ['./test/fixtures/forever'], {detached: true}); console.log(subprocess.pid); process.exit(); diff --git a/test/fixtures/sub-process b/test/fixtures/sub-process index 410e984ed..0b2aef885 100755 --- a/test/fixtures/sub-process +++ b/test/fixtures/sub-process @@ -4,5 +4,5 @@ const execa = require('../../'); const cleanup = process.argv[2] === 'true'; const detached = process.argv[3] === 'true'; -const subprocess = execa('node', ['./fixtures/forever'], {cleanup, detached}); +const subprocess = execa('node', ['./test/fixtures/forever'], {cleanup, detached}); process.send(subprocess.pid); diff --git a/test/fixtures/sub-process-exit b/test/fixtures/sub-process-exit index 2378d8f91..f21095b76 100755 --- a/test/fixtures/sub-process-exit +++ b/test/fixtures/sub-process-exit @@ -4,4 +4,4 @@ const execa = require('../../'); const cleanup = process.argv[2] === 'true'; const detached = process.argv[3] === 'true'; -execa('node', ['./fixtures/noop'], {cleanup, detached}); +execa('node', ['./test/fixtures/noop'], {cleanup, detached}); From f4b77c7ebeaa93310ae231108794354ddbcd4d03 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 7 Jun 2019 10:44:41 +0200 Subject: [PATCH 33/41] Capitalize `node.js` Co-Authored-By: ehmicky --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f16564fbf..a1863d6c2 100644 --- a/readme.md +++ b/readme.md @@ -453,7 +453,7 @@ Node.js executable used to create the child process. Type: `string[]`
Default: [`process.execArgv`](https://nodejs.org/api/process.html#process_process_execargv) -List of string arguments passed to the node.js executable. +List of string arguments passed to the Node.js executable. ## Tips From 0fac604651c8f78baa1f1d753b352c3173ced831 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 7 Jun 2019 10:45:29 +0200 Subject: [PATCH 34/41] Add shebang and `'use strict'` --- test/fixtures/{send.js => send} | 2 ++ test/node.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) rename test/fixtures/{send.js => send} (81%) mode change 100755 => 100644 diff --git a/test/fixtures/send.js b/test/fixtures/send old mode 100755 new mode 100644 similarity index 81% rename from test/fixtures/send.js rename to test/fixtures/send index 22fc2dbed..c215df6f7 --- a/test/fixtures/send.js +++ b/test/fixtures/send @@ -1,3 +1,5 @@ +#!/usr/bin/env node +'use strict'; process.on('message', message => { if (message === 'ping') { process.send('pong'); diff --git a/test/node.js b/test/node.js index 141c1b017..4c6fa0de8 100644 --- a/test/node.js +++ b/test/node.js @@ -38,7 +38,7 @@ test('node pass on execArgv', async t => { }); test('node\'s forked script has a communication channel', async t => { - const subprocess = execa.node('test/fixtures/send.js'); + const subprocess = execa.node('test/fixtures/send'); subprocess.send('ping'); const message = await pEvent(subprocess, 'message'); From b37f98b8e01a693e9c330be34259248d0357f5f0 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Fri, 7 Jun 2019 11:23:21 +0200 Subject: [PATCH 35/41] Move remaining fixtures files under `test` --- {fixtures => test/fixtures}/command with space | 0 {fixtures => test/fixtures}/no-killable | 0 test/test.js | 14 +++++++------- 3 files changed, 7 insertions(+), 7 deletions(-) rename {fixtures => test/fixtures}/command with space (100%) mode change 100755 => 100644 rename {fixtures => test/fixtures}/no-killable (100%) diff --git a/fixtures/command with space b/test/fixtures/command with space old mode 100755 new mode 100644 similarity index 100% rename from fixtures/command with space rename to test/fixtures/command with space diff --git a/fixtures/no-killable b/test/fixtures/no-killable similarity index 100% rename from fixtures/no-killable rename to test/fixtures/no-killable diff --git a/test/test.js b/test/test.js index fbc0a6e52..0eb1504bc 100644 --- a/test/test.js +++ b/test/test.js @@ -117,7 +117,7 @@ test('skip throwing when using reject option in sync mode', t => { }); test('execa() with .kill() after it with SIGKILL should kill cleanly', async t => { - const subprocess = execa('node', ['fixtures/no-killable'], { + const subprocess = execa('node', ['./test/fixtures/no-killable'], { stdio: ['ipc'] }); @@ -133,7 +133,7 @@ test('execa() with .kill() after it with SIGKILL should kill cleanly', async t = // Therefore, this feature and those tests do not make sense on Windows. if (process.platform !== 'win32') { test('execa() with .kill() after it with SIGTERM should not kill (no retry)', async t => { - const subprocess = execa('node', ['fixtures/no-killable'], { + const subprocess = execa('node', ['./test/fixtures/no-killable'], { stdio: ['ipc'] }); @@ -149,7 +149,7 @@ if (process.platform !== 'win32') { }); test('execa() with .kill() after it with SIGTERM should kill after 50 ms with SIGKILL', async t => { - const subprocess = execa('node', ['fixtures/no-killable'], { + const subprocess = execa('node', ['./test/fixtures/no-killable'], { stdio: ['ipc'] }); @@ -164,7 +164,7 @@ if (process.platform !== 'win32') { }); test('execa() with .kill() after it with nothing (undefined) should kill after 50 ms with SIGKILL', async t => { - const subprocess = execa('node', ['fixtures/no-killable'], { + const subprocess = execa('node', ['./test/fixtures/no-killable'], { stdio: ['ipc'] }); @@ -755,12 +755,12 @@ test('calling cancel method on a process which has been killed does not make err }); test('allow commands with spaces and no array arguments', async t => { - const {stdout} = await execa('./fixtures/command with space'); + const {stdout} = await execa('command with space'); t.is(stdout, ''); }); test('allow commands with spaces and array arguments', async t => { - const {stdout} = await execa('./fixtures/command with space', ['foo', 'bar']); + const {stdout} = await execa('command with space', ['foo', 'bar']); t.is(stdout, 'foo\nbar'); }); @@ -775,7 +775,7 @@ test('execa.command() ignores consecutive spaces', async t => { }); test('execa.command() allows escaping spaces in commands', async t => { - const {stdout} = await execa.command('./fixtures/command\\ with\\ space foo bar'); + const {stdout} = await execa.command('command\\ with\\ space foo bar'); t.is(stdout, 'foo\nbar'); }); From ed7e580654ec5d7cf09bc36f65f28bcc34856d1b Mon Sep 17 00:00:00 2001 From: GMartigny Date: Fri, 7 Jun 2019 11:41:14 +0200 Subject: [PATCH 36/41] Fix file execution rights thanks to windows --- test/fixtures/command with space | 0 test/fixtures/no-killable | 0 test/fixtures/send | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/fixtures/command with space mode change 100644 => 100755 test/fixtures/no-killable mode change 100644 => 100755 test/fixtures/send diff --git a/test/fixtures/command with space b/test/fixtures/command with space old mode 100644 new mode 100755 diff --git a/test/fixtures/no-killable b/test/fixtures/no-killable old mode 100644 new mode 100755 diff --git a/test/fixtures/send b/test/fixtures/send old mode 100644 new mode 100755 From 906045ef0521c50e1b569d59ffa94fdf7a9d4e24 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 13 Jun 2019 13:39:23 +0200 Subject: [PATCH 37/41] Rename `.node` specific params --- index.d.ts | 16 ++++++++-------- index.js | 8 ++++---- readme.md | 6 +++--- test/node.js | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/index.d.ts b/index.d.ts index e85e0c829..39dc75f09 100644 --- a/index.d.ts +++ b/index.d.ts @@ -196,16 +196,16 @@ declare namespace execa { /** Executable used to create the child process. - @default process.execPath - */ - readonly execPath?: string; + @default process.execPath + */ + readonly nodePath?: string; /** List of string arguments passed to the executable. - @default process.execArgv - */ - readonly execArgv?: string[]; + @default process.execArgv + */ + readonly nodeArguments?: string[]; } interface ExecaReturnBase { @@ -439,12 +439,12 @@ declare const execa: { /** Run a file through a forked process. - @param file - The program/script to execute. + @param scriptPath - Node.js script to execute. @param arguments - Arguments to pass to `file` on execution. @returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties. */ node( - file: string, + scriptPath: string, arguments?: readonly string[], options?: execa.Options ): execa.ExecaChildProcess; diff --git a/index.js b/index.js index f6a1b4d64..9305809d8 100644 --- a/index.js +++ b/index.js @@ -476,7 +476,7 @@ module.exports.commandSync = (command, options) => { return execa.sync(file, args, options); }; -module.exports.node = (filePath, args, options) => { +module.exports.node = (scriptPath, args, options) => { if (args && !Array.isArray(args) && typeof args === 'object') { options = args; args = []; @@ -486,10 +486,10 @@ module.exports.node = (filePath, args, options) => { options = options || {}; return execa( - options.execPath || process.execPath, + options.nodePath || process.execPath, [ - ...(options.execArgv || process.execArgv), - filePath, + ...(options.nodeArguments || process.execArgv), + scriptPath, ...(Array.isArray(args) ? args : []) ], { diff --git a/readme.md b/readme.md index a1863d6c2..400d818f5 100644 --- a/readme.md +++ b/readme.md @@ -185,7 +185,7 @@ Returns or throws a [`childProcessResult`](#childProcessResult). Run a file through a forked process. Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): - - the `execPath` and `execArgv` options can be used + - the `nodePath` and `nodeArguments` options can be used - the [`shell`](#shell) option cannot be used - an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio) @@ -441,14 +441,14 @@ Default: `false` If `true`, no quoting or escaping of arguments is done on Windows. Ignored on other platforms. This is set to `true` automatically when the `shell` option is `true`. -#### execPath *(for `.node()` only)* +#### nodePath *(for `.node()` only)* Type: `string`
Default: [`process.execPath`](https://nodejs.org/api/process.html#process_process_execpath) Node.js executable used to create the child process. -#### execArgv *(for `.node()` only)* +#### nodeArguments *(for `.node()` only)* Type: `string[]`
Default: [`process.execArgv`](https://nodejs.org/api/process.html#process_process_execargv) diff --git a/test/node.js b/test/node.js index 4c6fa0de8..c6ff30d8a 100644 --- a/test/node.js +++ b/test/node.js @@ -18,20 +18,20 @@ test('node pipe stdout', async t => { t.is(stdout, 'foo'); }); -test('node correctly use execPath', async t => { +test('node correctly use nodePath', async t => { const {stdout} = await execa.node(process.platform === 'win32' ? 'hello.cmd' : 'hello.sh', { stdout: 'pipe', - execPath: process.platform === 'win32' ? 'cmd.exe' : 'bash', - execArgv: process.platform === 'win32' ? ['/c'] : [] + nodePath: process.platform === 'win32' ? 'cmd.exe' : 'bash', + nodeArguments: process.platform === 'win32' ? ['/c'] : [] }); t.is(stdout, 'Hello World'); }); -test('node pass on execArgv', async t => { +test('node pass on nodeArguments', async t => { const {stdout} = await execa.node('console.log("foo")', { stdout: 'pipe', - execArgv: ['-e'] + nodeArguments: ['-e'] }); t.is(stdout, 'foo'); From 6e181cc40e2ccf349ebe566ad6c7ecd894a8345c Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 13 Jun 2019 13:48:26 +0200 Subject: [PATCH 38/41] Link `.node` params to their definition --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 400d818f5..6b643ab1e 100644 --- a/readme.md +++ b/readme.md @@ -185,7 +185,7 @@ Returns or throws a [`childProcessResult`](#childProcessResult). Run a file through a forked process. Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): - - the `nodePath` and `nodeArguments` options can be used + - the [`nodePath`](#nodepath-for-node-only) and [`nodeArguments`](#nodearguments-for-node-only) options can be used - the [`shell`](#shell) option cannot be used - an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio) From 87b861fe1a93d8bf97f1047bd62342c293079bac Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 13 Jun 2019 13:49:43 +0200 Subject: [PATCH 39/41] Change `.node` description --- index.d.ts | 14 +++++++------- readme.md | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index 39dc75f09..1bf1342c7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -194,14 +194,14 @@ declare namespace execa { interface NodeOptions extends CommonOptions { /** - Executable used to create the child process. + The Node.js executable to use. @default process.execPath */ readonly nodePath?: string; /** - List of string arguments passed to the executable. + List of string arguments passed to the Node.js executable. @default process.execArgv */ @@ -437,12 +437,12 @@ declare const execa: { commandSync(command: string, options?: execa.SyncOptions): execa.ExecaSyncReturnValue; /** - Run a file through a forked process. + Execute a Node.js file as a child process. - @param scriptPath - Node.js script to execute. - @param arguments - Arguments to pass to `file` on execution. - @returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties. - */ + @param scriptPath - Node.js script to execute. + @param arguments - Arguments to pass to `file` on execution. + @returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties. + */ node( scriptPath: string, arguments?: readonly string[], diff --git a/readme.md b/readme.md index 6b643ab1e..1d184c67f 100644 --- a/readme.md +++ b/readme.md @@ -182,7 +182,7 @@ Returns or throws a [`childProcessResult`](#childProcessResult). ### execa.node(file, [arguments], [options]) -Run a file through a forked process. +Execute a Node.js file as a child process. Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): - the [`nodePath`](#nodepath-for-node-only) and [`nodeArguments`](#nodearguments-for-node-only) options can be used From 6394e4dfc55fcabacca06a647f10afe3902290e7 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Thu, 13 Jun 2019 13:50:03 +0200 Subject: [PATCH 40/41] Minor tweak in syntax --- index.d.ts | 4 ++-- test/fixtures/detach | 2 +- test/fixtures/sub-process | 2 +- test/fixtures/sub-process-exit | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index 1bf1342c7..e9d53e8d0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -192,7 +192,7 @@ declare namespace execa { readonly input?: string | Buffer; } - interface NodeOptions extends CommonOptions { + interface NodeOptions extends Options { /** The Node.js executable to use. @@ -446,7 +446,7 @@ declare const execa: { node( scriptPath: string, arguments?: readonly string[], - options?: execa.Options + options?: execa.NodeOptions ): execa.ExecaChildProcess; node( file: string, diff --git a/test/fixtures/detach b/test/fixtures/detach index 101b30167..80f898009 100755 --- a/test/fixtures/detach +++ b/test/fixtures/detach @@ -1,7 +1,7 @@ #!/usr/bin/env node 'use strict'; -const execa = require('../../'); +const execa = require('../..'); const subprocess = execa('node', ['./test/fixtures/forever'], {detached: true}); console.log(subprocess.pid); diff --git a/test/fixtures/sub-process b/test/fixtures/sub-process index 0b2aef885..6920e7934 100755 --- a/test/fixtures/sub-process +++ b/test/fixtures/sub-process @@ -1,6 +1,6 @@ #!/usr/bin/env node 'use strict'; -const execa = require('../../'); +const execa = require('../..'); const cleanup = process.argv[2] === 'true'; const detached = process.argv[3] === 'true'; diff --git a/test/fixtures/sub-process-exit b/test/fixtures/sub-process-exit index f21095b76..2b350a2b6 100755 --- a/test/fixtures/sub-process-exit +++ b/test/fixtures/sub-process-exit @@ -1,6 +1,6 @@ #!/usr/bin/env node 'use strict'; -const execa = require('../../'); +const execa = require('../..'); const cleanup = process.argv[2] === 'true'; const detached = process.argv[3] === 'true'; From 5c15cf2f759117a4881fb78a809d90f5a9174031 Mon Sep 17 00:00:00 2001 From: Guillaume Martigny Date: Tue, 18 Jun 2019 13:11:00 +0200 Subject: [PATCH 41/41] Doc say `script` instead of `file` for `.node()` --- index.d.ts | 4 ++-- readme.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index 5735e033e..9a2184690 100644 --- a/index.d.ts +++ b/index.d.ts @@ -434,10 +434,10 @@ declare const execa: { commandSync(command: string, options?: execa.SyncOptions): execa.ExecaSyncReturnValue; /** - Execute a Node.js file as a child process. + Execute a Node.js script as a child process. @param scriptPath - Node.js script to execute. - @param arguments - Arguments to pass to `file` on execution. + @param arguments - Arguments to pass to `scriptPath` on execution. @returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties. */ node( diff --git a/readme.md b/readme.md index 08aab28b2..e0e857109 100644 --- a/readme.md +++ b/readme.md @@ -184,9 +184,9 @@ Same as [`execa.command()`](#execacommand-command-options) but synchronous. Returns or throws a [`childProcessResult`](#childProcessResult). -### execa.node(file, [arguments], [options]) +### execa.node(scriptPath, [arguments], [options]) -Execute a Node.js file as a child process. +Execute a Node.js script as a child process. Same as `execa('node', [file, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)): - the [`nodePath`](#nodepath-for-node-only) and [`nodeArguments`](#nodearguments-for-node-only) options can be used