Skip to content

Commit

Permalink
spawnSync shouldn't throw (#15561)
Browse files Browse the repository at this point in the history
Co-authored-by: Meghan Denny <[email protected]>
  • Loading branch information
Jarred-Sumner and nektro authored Dec 4, 2024
1 parent d27594e commit 0d5e4e1
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 18 deletions.
13 changes: 11 additions & 2 deletions src/bun.js/api/bun/subprocess.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1766,13 +1766,13 @@ pub const Subprocess = struct {
if (argv0 == null) {
var path_buf: bun.PathBuffer = undefined;
const resolved = Which.which(&path_buf, PATH, cwd, arg0.slice()) orelse {
return globalThis.throwInvalidArguments("Executable not found in $PATH: \"{s}\"", .{arg0.slice()});
return throwCommandNotFound(globalThis, arg0.slice());
};
argv0 = try allocator.dupeZ(u8, resolved);
} else {
var path_buf: bun.PathBuffer = undefined;
const resolved = Which.which(&path_buf, PATH, cwd, bun.sliceTo(argv0.?, 0)) orelse {
return globalThis.throwInvalidArguments("Executable not found in $PATH: \"{s}\"", .{arg0.slice()});
return throwCommandNotFound(globalThis, arg0.slice());
};
argv0 = try allocator.dupeZ(u8, resolved);
}
Expand Down Expand Up @@ -2314,6 +2314,15 @@ pub const Subprocess = struct {
return sync_value;
}

fn throwCommandNotFound(globalThis: *JSC.JSGlobalObject, command: []const u8) bun.JSError {
const message = bun.String.createFormat("Executable not found in $PATH: \"{s}\"", .{command}) catch bun.outOfMemory();
defer message.deref();
const err = message.toZigString().toErrorInstance(globalThis);
err.putZigString(globalThis, JSC.ZigString.static("code"), JSC.ZigString.init("ENOENT").toJS(globalThis));
err.putZigString(globalThis, JSC.ZigString.static("path"), JSC.ZigString.init(command).toJS(globalThis));
return globalThis.throwValue(err);
}

const node_cluster_binding = @import("./../../node/node_cluster_binding.zig");

pub fn handleIPCMessage(
Expand Down
2 changes: 1 addition & 1 deletion src/bun.js/bindings/bindings.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4197,7 +4197,7 @@ pub const JSValue = enum(i64) {
return cppFn("putRecord", .{ value, global, key, values_array, values_len });
}

fn putZigString(value: JSValue, global: *JSGlobalObject, key: *const ZigString, result: JSC.JSValue) void {
pub fn putZigString(value: JSValue, global: *JSGlobalObject, key: *const ZigString, result: JSC.JSValue) void {
@import("./headers.zig").JSC__JSValue__put(value, global, key, result);
}

Expand Down
44 changes: 29 additions & 15 deletions src/js/node/child_process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -558,20 +558,27 @@ function spawnSync(file, args, options) {
}
}

const {
stdout = null,
stderr = null,
success,
exitCode,
signalCode,
} = Bun.spawnSync({
cmd: options.args,
env: options.env || undefined,
cwd: options.cwd || undefined,
stdio: bunStdio,
windowsVerbatimArguments: options.windowsVerbatimArguments,
windowsHide: options.windowsHide,
});
var error;
try {
var {
stdout = null,
stderr = null,
success,
exitCode,
signalCode,
} = Bun.spawnSync({
cmd: options.args,
env: options.env || undefined,
cwd: options.cwd || undefined,
stdio: bunStdio,
windowsVerbatimArguments: options.windowsVerbatimArguments,
windowsHide: options.windowsHide,
});
} catch (err) {
error = err;
stdout = null;
stderr = null;
}

const result = {
signal: signalCode ?? null,
Expand All @@ -580,6 +587,10 @@ function spawnSync(file, args, options) {
output: [null, stdout, stderr],
};

if (error) {
result.error = error;
}

if (stdout && encoding && encoding !== "buffer") {
result.output[1] = result.output[1]?.toString(encoding);
}
Expand All @@ -591,8 +602,11 @@ function spawnSync(file, args, options) {
result.stdout = result.output[1];
result.stderr = result.output[2];

if (!success) {
if (!success && error == null) {
result.error = new SystemError(result.output[2], options.file, "spawnSync", -1, result.status);
}

if (result.error) {
result.error.spawnargs = ArrayPrototypeSlice.$call(options.args, 1);
}

Expand Down
10 changes: 10 additions & 0 deletions test/js/node/child_process/child_process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,3 +454,13 @@ it.if(!isWindows)("spawnSync correctly reports signal codes", () => {

expect(signal).toBe("SIGTRAP");
});

it("spawnSync(does-not-exist)", () => {
const x = spawnSync("does-not-exist");
expect(x.error?.code).toEqual("ENOENT");
expect(x.error.path).toEqual("does-not-exist");
expect(x.signal).toEqual(null);
expect(x.output).toEqual([null, null, null]);
expect(x.stdout).toEqual(null);
expect(x.stderr).toEqual(null);
});

0 comments on commit 0d5e4e1

Please sign in to comment.