This commit is contained in:
Andrew Kelley 2025-07-22 21:25:50 -07:00
parent 5e6b8e17ef
commit 1d2b870501
5 changed files with 38 additions and 97 deletions

View File

@ -510,13 +510,13 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
var result: ?Path = null;
const stdout_br = zp.poller.reader(.stdout);
const stdout = zp.poller.reader(.stdout);
poll: while (true) {
const Header = std.zig.Server.Message.Header;
while (stdout_br.buffered().len < @sizeOf(Header)) if (!try zp.poller.poll()) break :poll;
const header = (stdout_br.takeStruct(Header) catch unreachable).*;
while (stdout_br.buffered().len < header.bytes_len) if (!try zp.poller.poll()) break :poll;
const body = stdout_br.take(header.bytes_len) catch unreachable;
while (stdout.buffered().len < @sizeOf(Header)) if (!try zp.poller.poll()) break :poll;
const header = (stdout.takeStruct(Header) catch unreachable).*;
while (stdout.buffered().len < header.bytes_len) if (!try zp.poller.poll()) break :poll;
const body = stdout.take(header.bytes_len) catch unreachable;
switch (header.tag) {
.zig_version => {
if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
@ -606,8 +606,8 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
s.result_duration_ns = timer.read();
const stderr_br = zp.poller.reader(.stderr);
const stderr_contents = stderr_br.buffered();
const stderr = zp.poller.reader(.stderr);
const stderr_contents = stderr.buffered();
if (stderr_contents.len > 0) {
try s.result_error_msgs.append(arena, try arena.dupe(u8, stderr_contents));
}
@ -761,8 +761,8 @@ pub fn allocPrintCmd2(
};
var aw: std.io.Writer.Allocating = .init(arena);
const w = &aw.interface;
if (opt_cwd) |cwd| try w.print(arena, "cd {s} && ", .{cwd});
const writer = &aw.writer;
if (opt_cwd) |cwd| try writer.print(arena, "cd {s} && ", .{cwd});
if (opt_env) |env| {
const process_env_map = std.process.getEnvMap(arena) catch std.process.EnvMap.init(arena);
var it = env.iterator();
@ -772,15 +772,15 @@ pub fn allocPrintCmd2(
if (process_env_map.get(key)) |process_value| {
if (std.mem.eql(u8, value, process_value)) continue;
}
try w.print(arena, "{s}=", .{key});
try shell.escape(w, value, false);
try w.writeByte(arena, ' ');
try writer.print(arena, "{s}=", .{key});
try shell.escape(writer, value, false);
try writer.writeByte(arena, ' ');
}
}
try shell.escape(w, argv[0], true);
try shell.escape(writer, argv[0], true);
for (argv[1..]) |arg| {
try w.writeByte(arena, ' ');
try shell.escape(w, arg, false);
try writer.writeByte(arena, ' ');
try shell.escape(writer, arg, false);
}
return aw.getWritten();
}

View File

@ -73,12 +73,12 @@ skip_foreign_checks: bool,
/// external executor (such as qemu) but not fail if the executor is unavailable.
failing_to_execute_foreign_is_an_error: bool,
/// Deprecated for `stdio_limit`.
/// Deprecated in favor of `stdio_limit`.
max_stdio_size: usize,
/// If stderr or stdout exceeds this amount, the child process is killed and
/// the step fails.
stdio_limit: std.io.Limit,
stdio_limit: std.Io.Limit,
captured_stdout: ?*Output,
captured_stderr: ?*Output,
@ -1015,7 +1015,7 @@ fn populateGeneratedPaths(
}
}
fn formatTerm(term: ?std.process.Child.Term, w: *std.io.Writer) std.io.Writer.Error!void {
fn formatTerm(term: ?std.process.Child.Term, w: *std.Io.Writer) std.Io.Writer.Error!void {
if (term) |t| switch (t) {
.Exited => |code| try w.print("exited with code {d}", .{code}),
.Signal => |sig| try w.print("terminated with signal {d}", .{sig}),
@ -1504,7 +1504,7 @@ fn evalZigTest(
const gpa = run.step.owner.allocator;
const arena = run.step.owner.allocator;
var poller = std.io.poll(gpa, enum { stdout, stderr }, .{
var poller = std.Io.poll(gpa, enum { stdout, stderr }, .{
.stdout = child.stdout.?,
.stderr = child.stderr.?,
});
@ -1540,14 +1540,14 @@ fn evalZigTest(
var sub_prog_node: ?std.Progress.Node = null;
defer if (sub_prog_node) |n| n.end();
const stdout_br = poller.reader(.stdout);
const stderr_br = poller.reader(.stderr);
const stdout = poller.reader(.stdout);
const stderr = poller.reader(.stderr);
const any_write_failed = first_write_failed or poll: while (true) {
const Header = std.zig.Server.Message.Header;
while (stdout_br.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll false;
const header = (stdout_br.takeStruct(Header) catch unreachable).*;
while (stdout_br.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll false;
const body = stdout_br.take(header.bytes_len) catch unreachable;
while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll false;
const header = (stdout.takeStruct(Header, .little) catch unreachable).*;
while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll false;
const body = stdout.take(header.bytes_len) catch unreachable;
switch (header.tag) {
.zig_version => {
if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
@ -1604,8 +1604,8 @@ fn evalZigTest(
if (tr_hdr.flags.fail or tr_hdr.flags.leak or tr_hdr.flags.log_err_count > 0) {
const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0);
const stderr_contents = stderr_br.buffered();
stderr_br.toss(stderr_contents.len);
const stderr_contents = stderr.buffered();
stderr.toss(stderr_contents.len);
const msg = std.mem.trim(u8, stderr_contents, "\n");
const label = if (tr_hdr.flags.fail)
"failed"
@ -1665,7 +1665,7 @@ fn evalZigTest(
while (try poller.poll()) {}
}
const stderr_contents = std.mem.trim(u8, stderr_br.buffered(), "\n");
const stderr_contents = std.mem.trim(u8, stderr.buffered(), "\n");
if (stderr_contents.len > 0) {
run.step.result_stderr = try arena.dupe(u8, stderr_contents);
}
@ -1793,7 +1793,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {
run.stdio_limit = run.stdio_limit.min(.limited(run.max_stdio_size));
if (child.stdout) |stdout| {
if (child.stderr) |stderr| {
var poller = std.io.poll(arena, enum { stdout, stderr }, .{
var poller = std.Io.poll(arena, enum { stdout, stderr }, .{
.stdout = stdout,
.stderr = stderr,
});

View File

@ -82,9 +82,6 @@ pub const Limit = enum(usize) {
pub const Reader = @import("Io/Reader.zig");
pub const Writer = @import("Io/Writer.zig");
pub const ChangeDetectionStream = @import("Io/change_detection_stream.zig").ChangeDetectionStream;
pub const changeDetectionStream = @import("Io/change_detection_stream.zig").changeDetectionStream;
pub const tty = @import("Io/tty.zig");
pub fn poll(

View File

@ -1,55 +0,0 @@
const std = @import("../std.zig");
const io = std.io;
const mem = std.mem;
const assert = std.debug.assert;
/// Used to detect if the data written to a stream differs from a source buffer
pub fn ChangeDetectionStream(comptime WriterType: type) type {
return struct {
const Self = @This();
pub const Error = WriterType.Error;
pub const Writer = io.GenericWriter(*Self, Error, write);
anything_changed: bool,
underlying_writer: WriterType,
source_index: usize,
source: []const u8,
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
fn write(self: *Self, bytes: []const u8) Error!usize {
if (!self.anything_changed) {
const end = self.source_index + bytes.len;
if (end > self.source.len) {
self.anything_changed = true;
} else {
const src_slice = self.source[self.source_index..end];
self.source_index += bytes.len;
if (!mem.eql(u8, bytes, src_slice)) {
self.anything_changed = true;
}
}
}
return self.underlying_writer.write(bytes);
}
pub fn changeDetected(self: *Self) bool {
return self.anything_changed or (self.source_index != self.source.len);
}
};
}
pub fn changeDetectionStream(
source: []const u8,
underlying_writer: anytype,
) ChangeDetectionStream(@TypeOf(underlying_writer)) {
return ChangeDetectionStream(@TypeOf(underlying_writer)){
.anything_changed = false,
.underlying_writer = underlying_writer,
.source_index = 0,
.source = source,
};
}

View File

@ -348,7 +348,7 @@ pub const RunResult = struct {
stderr: []u8,
};
fn writeBufferedReaderToArrayList(allocator: Allocator, list: *std.ArrayListUnmanaged(u8), r: *std.io.Reader) !void {
fn writeBufferedReaderToArrayList(allocator: Allocator, list: *std.ArrayListUnmanaged(u8), r: *std.Io.Reader) !void {
assert(r.seek == 0);
if (list.capacity == 0) {
list.* = .{
@ -376,16 +376,16 @@ pub fn collectOutput(
assert(child.stdout_behavior == .Pipe);
assert(child.stderr_behavior == .Pipe);
var poller = std.io.poll(allocator, enum { stdout, stderr }, .{
var poller = std.Io.poll(allocator, enum { stdout, stderr }, .{
.stdout = child.stdout.?,
.stderr = child.stderr.?,
});
defer poller.deinit();
while (try poller.poll()) {
if (poller.reader(.stdout).buffered().len > max_output_bytes)
if (poller.reader(.stdout).bufferedLen() > max_output_bytes)
return error.StdoutStreamTooLong;
if (poller.reader(.stderr).buffered().len > max_output_bytes)
if (poller.reader(.stderr).bufferedLen() > max_output_bytes)
return error.StderrStreamTooLong;
}
@ -1002,17 +1002,16 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
}
fn writeIntFd(fd: i32, value: ErrInt) !void {
var fw = std.fs.File.writer(.{ .handle = fd });
var buffer: [8]u8 = undefined;
var bw = fw.interface().buffered(&buffer);
bw.writeInt(u64, value, .little) catch return error.SystemResources;
var fw: std.fs.File.Writer = .initMode(.{ .handle = fd }, &buffer, .streaming);
fw.interface.writeInt(u64, value, .little) catch unreachable;
fw.interface.flush() catch return error.SystemResources;
}
fn readIntFd(fd: i32) !ErrInt {
var fr = std.fs.File.reader(.{ .handle = fd });
var buffer: [8]u8 = undefined;
var br = fr.interface().buffered(&buffer);
return @intCast(br.takeInt(u64, .little) catch return error.SystemResources);
var fr: std.fs.File.Reader = .initMode(.{ .handle = fd }, &buffer, .streaming);
return @intCast(fr.interface.takeInt(u64, .little) catch return error.SystemResources);
}
const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);