Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d66d4fc

Browse filesBrowse files
giltayaraddaleax
authored andcommitted
child_process: promisify includes stdio in error
This converts the initial implementation of a promised exec that used the customPromisifyArgs support in util.promisify with a custom implementation. This is because exec and execFile, when there is an error, still supply the stdout and stderr of the process, and yet the promisified version with customPromisifyArgs does not supply this ability. I created a custom implementation and attached it to exec and execFile using the util.promisify.custom key. Fixes: #13364 PR-URL: #13388 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent bf06534 commit d66d4fc
Copy full SHA for d66d4fc

File tree

Expand file treeCollapse file tree

3 files changed

+52
-9
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+52
-9
lines changed
Open diff view settings
Collapse file

‎doc/api/child_process.md‎

Copy file name to clipboardExpand all lines: doc/api/child_process.md
+6-2Lines changed: 6 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,9 @@ child runs longer than `timeout` milliseconds.
215215
replace the existing process and uses a shell to execute the command.
216216

217217
If this method is invoked as its [`util.promisify()`][]ed version, it returns
218-
a Promise for an object with `stdout` and `stderr` properties.
218+
a Promise for an object with `stdout` and `stderr` properties. In case of an
219+
error, a rejected promise is returned, with the same `error` object given in the
220+
callback, but with an additional two properties `stdout` and `stderr`.
219221

220222
For example:
221223

@@ -281,7 +283,9 @@ stderr output. If `encoding` is `'buffer'`, or an unrecognized character
281283
encoding, `Buffer` objects will be passed to the callback instead.
282284

283285
If this method is invoked as its [`util.promisify()`][]ed version, it returns
284-
a Promise for an object with `stdout` and `stderr` properties.
286+
a Promise for an object with `stdout` and `stderr` properties. In case of an
287+
error, a rejected promise is returned, with the same `error` object given in the
288+
callback, but with an additional two properties `stdout` and `stderr`.
285289

286290
```js
287291
const util = require('util');
Collapse file

‎lib/child_process.js‎

Copy file name to clipboardExpand all lines: lib/child_process.js
+27-7Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
'use strict';
2323

2424
const util = require('util');
25-
const {
26-
deprecate, convertToValidSignal, customPromisifyArgs
27-
} = require('internal/util');
25+
const { deprecate, convertToValidSignal } = require('internal/util');
26+
const { createPromise,
27+
promiseResolve, promiseReject } = process.binding('util');
2828
const debug = util.debuglog('child_process');
2929

3030
const uv = process.binding('uv');
@@ -140,9 +140,27 @@ exports.exec = function(command /*, options, callback*/) {
140140
opts.callback);
141141
};
142142

143-
Object.defineProperty(exports.exec, customPromisifyArgs,
144-
{ value: ['stdout', 'stderr'], enumerable: false });
143+
const customPromiseExecFunction = (orig) => {
144+
return (...args) => {
145+
const promise = createPromise();
145146

147+
orig(...args, (err, stdout, stderr) => {
148+
if (err !== null) {
149+
err.stdout = stdout;
150+
err.stderr = stderr;
151+
promiseReject(promise, err);
152+
} else {
153+
promiseResolve(promise, { stdout, stderr });
154+
}
155+
});
156+
return promise;
157+
};
158+
};
159+
160+
Object.defineProperty(exports.exec, util.promisify.custom, {
161+
enumerable: false,
162+
value: customPromiseExecFunction(exports.exec)
163+
});
146164

147165
exports.execFile = function(file /*, args, options, callback*/) {
148166
var args = [];
@@ -338,8 +356,10 @@ exports.execFile = function(file /*, args, options, callback*/) {
338356
return child;
339357
};
340358

341-
Object.defineProperty(exports.execFile, customPromisifyArgs,
342-
{ value: ['stdout', 'stderr'], enumerable: false });
359+
Object.defineProperty(exports.execFile, util.promisify.custom, {
360+
enumerable: false,
361+
value: customPromiseExecFunction(exports.execFile)
362+
});
343363

344364
const _deprecatedCustomFds = deprecate(
345365
function deprecateCustomFds(options) {
Collapse file

‎test/parallel/test-child-process-promisified.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-child-process-promisified.js
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,22 @@ const execFile = promisify(child_process.execFile);
3232
assert(err.message.includes('doesntexist'));
3333
}));
3434
}
35+
const failingCodeWithStdoutErr =
36+
'console.log(42);console.error(43);process.exit(1)';
37+
{
38+
exec(`${process.execPath} -e "${failingCodeWithStdoutErr}"`)
39+
.catch(common.mustCall((err) => {
40+
assert.strictEqual(err.code, 1);
41+
assert.strictEqual(err.stdout, '42\n');
42+
assert.strictEqual(err.stderr, '43\n');
43+
}));
44+
}
45+
46+
{
47+
execFile(process.execPath, ['-e', failingCodeWithStdoutErr])
48+
.catch(common.mustCall((err) => {
49+
assert.strictEqual(err.code, 1);
50+
assert.strictEqual(err.stdout, '42\n');
51+
assert.strictEqual(err.stderr, '43\n');
52+
}));
53+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.