From d221e532dc2bfe45a1a2237e601460016c0c93aa Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 01/19] Add `all` option --- index.js | 3 ++- lib/stream.js | 17 ++++++----------- test/error.js | 4 ++-- test/stream.js | 48 +++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 51 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index 8b9df5fcc8..70466bb285 100644 --- a/index.js +++ b/index.js @@ -40,6 +40,7 @@ const handleArgs = (file, args, options = {}) => { encoding: 'utf8', reject: true, cleanup: true, + all: false, ...options, windowsHide: true }; @@ -150,7 +151,7 @@ const execa = (file, args, options) => { handleInput(spawned, parsed.options.input); - spawned.all = makeAllStream(spawned); + spawned.all = makeAllStream(spawned, parsed.options); return mergePromise(spawned, handlePromiseOnce); }; diff --git a/lib/stream.js b/lib/stream.js index 827a73f9b6..53d089d2be 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -19,7 +19,11 @@ const handleInput = (spawned, input) => { }; // `all` interleaves `stdout` and `stderr` -const makeAllStream = spawned => { +const makeAllStream = (spawned, {all}) => { + if (!all) { + return; + } + if (!spawned.stdout && !spawned.stderr) { return; } @@ -53,19 +57,10 @@ const getBufferedData = async (stream, streamPromise) => { }; const getStreamPromise = (stream, {encoding, buffer, maxBuffer}) => { - if (!stream) { + if (!stream || !buffer) { return; } - if (!buffer) { - // TODO: Use `ret = util.promisify(stream.finished)(stream);` when targeting Node.js 10 - return new Promise((resolve, reject) => { - stream - .once('end', resolve) - .once('error', reject); - }); - } - if (encoding) { return getStream(stream, {encoding, maxBuffer}); } diff --git a/test/error.js b/test/error.js index cb2caee45d..a009b041fe 100644 --- a/test/error.js +++ b/test/error.js @@ -10,7 +10,7 @@ const TIMEOUT_REGEXP = /timed out after/; const getExitRegExp = exitMessage => new RegExp(`failed with exit code ${exitMessage}`); test('stdout/stderr/all available on errors', async t => { - const {stdout, stderr, all} = await t.throwsAsync(execa('exit', ['2']), {message: getExitRegExp('2')}); + const {stdout, stderr, all} = await t.throwsAsync(execa('exit', ['2'], {all: true}), {message: getExitRegExp('2')}); t.is(typeof stdout, 'string'); t.is(typeof stderr, 'string'); t.is(typeof all, 'string'); @@ -21,7 +21,7 @@ const WRONG_COMMAND = process.platform === 'win32' ? ''; test('stdout/stderr/all on process errors', async t => { - const {stdout, stderr, all} = await t.throwsAsync(execa('wrong command')); + const {stdout, stderr, all} = await t.throwsAsync(execa('wrong command', {all: true})); t.is(stdout, ''); t.is(stderr, WRONG_COMMAND); t.is(all, WRONG_COMMAND); diff --git a/test/stream.js b/test/stream.js index 6cbab5e2e8..0dfcbfdb6f 100644 --- a/test/stream.js +++ b/test/stream.js @@ -27,7 +27,7 @@ test('pass `stderr` to a file descriptor', async t => { }); test.serial('result.all shows both `stdout` and `stderr` intermixed', async t => { - const {all} = await execa('noop-132'); + const {all} = await execa('noop-132', {all: true}); t.is(all, '132'); }); @@ -98,14 +98,14 @@ test('helpful error trying to provide an input stream in sync mode', t => { test('maxBuffer affects stdout', async t => { await t.notThrowsAsync(execa('max-buffer', ['stdout', '10'], {maxBuffer: 10})); - const {stdout, all} = await t.throwsAsync(execa('max-buffer', ['stdout', '11'], {maxBuffer: 10}), /max-buffer stdout/); + const {stdout, all} = await t.throwsAsync(execa('max-buffer', ['stdout', '11'], {maxBuffer: 10, all: true}), /max-buffer stdout/); t.is(stdout, '.'.repeat(10)); t.is(all, '.'.repeat(10)); }); test('maxBuffer affects stderr', async t => { await t.notThrowsAsync(execa('max-buffer', ['stderr', '10'], {maxBuffer: 10})); - const {stderr, all} = await t.throwsAsync(execa('max-buffer', ['stderr', '11'], {maxBuffer: 10}), /max-buffer stderr/); + const {stderr, all} = await t.throwsAsync(execa('max-buffer', ['stderr', '11'], {maxBuffer: 10, all: true}), /max-buffer stderr/); t.is(stderr, '.'.repeat(10)); t.is(all, '.'.repeat(10)); }); @@ -114,8 +114,7 @@ test('do not buffer stdout when `buffer` set to `false`', async t => { const promise = execa('max-buffer', ['stdout', '10'], {buffer: false}); const [result, stdout] = await Promise.all([ promise, - getStream(promise.stdout), - getStream(promise.all) + getStream(promise.stdout) ]); t.is(result.stdout, undefined); @@ -126,8 +125,7 @@ test('do not buffer stderr when `buffer` set to `false`', async t => { const promise = execa('max-buffer', ['stderr', '10'], {buffer: false}); const [result, stderr] = await Promise.all([ promise, - getStream(promise.stderr), - getStream(promise.all) + getStream(promise.stderr) ]); t.is(result.stderr, undefined); @@ -139,3 +137,39 @@ test('do not buffer when streaming', async t => { const result = await getStream(stdout); t.is(result, '....................\n'); }); + +test('buffer: false > promise resolves', async t => { + await t.notThrowsAsync(execa('echo', ['hello'], {buffer: false})); +}); + +test('buffer: false > promise does not resolve when output is big and is not read', async t => { + const {timedOut} = await t.throwsAsync(execa('max-buffer', ['stdout', '3000000'], {buffer: false, timeout: 1e3})); + t.true(timedOut); +}); + +test('buffer: false > promise resolves when output is big and is read', async t => { + const cp = execa('max-buffer', ['stdout', '3000000'], {buffer: false}); + cp.stdout.resume(); + cp.stderr.resume(); + await t.notThrowsAsync(cp); +}); + +test('buffer: false > promise does not resolve when output is big and "all" is used but not read', async t => { + const cp = execa('max-buffer', ['stdout', '3000000'], {buffer: false, all: true, timeout: 1e3}); + cp.stdout.resume(); + cp.stderr.resume(); + const {timedOut} = await t.throwsAsync(cp); + t.true(timedOut); +}); + +test('buffer: false > promise resolves when output is big and "all" is used and is read', async t => { + const cp = execa('max-buffer', ['stdout', '3000000'], {buffer: false, all: true}); + cp.stdout.resume(); + cp.stderr.resume(); + cp.all.resume(); + await t.notThrowsAsync(cp); +}); + +test('buffer: false > promise resolves when output is big but is not pipable', async t => { + await t.notThrowsAsync(execa('max-buffer', ['stdout', '3000000'], {buffer: false, stdout: 'ignore'})); +}); From 7d637153e7be14f999f07c4422346f65e6f71fac Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 02/19] Add documentation and tests --- index.d.ts | 26 +++++++++++++++++++++----- index.test-d.ts | 5 +++-- readme.md | 19 ++++++++++++++++--- test/stream.js | 9 +++++++-- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/index.d.ts b/index.d.ts index 210299a245..cce0ad9788 100644 --- a/index.d.ts +++ b/index.d.ts @@ -75,6 +75,12 @@ declare namespace execa { */ readonly reject?: boolean; + /** + Add `all` properties on the promise and the resolved value containing the output of the process on both `stdout` and `stderr`. + @default false + */ + readonly all?: boolean; + /** Strip the final [newline character](https://en.wikipedia.org/wiki/Newline) from the output. @@ -264,9 +270,13 @@ declare namespace execa { interface ExecaReturnValue extends ExecaSyncReturnValue { /** - The output of the process with `stdout` and `stderr` interleaved. + The output of the process on both stdout and stderr. + + This is `undefined`: + - unless the `all` option is `true`. + - if `execa.sync()` was used. */ - all: StdoutErrorType; + all?: StdoutErrorType; /** Whether the process was canceled. @@ -286,9 +296,13 @@ declare namespace execa { interface ExecaError extends ExecaSyncError { /** - The output of the process with `stdout` and `stderr` interleaved. + The output of the process on both stdout and stderr. + + This is `undefined`: + - unless the `all` option is `true`. + - if `execa.sync()` was used. */ - all: StdoutErrorType; + all?: StdoutErrorType; /** Whether the process was canceled. @@ -325,7 +339,9 @@ declare namespace execa { /** 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). - This is `undefined` when both `stdout` and `stderr` options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). + This is `undefined`: + - unless the `all` option is `true` + - when both `stdout` and `stderr` options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). */ all?: ReadableStream; } diff --git a/index.test-d.ts b/index.test-d.ts index 0b3347c7c9..f1261b34da 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -20,7 +20,7 @@ try { expectType(unicornsResult.exitCodeName); expectType(unicornsResult.stdout); expectType(unicornsResult.stderr); - expectType(unicornsResult.all); + expectType(unicornsResult.all); expectType(unicornsResult.failed); expectType(unicornsResult.timedOut); expectType(unicornsResult.isCanceled); @@ -34,7 +34,7 @@ try { expectType(execaError.exitCodeName); expectType(execaError.stdout); expectType(execaError.stderr); - expectType(execaError.all); + expectType(execaError.all); expectType(execaError.failed); expectType(execaError.timedOut); expectType(execaError.isCanceled); @@ -99,6 +99,7 @@ execa('unicorns', {stderr: 'inherit'}); execa('unicorns', {stderr: process.stderr}); execa('unicorns', {stderr: 1}); execa('unicorns', {stderr: undefined}); +execa('unicorns', {all: true}); execa('unicorns', {reject: false}); execa('unicorns', {stripFinalNewline: false}); execa('unicorns', {extendEnv: false}); diff --git a/readme.md b/readme.md index b5633f2af2..27563ffc3f 100644 --- a/readme.md +++ b/readme.md @@ -168,7 +168,9 @@ Type: `ReadableStream | undefined` 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). -This is `undefined` when both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). +This is `undefined`: + - unless the [`all` option](#all-2) is `true` + - when both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). ### execa.sync(file, [arguments], [options]) @@ -237,9 +239,13 @@ The output of the process on stderr. #### all -Type: `string | Buffer` +Type: `string | Buffer | undefined` + +The output of the process on both stdout and stderr. -The output of the process on both stdout and stderr. `undefined` if `execa.sync()` was used. +This is `undefined`: + - unless the [`all` option](#all-2) is `true`. + - if `execa.sync()` was used. #### failed @@ -336,6 +342,13 @@ Default: `pipe` Same options as [`stdio`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). +#### all + +Type: `boolean`
+Default: `false` + +Add `all` properties on the [promise](#all) and the [resolved value](#all-1) containing the output of the process on both `stdout` and `stderr`. + #### reject Type: `boolean`
diff --git a/test/stream.js b/test/stream.js index 0dfcbfdb6f..be25d85323 100644 --- a/test/stream.js +++ b/test/stream.js @@ -31,6 +31,11 @@ test.serial('result.all shows both `stdout` and `stderr` intermixed', async t => t.is(all, '132'); }); +test('result.all is undefined unless opts.all is true', async t => { + const {all} = await execa('noop'); + t.is(all, undefined); +}); + test('stdout/stderr/all are undefined if ignored', async t => { const {stdout, stderr, all} = await execa('noop', {stdio: 'ignore'}); t.is(stdout, undefined); @@ -142,7 +147,7 @@ test('buffer: false > promise resolves', async t => { await t.notThrowsAsync(execa('echo', ['hello'], {buffer: false})); }); -test('buffer: false > promise does not resolve when output is big and is not read', async t => { +test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { const {timedOut} = await t.throwsAsync(execa('max-buffer', ['stdout', '3000000'], {buffer: false, timeout: 1e3})); t.true(timedOut); }); @@ -154,7 +159,7 @@ test('buffer: false > promise resolves when output is big and is read', async t await t.notThrowsAsync(cp); }); -test('buffer: false > promise does not resolve when output is big and "all" is used but not read', async t => { +test.serial('buffer: false > promise does not resolve when output is big and "all" is used but not read', async t => { const cp = execa('max-buffer', ['stdout', '3000000'], {buffer: false, all: true, timeout: 1e3}); cp.stdout.resume(); cp.stderr.resume(); From 9ffa1f469ca63c41fcc8d6de2c173afe756f5772 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 03/19] Update documentation --- index.d.ts | 20 ++++++++++---------- readme.md | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/index.d.ts b/index.d.ts index cce0ad9788..da282e7be7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -76,7 +76,7 @@ declare namespace execa { readonly reject?: boolean; /** - Add `all` properties on the promise and the resolved value containing the output of the process on both `stdout` and `stderr`. + Add `all` properties on the promise and the resolved value. Those properties contain the output of the process on both `stdout` and `stderr`. @default false */ readonly all?: boolean; @@ -272,9 +272,9 @@ declare namespace execa { /** The output of the process on both stdout and stderr. - This is `undefined`: - - unless the `all` option is `true`. - - if `execa.sync()` was used. + This is `undefined` if: + - the `all` option is `false` (default value). + - `execa.sync()` was used. */ all?: StdoutErrorType; @@ -298,9 +298,9 @@ declare namespace execa { /** The output of the process on both stdout and stderr. - This is `undefined`: - - unless the `all` option is `true`. - - if `execa.sync()` was used. + This is `undefined` if: + - the `all` option is `false` (default value). + - `execa.sync()` was used. */ all?: StdoutErrorType; @@ -339,9 +339,9 @@ declare namespace execa { /** 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). - This is `undefined`: - - unless the `all` option is `true` - - when both `stdout` and `stderr` options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). + This is `undefined` if: + - the `all` option is `false` (the default value) + - both `stdout` and `stderr` options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). */ all?: ReadableStream; } diff --git a/readme.md b/readme.md index 27563ffc3f..8559ceb7ae 100644 --- a/readme.md +++ b/readme.md @@ -168,9 +168,9 @@ Type: `ReadableStream | undefined` 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). -This is `undefined`: - - unless the [`all` option](#all-2) is `true` - - when both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). +This is `undefined` if: + - the [`all` option](#all-2) is `false` (the default value) + - both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). ### execa.sync(file, [arguments], [options]) @@ -243,9 +243,9 @@ Type: `string | Buffer | undefined` The output of the process on both stdout and stderr. -This is `undefined`: - - unless the [`all` option](#all-2) is `true`. - - if `execa.sync()` was used. +This is `undefined` if: + - the [`all` option](#all-2) is `false` (the default value). + - `execa.sync()` was used. #### failed @@ -347,7 +347,7 @@ Same options as [`stdio`](https://nodejs.org/dist/latest-v6.x/docs/api/child_pro Type: `boolean`
Default: `false` -Add `all` properties on the [promise](#all) and the [resolved value](#all-1) containing the output of the process on both `stdout` and `stderr`. +Add `all` properties on the [promise](#all) and the [resolved value](#all-1). Those properties contain the output of the process on both `stdout` and `stderr`. #### reject From f26b1afbdf84e03496e85b5ad01583b0401a33a0 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 04/19] Update documentation --- index.d.ts | 8 ++++---- readme.md | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/index.d.ts b/index.d.ts index da282e7be7..c410b6c007 100644 --- a/index.d.ts +++ b/index.d.ts @@ -76,7 +76,7 @@ declare namespace execa { readonly reject?: boolean; /** - Add `all` properties on the promise and the resolved value. Those properties contain the output of the process on both `stdout` and `stderr`. + Add `all` properties on the promise and the resolved value. Those properties contain the output of the process with `stdout` and `stderr` interleaved. @default false */ readonly all?: boolean; @@ -270,7 +270,7 @@ declare namespace execa { interface ExecaReturnValue extends ExecaSyncReturnValue { /** - The output of the process on both stdout and stderr. + The output of the process with stdout and stderr interleaved. This is `undefined` if: - the `all` option is `false` (default value). @@ -296,7 +296,7 @@ declare namespace execa { interface ExecaError extends ExecaSyncError { /** - The output of the process on both stdout and stderr. + The output of the process with stdout and stderr interleaved. This is `undefined` if: - the `all` option is `false` (default value). @@ -341,7 +341,7 @@ declare namespace execa { This is `undefined` if: - the `all` option is `false` (the default value) - - both `stdout` and `stderr` options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). + - both `stdout` and `stderr` options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). */ all?: ReadableStream; } diff --git a/readme.md b/readme.md index 8559ceb7ae..c24e6faf57 100644 --- a/readme.md +++ b/readme.md @@ -170,7 +170,7 @@ Stream combining/interleaving [`stdout`](https://nodejs.org/api/child_process.ht This is `undefined` if: - the [`all` option](#all-2) is `false` (the default value) - - both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'pipe'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). + - both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). ### execa.sync(file, [arguments], [options]) @@ -241,7 +241,7 @@ The output of the process on stderr. Type: `string | Buffer | undefined` -The output of the process on both stdout and stderr. +The output of the process with stdout and stderr interleaved. This is `undefined` if: - the [`all` option](#all-2) is `false` (the default value). @@ -347,7 +347,7 @@ Same options as [`stdio`](https://nodejs.org/dist/latest-v6.x/docs/api/child_pro Type: `boolean`
Default: `false` -Add `all` properties on the [promise](#all) and the [resolved value](#all-1). Those properties contain the output of the process on both `stdout` and `stderr`. +Add `all` properties on the [promise](#all) and the [resolved value](#all-1). Those properties contain the output of the process with `stdout` and `stderr` interleaved. #### reject From 49d18a842b1371e861fdf55879a91204818c66d6 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 05/19] Update documentation --- index.d.ts | 4 ++-- readme.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index c410b6c007..e55ba29053 100644 --- a/index.d.ts +++ b/index.d.ts @@ -270,7 +270,7 @@ declare namespace execa { interface ExecaReturnValue extends ExecaSyncReturnValue { /** - The output of the process with stdout and stderr interleaved. + The output of the process with `stdout` and `stderr` interleaved. This is `undefined` if: - the `all` option is `false` (default value). @@ -296,7 +296,7 @@ declare namespace execa { interface ExecaError extends ExecaSyncError { /** - The output of the process with stdout and stderr interleaved. + The output of the process with `stdout` and `stderr` interleaved. This is `undefined` if: - the `all` option is `false` (default value). diff --git a/readme.md b/readme.md index c24e6faf57..0586e222f0 100644 --- a/readme.md +++ b/readme.md @@ -241,7 +241,7 @@ The output of the process on stderr. Type: `string | Buffer | undefined` -The output of the process with stdout and stderr interleaved. +The output of the process with `stdout` and `stderr` interleaved. This is `undefined` if: - the [`all` option](#all-2) is `false` (the default value). From 03a448666f3f932adad3b52809a517f62191bc53 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 06/19] Update documentation --- index.d.ts | 6 +++--- readme.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index e55ba29053..a83a0a869e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -272,7 +272,7 @@ declare namespace execa { /** The output of the process with `stdout` and `stderr` interleaved. - This is `undefined` if: + This is `undefined` if either: - the `all` option is `false` (default value). - `execa.sync()` was used. */ @@ -298,7 +298,7 @@ declare namespace execa { /** The output of the process with `stdout` and `stderr` interleaved. - This is `undefined` if: + This is `undefined` if either: - the `all` option is `false` (default value). - `execa.sync()` was used. */ @@ -339,7 +339,7 @@ declare namespace execa { /** 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). - This is `undefined` if: + This is `undefined` if either: - the `all` option is `false` (the default value) - both `stdout` and `stderr` options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). */ diff --git a/readme.md b/readme.md index 0586e222f0..dc47020c85 100644 --- a/readme.md +++ b/readme.md @@ -168,7 +168,7 @@ Type: `ReadableStream | undefined` 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). -This is `undefined` if: +This is `undefined` if either: - the [`all` option](#all-2) is `false` (the default value) - both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). @@ -243,7 +243,7 @@ Type: `string | Buffer | undefined` The output of the process with `stdout` and `stderr` interleaved. -This is `undefined` if: +This is `undefined` if either: - the [`all` option](#all-2) is `false` (the default value). - `execa.sync()` was used. From 8c55a421667ad84525ad9ec6b9145f4c32391264 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 07/19] Update documentation --- index.d.ts | 10 +++++----- readme.md | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index a83a0a869e..af01ffae41 100644 --- a/index.d.ts +++ b/index.d.ts @@ -273,8 +273,8 @@ declare namespace execa { The output of the process with `stdout` and `stderr` interleaved. This is `undefined` if either: - - the `all` option is `false` (default value). - - `execa.sync()` was used. + - the `all` option is `false` (default value) + - `execa.sync()` was used */ all?: StdoutErrorType; @@ -299,8 +299,8 @@ declare namespace execa { The output of the process with `stdout` and `stderr` interleaved. This is `undefined` if either: - - the `all` option is `false` (default value). - - `execa.sync()` was used. + - the `all` option is `false` (default value) + - `execa.sync()` was used */ all?: StdoutErrorType; @@ -341,7 +341,7 @@ declare namespace execa { This is `undefined` if either: - the `all` option is `false` (the default value) - - both `stdout` and `stderr` options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). + - both `stdout` and `stderr` options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio) */ all?: ReadableStream; } diff --git a/readme.md b/readme.md index dc47020c85..aaf74778af 100644 --- a/readme.md +++ b/readme.md @@ -170,7 +170,7 @@ Stream combining/interleaving [`stdout`](https://nodejs.org/api/child_process.ht This is `undefined` if either: - the [`all` option](#all-2) is `false` (the default value) - - both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio). + - both [`stdout`](#stdout-1) and [`stderr`](#stderr-1) options are set to [`'inherit'`, `'ipc'`, `Stream` or `integer`](https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_options_stdio) ### execa.sync(file, [arguments], [options]) @@ -244,8 +244,8 @@ Type: `string | Buffer | undefined` The output of the process with `stdout` and `stderr` interleaved. This is `undefined` if either: - - the [`all` option](#all-2) is `false` (the default value). - - `execa.sync()` was used. + - the [`all` option](#all-2) is `false` (the default value) + - `execa.sync()` was used #### failed From ffae31ca73cc59f3e21010d7850645f3c2231711 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 08/19] Refactoring --- lib/stream.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/stream.js b/lib/stream.js index 53d089d2be..2a87068274 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -20,11 +20,7 @@ const handleInput = (spawned, input) => { // `all` interleaves `stdout` and `stderr` const makeAllStream = (spawned, {all}) => { - if (!all) { - return; - } - - if (!spawned.stdout && !spawned.stderr) { + if (!all || (!spawned.stdout && !spawned.stderr)) { return; } From 5c8bf99fb4b65a53df3d50ae6e2097a5e2c6169c Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 09/19] Fix tests --- test/stream.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stream.js b/test/stream.js index be25d85323..6acda35c2d 100644 --- a/test/stream.js +++ b/test/stream.js @@ -37,14 +37,14 @@ test('result.all is undefined unless opts.all is true', async t => { }); test('stdout/stderr/all are undefined if ignored', async t => { - const {stdout, stderr, all} = await execa('noop', {stdio: 'ignore'}); + const {stdout, stderr, all} = await execa('noop', {stdio: 'ignore', all: true}); t.is(stdout, undefined); t.is(stderr, undefined); t.is(all, undefined); }); test('stdout/stderr/all are undefined if ignored in sync mode', t => { - const {stdout, stderr, all} = execa.sync('noop', {stdio: 'ignore'}); + const {stdout, stderr, all} = execa.sync('noop', {stdio: 'ignore', all: true}); t.is(stdout, undefined); t.is(stderr, undefined); t.is(all, undefined); From 2e02fa18f1be055c245ab1793f29282dc58cf792 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 10/19] Fix test --- test/stream.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stream.js b/test/stream.js index 6acda35c2d..4ce078fabe 100644 --- a/test/stream.js +++ b/test/stream.js @@ -144,7 +144,7 @@ test('do not buffer when streaming', async t => { }); test('buffer: false > promise resolves', async t => { - await t.notThrowsAsync(execa('echo', ['hello'], {buffer: false})); + await t.notThrowsAsync(execa('noop', {buffer: false})); }); test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { From d54279b8366c781365e60a550fba2bfedef78991 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 11/19] Simplify tests --- test/fixtures/max-buffer | 4 ++-- test/stream.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/fixtures/max-buffer b/test/fixtures/max-buffer index 7385a83083..d1cfea941c 100755 --- a/test/fixtures/max-buffer +++ b/test/fixtures/max-buffer @@ -1,6 +1,6 @@ #!/usr/bin/env node 'use strict'; -const output = process.argv[2]; -const bytes = Number(process.argv[3]); +const output = process.argv[2] || 'stdout'; +const bytes = Number(process.argv[3] || 1e7); process[output].write('.'.repeat(bytes - 1) + '\n'); diff --git a/test/stream.js b/test/stream.js index 4ce078fabe..a610b24ab5 100644 --- a/test/stream.js +++ b/test/stream.js @@ -148,19 +148,19 @@ test('buffer: false > promise resolves', async t => { }); test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { - const {timedOut} = await t.throwsAsync(execa('max-buffer', ['stdout', '3000000'], {buffer: false, timeout: 1e3})); + const {timedOut} = await t.throwsAsync(execa('max-buffer', {buffer: false, timeout: 1e3})); t.true(timedOut); }); test('buffer: false > promise resolves when output is big and is read', async t => { - const cp = execa('max-buffer', ['stdout', '3000000'], {buffer: false}); + const cp = execa('max-buffer', {buffer: false}); cp.stdout.resume(); cp.stderr.resume(); await t.notThrowsAsync(cp); }); test.serial('buffer: false > promise does not resolve when output is big and "all" is used but not read', async t => { - const cp = execa('max-buffer', ['stdout', '3000000'], {buffer: false, all: true, timeout: 1e3}); + const cp = execa('max-buffer', {buffer: false, all: true, timeout: 1e3}); cp.stdout.resume(); cp.stderr.resume(); const {timedOut} = await t.throwsAsync(cp); @@ -168,7 +168,7 @@ test.serial('buffer: false > promise does not resolve when output is big and "al }); test('buffer: false > promise resolves when output is big and "all" is used and is read', async t => { - const cp = execa('max-buffer', ['stdout', '3000000'], {buffer: false, all: true}); + const cp = execa('max-buffer', {buffer: false, all: true}); cp.stdout.resume(); cp.stderr.resume(); cp.all.resume(); @@ -176,5 +176,5 @@ test('buffer: false > promise resolves when output is big and "all" is used and }); test('buffer: false > promise resolves when output is big but is not pipable', async t => { - await t.notThrowsAsync(execa('max-buffer', ['stdout', '3000000'], {buffer: false, stdout: 'ignore'})); + await t.notThrowsAsync(execa('max-buffer', {buffer: false, stdout: 'ignore'})); }); From eede7661722e1ba79f7674957a4ee5a6df7a2de6 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 12/19] Refactor constant --- test/stream.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/stream.js b/test/stream.js index a610b24ab5..09c3559f60 100644 --- a/test/stream.js +++ b/test/stream.js @@ -147,8 +147,10 @@ test('buffer: false > promise resolves', async t => { await t.notThrowsAsync(execa('noop', {buffer: false})); }); +const BUFFER_TIMEOUT = 1e3; + test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { - const {timedOut} = await t.throwsAsync(execa('max-buffer', {buffer: false, timeout: 1e3})); + const {timedOut} = await t.throwsAsync(execa('max-buffer', {buffer: false, timeout: BUFFER_TIMEOUT})); t.true(timedOut); }); @@ -160,7 +162,7 @@ test('buffer: false > promise resolves when output is big and is read', async t }); test.serial('buffer: false > promise does not resolve when output is big and "all" is used but not read', async t => { - const cp = execa('max-buffer', {buffer: false, all: true, timeout: 1e3}); + const cp = execa('max-buffer', {buffer: false, all: true, timeout: BUFFER_TIMEOUT}); cp.stdout.resume(); cp.stderr.resume(); const {timedOut} = await t.throwsAsync(cp); From dfb69be4d9ee5ae4fc4f721424c81558a80f8759 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Mon, 15 Jul 2019 10:00:00 +0200 Subject: [PATCH 13/19] Move lines --- test/stream.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/stream.js b/test/stream.js index 09c3559f60..c680978a17 100644 --- a/test/stream.js +++ b/test/stream.js @@ -147,13 +147,6 @@ test('buffer: false > promise resolves', async t => { await t.notThrowsAsync(execa('noop', {buffer: false})); }); -const BUFFER_TIMEOUT = 1e3; - -test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { - const {timedOut} = await t.throwsAsync(execa('max-buffer', {buffer: false, timeout: BUFFER_TIMEOUT})); - t.true(timedOut); -}); - test('buffer: false > promise resolves when output is big and is read', async t => { const cp = execa('max-buffer', {buffer: false}); cp.stdout.resume(); @@ -161,14 +154,6 @@ test('buffer: false > promise resolves when output is big and is read', async t await t.notThrowsAsync(cp); }); -test.serial('buffer: false > promise does not resolve when output is big and "all" is used but not read', async t => { - const cp = execa('max-buffer', {buffer: false, all: true, timeout: BUFFER_TIMEOUT}); - cp.stdout.resume(); - cp.stderr.resume(); - const {timedOut} = await t.throwsAsync(cp); - t.true(timedOut); -}); - test('buffer: false > promise resolves when output is big and "all" is used and is read', async t => { const cp = execa('max-buffer', {buffer: false, all: true}); cp.stdout.resume(); @@ -180,3 +165,18 @@ test('buffer: false > promise resolves when output is big and "all" is used and test('buffer: false > promise resolves when output is big but is not pipable', async t => { await t.notThrowsAsync(execa('max-buffer', {buffer: false, stdout: 'ignore'})); }); + +const BUFFER_TIMEOUT = 1e3; + +test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { + const {timedOut} = await t.throwsAsync(execa('max-buffer', {buffer: false, timeout: BUFFER_TIMEOUT})); + t.true(timedOut); +}); + +test.serial('buffer: false > promise does not resolve when output is big and "all" is used but not read', async t => { + const cp = execa('max-buffer', {buffer: false, all: true, timeout: BUFFER_TIMEOUT}); + cp.stdout.resume(); + cp.stderr.resume(); + const {timedOut} = await t.throwsAsync(cp); + t.true(timedOut); +}); From a869a8ebb23f5b64eb918b8287a446640dd8aef6 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Tue, 16 Jul 2019 10:00:00 +0200 Subject: [PATCH 14/19] Simplify test --- test/stream.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/stream.js b/test/stream.js index c680978a17..2e5b55081d 100644 --- a/test/stream.js +++ b/test/stream.js @@ -156,8 +156,6 @@ test('buffer: false > promise resolves when output is big and is read', async t test('buffer: false > promise resolves when output is big and "all" is used and is read', async t => { const cp = execa('max-buffer', {buffer: false, all: true}); - cp.stdout.resume(); - cp.stderr.resume(); cp.all.resume(); await t.notThrowsAsync(cp); }); From 522a0877150119cb0cdde830090bdbbe795f4b12 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Tue, 16 Jul 2019 10:00:00 +0200 Subject: [PATCH 15/19] Move test --- test/stream.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/stream.js b/test/stream.js index 2e5b55081d..11c66b3ce2 100644 --- a/test/stream.js +++ b/test/stream.js @@ -147,6 +147,10 @@ test('buffer: false > promise resolves', async t => { await t.notThrowsAsync(execa('noop', {buffer: false})); }); +test('buffer: false > promise resolves when output is big but is not pipable', async t => { + await t.notThrowsAsync(execa('max-buffer', {buffer: false, stdout: 'ignore'})); +}); + test('buffer: false > promise resolves when output is big and is read', async t => { const cp = execa('max-buffer', {buffer: false}); cp.stdout.resume(); @@ -160,10 +164,6 @@ test('buffer: false > promise resolves when output is big and "all" is used and await t.notThrowsAsync(cp); }); -test('buffer: false > promise resolves when output is big but is not pipable', async t => { - await t.notThrowsAsync(execa('max-buffer', {buffer: false, stdout: 'ignore'})); -}); - const BUFFER_TIMEOUT = 1e3; test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { From 631b60cb7f1c3f52807a35ec03211ebad1eb6699 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Tue, 16 Jul 2019 10:00:00 +0200 Subject: [PATCH 16/19] Update documentation --- index.d.ts | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index af01ffae41..7895ba3fc5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -39,7 +39,7 @@ declare namespace execa { readonly localDir?: string; /** - Buffer the output from the spawned process. When buffering is disabled you must consume the output of the `stdout` and `stderr` streams because the promise will not be resolved/rejected until they have completed. + Buffer the output from the spawned process. When set to `false`, you must read the output of `stdout` and `stderr` (or `all` if the `all` option is `true`). Otherwise the returned promise will not be resolved/rejected. If the spawned process fails, `error.stdout`, `error.stderr`, and `error.all` will contain the buffered data. diff --git a/readme.md b/readme.md index aaf74778af..8855d92e32 100644 --- a/readme.md +++ b/readme.md @@ -310,7 +310,7 @@ Preferred path to find locally installed binaries in (use with `preferLocal`). Type: `boolean`
Default: `true` -Buffer the output from the spawned process. When buffering is disabled you must consume the output of the `stdout` and `stderr` streams because the promise will not be resolved/rejected until they have completed. +Buffer the output from the spawned process. When set to `false`, you must read the output of [`stdout`](#stdout-1) and [`stderr`](#stderr-1) (or [`all`](#all) if the [`all`](#all-2) option is `true`). Otherwise the returned promise will not be resolved/rejected. If the spawned process fails, [`error.stdout`](#stdout), [`error.stderr`](#stderr), and [`error.all`](#all) will contain the buffered data. From 04a107bcaae5e0e46d185f89e825cce8a7d1aa7e Mon Sep 17 00:00:00 2001 From: tiagonapoli Date: Tue, 16 Jul 2019 12:43:41 -0300 Subject: [PATCH 17/19] Add test --- test/stream.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/stream.js b/test/stream.js index 11c66b3ce2..fc388ad9f0 100644 --- a/test/stream.js +++ b/test/stream.js @@ -164,6 +164,12 @@ test('buffer: false > promise resolves when output is big and "all" is used and await t.notThrowsAsync(cp); }); +test('buffer: false > promise rejects when process returns non-zero', async t => { + const cp = execa('fail', {buffer: false}); + const {exitCode} = await t.throwsAsync(cp); + t.is(exitCode, 2); +}); + const BUFFER_TIMEOUT = 1e3; test.serial('buffer: false > promise does not resolve when output is big and is not read', async t => { From 595c2424bc71b41f7f00e5e9fb244c8b1b68ea43 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 31 Jul 2019 18:21:05 +0200 Subject: [PATCH 18/19] Update index.d.ts --- index.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 7895ba3fc5..54f2a1afdb 100644 --- a/index.d.ts +++ b/index.d.ts @@ -76,7 +76,8 @@ declare namespace execa { readonly reject?: boolean; /** - Add `all` properties on the promise and the resolved value. Those properties contain the output of the process with `stdout` and `stderr` interleaved. + Add an `.all` property on the promise and the resolved value. The property contains the output of the process with `stdout` and `stderr` interleaved. + @default false */ readonly all?: boolean; From 2470f2102ea610dfc6d520f355f04b95922cda3d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 31 Jul 2019 18:22:42 +0200 Subject: [PATCH 19/19] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8855d92e32..fa0e85da5c 100644 --- a/readme.md +++ b/readme.md @@ -347,7 +347,7 @@ Same options as [`stdio`](https://nodejs.org/dist/latest-v6.x/docs/api/child_pro Type: `boolean`
Default: `false` -Add `all` properties on the [promise](#all) and the [resolved value](#all-1). Those properties contain the output of the process with `stdout` and `stderr` interleaved. +Add an `.all` property on the [promise](#all) and the [resolved value](#all-1). The property contains the output of the process with `stdout` and `stderr` interleaved. #### reject