Refactor shell script parsing and cancellation handling

Co-authored-by: zack <zack@theradisic.com>
This commit is contained in:
Cursor Agent
2025-06-28 01:07:18 +00:00
parent 529fc777f9
commit cc51e9f8e4
7 changed files with 26 additions and 34 deletions

View File

@@ -69,24 +69,25 @@ pub fn setEnv(this: *ParsedShellScript, globalThis: *JSC.JSGlobalObject, callfra
return globalThis.throw("$`...`.env(): expected an object argument", .{});
};
var iter = try JSC.JSObject.DictionaryIterator.init(globalThis, jsenv.asObjectRef() orelse {
const obj_ref = jsenv.asObjectRef() orelse {
return globalThis.throw("$`...`.env(): expected an object argument", .{});
});
};
const obj: *JSC.JSObject = @ptrCast(obj_ref);
var iter = try JSC.JSPropertyIterator(.{ .skip_empty_name = false, .include_value = true }).init(globalThis, obj);
defer iter.deinit();
if (this.export_env == null) {
this.export_env = EnvMap.init(bun.default_allocator);
}
while (iter.next()) |entry| {
var key = try entry.key.toOwnedSlice(globalThis);
const len = @as(u32, @truncate(entry.key.getLength(globalThis)));
while (try iter.next()) |key| {
var value = iter.value;
if (value.isUndefined()) continue;
var val = entry.value;
var val_slice = try val.toOwnedSlice(globalThis);
if (entry.key_allocated) key = try EnvStr.EnvKey.toOwnedSlice(key);
try this.export_env.?.put(key, val_slice);
_ = len; // autofix
const key_str = try key.toOwnedSlice(bun.default_allocator);
const val_slice = try (try value.getZigString(globalThis)).toOwnedSlice(bun.default_allocator);
this.export_env.?.insert(EnvStr.initRefCounted(key_str), EnvStr.initRefCounted(val_slice));
}
return .js_undefined;

View File

@@ -129,7 +129,7 @@ pub const Yield = union(enum) {
}
}
state: switch (current_yield) {
switch (current_yield) {
.pipeline => |x| {
pipeline_stack.append(x) catch bun.outOfMemory();
current_yield = x.next();

View File

@@ -178,6 +178,11 @@ pub fn next(this: *Cp) Yield {
return this.bltn().done(0);
}
pub fn cancel(cp: *Cp) void {
// TODO: Add atomic cancellation flag for threaded execution
_ = cp;
}
pub fn deinit(cp: *Cp) void {
assert(cp.state == .done or cp.state == .waiting_write_err);
}

View File

@@ -711,7 +711,7 @@ pub fn cancel(this: *Cmd) Yield {
.none => {},
.subproc => |*subproc| {
// Try to kill the subprocess with SIGTERM
_ = subproc.child.tryKill(std.posix.SIGTERM);
_ = subproc.child.tryKill(@intFromEnum(bun.SignalCode.SIGTERM));
},
.bltn => |*builtin| {
// Call cancel on the builtin
@@ -721,14 +721,10 @@ pub fn cancel(this: *Cmd) Yield {
// Cancel any pending IO chunks
if (this.io.stdout == .fd) {
if (this.io.stdout.fd.writer) |writer| {
writer.cancelChunks(this);
}
this.io.stdout.fd.writer.cancelChunks(this);
}
if (this.io.stderr == .fd) {
if (this.io.stderr.fd.writer) |writer| {
writer.cancelChunks(this);
}
this.io.stderr.fd.writer.cancelChunks(this);
}
return .suspended;

View File

@@ -215,14 +215,10 @@ pub fn cancel(this: *CondExpr) Yield {
// Cancel any IO chunks
if (this.io.stdout == .fd) {
if (this.io.stdout.fd.writer) |writer| {
writer.cancelChunks(this);
}
this.io.stdout.fd.writer.cancelChunks(this);
}
if (this.io.stderr == .fd) {
if (this.io.stderr.fd.writer) |writer| {
writer.cancelChunks(this);
}
this.io.stderr.fd.writer.cancelChunks(this);
}
// Report cancellation to parent

View File

@@ -151,15 +151,13 @@ pub fn cancel(this: *Expansion) Yield {
// If a command substitution is running, cancel the child Script
if (this.child_state == .cmd_subst) {
if (this.child_state.cmd_subst.cmd) |child| {
_ = child.cancel();
}
_ = this.child_state.cmd_subst.cmd.cancel();
}
// Clean up state
if (this.current_out.items.len > 0) {
switch (this.out) {
.array_of_ptr => |buf| {
.array_of_ptr => {
for (this.current_out.items) |item| {
_ = item; // Unused, we're cancelling
}

View File

@@ -175,14 +175,10 @@ pub fn cancel(this: *Subshell) Yield {
// Cancel any IO chunks
if (this.io.stdout == .fd) {
if (this.io.stdout.fd.writer) |writer| {
writer.cancelChunks(this);
}
this.io.stdout.fd.writer.cancelChunks(this);
}
if (this.io.stderr == .fd) {
if (this.io.stderr.fd.writer) |writer| {
writer.cancelChunks(this);
}
this.io.stderr.fd.writer.cancelChunks(this);
}
// Report cancellation to parent