-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
child_process: exec's promisify impl now includes stdout/err in error #13388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
e44a057
e2182e5
6adbd98
e37cb7e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
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
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,9 +22,9 @@ | |
| 'use strict'; | ||
|
|
||
| const util = require('util'); | ||
| const { | ||
| deprecate, convertToValidSignal, customPromisifyArgs | ||
| } = require('internal/util'); | ||
| const { deprecate, convertToValidSignal } = require('internal/util'); | ||
| const { createPromise, | ||
| promiseResolve, promiseReject } = process.binding('util'); | ||
| const debug = util.debuglog('child_process'); | ||
|
|
||
| const uv = process.binding('uv'); | ||
|
|
@@ -140,9 +140,21 @@ exports.exec = function(command /*, options, callback*/) { | |
| opts.callback); | ||
| }; | ||
|
|
||
| Object.defineProperty(exports.exec, customPromisifyArgs, | ||
| { value: ['stdout', 'stderr'], enumerable: false }); | ||
|
|
||
| Object.defineProperty(exports.exec, util.promisify.custom, { | ||
| enumerable: false, value: function(...args) { | ||
| const promise = createPromise(); | ||
| exports.exec.call(this, ...args, (err, stdout, stderr) => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don’t think you need to use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely, that was my first all. And to use an arrow function instead of a regular function (as the property value). But then I looked at OK - I'll refactor the value of the property into an arrow function + call |
||
| if (err !== null) { | ||
| err.stdout = stdout; | ||
| err.stderr = stderr; | ||
| promiseReject(promise, err); | ||
| } else { | ||
| promiseResolve(promise, { stdout, stderr }); | ||
| } | ||
| }); | ||
| return promise; | ||
| } | ||
| }); | ||
|
|
||
| exports.execFile = function(file /*, args, options, callback*/) { | ||
| var args = []; | ||
|
|
@@ -338,8 +350,21 @@ exports.execFile = function(file /*, args, options, callback*/) { | |
| return child; | ||
| }; | ||
|
|
||
| Object.defineProperty(exports.execFile, customPromisifyArgs, | ||
| { value: ['stdout', 'stderr'], enumerable: false }); | ||
| Object.defineProperty(exports.execFile, util.promisify.custom, { | ||
| enumerable: false, value: function(...args) { | ||
| const promise = createPromise(); | ||
| exports.execFile.call(this, ...args, (err, stdout, stderr) => { | ||
| if (err !== null) { | ||
| err.stdout = stdout; | ||
| err.stderr = stderr; | ||
| promiseReject(promise, err); | ||
| } else { | ||
| promiseResolve(promise, { stdout, stderr }); | ||
| } | ||
| }); | ||
| return promise; | ||
| } | ||
| }); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two functions are nearly identical. It should be okay, but it shouldn’t be too hard to merge these, right?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do |
||
|
|
||
| const _deprecatedCustomFds = deprecate( | ||
| function deprecateCustomFds(options) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,3 +32,22 @@ const execFile = promisify(child_process.execFile); | |
| assert(err.message.includes('doesntexist')); | ||
| })); | ||
| } | ||
| const failingCodeWithStdoutErr = | ||
| 'console.log("out");console.error("err");process.exit(1)'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some people have figured out that you can use template literals for getting good multiline JS code. :)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very much not a fan of multiline termplate literals :-(
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer not to - this string goes into the command line, and I have no idea what this will do there, especially not in windows. |
||
| { | ||
| exec(`${process.execPath} -e '${failingCodeWithStdoutErr}'`) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this work on Windows? I think there was some weirdness with single/double quotes. (If you don’t know, that’s okay; CI will tell us.)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "A wise man does not fall into a hole that a smart man can get out of" :-). I'll change it to output numbers and then use double quotes like the other tests. |
||
| .catch(common.mustCall((err) => { | ||
| assert.strictEqual(err.code, 1); | ||
| assert.strictEqual(err.stdout, 'out\n'); | ||
| assert.strictEqual(err.stderr, 'err\n'); | ||
| })); | ||
| } | ||
|
|
||
| { | ||
| execFile(process.execPath, ['-e', failingCodeWithStdoutErr]) | ||
| .catch(common.mustCall((err) => { | ||
| assert.strictEqual(err.code, 1); | ||
| assert.strictEqual(err.stdout, 'out\n'); | ||
| assert.strictEqual(err.stderr, 'err\n'); | ||
| })); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we prefer breaking after the
,, and if you want, you can use thevalue(...args) {shorthand notation