| ... | @@ -453,16 +453,16 @@ pub fn spawnPath(io: Io, dir: Io.Dir, options: SpawnOptions) SpawnError!Child { | ... | @@ -453,16 +453,16 @@ pub fn spawnPath(io: Io, dir: Io.Dir, options: SpawnOptions) SpawnError!Child { |
| 453 | return io.vtable.processSpawnPath(io.userdata, dir, options); | 453 | return io.vtable.processSpawnPath(io.userdata, dir, options); |
| 454 | } | 454 | } |
| 455 | | 455 | |
| 456 | pub const RunError = SpawnError || Child.CollectOutputError; | 456 | pub const RunError = SpawnError || error{ |
| | 457 | StreamTooLong, |
| | 458 | } || Io.ConcurrentError || Allocator.Error || Io.File.Reader.Error || Io.Timeout.Error; |
| 457 | | 459 | |
| 458 | pub const RunOptions = struct { | 460 | pub const RunOptions = struct { |
| 459 | argv: []const []const u8, | 461 | argv: []const []const u8, |
| 460 | stderr_limit: Io.Limit = .unlimited, | 462 | stderr_limit: Io.Limit = .unlimited, |
| 461 | stdout_limit: Io.Limit = .unlimited, | 463 | stdout_limit: Io.Limit = .unlimited, |
| 462 | /// How many bytes to initially allocate for stderr. | 464 | /// How many bytes to initially allocate for stderr and stdout. |
| 463 | stderr_reserve_amount: usize = 1, | 465 | reserve_amount: usize = 64, |
| 464 | /// How many bytes to initially allocate for stdout. | | |
| 465 | stdout_reserve_amount: usize = 1, | | |
| 466 | | 466 | |
| 467 | /// Set to change the current working directory when spawning the child process. | 467 | /// Set to change the current working directory when spawning the child process. |
| 468 | cwd: ?[]const u8 = null, | 468 | cwd: ?[]const u8 = null, |
| ... | @@ -516,29 +516,36 @@ pub fn run(gpa: Allocator, io: Io, options: RunOptions) RunError!RunResult { | ... | @@ -516,29 +516,36 @@ pub fn run(gpa: Allocator, io: Io, options: RunOptions) RunError!RunResult { |
| 516 | }); | 516 | }); |
| 517 | defer child.kill(io); | 517 | defer child.kill(io); |
| 518 | | 518 | |
| 519 | var stdout: std.ArrayList(u8) = .empty; | 519 | var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; |
| 520 | defer stdout.deinit(gpa); | 520 | var multi_reader: Io.File.MultiReader = undefined; |
| 521 | var stderr: std.ArrayList(u8) = .empty; | 521 | multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); |
| 522 | defer stderr.deinit(gpa); | 522 | defer multi_reader.deinit(); |
| 523 | | 523 | |
| 524 | try stdout.ensureUnusedCapacity(gpa, options.stdout_reserve_amount); | 524 | const stdout_reader = multi_reader.reader(0); |
| 525 | try stderr.ensureUnusedCapacity(gpa, options.stderr_reserve_amount); | 525 | const stderr_reader = multi_reader.reader(1); |
| 526 | | 526 | |
| 527 | try child.collectOutput(io, .{ | 527 | while (multi_reader.fill(options.reserve_amount, options.timeout)) |_| { |
| 528 | .allocator = gpa, | 528 | if (options.stdout_limit.toInt()) |limit| { |
| 529 | .stdout = &stdout, | 529 | if (stdout_reader.buffered().len > limit) |
| 530 | .stderr = &stderr, | 530 | return error.StreamTooLong; |
| 531 | .stdout_limit = options.stdout_limit, | 531 | } |
| 532 | .stderr_limit = options.stderr_limit, | 532 | if (options.stderr_limit.toInt()) |limit| { |
| 533 | .timeout = options.timeout, | 533 | if (stderr_reader.buffered().len > limit) |
| 534 | }); | 534 | return error.StreamTooLong; |
| | 535 | } |
| | 536 | } else |err| switch (err) { |
| | 537 | error.EndOfStream => {}, |
| | 538 | else => |e| return e, |
| | 539 | } |
| | 540 | |
| | 541 | try multi_reader.checkAnyError(); |
| 535 | | 542 | |
| 536 | const term = try child.wait(io); | 543 | const term = try child.wait(io); |
| 537 | | 544 | |
| 538 | const stdout_slice = try stdout.toOwnedSlice(gpa); | 545 | const stdout_slice = try multi_reader.toOwnedSlice(0); |
| 539 | errdefer gpa.free(stdout_slice); | 546 | errdefer gpa.free(stdout_slice); |
| 540 | | 547 | |
| 541 | const stderr_slice = try stderr.toOwnedSlice(gpa); | 548 | const stderr_slice = try multi_reader.toOwnedSlice(1); |
| 542 | errdefer gpa.free(stderr_slice); | 549 | errdefer gpa.free(stderr_slice); |
| 543 | | 550 | |
| 544 | return .{ | 551 | return .{ |