diff options
| author | 2023-02-22 14:39:40 -0600 | |
|---|---|---|
| committer | 2023-02-22 12:39:40 -0800 | |
| commit | 9be68ac2350b965037f408ce4d47c3b9d9a76b63 (patch) | |
| tree | 6901760d1be141ae97a55910d411fcb4beada773 | |
| parent | ee60a5c55cdafc96268efdebb73aedb3a2ac88fa (diff) | |
| download | bun-9be68ac2350b965037f408ce4d47c3b9d9a76b63.tar.gz bun-9be68ac2350b965037f408ce4d47c3b9d9a76b63.tar.zst bun-9be68ac2350b965037f408ce4d47c3b9d9a76b63.zip | |
fix(child_process): match Node's promisified exec fn (#2128)
| -rw-r--r-- | src/bun.js/child_process.exports.js | 115 | ||||
| -rw-r--r-- | test/bun.js/child_process.test.ts | 12 |
2 files changed, 84 insertions, 43 deletions
diff --git a/src/bun.js/child_process.exports.js b/src/bun.js/child_process.exports.js index afb427461..fefacd708 100644 --- a/src/bun.js/child_process.exports.js +++ b/src/bun.js/child_process.exports.js @@ -6,9 +6,47 @@ const { const { constants: { signals }, } = import.meta.require("node:os"); +const { promisify } = import.meta.require("node:util"); const { ArrayBuffer } = import.meta.primordials; +var Uint8Array = globalThis.Uint8Array; +var String = globalThis.String; +var Object = globalThis.Object; +var Buffer = globalThis.Buffer; +var Promise = globalThis.Promise; + +var PromiseAll = Promise.all; + +var ObjectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty; +var ObjectCreate = Object.create; +var ObjectAssign = Object.assign; +var ObjectDefineProperty = Object.defineProperty; +var BufferConcat = Buffer.concat; +var BufferIsEncoding = Buffer.isEncoding; + +var kEmptyObject = ObjectCreate(null); + +var ArrayPrototypePush = Array.prototype.push; +var ArrayPrototypeReduce = Array.prototype.reduce; +var ArrayPrototypeFilter = Array.prototype.filter; +var ArrayPrototypeJoin = Array.prototype.join; +var ArrayPrototypeMap = Array.prototype.map; +var ArrayPrototypeIncludes = Array.prototype.includes; +var ArrayPrototypeSlice = Array.prototype.slice; +var ArrayPrototypeUnshift = Array.prototype.unshift; +var ArrayIsArray = Array.isArray; + +// var ArrayBuffer = ArrayBuffer; +var ArrayBufferIsView = ArrayBuffer.isView; + +var NumberIsInteger = Number.isInteger; +var MathAbs = Math.abs; + +var StringPrototypeToUpperCase = String.prototype.toUpperCase; +var StringPrototypeIncludes = String.prototype.includes; +var Uint8ArrayPrototypeIncludes = Uint8Array.prototype.includes; + const MAX_BUFFER = 1024 * 1024; // General debug vs tracking stdio streams. Useful for stream debugging in particular @@ -34,9 +72,8 @@ if (__TRACK_STDIO__) { // 3. ChildProcess "class" // 4. ChildProcess helpers // 5. Validators -// 6. Primordials -// 7. Random utilities -// 8. Node errors / error polyfills +// 6. Random utilities +// 7. Node errors / error polyfills // TODO: // Port rest of node tests @@ -456,6 +493,35 @@ export function exec(command, options, callback) { return execFile(opts.file, opts.options, opts.callback); } +const customPromiseExecFunction = orig => { + return (...args) => { + let resolve; + let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + + promise.child = orig(...args, (err, stdout, stderr) => { + if (err !== null) { + err.stdout = stdout; + err.stderr = stderr; + reject(err); + } else { + resolve({ stdout, stderr }); + } + }); + + return promise; + }; +}; + +ObjectDefineProperty(exec, promisify.custom, { + __proto__: null, + enumerable: false, + value: customPromiseExecFunction(exec), +}); + /** * Spawns a new process synchronously using the given `file`. * @param {string} file @@ -685,7 +751,7 @@ function normalizeExecFileArgs(file, args, options, callback) { } if (options == null) { - options = {}; + options = kEmptyObject; } if (callback != null) { @@ -1439,49 +1505,12 @@ function getValidatedPath(fileURLOrPath, propName = "path") { return path; } -//------------------------------------------------------------------------------ -// Section 6. Primordials -//------------------------------------------------------------------------------ -var Uint8Array = globalThis.Uint8Array; -var String = globalThis.String; -var Object = globalThis.Object; -var Buffer = globalThis.Buffer; -var Promise = globalThis.Promise; - -var PromiseAll = Promise.all; - -var ObjectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty; -var ObjectCreate = Object.create; -var ObjectAssign = Object.assign; -var BufferConcat = Buffer.concat; -var BufferIsEncoding = Buffer.isEncoding; - -var ArrayPrototypePush = Array.prototype.push; -var ArrayPrototypeReduce = Array.prototype.reduce; -var ArrayPrototypeFilter = Array.prototype.filter; -var ArrayPrototypeJoin = Array.prototype.join; -var ArrayPrototypeMap = Array.prototype.map; -var ArrayPrototypeIncludes = Array.prototype.includes; -var ArrayPrototypeSlice = Array.prototype.slice; -var ArrayPrototypeUnshift = Array.prototype.unshift; -var ArrayIsArray = Array.isArray; - -// var ArrayBuffer = ArrayBuffer; -var ArrayBufferIsView = ArrayBuffer.isView; - -var NumberIsInteger = Number.isInteger; -var MathAbs = Math.abs; - -var StringPrototypeToUpperCase = String.prototype.toUpperCase; -var StringPrototypeIncludes = String.prototype.includes; -var Uint8ArrayPrototypeIncludes = Uint8Array.prototype.includes; - function isUint8Array(value) { return typeof value === "object" && value !== null && value instanceof Uint8Array; } //------------------------------------------------------------------------------ -// Section 7. Random utilities +// Section 6. Random utilities //------------------------------------------------------------------------------ function isURLInstance(fileURLOrPath) { @@ -1494,7 +1523,7 @@ function toPathIfFileURL(fileURLOrPath) { } //------------------------------------------------------------------------------ -// Section 8. Node errors / error polyfills +// Section 7. Node errors / error polyfills //------------------------------------------------------------------------------ var Error = globalThis.Error; var TypeError = globalThis.TypeError; diff --git a/test/bun.js/child_process.test.ts b/test/bun.js/child_process.test.ts index 7c1315baf..7f2c6b383 100644 --- a/test/bun.js/child_process.test.ts +++ b/test/bun.js/child_process.test.ts @@ -2,6 +2,7 @@ import { describe, it as it_, expect as expect_ } from "bun:test"; import { gcTick } from "gc"; import { ChildProcess, spawn, execFile, exec, fork, spawnSync, execFileSync, execSync } from "node:child_process"; import { tmpdir } from "node:os"; +import { promisify } from "node:util"; const expect: typeof expect_ = (actual: unknown) => { gcTick(); @@ -263,6 +264,17 @@ describe("exec()", () => { }); expect(SEMVER_REGEX.test(result.toString().trim())).toBe(true); }); + + it("should return an object w/ stdout and stderr when promisified", async () => { + const result = await promisify(exec)("bun -v"); + expect(typeof result).toBe("object"); + expect(typeof result.stdout).toBe("string"); + expect(typeof result.stderr).toBe("string"); + + const { stdout, stderr } = result; + expect(SEMVER_REGEX.test(stdout.trim())).toBe(true); + expect(stderr.trim()).toBe(""); + }); }); describe("fork()", () => { |
