| author | |
| committer | |
| log | 11958a306f30268b17454a25bc365e67aad84efd |
| tree | 014d51a6105cb1577763d4f9075a6f930c69e4c7 |
| parent | 3cb5bbb36d09baf4f08464c1d047607a1f09a967 |
21 files changed, 1324 insertions(+), 171 deletions(-)
build.zig+21| ... | ... | @@ -804,6 +804,27 @@ pub fn build(b: *std.Build) !void { |
| 804 | 804 | .skip_wasm = skip_wasm, |
| 805 | 805 | .max_rss = 4_300_000_000, |
| 806 | 806 | })) |test_libc_nsz_step| test_step.dependOn(test_libc_nsz_step); |
| 807 | ||
| 808 | const runner = b.addExecutable(.{ | |
| 809 | .name = "runner", | |
| 810 | .root_module = b.createModule(.{ | |
| 811 | .root_source_file = b.path("test/src/runner.zig"), | |
| 812 | .target = b.graph.host, | |
| 813 | }), | |
| 814 | }); | |
| 815 | test_step.dependOn(try tests.addNewIncrementalTests(b, runner, .{ | |
| 816 | .test_filters = test_filters, | |
| 817 | .test_target_filters = test_target_filters, | |
| 818 | .skip_non_native = skip_non_native, | |
| 819 | .skip_wasm = skip_wasm, | |
| 820 | .skip_freebsd = skip_freebsd, | |
| 821 | .skip_netbsd = skip_netbsd, | |
| 822 | .skip_openbsd = skip_openbsd, | |
| 823 | .skip_windows = skip_windows, | |
| 824 | .skip_darwin = skip_darwin, | |
| 825 | .skip_linux = skip_linux, | |
| 826 | .skip_llvm = skip_llvm, | |
| 827 | })); | |
| 807 | 828 | } |
| 808 | 829 | |
| 809 | 830 | fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { |
lib/compiler/Maker/Step.zig+4-1| ... | ... | @@ -270,7 +270,10 @@ pub fn make( |
| 270 | 270 | .compile => break :t null, |
| 271 | 271 | .run => { |
| 272 | 272 | const run_flags: Configuration.Step.Run.Flags = @bitCast(flags); |
| 273 | if (run_flags.stdio == .zig_test) break :t null; | |
| 273 | switch (run_flags.stdio) { | |
| 274 | .infer_from_args, .inherit, .check => {}, | |
| 275 | .zig_test, .protocol => break :t null, | |
| 276 | } | |
| 274 | 277 | }, |
| 275 | 278 | else => {}, |
| 276 | 279 | } |
lib/compiler/Maker/Step/Run.zig+504-113| ... | ... | @@ -73,18 +73,24 @@ pub fn make( |
| 73 | 73 | man.hash.add(conf_run.flags.color); |
| 74 | 74 | man.hash.add(conf_run.flags.disable_zig_progress); |
| 75 | 75 | |
| 76 | var any_dep_files = false; | |
| 76 | var any_discovered_inputs = switch (conf_run.flags.stdio) { | |
| 77 | .infer_from_args, .inherit, .check, .zig_test => false, | |
| 78 | .protocol => true, | |
| 79 | }; | |
| 77 | 80 | var any_output_args = false; |
| 78 | 81 | var any_cli_positionals = false; |
| 79 | 82 | |
| 80 | for (conf_run.args.slice) |arg_index| { | |
| 83 | for (switch (conf_run.flags.stdio) { | |
| 84 | .infer_from_args, .inherit, .check, .zig_test => conf_run.args.slice, | |
| 85 | .protocol => conf_run.args.slice[0..1], // arguments communicated over protocol | |
| 86 | }) |arg_index| { | |
| 81 | 87 | const arg = arg_index.get(conf); |
| 82 | 88 | try argv_list.ensureUnusedCapacity(gpa, 1); |
| 83 | 89 | switch (arg.flags.tag) { |
| 84 | 90 | .string => { |
| 85 | const prefix = arg.prefix.value.?.slice(conf); | |
| 86 | argv_list.appendAssumeCapacity(prefix); | |
| 87 | man.hash.addBytesZ(prefix); | |
| 91 | const string = arg.prefix.value.?.slice(conf); | |
| 92 | argv_list.appendAssumeCapacity(string); | |
| 93 | man.hash.addBytesZ(string); | |
| 88 | 94 | }, |
| 89 | 95 | .path_file => { |
| 90 | 96 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| ... | ... | @@ -118,14 +124,14 @@ pub fn make( |
| 118 | 124 | result.writer.writeAll(prefix) catch return error.OutOfMemory; |
| 119 | 125 | |
| 120 | 126 | const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err| |
| 121 | return step.fail(maker, "unable to open input file {f}: {t}", .{ file_path, err }); | |
| 127 | return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err }); | |
| 122 | 128 | defer file.close(io); |
| 123 | 129 | |
| 124 | 130 | var file_reader = file.reader(io, &.{}); |
| 125 | 131 | _ = file_reader.interface.streamRemaining(&result.writer) catch |err| switch (err) { |
| 126 | 132 | error.ReadFailed => switch (file_reader.err.?) { |
| 127 | 133 | error.Canceled => |e| return e, |
| 128 | else => |e| return step.fail(maker, "failed to read from {f}: {t}", .{ file_path, e }), | |
| 134 | else => |e| return step.fail(maker, "failed to read from {qf}: {t}", .{ file_path, e }), | |
| 129 | 135 | }, |
| 130 | 136 | error.WriteFailed => return error.OutOfMemory, |
| 131 | 137 | }; |
| ... | ... | @@ -133,8 +139,8 @@ pub fn make( |
| 133 | 139 | |
| 134 | 140 | argv_list.appendAssumeCapacity(result.written()); |
| 135 | 141 | man.hash.addBytesZ(prefix); |
| 136 | man.hash.addBytesZ(suffix); | |
| 137 | 142 | _ = try man.addInputPath(file_path, .{}); |
| 143 | man.hash.addBytesZ(suffix); | |
| 138 | 144 | }, |
| 139 | 145 | .artifact => { |
| 140 | 146 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| ... | ... | @@ -168,7 +174,7 @@ pub fn make( |
| 168 | 174 | man.hash.addBytesZ(suffix); |
| 169 | 175 | man.hash.add(arg.flags.dep_file); |
| 170 | 176 | |
| 171 | any_dep_files = any_dep_files or arg.flags.dep_file; | |
| 177 | if (arg.flags.dep_file) any_discovered_inputs = true; | |
| 172 | 178 | any_output_args = true; |
| 173 | 179 | |
| 174 | 180 | // Add a placeholder into the argument list because we need the |
| ... | ... | @@ -176,9 +182,10 @@ pub fn make( |
| 176 | 182 | // object directory is computed. |
| 177 | 183 | try output_placeholders.append(gpa, .{ |
| 178 | 184 | .index = @intCast(argv_list.items.len), |
| 185 | .offset = 0, | |
| 179 | 186 | .arg_index = arg_index, |
| 180 | 187 | }); |
| 181 | argv_list.items.len += 1; | |
| 188 | _ = argv_list.addOneAssumeCapacity(); | |
| 182 | 189 | }, |
| 183 | 190 | .passthru => { |
| 184 | 191 | any_cli_positionals = true; |
| ... | ... | @@ -195,14 +202,285 @@ pub fn make( |
| 195 | 202 | } |
| 196 | 203 | } |
| 197 | 204 | |
| 198 | man.hash.add(conf_run.flags.test_runner_mode); | |
| 199 | if (conf_run.flags.test_runner_mode) { | |
| 200 | const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false); | |
| 205 | var owned_dirs: std.bit_set.Dynamic = .{}; | |
| 206 | var inherit_dirs: std.ArrayList(Io.Dir) = .empty; | |
| 207 | var owned_files: std.bit_set.Dynamic = .{}; | |
| 208 | var inherit_files: std.ArrayList(Io.File) = .empty; | |
| 209 | var protocol_args: std.ArrayList(u8) = .empty; | |
| 210 | defer { | |
| 211 | for (inherit_dirs.items, 0..) |inherit_dir, inherit_dir_index| | |
| 212 | if (owned_dirs.isSet(inherit_dir_index)) inherit_dir.close(io); | |
| 213 | for (inherit_files.items, 0..) |inherit_file, inherit_file_index| | |
| 214 | if (owned_files.isSet(inherit_file_index)) inherit_file.close(io); | |
| 215 | owned_dirs.deinit(gpa); | |
| 216 | inherit_dirs.deinit(gpa); | |
| 217 | owned_files.deinit(gpa); | |
| 218 | inherit_files.deinit(gpa); | |
| 219 | protocol_args.deinit(gpa); | |
| 220 | } | |
| 221 | switch (conf_run.flags.stdio) { | |
| 222 | .infer_from_args, .inherit, .check => {}, | |
| 223 | .zig_test => { | |
| 224 | const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false); | |
| 225 | ||
| 226 | try argv_list.ensureUnusedCapacity(gpa, 3); | |
| 227 | argv_list.appendAssumeCapacity(try arena.print("--cache-dir={s}", .{cache_dir_string})); | |
| 228 | argv_list.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{graph.random_seed})); | |
| 229 | argv_list.appendAssumeCapacity("--listen=-"); | |
| 230 | }, | |
| 231 | .protocol => for (conf_run.args.slice[1..]) |arg_index| { | |
| 232 | const arg = arg_index.get(conf); | |
| 233 | switch (arg.flags.tag) { | |
| 234 | .string => { | |
| 235 | const string = arg.prefix.value.?.slice(conf); | |
| 236 | ||
| 237 | man.hash.addBytesZ(string); | |
| 238 | ||
| 239 | try protocol_args.ensureUnusedCapacity(gpa, 1 + string.len + 1); | |
| 240 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string)); | |
| 241 | protocol_args.appendSliceAssumeCapacity(string); | |
| 242 | protocol_args.appendAssumeCapacity(0); | |
| 243 | }, | |
| 244 | .path_file => { | |
| 245 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; | |
| 246 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; | |
| 247 | const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); | |
| 248 | ||
| 249 | try owned_files.resize(gpa, owned_files.bit_length + 1, true); | |
| 250 | try inherit_files.ensureUnusedCapacity(gpa, 1); | |
| 251 | const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err| | |
| 252 | return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err }); | |
| 253 | inherit_files.appendAssumeCapacity(file); | |
| 254 | ||
| 255 | man.hash.addBytesZ(prefix); | |
| 256 | _ = try man.addInputPath(file_path, .{}); | |
| 257 | man.hash.addBytesZ(suffix); | |
| 258 | ||
| 259 | try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 + | |
| 260 | 1 + @sizeOf(Io.File.Handle) + | |
| 261 | 1 + suffix.len + 1); | |
| 262 | if (prefix.len > 0) { | |
| 263 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix)); | |
| 264 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 265 | protocol_args.appendAssumeCapacity(0); | |
| 266 | } | |
| 267 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file)); | |
| 268 | const file_handle: *align(1) Io.File.Handle = | |
| 269 | @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle))); | |
| 270 | file_handle.* = file.handle; | |
| 271 | if (suffix.len > 0) { | |
| 272 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix)); | |
| 273 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 274 | protocol_args.appendAssumeCapacity(0); | |
| 275 | } | |
| 276 | }, | |
| 277 | .path_directory => { | |
| 278 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; | |
| 279 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; | |
| 280 | const dir_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); | |
| 281 | ||
| 282 | const has_sub_path = dir_path.sub_path.len > 0; | |
| 283 | try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, has_sub_path); | |
| 284 | try inherit_dirs.ensureUnusedCapacity(gpa, 1); | |
| 285 | const dir = if (has_sub_path) | |
| 286 | dir_path.root_dir.handle.openDir(io, dir_path.sub_path, .{ | |
| 287 | .iterate = true, | |
| 288 | }) catch |err| return step.fail(maker, "unable to open input dir {qf}: {t}", .{ dir_path, err }) | |
| 289 | else | |
| 290 | dir_path.root_dir.handle; | |
| 291 | inherit_dirs.appendAssumeCapacity(dir); | |
| 292 | ||
| 293 | man.hash.addBytesZ(prefix); | |
| 294 | man.hash.addOptionalBytes(dir_path.root_dir.path); | |
| 295 | man.hash.addBytes(dir_path.sub_path); | |
| 296 | man.hash.addBytesZ(suffix); | |
| 297 | ||
| 298 | try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 + | |
| 299 | 1 + @sizeOf(Io.Dir.Handle) + | |
| 300 | 1 + suffix.len + 1); | |
| 301 | if (prefix.len > 0) { | |
| 302 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix)); | |
| 303 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 304 | protocol_args.appendAssumeCapacity(0); | |
| 305 | } | |
| 306 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_dir)); | |
| 307 | const dir_handle: *align(1) Io.Dir.Handle = | |
| 308 | @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle))); | |
| 309 | dir_handle.* = dir.handle; | |
| 310 | if (suffix.len > 0) { | |
| 311 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix)); | |
| 312 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 313 | protocol_args.appendAssumeCapacity(0); | |
| 314 | } | |
| 315 | }, | |
| 316 | .file_content => { | |
| 317 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; | |
| 318 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; | |
| 319 | const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); | |
| 320 | ||
| 321 | try owned_files.resize(gpa, owned_files.bit_length + 1, true); | |
| 322 | try inherit_files.ensureUnusedCapacity(gpa, 1); | |
| 323 | const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err| | |
| 324 | return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err }); | |
| 325 | inherit_files.appendAssumeCapacity(file); | |
| 326 | ||
| 327 | man.hash.addBytesZ(prefix); | |
| 328 | _ = try man.addInputPath(file_path, .{}); | |
| 329 | man.hash.addBytesZ(suffix); | |
| 330 | ||
| 331 | try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 + | |
| 332 | 1 + @sizeOf(Io.File.Handle) + | |
| 333 | 1 + suffix.len + 1); | |
| 334 | if (prefix.len > 0) { | |
| 335 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix)); | |
| 336 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 337 | protocol_args.appendAssumeCapacity(0); | |
| 338 | } | |
| 339 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file_content)); | |
| 340 | const file_handle: *align(1) Io.File.Handle = | |
| 341 | @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle))); | |
| 342 | file_handle.* = file.handle; | |
| 343 | if (suffix.len > 0) { | |
| 344 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix)); | |
| 345 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 346 | protocol_args.appendAssumeCapacity(0); | |
| 347 | } | |
| 348 | }, | |
| 349 | .artifact => { | |
| 350 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; | |
| 351 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; | |
| 352 | const producer_index = arg.producer.value.?; | |
| 353 | const producer_step = producer_index.ptr(conf); | |
| 354 | const producer = producer_step.extended.get(conf.extra).compile; | |
| 355 | const producer_make_comp_step = maker.stepByIndex(producer_index); | |
| 356 | const producer_make_comp = &producer_make_comp_step.extended.compile; | |
| 357 | ||
| 358 | const file_path = producer_make_comp.installed_path orelse | |
| 359 | maker.generatedPath(producer.generated_bin.value.?); | |
| 360 | ||
| 361 | try owned_files.resize(gpa, owned_files.bit_length + 1, true); | |
| 362 | try inherit_files.ensureUnusedCapacity(gpa, 1); | |
| 363 | const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err| | |
| 364 | return step.fail(maker, "unable to open input artifact {qf}: {t}", .{ file_path, err }); | |
| 365 | inherit_files.appendAssumeCapacity(file); | |
| 366 | ||
| 367 | man.hash.addBytesZ(prefix); | |
| 368 | _ = try man.addInputPath(file_path, .{}); | |
| 369 | man.hash.addBytesZ(suffix); | |
| 370 | ||
| 371 | try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 + | |
| 372 | 1 + @sizeOf(Io.File.Handle) + | |
| 373 | 1 + suffix.len + 1); | |
| 374 | if (prefix.len > 0) { | |
| 375 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix)); | |
| 376 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 377 | protocol_args.appendAssumeCapacity(0); | |
| 378 | } | |
| 379 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file)); | |
| 380 | const file_handle: *align(1) Io.File.Handle = | |
| 381 | @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle))); | |
| 382 | file_handle.* = file.handle; | |
| 383 | if (suffix.len > 0) { | |
| 384 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix)); | |
| 385 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 386 | protocol_args.appendAssumeCapacity(0); | |
| 387 | } | |
| 388 | }, | |
| 389 | .output_file => { | |
| 390 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; | |
| 391 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; | |
| 392 | const basename = arg.basename.value.?.slice(conf); | |
| 393 | ||
| 394 | man.hash.addBytesZ(prefix); | |
| 395 | man.hash.addBytesZ(basename); | |
| 396 | man.hash.addBytesZ(suffix); | |
| 397 | assert(!arg.flags.dep_file); | |
| 398 | ||
| 399 | try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 + | |
| 400 | 1 + @sizeOf(Io.File.Handle) + | |
| 401 | 1 + suffix.len + 1); | |
| 402 | if (prefix.len > 0) { | |
| 403 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix)); | |
| 404 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 405 | protocol_args.appendAssumeCapacity(0); | |
| 406 | } | |
| 407 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_file)); | |
| 408 | ||
| 409 | // Add a placeholder into the argument list because we need the | |
| 410 | // manifest hash to be updated with all arguments before the | |
| 411 | // object directory is computed. | |
| 412 | try owned_files.resize(gpa, owned_files.bit_length + 1, false); | |
| 413 | try inherit_files.ensureUnusedCapacity(gpa, 1); | |
| 414 | try output_placeholders.append(gpa, .{ | |
| 415 | .index = @intCast(inherit_files.items.len), | |
| 416 | .offset = @intCast(protocol_args.items.len), | |
| 417 | .arg_index = arg_index, | |
| 418 | }); | |
| 419 | _ = inherit_files.addOneAssumeCapacity(); | |
| 420 | ||
| 421 | _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)); | |
| 422 | if (suffix.len > 0) { | |
| 423 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix)); | |
| 424 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 425 | protocol_args.appendAssumeCapacity(0); | |
| 426 | } | |
| 427 | }, | |
| 428 | .output_directory => { | |
| 429 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; | |
| 430 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; | |
| 431 | const basename = arg.basename.value.?.slice(conf); | |
| 432 | ||
| 433 | man.hash.addBytesZ(prefix); | |
| 434 | man.hash.addBytesZ(basename); | |
| 435 | man.hash.addBytesZ(suffix); | |
| 436 | assert(!arg.flags.dep_file); | |
| 437 | ||
| 438 | try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 + | |
| 439 | 1 + @sizeOf(Io.Dir.Handle) + | |
| 440 | 1 + suffix.len + 1); | |
| 441 | if (prefix.len > 0) { | |
| 442 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix)); | |
| 443 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 444 | protocol_args.appendAssumeCapacity(0); | |
| 445 | } | |
| 446 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_dir)); | |
| 447 | ||
| 448 | // Add a placeholder into the argument list because we need the | |
| 449 | // manifest hash to be updated with all arguments before the | |
| 450 | // object directory is computed. | |
| 451 | try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, false); | |
| 452 | try inherit_dirs.ensureUnusedCapacity(gpa, 1); | |
| 453 | try output_placeholders.append(gpa, .{ | |
| 454 | .index = @intCast(inherit_dirs.items.len), | |
| 455 | .offset = @intCast(protocol_args.items.len), | |
| 456 | .arg_index = arg_index, | |
| 457 | }); | |
| 458 | _ = inherit_dirs.addOneAssumeCapacity(); | |
| 201 | 459 | |
| 202 | try argv_list.ensureUnusedCapacity(gpa, 3); | |
| 203 | argv_list.appendAssumeCapacity(try arena.print("--cache-dir={s}", .{cache_dir_string})); | |
| 204 | argv_list.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{graph.random_seed})); | |
| 205 | argv_list.appendAssumeCapacity("--listen=-"); | |
| 460 | _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle)); | |
| 461 | if (suffix.len > 0) { | |
| 462 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix)); | |
| 463 | protocol_args.appendSliceAssumeCapacity(prefix); | |
| 464 | protocol_args.appendAssumeCapacity(0); | |
| 465 | } | |
| 466 | }, | |
| 467 | .passthru => if (maker.run_args) |run_args| { | |
| 468 | man.hash.addListOfBytes(run_args); | |
| 469 | ||
| 470 | for (run_args) |run_arg| { | |
| 471 | try protocol_args.ensureUnusedCapacity(gpa, 1 + run_arg.len + 1); | |
| 472 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string)); | |
| 473 | protocol_args.appendSliceAssumeCapacity(run_arg); | |
| 474 | protocol_args.appendAssumeCapacity(0); | |
| 475 | } | |
| 476 | }, | |
| 477 | .enable_darling => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value), | |
| 478 | .enable_qemu => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value), | |
| 479 | .enable_rosetta => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value), | |
| 480 | .enable_wasmtime => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value), | |
| 481 | .enable_wine => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value), | |
| 482 | } | |
| 483 | }, | |
| 206 | 484 | } |
| 207 | 485 | |
| 208 | 486 | switch (conf_run.stdin.u) { |
| ... | ... | @@ -227,7 +505,7 @@ pub fn make( |
| 227 | 505 | } |
| 228 | 506 | |
| 229 | 507 | switch (conf_run.flags.stdio) { |
| 230 | .infer_from_args, .inherit, .zig_test => {}, | |
| 508 | .infer_from_args, .inherit, .zig_test, .protocol => {}, | |
| 231 | 509 | .check => { |
| 232 | 510 | man.hash.addBytes(if (conf_run.expect_stderr_exact.value) |bytes| bytes.slice(conf) else ""); |
| 233 | 511 | man.hash.addBytes(if (conf_run.expect_stdout_exact.value) |bytes| bytes.slice(conf) else ""); |
| ... | ... | @@ -256,7 +534,7 @@ pub fn make( |
| 256 | 534 | conf_run.captured_stdout.value == null and |
| 257 | 535 | conf_run.captured_stderr.value == null, |
| 258 | 536 | .inherit => true, |
| 259 | .check, .zig_test => false, | |
| 537 | .check, .zig_test, .protocol => false, | |
| 260 | 538 | }; |
| 261 | 539 | |
| 262 | 540 | if (!has_side_effects and try step.cacheHitWatched(maker, &man, progress_node)) { |
| ... | ... | @@ -268,13 +546,22 @@ pub fn make( |
| 268 | 546 | return; |
| 269 | 547 | } |
| 270 | 548 | |
| 271 | if (!any_dep_files) { | |
| 549 | if (!any_discovered_inputs) { | |
| 272 | 550 | // We already know the final output paths; use them directly. |
| 273 | 551 | const digest = if (has_side_effects) man.hash.final() else man.missDigestHex(); |
| 274 | 552 | const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest; |
| 275 | 553 | try populateGeneratedStdIo(maker, &conf_run, &digest); |
| 276 | try populateGeneratedPathsCreateDirs(arena, run_index, maker, output_dir_path, output_placeholders.items, argv_list.items); | |
| 277 | try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null); | |
| 554 | try populateGeneratedPathsCreateDirs(arena, run_index, maker, output_dir_path, output_placeholders.items, switch (conf_run.flags.stdio) { | |
| 555 | .infer_from_args, .inherit, .check, .zig_test => .{ .argv = argv_list.items }, | |
| 556 | .protocol => .{ .protocol = .{ | |
| 557 | .owned_dirs = &owned_dirs, | |
| 558 | .inherit_dirs = inherit_dirs.items, | |
| 559 | .owned_files = &owned_files, | |
| 560 | .inherit_files = inherit_files.items, | |
| 561 | .args = protocol_args.items, | |
| 562 | } }, | |
| 563 | }); | |
| 564 | try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, inherit_dirs.items, inherit_files.items, protocol_args.items, has_side_effects, output_dir_path, null); | |
| 278 | 565 | if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man); |
| 279 | 566 | return; |
| 280 | 567 | } |
| ... | ... | @@ -284,8 +571,17 @@ pub fn make( |
| 284 | 571 | io.random(@ptrCast(&rand_int)); |
| 285 | 572 | const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); |
| 286 | 573 | |
| 287 | try populateGeneratedPathsCreateDirs(arena, run_index, maker, tmp_dir_path, output_placeholders.items, argv_list.items); | |
| 288 | try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, tmp_dir_path, null); | |
| 574 | try populateGeneratedPathsCreateDirs(arena, run_index, maker, tmp_dir_path, output_placeholders.items, switch (conf_run.flags.stdio) { | |
| 575 | .infer_from_args, .inherit, .check, .zig_test => .{ .argv = argv_list.items }, | |
| 576 | .protocol => .{ .protocol = .{ | |
| 577 | .owned_dirs = &owned_dirs, | |
| 578 | .inherit_dirs = inherit_dirs.items, | |
| 579 | .owned_files = &owned_files, | |
| 580 | .inherit_files = inherit_files.items, | |
| 581 | .args = protocol_args.items, | |
| 582 | } }, | |
| 583 | }); | |
| 584 | try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, inherit_dirs.items, inherit_files.items, protocol_args.items, has_side_effects, tmp_dir_path, null); | |
| 289 | 585 | |
| 290 | 586 | for (output_placeholders.items) |placeholder| { |
| 291 | 587 | const arg = placeholder.arg_index.get(conf); |
| ... | ... | @@ -296,10 +592,10 @@ pub fn make( |
| 296 | 592 | var diagnostic: Cache.DepTokenizer.Token = undefined; |
| 297 | 593 | man.addInputDepFile(generated_path, &diagnostic) catch |err| switch (err) { |
| 298 | 594 | error.OutOfMemory, error.Canceled => |e| return e, |
| 299 | error.InvalidDepFile => return step.fail(maker, "failed adding dep file {f} to cache: {f}", .{ | |
| 595 | error.InvalidDepFile => return step.fail(maker, "failed adding dep file {qf} to cache: {f}", .{ | |
| 300 | 596 | generated_path, diagnostic, |
| 301 | 597 | }), |
| 302 | else => |e| return step.fail(maker, "failed adding dep file {f} to cache: {t}", .{ | |
| 598 | else => |e| return step.fail(maker, "failed adding dep file {qf} to cache: {t}", .{ | |
| 303 | 599 | generated_path, e, |
| 304 | 600 | }), |
| 305 | 601 | }; |
| ... | ... | @@ -307,13 +603,13 @@ pub fn make( |
| 307 | 603 | var diagnostic: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; |
| 308 | 604 | man.addDiscoveredDepFile(generated_path, &diagnostic) catch |err| switch (err) { |
| 309 | 605 | error.OutOfMemory, error.Canceled => |e| return e, |
| 310 | error.InvalidDepFile => return step.fail(maker, "failed adding dep file {f} to cache: {f}", .{ | |
| 606 | error.InvalidDepFile => return step.fail(maker, "failed adding dep file {qf} to cache: {f}", .{ | |
| 311 | 607 | generated_path, diagnostic.dep_tokenizer, |
| 312 | 608 | }), |
| 313 | error.FileSystemFailure => return step.fail(maker, "failed adding a path from dep file {f} to cache: {f}", .{ | |
| 609 | error.FileSystemFailure => return step.fail(maker, "failed adding a path from dep file {qf} to cache: {f}", .{ | |
| 314 | 610 | generated_path, diagnostic.add_discovered_path, |
| 315 | 611 | }), |
| 316 | else => |e| return step.fail(maker, "failed adding dep file {f} to cache: {t}", .{ | |
| 612 | else => |e| return step.fail(maker, "failed adding dep file {qf} to cache: {t}", .{ | |
| 317 | 613 | generated_path, e, |
| 318 | 614 | }), |
| 319 | 615 | }; |
| ... | ... | @@ -342,7 +638,7 @@ pub fn make( |
| 342 | 638 | ) catch |err| switch (err) { |
| 343 | 639 | error.DirNotEmpty => { |
| 344 | 640 | dst_path.root_dir.handle.deleteTree(io, dst_path.sub_path) catch |del_err| |
| 345 | return step.fail(maker, "failed to remove tree {f}: {t}", .{ dst_path, del_err }); | |
| 641 | return step.fail(maker, "failed to remove tree {qf}: {t}", .{ dst_path, del_err }); | |
| 346 | 642 | |
| 347 | 643 | Dir.rename( |
| 348 | 644 | tmp_path.root_dir.handle, |
| ... | ... | @@ -350,11 +646,11 @@ pub fn make( |
| 350 | 646 | dst_path.root_dir.handle, |
| 351 | 647 | dst_path.sub_path, |
| 352 | 648 | io, |
| 353 | ) catch |retry_err| return step.fail(maker, "failed to rename directory {f} to {f}: {t}", .{ | |
| 649 | ) catch |retry_err| return step.fail(maker, "failed to rename directory {qf} to {qf}: {t}", .{ | |
| 354 | 650 | tmp_path, dst_path, retry_err, |
| 355 | 651 | }); |
| 356 | 652 | }, |
| 357 | else => return step.fail(maker, "failed to rename directory {f} to {f}: {t}", .{ | |
| 653 | else => return step.fail(maker, "failed to rename directory {qf} to {qf}: {t}", .{ | |
| 358 | 654 | tmp_path, dst_path, err, |
| 359 | 655 | }), |
| 360 | 656 | }; |
| ... | ... | @@ -386,19 +682,30 @@ fn thirdPartyToggle( |
| 386 | 682 | enable: ?Configuration.String, |
| 387 | 683 | disable: ?Configuration.String, |
| 388 | 684 | ) void { |
| 389 | if (setting) { | |
| 390 | if (enable) |string| { | |
| 391 | const slice = string.slice(conf); | |
| 392 | if (man_hash) |h| h.addBytesZ(slice); | |
| 393 | argv_list.appendAssumeCapacity(slice); | |
| 394 | } | |
| 395 | } else { | |
| 396 | if (disable) |string| { | |
| 397 | const slice = string.slice(conf); | |
| 398 | if (man_hash) |h| h.addBytesZ(slice); | |
| 399 | argv_list.appendAssumeCapacity(slice); | |
| 400 | } | |
| 401 | } | |
| 685 | const string = (if (setting) enable else disable) orelse return; | |
| 686 | const slice = string.slice(conf); | |
| 687 | if (man_hash) |h| h.addBytesZ(slice); | |
| 688 | argv_list.appendAssumeCapacity(slice); | |
| 689 | } | |
| 690 | ||
| 691 | fn thirdPartyToggleProtocol( | |
| 692 | gpa: Allocator, | |
| 693 | man_hash: *Cache.HashHelper, | |
| 694 | protocol_args: *std.ArrayList(u8), | |
| 695 | conf: *const Configuration, | |
| 696 | setting: bool, | |
| 697 | enable: ?Configuration.String, | |
| 698 | disable: ?Configuration.String, | |
| 699 | ) Allocator.Error!void { | |
| 700 | const string = (if (setting) enable else disable) orelse return; | |
| 701 | const slice = string.slice(conf); | |
| 702 | ||
| 703 | man_hash.addBytesZ(slice); | |
| 704 | ||
| 705 | try protocol_args.ensureUnusedCapacity(gpa, 1 + slice.len + 1); | |
| 706 | protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string)); | |
| 707 | protocol_args.appendSliceAssumeCapacity(slice); | |
| 708 | protocol_args.appendAssumeCapacity(0); | |
| 402 | 709 | } |
| 403 | 710 | |
| 404 | 711 | /// Reads stdout of a Zig test process until a termination condition is reached: |
| ... | ... | @@ -412,6 +719,7 @@ fn waitZigTest( |
| 412 | 719 | maker: *Maker, |
| 413 | 720 | child: *process.Child, |
| 414 | 721 | progress_node: std.Progress.Node, |
| 722 | protocol_args: []const u8, | |
| 415 | 723 | multi_reader: *Io.File.MultiReader, |
| 416 | 724 | opt_metadata: *?TestMetadata, |
| 417 | 725 | results: *Step.TestResults, |
| ... | ... | @@ -444,6 +752,14 @@ fn waitZigTest( |
| 444 | 752 | .out = &stdin_writer.interface, |
| 445 | 753 | }; |
| 446 | 754 | |
| 755 | if (protocol_args.len > 0) { | |
| 756 | try client.serveMessageHeader(.{ | |
| 757 | .tag = .args, | |
| 758 | .bytes_len = @intCast(protocol_args.len), | |
| 759 | }); | |
| 760 | try client.out.writeAll(protocol_args); | |
| 761 | } | |
| 762 | ||
| 447 | 763 | if (opt_metadata.*) |*md| { |
| 448 | 764 | // Previous unit test process died or was killed; we're continuing where it left off |
| 449 | 765 | requestNextTest(&client, md, &sub_prog_node) catch |err| return .{ .write_failed = err }; |
| ... | ... | @@ -492,6 +808,7 @@ fn waitZigTest( |
| 492 | 808 | var body_r: std.Io.Reader = .fixed(body); |
| 493 | 809 | |
| 494 | 810 | switch (header.tag) { |
| 811 | else => {}, // ignore other messages | |
| 495 | 812 | .zig_version => { |
| 496 | 813 | if (!std.mem.eql(u8, builtin.zig_version_string, body)) return step.fail( |
| 497 | 814 | maker, |
| ... | ... | @@ -583,7 +900,6 @@ fn waitZigTest( |
| 583 | 900 | |
| 584 | 901 | requestNextTest(&client, md, &sub_prog_node) catch |err| return .{ .write_failed = err }; |
| 585 | 902 | }, |
| 586 | else => {}, // ignore other messages | |
| 587 | 903 | } |
| 588 | 904 | } |
| 589 | 905 | } |
| ... | ... | @@ -820,6 +1136,7 @@ const FuzzTestRunner = struct { |
| 820 | 1136 | } |
| 821 | 1137 | |
| 822 | 1138 | switch (header.tag) { |
| 1139 | else => {}, // ignore other messages | |
| 823 | 1140 | .zig_version => { |
| 824 | 1141 | if (!std.mem.eql(u8, builtin.zig_version_string, body)) return step.fail( |
| 825 | 1142 | maker, |
| ... | ... | @@ -882,7 +1199,6 @@ const FuzzTestRunner = struct { |
| 882 | 1199 | f.pending_broadcasts.appendSliceAssumeCapacity(@ptrCast(&footer)); |
| 883 | 1200 | } |
| 884 | 1201 | }, |
| 885 | else => {}, // ignore other messages | |
| 886 | 1202 | } |
| 887 | 1203 | |
| 888 | 1204 | instance.message.clearRetainingCapacity(); |
| ... | ... | @@ -1146,6 +1462,7 @@ fn evalZigTest( |
| 1146 | 1462 | maker: *Maker, |
| 1147 | 1463 | progress_node: std.Progress.Node, |
| 1148 | 1464 | spawn_options: process.SpawnOptions, |
| 1465 | protocol_args: []const u8, | |
| 1149 | 1466 | fuzz_context: ?FuzzContext, |
| 1150 | 1467 | ) !void { |
| 1151 | 1468 | if (fuzz_context != null) { |
| ... | ... | @@ -1194,6 +1511,7 @@ fn evalZigTest( |
| 1194 | 1511 | maker, |
| 1195 | 1512 | &child, |
| 1196 | 1513 | progress_node, |
| 1514 | protocol_args, | |
| 1197 | 1515 | &multi_reader, |
| 1198 | 1516 | &test_metadata, |
| 1199 | 1517 | &test_results, |
| ... | ... | @@ -1402,7 +1720,7 @@ fn evalGeneric( |
| 1402 | 1720 | var write_buffer: [1024]u8 = undefined; |
| 1403 | 1721 | var stdin_writer = child.stdin.?.writerStreaming(io, &write_buffer); |
| 1404 | 1722 | _ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) { |
| 1405 | error.ReadFailed => return step.fail(maker, "failed to read from {f}: {t}", .{ | |
| 1723 | error.ReadFailed => return step.fail(maker, "failed to read from {qf}: {t}", .{ | |
| 1406 | 1724 | path, file_reader.err.?, |
| 1407 | 1725 | }), |
| 1408 | 1726 | error.WriteFailed => return step.fail(maker, "failed to write to stdin: {t}", .{ |
| ... | ... | @@ -1490,6 +1808,7 @@ fn evalGeneric( |
| 1490 | 1808 | |
| 1491 | 1809 | const IndexedOutput = struct { |
| 1492 | 1810 | index: u32, |
| 1811 | offset: u32, | |
| 1493 | 1812 | arg_index: Configuration.Step.Run.Arg.Index, |
| 1494 | 1813 | }; |
| 1495 | 1814 | |
| ... | ... | @@ -1516,13 +1835,16 @@ pub fn rerunInFuzzMode( |
| 1516 | 1835 | var argv_list: std.ArrayList([]const u8) = .empty; |
| 1517 | 1836 | defer argv_list.deinit(gpa); |
| 1518 | 1837 | |
| 1519 | for (conf_run.args.slice) |arg_index| { | |
| 1838 | for (switch (conf_run.flags.stdio) { | |
| 1839 | .infer_from_args, .inherit, .check, .zig_test => conf_run.args.slice, | |
| 1840 | .protocol => @panic("protocol fuzz unimplemented"), | |
| 1841 | }) |arg_index| { | |
| 1520 | 1842 | const arg = arg_index.get(conf); |
| 1521 | 1843 | try argv_list.ensureUnusedCapacity(gpa, 1); |
| 1522 | 1844 | switch (arg.flags.tag) { |
| 1523 | 1845 | .string => { |
| 1524 | const prefix = arg.prefix.value.?.slice(conf); | |
| 1525 | argv_list.appendAssumeCapacity(prefix); | |
| 1846 | const string = arg.prefix.value.?.slice(conf); | |
| 1847 | argv_list.appendAssumeCapacity(string); | |
| 1526 | 1848 | }, |
| 1527 | 1849 | .path_file => { |
| 1528 | 1850 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| ... | ... | @@ -1550,14 +1872,14 @@ pub fn rerunInFuzzMode( |
| 1550 | 1872 | result.writer.writeAll(prefix) catch return error.OutOfMemory; |
| 1551 | 1873 | |
| 1552 | 1874 | const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err| |
| 1553 | return step.fail(maker, "unable to open input file {f}: {t}", .{ file_path, err }); | |
| 1875 | return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err }); | |
| 1554 | 1876 | defer file.close(io); |
| 1555 | 1877 | |
| 1556 | 1878 | var file_reader = file.reader(io, &.{}); |
| 1557 | 1879 | _ = file_reader.interface.streamRemaining(&result.writer) catch |err| switch (err) { |
| 1558 | 1880 | error.ReadFailed => switch (file_reader.err.?) { |
| 1559 | 1881 | error.Canceled => |e| return e, |
| 1560 | else => |e| return step.fail(maker, "failed to read from {f}: {t}", .{ file_path, e }), | |
| 1882 | else => |e| return step.fail(maker, "failed to read from {qf}: {t}", .{ file_path, e }), | |
| 1561 | 1883 | }, |
| 1562 | 1884 | error.WriteFailed => return error.OutOfMemory, |
| 1563 | 1885 | }; |
| ... | ... | @@ -1591,14 +1913,17 @@ pub fn rerunInFuzzMode( |
| 1591 | 1913 | .enable_wine => thirdPartyToggle(null, &argv_list, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value), |
| 1592 | 1914 | } |
| 1593 | 1915 | } |
| 1594 | ||
| 1595 | if (conf_run.flags.test_runner_mode) { | |
| 1596 | const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false); | |
| 1597 | ||
| 1598 | try argv_list.ensureUnusedCapacity(gpa, 3); | |
| 1599 | argv_list.appendAssumeCapacity(try arena.print("--cache-dir={s}", .{cache_dir_string})); | |
| 1600 | argv_list.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{graph.random_seed})); | |
| 1601 | argv_list.appendAssumeCapacity("--listen=-"); | |
| 1916 | switch (conf_run.flags.stdio) { | |
| 1917 | .infer_from_args, .inherit, .check => {}, | |
| 1918 | .zig_test => { | |
| 1919 | const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false); | |
| 1920 | ||
| 1921 | try argv_list.ensureUnusedCapacity(gpa, 3); | |
| 1922 | argv_list.appendAssumeCapacity(try arena.print("--cache-dir={s}", .{cache_dir_string})); | |
| 1923 | argv_list.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{graph.random_seed})); | |
| 1924 | argv_list.appendAssumeCapacity("--listen=-"); | |
| 1925 | }, | |
| 1926 | .protocol => unreachable, | |
| 1602 | 1927 | } |
| 1603 | 1928 | |
| 1604 | 1929 | step.clearFailedCommand(gpa); |
| ... | ... | @@ -1607,7 +1932,7 @@ pub fn rerunInFuzzMode( |
| 1607 | 1932 | var rand_int: u64 = undefined; |
| 1608 | 1933 | io.random(@ptrCast(&rand_int)); |
| 1609 | 1934 | const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); |
| 1610 | try runCommand(arena, run, run_index, maker, prog_node, argv_list.items, has_side_effects, tmp_dir_path, .{ | |
| 1935 | try runCommand(arena, run, run_index, maker, prog_node, argv_list.items, &.{}, &.{}, &.{}, has_side_effects, tmp_dir_path, .{ | |
| 1611 | 1936 | .fuzz = fuzz, |
| 1612 | 1937 | }); |
| 1613 | 1938 | } |
| ... | ... | @@ -1633,7 +1958,16 @@ fn populateGeneratedPathsCreateDirs( |
| 1633 | 1958 | maker: *Maker, |
| 1634 | 1959 | output_dir_path: []const u8, |
| 1635 | 1960 | output_placeholders: []const IndexedOutput, |
| 1636 | argv: [][]const u8, | |
| 1961 | populate: union(enum) { | |
| 1962 | argv: [][]const u8, | |
| 1963 | protocol: struct { | |
| 1964 | owned_dirs: *std.bit_set.Dynamic, | |
| 1965 | inherit_dirs: []Io.Dir, | |
| 1966 | owned_files: *std.bit_set.Dynamic, | |
| 1967 | inherit_files: []Io.File, | |
| 1968 | args: []u8, | |
| 1969 | }, | |
| 1970 | }, | |
| 1637 | 1971 | ) !void { |
| 1638 | 1972 | const step = maker.stepByIndex(run_index); |
| 1639 | 1973 | const conf = &maker.scanned_config.configuration; |
| ... | ... | @@ -1653,16 +1987,52 @@ fn populateGeneratedPathsCreateDirs( |
| 1653 | 1987 | const create_path: Path = .{ |
| 1654 | 1988 | .root_dir = cache_root, |
| 1655 | 1989 | .sub_path = switch (arg.flags.tag) { |
| 1990 | else => unreachable, | |
| 1656 | 1991 | .output_file => Dir.path.dirname(generated_path.sub_path).?, |
| 1657 | 1992 | .output_directory => generated_path.sub_path, |
| 1658 | else => unreachable, | |
| 1659 | 1993 | }, |
| 1660 | 1994 | }; |
| 1661 | 1995 | create_path.root_dir.handle.createDirPath(io, create_path.sub_path) catch |err| |
| 1662 | return step.fail(maker, "unable to make path {f}: {t}", .{ create_path, err }); | |
| 1996 | return step.fail(maker, "unable to make path {qf}: {t}", .{ create_path, err }); | |
| 1663 | 1997 | |
| 1664 | const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path, arg.flags.make_absolute); | |
| 1665 | argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix }); | |
| 1998 | switch (populate) { | |
| 1999 | .argv => |argv| { | |
| 2000 | const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path, arg.flags.make_absolute); | |
| 2001 | argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix }); | |
| 2002 | }, | |
| 2003 | .protocol => |protocol| switch (arg.flags.tag) { | |
| 2004 | else => unreachable, | |
| 2005 | .output_file => { | |
| 2006 | const file = generated_path.root_dir.handle.createFile( | |
| 2007 | io, | |
| 2008 | generated_path.sub_path, | |
| 2009 | .{ .read = true }, | |
| 2010 | ) catch |err| return step.fail(maker, "unable to create output file {qf}: {t}", .{ | |
| 2011 | generated_path, err, | |
| 2012 | }); | |
| 2013 | protocol.inherit_files[placeholder.index] = file; | |
| 2014 | protocol.owned_files.set(placeholder.index); | |
| 2015 | const file_handle: *align(1) Io.File.Handle = | |
| 2016 | @ptrCast(protocol.args[placeholder.offset..][0..@sizeOf(Io.File.Handle)]); | |
| 2017 | file_handle.* = file.handle; | |
| 2018 | }, | |
| 2019 | .output_directory => { | |
| 2020 | assert(generated_path.sub_path.len > 0); | |
| 2021 | const dir = generated_path.root_dir.handle.openDir( | |
| 2022 | io, | |
| 2023 | generated_path.sub_path, | |
| 2024 | .{ .iterate = true }, | |
| 2025 | ) catch |err| return step.fail(maker, "unable to open output dir {qf}: {t}", .{ | |
| 2026 | generated_path, err, | |
| 2027 | }); | |
| 2028 | protocol.inherit_dirs[placeholder.index] = dir; | |
| 2029 | protocol.owned_dirs.set(placeholder.index); | |
| 2030 | const dir_handle: *align(1) Io.Dir.Handle = | |
| 2031 | @ptrCast(protocol.args[placeholder.offset..][0..@sizeOf(Io.Dir.Handle)]); | |
| 2032 | dir_handle.* = dir.handle; | |
| 2033 | }, | |
| 2034 | }, | |
| 2035 | } | |
| 1666 | 2036 | } |
| 1667 | 2037 | } |
| 1668 | 2038 | |
| ... | ... | @@ -1711,6 +2081,9 @@ fn runCommand( |
| 1711 | 2081 | maker: *Maker, |
| 1712 | 2082 | progress_node: std.Progress.Node, |
| 1713 | 2083 | argv: []const []const u8, |
| 2084 | inherit_dirs: []const Io.Dir, | |
| 2085 | inherit_files: []const Io.File, | |
| 2086 | protocol_args: []const u8, | |
| 1714 | 2087 | has_side_effects: bool, |
| 1715 | 2088 | output_dir_path: []const u8, |
| 1716 | 2089 | fuzz_context: ?FuzzContext, |
| ... | ... | @@ -1777,10 +2150,14 @@ fn runCommand( |
| 1777 | 2150 | progress_node, |
| 1778 | 2151 | argv, |
| 1779 | 2152 | &environ_map, |
| 2153 | inherit_dirs, | |
| 2154 | inherit_files, | |
| 2155 | protocol_args, | |
| 1780 | 2156 | has_side_effects, |
| 1781 | 2157 | fuzz_context, |
| 1782 | 2158 | ) catch |err| term: { |
| 1783 | 2159 | switch (err) { |
| 2160 | else => {}, | |
| 1784 | 2161 | error.InvalidExe, // cpu arch mismatch |
| 1785 | 2162 | error.FileNotFound, // can happen with a wrong dynamic linker path |
| 1786 | 2163 | => interpret: { |
| ... | ... | @@ -1928,6 +2305,9 @@ fn runCommand( |
| 1928 | 2305 | progress_node, |
| 1929 | 2306 | interp_argv.items, |
| 1930 | 2307 | &environ_map, |
| 2308 | inherit_dirs, | |
| 2309 | inherit_files, | |
| 2310 | protocol_args, | |
| 1931 | 2311 | has_side_effects, |
| 1932 | 2312 | fuzz_context, |
| 1933 | 2313 | ) catch |e| { |
| ... | ... | @@ -1937,21 +2317,21 @@ fn runCommand( |
| 1937 | 2317 | }; |
| 1938 | 2318 | }, |
| 1939 | 2319 | error.MakeFailed, error.OutOfMemory, error.Canceled => |e| return e, |
| 1940 | else => {}, | |
| 1941 | 2320 | } |
| 1942 | 2321 | return step.fail(maker, "failed to spawn and capture stdio from {s}: {t}", .{ argv[0], err }); |
| 1943 | 2322 | }; |
| 1944 | 2323 | |
| 1945 | const generic_result = opt_generic_result orelse { | |
| 1946 | assert(conf_run.flags.stdio == .zig_test); | |
| 1947 | // Specific errors have already been reported, and test results are populated. All we need | |
| 1948 | // to do is report step failure if any test failed. | |
| 1949 | if (!step.test_results.isSuccess()) return error.MakeFailed; | |
| 1950 | return; | |
| 2324 | const generic_result = switch (conf_run.flags.stdio) { | |
| 2325 | .infer_from_args, .inherit, .check => opt_generic_result.?, | |
| 2326 | .zig_test, .protocol => { | |
| 2327 | assert(opt_generic_result == null); | |
| 2328 | // Specific errors have already been reported, and test results are populated. All we need | |
| 2329 | // to do is report step failure if any test failed. | |
| 2330 | if (!step.test_results.isSuccess()) return error.MakeFailed; | |
| 2331 | return; | |
| 2332 | }, | |
| 1951 | 2333 | }; |
| 1952 | ||
| 1953 | 2334 | assert(fuzz_context == null); |
| 1954 | assert(conf_run.flags.stdio != .zig_test); | |
| 1955 | 2335 | |
| 1956 | 2336 | // Capture stdout and stderr to GeneratedFile objects. |
| 1957 | 2337 | const Stream = struct { |
| ... | ... | @@ -1978,7 +2358,7 @@ fn runCommand( |
| 1978 | 2358 | |
| 1979 | 2359 | const sub_path_parent = output_path.dirname().?; |
| 1980 | 2360 | sub_path_parent.root_dir.handle.createDirPath(io, sub_path_parent.sub_path) catch |err| |
| 1981 | return step.fail(maker, "unable to make path {f}: {t}", .{ sub_path_parent, err }); | |
| 2361 | return step.fail(maker, "unable to make path {qf}: {t}", .{ sub_path_parent, err }); | |
| 1982 | 2362 | |
| 1983 | 2363 | const data = switch (stream.trim_whitespace) { |
| 1984 | 2364 | .none => stream.bytes.?, |
| ... | ... | @@ -1989,12 +2369,12 @@ fn runCommand( |
| 1989 | 2369 | output_path.root_dir.handle.writeFile(io, .{ |
| 1990 | 2370 | .sub_path = output_path.sub_path, |
| 1991 | 2371 | .data = data, |
| 1992 | }) catch |err| return step.fail(maker, "unable to write file {f}: {t}", .{ output_path, err }); | |
| 2372 | }) catch |err| return step.fail(maker, "unable to write file {qf}: {t}", .{ output_path, err }); | |
| 1993 | 2373 | } |
| 1994 | 2374 | } |
| 1995 | 2375 | |
| 1996 | 2376 | switch (conf_run.flags.stdio) { |
| 1997 | .zig_test => unreachable, | |
| 2377 | .zig_test, .protocol => unreachable, | |
| 1998 | 2378 | .check => { |
| 1999 | 2379 | if (conf_run.expect_stderr_exact.value) |bytes| { |
| 2000 | 2380 | const expected_bytes = bytes.slice(conf); |
| ... | ... | @@ -2186,6 +2566,9 @@ fn spawnChildAndCollect( |
| 2186 | 2566 | progress_node: std.Progress.Node, |
| 2187 | 2567 | argv: []const []const u8, |
| 2188 | 2568 | environ_map: *EnvMap, |
| 2569 | inherit_dirs: []const Io.Dir, | |
| 2570 | inherit_files: []const Io.File, | |
| 2571 | protocol_args: []const u8, | |
| 2189 | 2572 | has_side_effects: bool, |
| 2190 | 2573 | fuzz_context: ?FuzzContext, |
| 2191 | 2574 | ) !?EvalGenericResult { |
| ... | ... | @@ -2199,7 +2582,10 @@ fn spawnChildAndCollect( |
| 2199 | 2582 | |
| 2200 | 2583 | if (fuzz_context != null) { |
| 2201 | 2584 | assert(!has_side_effects); |
| 2202 | assert(conf_run.flags.stdio == .zig_test); | |
| 2585 | switch (conf_run.flags.stdio) { | |
| 2586 | .infer_from_args, .inherit, .check => unreachable, | |
| 2587 | .zig_test, .protocol => {}, | |
| 2588 | } | |
| 2203 | 2589 | } |
| 2204 | 2590 | |
| 2205 | 2591 | const child_cwd: process.Child.Cwd = if (conf_run.cwd.value) |lazy_cwd| |
| ... | ... | @@ -2237,20 +2623,22 @@ fn spawnChildAndCollect( |
| 2237 | 2623 | .infer_from_args => if (maker.protocol_server == null and has_side_effects) .inherit else .ignore, |
| 2238 | 2624 | .inherit => .inherit, |
| 2239 | 2625 | .check => .ignore, |
| 2240 | .zig_test => .pipe, | |
| 2626 | .zig_test, .protocol => .pipe, | |
| 2241 | 2627 | }, |
| 2242 | 2628 | .stdout = if (conf_run.captured_stdout.value != null) .pipe else switch (conf_run.flags.stdio) { |
| 2243 | 2629 | .infer_from_args => if (maker.protocol_server == null and has_side_effects) .inherit else .ignore, |
| 2244 | 2630 | .inherit => .inherit, |
| 2245 | 2631 | .check => if (checksContainStdout(&conf_run)) .pipe else .ignore, |
| 2246 | .zig_test => .pipe, | |
| 2632 | .zig_test, .protocol => .pipe, | |
| 2247 | 2633 | }, |
| 2248 | 2634 | .stderr = if (conf_run.captured_stderr.value != null) .pipe else switch (conf_run.flags.stdio) { |
| 2249 | 2635 | .infer_from_args => if (maker.protocol_server == null and has_side_effects) .inherit else .pipe, |
| 2250 | 2636 | .inherit => if (maker.protocol_server == null) .inherit else .pipe, |
| 2251 | 2637 | .check => .pipe, |
| 2252 | .zig_test => .pipe, | |
| 2638 | .zig_test, .protocol => .pipe, | |
| 2253 | 2639 | }, |
| 2640 | .inherit_dirs = inherit_dirs, | |
| 2641 | .inherit_files = inherit_files, | |
| 2254 | 2642 | }; |
| 2255 | 2643 | |
| 2256 | 2644 | if (maker.protocol_server != null) { |
| ... | ... | @@ -2263,35 +2651,38 @@ fn spawnChildAndCollect( |
| 2263 | 2651 | assert(spawn_options.stderr != .inherit); |
| 2264 | 2652 | } |
| 2265 | 2653 | |
| 2266 | if (conf_run.flags.stdio == .zig_test) { | |
| 2267 | try setColorEnvironmentVariables(&conf_run, environ_map, graph.stderr_mode.?); | |
| 2268 | const started: Io.Clock.Timestamp = .now(io, .awake); | |
| 2269 | const result = evalZigTest(run, run_index, maker, progress_node, spawn_options, fuzz_context) catch |err| switch (err) { | |
| 2270 | error.Canceled => |e| return e, | |
| 2271 | else => |e| e, | |
| 2272 | }; | |
| 2273 | step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); | |
| 2274 | try result; | |
| 2275 | return null; | |
| 2276 | } else { | |
| 2277 | const inherit = spawn_options.stdout == .inherit or spawn_options.stderr == .inherit; | |
| 2278 | if (!conf_run.flags.disable_zig_progress and !inherit) { | |
| 2279 | spawn_options.progress_node = progress_node; | |
| 2280 | } | |
| 2281 | const terminal_mode: Io.Terminal.Mode = if (inherit) m: { | |
| 2282 | const stderr = try io.lockStderr(&.{}, graph.stderr_mode); | |
| 2283 | break :m stderr.terminal_mode; | |
| 2284 | } else .no_color; | |
| 2285 | defer if (inherit) io.unlockStderr(); | |
| 2286 | try setColorEnvironmentVariables(&conf_run, environ_map, terminal_mode); | |
| 2287 | ||
| 2288 | const started: Io.Clock.Timestamp = .now(io, .awake); | |
| 2289 | const result = evalGeneric(arena, run_index, maker, spawn_options) catch |err| switch (err) { | |
| 2290 | error.Canceled => |e| return e, | |
| 2291 | else => |e| e, | |
| 2292 | }; | |
| 2293 | step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); | |
| 2294 | return try result; | |
| 2654 | switch (conf_run.flags.stdio) { | |
| 2655 | .infer_from_args, .inherit, .check => { | |
| 2656 | const inherit = spawn_options.stdout == .inherit or spawn_options.stderr == .inherit; | |
| 2657 | if (!conf_run.flags.disable_zig_progress and !inherit) { | |
| 2658 | spawn_options.progress_node = progress_node; | |
| 2659 | } | |
| 2660 | const terminal_mode: Io.Terminal.Mode = if (inherit) m: { | |
| 2661 | const stderr = try io.lockStderr(&.{}, graph.stderr_mode); | |
| 2662 | break :m stderr.terminal_mode; | |
| 2663 | } else .no_color; | |
| 2664 | defer if (inherit) io.unlockStderr(); | |
| 2665 | try setColorEnvironmentVariables(&conf_run, environ_map, terminal_mode); | |
| 2666 | ||
| 2667 | const started: Io.Clock.Timestamp = .now(io, .awake); | |
| 2668 | const result = evalGeneric(arena, run_index, maker, spawn_options) catch |err| switch (err) { | |
| 2669 | error.Canceled => |e| return e, | |
| 2670 | else => |e| e, | |
| 2671 | }; | |
| 2672 | step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); | |
| 2673 | return try result; | |
| 2674 | }, | |
| 2675 | .zig_test, .protocol => { | |
| 2676 | try setColorEnvironmentVariables(&conf_run, environ_map, graph.stderr_mode.?); | |
| 2677 | const started: Io.Clock.Timestamp = .now(io, .awake); | |
| 2678 | const result = evalZigTest(run, run_index, maker, progress_node, spawn_options, protocol_args, fuzz_context) catch |err| switch (err) { | |
| 2679 | error.Canceled => |e| return e, | |
| 2680 | else => |e| e, | |
| 2681 | }; | |
| 2682 | step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); | |
| 2683 | try result; | |
| 2684 | return null; | |
| 2685 | }, | |
| 2295 | 2686 | } |
| 2296 | 2687 | } |
| 2297 | 2688 | |
| ... | ... | @@ -2341,7 +2732,7 @@ fn setColorEnvironmentVariables( |
| 2341 | 2732 | .auto => { |
| 2342 | 2733 | const capture_stderr = conf_run.captured_stderr.value != null or switch (conf_run.flags.stdio) { |
| 2343 | 2734 | .check => checksContainStderr(conf_run), |
| 2344 | .infer_from_args, .inherit, .zig_test => false, | |
| 2735 | .infer_from_args, .inherit, .zig_test, .protocol => false, | |
| 2345 | 2736 | }; |
| 2346 | 2737 | if (capture_stderr) { |
| 2347 | 2738 | continue :color .disable; |
lib/std/Build.zig+1-4| ... | ... | @@ -768,9 +768,8 @@ pub fn addRunArtifact(b: *Build, exe: *Step.Compile) *Step.Run { |
| 768 | 768 | |
| 769 | 769 | const run_step = Step.Run.create(b, step_name); |
| 770 | 770 | run_step.producer = exe; |
| 771 | run_step.addArtifactArg(exe); | |
| 771 | 772 | if (exe.kind == .@"test") { |
| 772 | run_step.addArtifactArg(exe); | |
| 773 | ||
| 774 | 773 | const test_server_mode: bool = s: { |
| 775 | 774 | if (exe.test_runner) |r| break :s r.mode == .server; |
| 776 | 775 | if (exe.use_llvm == false) { |
| ... | ... | @@ -802,8 +801,6 @@ pub fn addRunArtifact(b: *Build, exe: *Step.Compile) *Step.Run { |
| 802 | 801 | // communicate failure via its exit code. |
| 803 | 802 | run_step.expectExitCode(0); |
| 804 | 803 | } |
| 805 | } else { | |
| 806 | run_step.addArtifactArg(exe); | |
| 807 | 804 | } |
| 808 | 805 | |
| 809 | 806 | return run_step; |
lib/std/Build/Configuration.zig+1-2| ... | ... | @@ -665,7 +665,7 @@ pub const Step = extern struct { |
| 665 | 665 | pub const Tag = enum(u2) { none, bytes, lazy_path }; |
| 666 | 666 | }; |
| 667 | 667 | pub const TrimWhitespace = enum(u2) { none, all, leading, trailing }; |
| 668 | pub const StdIo = enum(u2) { infer_from_args, inherit, check, zig_test }; | |
| 668 | pub const StdIo = enum(u3) { infer_from_args, inherit, check, zig_test, protocol }; | |
| 669 | 669 | |
| 670 | 670 | pub const ExpectTermStatus = enum(u2) { exited, signal, stopped, unknown }; |
| 671 | 671 | |
| ... | ... | @@ -675,7 +675,6 @@ pub const Step = extern struct { |
| 675 | 675 | skip_foreign_checks: bool, |
| 676 | 676 | failing_to_execute_foreign_is_an_error: bool, |
| 677 | 677 | has_side_effects: bool, |
| 678 | test_runner_mode: bool, | |
| 679 | 678 | color: Color, |
| 680 | 679 | stdin: StdIn.Tag, |
| 681 | 680 | stdio: StdIo, |
lib/std/Build/Serialize.zig+1-1| ... | ... | @@ -462,13 +462,13 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi |
| 462 | 462 | .skip_foreign_checks = run.skip_foreign_checks, |
| 463 | 463 | .failing_to_execute_foreign_is_an_error = run.failing_to_execute_foreign_is_an_error, |
| 464 | 464 | .has_side_effects = run.has_side_effects, |
| 465 | .test_runner_mode = run.test_runner_mode, | |
| 466 | 465 | .color = run.color, |
| 467 | 466 | .stdio = switch (run.stdio) { |
| 468 | 467 | .infer_from_args => .infer_from_args, |
| 469 | 468 | .inherit => .inherit, |
| 470 | 469 | .check => .check, |
| 471 | 470 | .zig_test => .zig_test, |
| 471 | .protocol => .protocol, | |
| 472 | 472 | }, |
| 473 | 473 | .stdin = switch (run.stdin) { |
| 474 | 474 | .none => .none, |
lib/std/Build/Step/Run.zig+16-7| ... | ... | @@ -92,7 +92,6 @@ captured_stdout: ?*CapturedStdIo, |
| 92 | 92 | captured_stderr: ?*CapturedStdIo, |
| 93 | 93 | |
| 94 | 94 | has_side_effects: bool, |
| 95 | test_runner_mode: bool = false, | |
| 96 | 95 | |
| 97 | 96 | /// If this Run step was produced by a Compile step, it is tracked here. |
| 98 | 97 | producer: ?*Step.Compile, |
| ... | ... | @@ -127,7 +126,10 @@ pub const StdIo = union(enum) { |
| 127 | 126 | check: std.ArrayList(Check), |
| 128 | 127 | /// This Run step is running a zig unit test binary and will communicate |
| 129 | 128 | /// extra metadata over the IPC protocol. |
| 129 | /// Deprecated, use `.protocol`. | |
| 130 | 130 | zig_test, |
| 131 | /// This Run step is running a binary that will communicate over the IPC protocol. | |
| 132 | protocol, | |
| 131 | 133 | |
| 132 | 134 | pub const Check = union(enum) { |
| 133 | 135 | expect_stderr_exact: []const u8, |
| ... | ... | @@ -243,10 +245,13 @@ pub fn setName(run: *Run, name: []const u8) void { |
| 243 | 245 | run.rename_step_with_output_arg = false; |
| 244 | 246 | } |
| 245 | 247 | |
| 248 | /// Deprecated, use `enableProtocolMode`. | |
| 246 | 249 | pub fn enableTestRunnerMode(run: *Run) void { |
| 247 | if (run.test_runner_mode) return; | |
| 248 | 250 | run.stdio = .zig_test; |
| 249 | run.test_runner_mode = true; | |
| 251 | } | |
| 252 | ||
| 253 | pub fn enableProtocolMode(run: *Run) void { | |
| 254 | run.stdio = .protocol; | |
| 250 | 255 | } |
| 251 | 256 | |
| 252 | 257 | pub const ArgOptions = struct { |
| ... | ... | @@ -750,8 +755,10 @@ pub fn addCheck(run: *Run, new_check: StdIo.Check) void { |
| 750 | 755 | } |
| 751 | 756 | |
| 752 | 757 | pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPath { |
| 753 | assert(run.stdio != .inherit); | |
| 754 | assert(run.stdio != .zig_test); | |
| 758 | switch (run.stdio) { | |
| 759 | .infer_from_args, .check => {}, | |
| 760 | .inherit, .zig_test, .protocol => unreachable, | |
| 761 | } | |
| 755 | 762 | |
| 756 | 763 | const b = run.step.owner; |
| 757 | 764 | const graph = b.graph; |
| ... | ... | @@ -771,8 +778,10 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa |
| 771 | 778 | } |
| 772 | 779 | |
| 773 | 780 | pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPath { |
| 774 | assert(run.stdio != .inherit); | |
| 775 | assert(run.stdio != .zig_test); | |
| 781 | switch (run.stdio) { | |
| 782 | .infer_from_args, .check => {}, | |
| 783 | .inherit, .zig_test, .protocol => unreachable, | |
| 784 | } | |
| 776 | 785 | |
| 777 | 786 | const b = run.step.owner; |
| 778 | 787 | const graph = b.graph; |
lib/std/Io/Reader/Limited.zig+2-4| ... | ... | @@ -28,8 +28,7 @@ pub fn init(reader: *Reader, limit: Limit, buffer: []u8) Limited { |
| 28 | 28 | fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { |
| 29 | 29 | const l: *Limited = @fieldParentPtr("interface", r); |
| 30 | 30 | if (l.remaining == .nothing) return error.EndOfStream; |
| 31 | const combined_limit = limit.min(l.remaining); | |
| 32 | const n = try l.unlimited.stream(w, combined_limit); | |
| 31 | const n = try l.unlimited.stream(w, limit.min(l.remaining)); | |
| 33 | 32 | l.remaining = l.remaining.subtract(n).?; |
| 34 | 33 | return n; |
| 35 | 34 | } |
| ... | ... | @@ -53,8 +52,7 @@ test stream { |
| 53 | 52 | fn discard(r: *Reader, limit: Limit) Reader.Error!usize { |
| 54 | 53 | const l: *Limited = @fieldParentPtr("interface", r); |
| 55 | 54 | if (l.remaining == .nothing) return error.EndOfStream; |
| 56 | const combined_limit = limit.min(l.remaining); | |
| 57 | const n = try l.unlimited.discard(combined_limit); | |
| 55 | const n = try l.unlimited.discard(limit.min(l.remaining)); | |
| 58 | 56 | l.remaining = l.remaining.subtract(n).?; |
| 59 | 57 | return n; |
| 60 | 58 | } |
lib/std/Io/Threaded.zig+36-31| ... | ... | @@ -4462,7 +4462,7 @@ fn dirCreateFilePosix( |
| 4462 | 4462 | var fl_flags: usize = fl: { |
| 4463 | 4463 | const syscall: Syscall = try .start(); |
| 4464 | 4464 | while (true) { |
| 4465 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0)); | |
| 4465 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(u32, 0)); | |
| 4466 | 4466 | switch (posix.errno(rc)) { |
| 4467 | 4467 | .SUCCESS => { |
| 4468 | 4468 | syscall.finish(); |
| ... | ... | @@ -5058,7 +5058,7 @@ fn dirOpenFilePosix( |
| 5058 | 5058 | var fl_flags: usize = fl: { |
| 5059 | 5059 | const syscall: Syscall = try .start(); |
| 5060 | 5060 | while (true) { |
| 5061 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0)); | |
| 5061 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(u32, 0)); | |
| 5062 | 5062 | switch (posix.errno(rc)) { |
| 5063 | 5063 | .SUCCESS => { |
| 5064 | 5064 | syscall.finish(); |
| ... | ... | @@ -15230,16 +15230,12 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp |
| 15230 | 15230 | const argv_buf = try arena.allocSentinel(?[*:0]const u8, options.argv.len, null); |
| 15231 | 15231 | for (options.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeSentinel(u8, arg, 0)).ptr; |
| 15232 | 15232 | |
| 15233 | const prog_fileno = 3; | |
| 15234 | comptime assert(@max(posix.STDIN_FILENO, posix.STDOUT_FILENO, posix.STDERR_FILENO) + 1 == prog_fileno); | |
| 15235 | ||
| 15236 | 15233 | const env_block = env_block: { |
| 15237 | const prog_fd: i32 = if (prog_pipe[1] == -1) -1 else prog_fileno; | |
| 15238 | 15234 | if (options.environ_map) |environ_map| break :env_block try environ_map.createPosixBlock(arena, .{ |
| 15239 | .zig_progress_fd = prog_fd, | |
| 15235 | .zig_progress_fd = prog_pipe[1], | |
| 15240 | 15236 | }); |
| 15241 | 15237 | break :env_block try t.environ.process_environ.createPosixBlock(arena, .{ |
| 15242 | .zig_progress_fd = prog_fd, | |
| 15238 | .zig_progress_fd = prog_pipe[1], | |
| 15243 | 15239 | }); |
| 15244 | 15240 | }; |
| 15245 | 15241 | |
| ... | ... | @@ -15267,23 +15263,42 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp |
| 15267 | 15263 | if (Thread.current) |current_thread| current_thread.cancel_protection = .blocked; |
| 15268 | 15264 | const ep1 = err_pipe[1]; |
| 15269 | 15265 | |
| 15270 | setUpChildIo(options.stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkBail(ep1, err); | |
| 15271 | setUpChildIo(options.stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkBail(ep1, err); | |
| 15272 | setUpChildIo(options.stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkBail(ep1, err); | |
| 15273 | ||
| 15266 | // Must happen befor clobbering fds below. | |
| 15274 | 15267 | switch (options.cwd) { |
| 15275 | 15268 | .inherit => {}, |
| 15276 | .dir => |cwd| { | |
| 15277 | fchdir(cwd.handle) catch |err| forkBail(ep1, err); | |
| 15278 | }, | |
| 15279 | .path => |cwd| { | |
| 15280 | chdir(cwd) catch |err| forkBail(ep1, err); | |
| 15281 | }, | |
| 15269 | .dir => |cwd| fchdir(cwd.handle) catch |err| forkBail(ep1, err), | |
| 15270 | .path => |cwd| chdir(cwd) catch |err| forkBail(ep1, err), | |
| 15282 | 15271 | } |
| 15283 | 15272 | |
| 15284 | // Must happen after fchdir above, the cwd file descriptor might be | |
| 15285 | // equal to prog_fileno and be clobbered by this dup2 call. | |
| 15286 | if (prog_pipe[1] != -1) dup2(prog_pipe[1], prog_fileno) catch |err| forkBail(ep1, err); | |
| 15273 | for (options.inherit_dirs) |dir| switch (posix.errno( | |
| 15274 | posix.system.fcntl(dir.handle, posix.F.SETFD, @as(u32, 0)), | |
| 15275 | )) { | |
| 15276 | .SUCCESS => {}, | |
| 15277 | else => |err| forkBail(ep1, posix.unexpectedErrno(err)), | |
| 15278 | }; | |
| 15279 | for (options.inherit_files) |file| switch (posix.errno( | |
| 15280 | posix.system.fcntl(file.handle, posix.F.SETFD, @as(u32, 0)), | |
| 15281 | )) { | |
| 15282 | .SUCCESS => {}, | |
| 15283 | else => |err| forkBail(ep1, posix.unexpectedErrno(err)), | |
| 15284 | }; | |
| 15285 | if (prog_pipe[1] != -1) switch (posix.errno( | |
| 15286 | posix.system.fcntl(prog_pipe[1], posix.F.SETFD, @as(u32, 0)), | |
| 15287 | )) { | |
| 15288 | .SUCCESS => {}, | |
| 15289 | else => |err| forkBail(ep1, posix.unexpectedErrno(err)), | |
| 15290 | }; | |
| 15291 | for ( | |
| 15292 | [_]process.SpawnOptions.StdIo{ options.stdin, options.stdout, options.stderr }, | |
| 15293 | [_]posix.fd_t{ stdin_pipe[0], stdout_pipe[1], stderr_pipe[1] }, | |
| 15294 | [_]posix.fd_t{ posix.STDIN_FILENO, posix.STDOUT_FILENO, posix.STDERR_FILENO }, | |
| 15295 | ) |stdio, pipe_fd, std_fd| switch (stdio) { | |
| 15296 | .pipe => dup2(pipe_fd, std_fd) catch |err| forkBail(ep1, err), | |
| 15297 | .close => closeFd(std_fd), | |
| 15298 | .inherit => {}, | |
| 15299 | .ignore => dup2(dev_null_fd, std_fd) catch |err| forkBail(ep1, err), | |
| 15300 | .file => |file| dup2(file.handle, std_fd) catch |err| forkBail(ep1, err), | |
| 15301 | }; | |
| 15287 | 15302 | |
| 15288 | 15303 | if (options.gid) |gid| { |
| 15289 | 15304 | switch (posix.errno(posix.system.setregid(gid, gid))) { |
| ... | ... | @@ -15746,16 +15761,6 @@ fn destroyPipe(pipe: [2]posix.fd_t) void { |
| 15746 | 15761 | if (pipe[0] != pipe[1]) closeFd(pipe[1]); |
| 15747 | 15762 | } |
| 15748 | 15763 | |
| 15749 | fn setUpChildIo(stdio: process.SpawnOptions.StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void { | |
| 15750 | switch (stdio) { | |
| 15751 | .pipe => try dup2(pipe_fd, std_fileno), | |
| 15752 | .close => closeFd(std_fileno), | |
| 15753 | .inherit => {}, | |
| 15754 | .ignore => try dup2(dev_null_fd, std_fileno), | |
| 15755 | .file => |file| try dup2(file.handle, std_fileno), | |
| 15756 | } | |
| 15757 | } | |
| 15758 | ||
| 15759 | 15764 | fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child { |
| 15760 | 15765 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 15761 | 15766 |
lib/std/bit_set.zig+2-7| ... | ... | @@ -723,13 +723,8 @@ pub const Dynamic = struct { |
| 723 | 723 | // That slot holds the size of the true allocation, which |
| 724 | 724 | // is needed by Zig's allocator interface in case a shrink |
| 725 | 725 | // fails. |
| 726 | ||
| 727 | // Don't modify this value. Ideally it would go in const data so | |
| 728 | // modifications would cause a bus error, but the only way | |
| 729 | // to discard a const qualifier is through intFromPtr, which | |
| 730 | // cannot currently round trip at comptime. | |
| 731 | var empty_masks_data = [_]MaskInt{ 0, undefined }; | |
| 732 | const empty_masks_ptr = empty_masks_data[1..2]; | |
| 726 | const empty_masks_data = [_]MaskInt{ 0, undefined }; | |
| 727 | const empty_masks_ptr = @constCast(empty_masks_data[1..2]); | |
| 733 | 728 | |
| 734 | 729 | /// Creates a bit set with no elements present. |
| 735 | 730 | /// If bit_length is not zero, deinit must eventually be called. |
lib/std/process.zig+2| ... | ... | @@ -390,6 +390,8 @@ pub const SpawnOptions = struct { |
| 390 | 390 | stdin: StdIo = .inherit, |
| 391 | 391 | stdout: StdIo = .inherit, |
| 392 | 392 | stderr: StdIo = .inherit, |
| 393 | inherit_dirs: []const Dir = &.{}, | |
| 394 | inherit_files: []const File = &.{}, | |
| 393 | 395 | |
| 394 | 396 | /// Set to true to obtain rusage information for the child process. |
| 395 | 397 | /// Depending on the target platform and implementation status, the |
lib/std/zig/Client.zig+28| ... | ... | @@ -60,6 +60,7 @@ pub const Message = struct { |
| 60 | 60 | start_fuzzing, |
| 61 | 61 | /// The message body has the same format as in Server. |
| 62 | 62 | new_fuzz_input, |
| 63 | args, | |
| 63 | 64 | |
| 64 | 65 | /// Asks the server to run a list of steps. |
| 65 | 66 | /// Body is a `BuildSteps`. |
| ... | ... | @@ -69,6 +70,33 @@ pub const Message = struct { |
| 69 | 70 | _, |
| 70 | 71 | }; |
| 71 | 72 | |
| 73 | pub const Arg = enum(u8) { | |
| 74 | /// Trailing: | |
| 75 | /// * string: [:0]const u8, | |
| 76 | string, | |
| 77 | /// Trailing: | |
| 78 | /// * string: [:0]const u8, | |
| 79 | prefix, | |
| 80 | /// Trailing: | |
| 81 | /// * string: [:0]const u8, | |
| 82 | suffix, | |
| 83 | /// Trailing: | |
| 84 | /// * handle: Handle, | |
| 85 | input_file, | |
| 86 | /// Trailing: | |
| 87 | /// * handle: Handle, | |
| 88 | input_dir, | |
| 89 | /// Trailing: | |
| 90 | /// * handle: Handle, | |
| 91 | input_file_content, | |
| 92 | /// Trailing: | |
| 93 | /// * handle: Handle, | |
| 94 | output_file, | |
| 95 | /// Trailing: | |
| 96 | /// * handle: Handle, | |
| 97 | output_dir, | |
| 98 | }; | |
| 99 | ||
| 72 | 100 | /// Trailing: |
| 73 | 101 | /// * step_indices: [step_count]std.Build.Configuration.Step.Index, |
| 74 | 102 | pub const BuildSteps = extern struct { |
test/incremental2/change_panic_handler_explicit/0-main.zig created+46| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | pub fn main() !u8 { | |
| 2 | var a: u8 = undefined; | |
| 3 | a = 255; | |
| 4 | _ = a + 1; | |
| 5 | return 1; | |
| 6 | } | |
| 7 | const no_panic = std.debug.no_panic; | |
| 8 | pub const panic = struct { | |
| 9 | pub const call = myPanic; | |
| 10 | pub fn integerOverflow() noreturn { | |
| 11 | @panic("integer overflow"); | |
| 12 | } | |
| 13 | pub const sentinelMismatch = no_panic.sentinelMismatch; | |
| 14 | pub const unwrapError = no_panic.unwrapError; | |
| 15 | pub const outOfBounds = no_panic.outOfBounds; | |
| 16 | pub const startGreaterThanEnd = no_panic.startGreaterThanEnd; | |
| 17 | pub const inactiveUnionField = no_panic.inactiveUnionField; | |
| 18 | pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder; | |
| 19 | pub const reachedUnreachable = no_panic.reachedUnreachable; | |
| 20 | pub const unwrapNull = no_panic.unwrapNull; | |
| 21 | pub const castToNull = no_panic.castToNull; | |
| 22 | pub const incorrectAlignment = no_panic.incorrectAlignment; | |
| 23 | pub const invalidErrorCode = no_panic.invalidErrorCode; | |
| 24 | pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; | |
| 25 | pub const integerOutOfBounds = no_panic.integerOutOfBounds; | |
| 26 | pub const shlOverflow = no_panic.shlOverflow; | |
| 27 | pub const shrOverflow = no_panic.shrOverflow; | |
| 28 | pub const divideByZero = no_panic.divideByZero; | |
| 29 | pub const exactDivisionRemainder = no_panic.exactDivisionRemainder; | |
| 30 | pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds; | |
| 31 | pub const corruptSwitch = no_panic.corruptSwitch; | |
| 32 | pub const shiftRhsTooBig = no_panic.shiftRhsTooBig; | |
| 33 | pub const invalidEnumValue = no_panic.invalidEnumValue; | |
| 34 | pub const forLenMismatch = no_panic.forLenMismatch; | |
| 35 | pub const copyLenMismatch = no_panic.copyLenMismatch; | |
| 36 | pub const memcpyAlias = no_panic.memcpyAlias; | |
| 37 | pub const noreturnReturned = no_panic.noreturnReturned; | |
| 38 | pub const loadUninstantiableType = no_panic.loadUninstantiableType; | |
| 39 | }; | |
| 40 | fn myPanic(msg: []const u8, _: ?usize) noreturn { | |
| 41 | var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); | |
| 42 | stdout_writer.interface.print("panic message: {s}\n", .{msg}) catch {}; | |
| 43 | std.process.exit(0); | |
| 44 | } | |
| 45 | const std = @import("std"); | |
| 46 | const io = std.Io.Threaded.global_single_threaded.io(); |
test/incremental2/change_panic_handler_explicit/1-main.zig created+46| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | pub fn main() !u8 { | |
| 2 | var a: u8 = undefined; | |
| 3 | a = 255; | |
| 4 | _ = a + 1; | |
| 5 | return 1; | |
| 6 | } | |
| 7 | const no_panic = std.debug.no_panic; | |
| 8 | pub const panic = struct { | |
| 9 | pub const call = myPanic; | |
| 10 | pub fn integerOverflow() noreturn { | |
| 11 | @panic("integer overflow"); | |
| 12 | } | |
| 13 | pub const sentinelMismatch = no_panic.sentinelMismatch; | |
| 14 | pub const unwrapError = no_panic.unwrapError; | |
| 15 | pub const outOfBounds = no_panic.outOfBounds; | |
| 16 | pub const startGreaterThanEnd = no_panic.startGreaterThanEnd; | |
| 17 | pub const inactiveUnionField = no_panic.inactiveUnionField; | |
| 18 | pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder; | |
| 19 | pub const reachedUnreachable = no_panic.reachedUnreachable; | |
| 20 | pub const unwrapNull = no_panic.unwrapNull; | |
| 21 | pub const castToNull = no_panic.castToNull; | |
| 22 | pub const incorrectAlignment = no_panic.incorrectAlignment; | |
| 23 | pub const invalidErrorCode = no_panic.invalidErrorCode; | |
| 24 | pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; | |
| 25 | pub const integerOutOfBounds = no_panic.integerOutOfBounds; | |
| 26 | pub const shlOverflow = no_panic.shlOverflow; | |
| 27 | pub const shrOverflow = no_panic.shrOverflow; | |
| 28 | pub const divideByZero = no_panic.divideByZero; | |
| 29 | pub const exactDivisionRemainder = no_panic.exactDivisionRemainder; | |
| 30 | pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds; | |
| 31 | pub const corruptSwitch = no_panic.corruptSwitch; | |
| 32 | pub const shiftRhsTooBig = no_panic.shiftRhsTooBig; | |
| 33 | pub const invalidEnumValue = no_panic.invalidEnumValue; | |
| 34 | pub const forLenMismatch = no_panic.forLenMismatch; | |
| 35 | pub const copyLenMismatch = no_panic.copyLenMismatch; | |
| 36 | pub const memcpyAlias = no_panic.memcpyAlias; | |
| 37 | pub const noreturnReturned = no_panic.noreturnReturned; | |
| 38 | pub const loadUninstantiableType = no_panic.loadUninstantiableType; | |
| 39 | }; | |
| 40 | fn myPanic(msg: []const u8, _: ?usize) noreturn { | |
| 41 | var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); | |
| 42 | stdout_writer.interface.print("new panic message: {s}\n", .{msg}) catch {}; | |
| 43 | std.process.exit(0); | |
| 44 | } | |
| 45 | const std = @import("std"); | |
| 46 | const io = std.Io.Threaded.global_single_threaded.io(); |
test/incremental2/change_panic_handler_explicit/2-main.zig created+46| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | pub fn main() !u8 { | |
| 2 | var a: u8 = undefined; | |
| 3 | a = 255; | |
| 4 | _ = a + 1; | |
| 5 | return 1; | |
| 6 | } | |
| 7 | const no_panic = std.debug.no_panic; | |
| 8 | pub const panic = struct { | |
| 9 | pub const call = myPanicNew; | |
| 10 | pub fn integerOverflow() noreturn { | |
| 11 | @panic("integer overflow"); | |
| 12 | } | |
| 13 | pub const sentinelMismatch = no_panic.sentinelMismatch; | |
| 14 | pub const unwrapError = no_panic.unwrapError; | |
| 15 | pub const outOfBounds = no_panic.outOfBounds; | |
| 16 | pub const startGreaterThanEnd = no_panic.startGreaterThanEnd; | |
| 17 | pub const inactiveUnionField = no_panic.inactiveUnionField; | |
| 18 | pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder; | |
| 19 | pub const reachedUnreachable = no_panic.reachedUnreachable; | |
| 20 | pub const unwrapNull = no_panic.unwrapNull; | |
| 21 | pub const castToNull = no_panic.castToNull; | |
| 22 | pub const incorrectAlignment = no_panic.incorrectAlignment; | |
| 23 | pub const invalidErrorCode = no_panic.invalidErrorCode; | |
| 24 | pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; | |
| 25 | pub const integerOutOfBounds = no_panic.integerOutOfBounds; | |
| 26 | pub const shlOverflow = no_panic.shlOverflow; | |
| 27 | pub const shrOverflow = no_panic.shrOverflow; | |
| 28 | pub const divideByZero = no_panic.divideByZero; | |
| 29 | pub const exactDivisionRemainder = no_panic.exactDivisionRemainder; | |
| 30 | pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds; | |
| 31 | pub const corruptSwitch = no_panic.corruptSwitch; | |
| 32 | pub const shiftRhsTooBig = no_panic.shiftRhsTooBig; | |
| 33 | pub const invalidEnumValue = no_panic.invalidEnumValue; | |
| 34 | pub const forLenMismatch = no_panic.forLenMismatch; | |
| 35 | pub const copyLenMismatch = no_panic.copyLenMismatch; | |
| 36 | pub const memcpyAlias = no_panic.memcpyAlias; | |
| 37 | pub const noreturnReturned = no_panic.noreturnReturned; | |
| 38 | pub const loadUninstantiableType = no_panic.loadUninstantiableType; | |
| 39 | }; | |
| 40 | fn myPanicNew(msg: []const u8, _: ?usize) noreturn { | |
| 41 | var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); | |
| 42 | stdout_writer.interface.print("third panic message: {s}\n", .{msg}) catch {}; | |
| 43 | std.process.exit(0); | |
| 44 | } | |
| 45 | const std = @import("std"); | |
| 46 | const io = std.Io.Threaded.global_single_threaded.io(); |
test/incremental2/change_panic_handler_explicit/manifest created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | #exe { | |
| 2 | -Mroot=main.zig | |
| 3 | #} | |
| 4 | ||
| 5 | #write main.zig 0-main.zig | |
| 6 | #update | |
| 7 | #check stdout { | |
| 8 | panic message: integer overflow | |
| 9 | #} | |
| 10 | ||
| 11 | #write main.zig 1-main.zig | |
| 12 | #update { | |
| 13 | change the panic handler body#} | |
| 14 | #check stdout { | |
| 15 | new panic message: integer overflow | |
| 16 | #} | |
| 17 | ||
| 18 | #write main.zig 2-main.zig | |
| 19 | #update { | |
| 20 | change the panic handler function value#} | |
| 21 | #check stdout { | |
| 22 | third panic message: integer overflow | |
| 23 | #} |
test/incremental2/hello created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | #exe { | |
| 2 | -Mroot=main.zig | |
| 3 | #} | |
| 4 | ||
| 5 | #write main.zig { | |
| 6 | const std = @import("std"); | |
| 7 | const io = std.Io.Threaded.global_single_threaded.io(); | |
| 8 | pub fn main() !void { | |
| 9 | try std.Io.File.stdout().writeStreamingAll(io, "good morning\n"); | |
| 10 | } | |
| 11 | #} | |
| 12 | #update | |
| 13 | #check stdout { | |
| 14 | good morning | |
| 15 | #} | |
| 16 | ||
| 17 | #write main.zig { | |
| 18 | const std = @import("std"); | |
| 19 | const io = std.Io.Threaded.global_single_threaded.io(); | |
| 20 | pub fn main() !void { | |
| 21 | try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n"); | |
| 22 | } | |
| 23 | #} | |
| 24 | #update { | |
| 25 | change the string#} | |
| 26 | #check stdout { | |
| 27 | おはようございます | |
| 28 | #} |
test/src/runner.zig created+279| ... | ... | @@ -0,0 +1,279 @@ |
| 1 | const std = @import("std"); | |
| 2 | const Args = struct { | |
| 3 | test_dir: ?std.Io.Dir, | |
| 4 | manifest_file: ?std.Io.File, | |
| 5 | zig_file: ?std.Io.File, | |
| 6 | lib_dir: ?std.Io.Dir, | |
| 7 | src_dir: ?std.Io.Dir, | |
| 8 | }; | |
| 9 | pub fn main(init: std.process.Init) !void { | |
| 10 | var stdin_buffer: [512]u8 = undefined; | |
| 11 | var stdout_buffer: [512]u8 = undefined; | |
| 12 | var stderr_buffer: [512]u8 = undefined; | |
| 13 | var stdin: std.Io.File.Reader = .initStreaming(.stdin(), init.io, &stdin_buffer); | |
| 14 | var stdout: std.Io.File.Writer = .initStreaming(.stdout(), init.io, &stdout_buffer); | |
| 15 | var stderr: std.Io.File.Writer = .initStreaming(.stderr(), init.io, &stderr_buffer); | |
| 16 | var server: std.zig.Server = .{ | |
| 17 | .in = &stdin.interface, | |
| 18 | .out = &stdout.interface, | |
| 19 | }; | |
| 20 | try server.serveStringMessage(.zig_version, @import("builtin").zig_version_string); | |
| 21 | var args: Args = .{ | |
| 22 | .test_dir = null, | |
| 23 | .manifest_file = null, | |
| 24 | .zig_file = null, | |
| 25 | .lib_dir = null, | |
| 26 | .src_dir = null, | |
| 27 | }; | |
| 28 | while (true) { | |
| 29 | const hdr = try server.receiveMessage(); | |
| 30 | switch (hdr.tag) { | |
| 31 | else => { | |
| 32 | std.debug.print("unsupported message: {t}\n", .{hdr.tag}); | |
| 33 | std.process.exit(1); | |
| 34 | }, | |
| 35 | .exit => { | |
| 36 | std.process.exit(0); | |
| 37 | }, | |
| 38 | .args => { | |
| 39 | const args_body = try init.arena.allocator().alloc(u8, hdr.bytes_len); | |
| 40 | try server.in.readSliceAll(args_body); | |
| 41 | var state: enum { positional, zig, lib, src } = .positional; | |
| 42 | var args_body_offset: usize = 0; | |
| 43 | while (args_body.len - args_body_offset > 0) { | |
| 44 | const arg: std.zig.Client.Message.Arg = | |
| 45 | @fromBackingInt(args_body[args_body_offset]); | |
| 46 | args_body_offset += 1; | |
| 47 | switch (arg) { | |
| 48 | .string => { | |
| 49 | const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; | |
| 50 | const string = args_body[args_body_offset..end]; | |
| 51 | args_body_offset = end + 1; | |
| 52 | _ = string; | |
| 53 | }, | |
| 54 | .prefix => { | |
| 55 | const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; | |
| 56 | const string = args_body[args_body_offset..end]; | |
| 57 | args_body_offset = end + 1; | |
| 58 | state = if (std.mem.eql(u8, string, "--zig=")) | |
| 59 | .zig | |
| 60 | else if (std.mem.eql(u8, string, "--lib=")) | |
| 61 | .lib | |
| 62 | else if (std.mem.eql(u8, string, "--src=")) | |
| 63 | .src | |
| 64 | else | |
| 65 | unreachable; | |
| 66 | continue; | |
| 67 | }, | |
| 68 | .suffix => unreachable, | |
| 69 | .input_dir, .output_dir => { | |
| 70 | const dir_handle: *align(1) const std.Io.Dir.Handle = @ptrCast( | |
| 71 | args_body[args_body_offset..][0..@sizeOf(std.Io.Dir.Handle)], | |
| 72 | ); | |
| 73 | args_body_offset += @sizeOf(std.Io.Dir.Handle); | |
| 74 | const dir: std.Io.Dir = .{ | |
| 75 | .handle = dir_handle.*, | |
| 76 | }; | |
| 77 | switch (state) { | |
| 78 | .positional => { | |
| 79 | std.debug.assert(args.test_dir == null); | |
| 80 | args.test_dir = dir; | |
| 81 | std.debug.assert(args.manifest_file == null); | |
| 82 | args.manifest_file = try dir.openFile(init.io, "manifest", .{}); | |
| 83 | }, | |
| 84 | .zig => unreachable, | |
| 85 | .lib => { | |
| 86 | std.debug.assert(args.lib_dir == null); | |
| 87 | args.lib_dir = dir; | |
| 88 | }, | |
| 89 | .src => { | |
| 90 | std.debug.assert(args.src_dir == null); | |
| 91 | args.src_dir = dir; | |
| 92 | }, | |
| 93 | } | |
| 94 | }, | |
| 95 | .input_file, .input_file_content, .output_file => { | |
| 96 | const file_handle: *align(1) const std.Io.File.Handle = @ptrCast( | |
| 97 | args_body[args_body_offset..][0..@sizeOf(std.Io.File.Handle)], | |
| 98 | ); | |
| 99 | args_body_offset += @sizeOf(std.Io.File.Handle); | |
| 100 | const file: std.Io.File = .{ | |
| 101 | .handle = file_handle.*, | |
| 102 | .flags = .{ .nonblocking = false }, | |
| 103 | }; | |
| 104 | switch (state) { | |
| 105 | .positional => { | |
| 106 | std.debug.assert(args.manifest_file == null); | |
| 107 | args.manifest_file = file; | |
| 108 | }, | |
| 109 | .zig => { | |
| 110 | std.debug.assert(args.zig_file == null); | |
| 111 | args.zig_file = file; | |
| 112 | }, | |
| 113 | .lib, .src => unreachable, | |
| 114 | } | |
| 115 | }, | |
| 116 | } | |
| 117 | state = .positional; | |
| 118 | } | |
| 119 | }, | |
| 120 | .query_test_metadata => try server.serveTestMetadata(.{ | |
| 121 | .names = &.{0}, | |
| 122 | .expected_panic_msgs = &.{0}, | |
| 123 | .string_bytes = "runner\x00", | |
| 124 | }), | |
| 125 | .run_test => { | |
| 126 | const test_index = try server.receiveBody_u32(); | |
| 127 | try server.serveBodylessMessage(.test_started); | |
| 128 | const test_result = runTest(init.io, &stderr.interface, &args); | |
| 129 | try stderr.flush(); | |
| 130 | try server.serveTestResults(.{ | |
| 131 | .index = test_index, | |
| 132 | .flags = .{ | |
| 133 | .status = if (test_result) .pass else |err| switch (err) { | |
| 134 | else => status: { | |
| 135 | if (@errorReturnTrace()) |trace| std.debug.dumpErrorReturnTrace(trace); | |
| 136 | break :status .fail; | |
| 137 | }, | |
| 138 | error.SkipZigTest => .skip, | |
| 139 | }, | |
| 140 | .fuzz = false, | |
| 141 | .log_err_count = 0, | |
| 142 | .leak_count = 0, | |
| 143 | }, | |
| 144 | }); | |
| 145 | }, | |
| 146 | } | |
| 147 | } | |
| 148 | } | |
| 149 | fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void { | |
| 150 | const manifest_file = args.manifest_file orelse return error.MissingManifestArg; | |
| 151 | const src_dir = args.src_dir orelse return error.MissingSrcDir; | |
| 152 | var manifest_buffer: [512]u8 = undefined; | |
| 153 | var manifest_fr = manifest_file.reader(io, &manifest_buffer); | |
| 154 | var skip_delimiter = false; | |
| 155 | var update_mtime = std.Io.Clock.real.now(io); | |
| 156 | var update_num: usize = 0; | |
| 157 | while (manifest_fr.interface.takeSentinel('\n')) |untrimmed_line| { | |
| 158 | const line = std.mem.trimEnd(u8, untrimmed_line, "\r"); | |
| 159 | var line_it = std.mem.tokenizeScalar(u8, line, ' '); | |
| 160 | const cmd_str = std.mem.cutPrefix(u8, line_it.next() orelse continue, "#").?; | |
| 161 | if (skip_delimiter) { | |
| 162 | std.debug.assert(std.mem.eql(u8, cmd_str, "}")); | |
| 163 | skip_delimiter = false; | |
| 164 | continue; | |
| 165 | } | |
| 166 | const cmd = std.meta.stringToEnum( | |
| 167 | enum { obj, exe, lib, write, delete, update, check }, | |
| 168 | cmd_str, | |
| 169 | ) orelse return error.UnknownCommand; | |
| 170 | var maybe_arg = line_it.next(); | |
| 171 | var contents_file: ?std.Io.File = null; | |
| 172 | defer if (contents_file) |file| file.close(io); | |
| 173 | var contents_impl: union { | |
| 174 | dr: DelimitedReader, | |
| 175 | fr: std.Io.File.Reader, | |
| 176 | } = undefined; | |
| 177 | const contents_r: *std.Io.Reader = contents_r: { | |
| 178 | switch (cmd) { | |
| 179 | else => {}, | |
| 180 | .delete => break :contents_r .ending, | |
| 181 | } | |
| 182 | const contents_path = contents_path: { | |
| 183 | const line_rest = line_it.rest(); | |
| 184 | if (line_rest.len > 0) break :contents_path line_rest; | |
| 185 | const contents_path = maybe_arg orelse break :contents_r .ending; | |
| 186 | maybe_arg = null; | |
| 187 | break :contents_path contents_path; | |
| 188 | }; | |
| 189 | if (std.mem.eql(u8, contents_path, "{")) { | |
| 190 | contents_impl = .{ .dr = .init(&manifest_fr.interface, "#}", &.{}) }; | |
| 191 | skip_delimiter = true; | |
| 192 | break :contents_r &contents_impl.dr.interface; | |
| 193 | } | |
| 194 | const test_dir = args.test_dir orelse return error.ContentsFileInFileTest; | |
| 195 | contents_file = try test_dir.openFile(io, contents_path, .{}); | |
| 196 | contents_impl = .{ .fr = contents_file.?.reader(io, &.{}) }; | |
| 197 | break :contents_r &contents_impl.fr.interface; | |
| 198 | }; | |
| 199 | switch (cmd) { | |
| 200 | else => { | |
| 201 | try stderr.print("{t} {s} {{\n", .{ cmd, maybe_arg orelse "" }); | |
| 202 | _ = try contents_r.streamRemaining(stderr); | |
| 203 | try stderr.writeAll("\n}\n"); | |
| 204 | }, | |
| 205 | .write => { | |
| 206 | const file = try src_dir.createFile(io, maybe_arg orelse return error.MissingArg, .{}); | |
| 207 | defer file.close(io); | |
| 208 | var fw = file.writer(io, &.{}); | |
| 209 | _ = try contents_r.streamRemaining(&fw.interface); | |
| 210 | try file.setTimestamps(io, .{ .modify_timestamp = .{ .new = update_mtime } }); | |
| 211 | }, | |
| 212 | .delete => try src_dir.deleteFile(io, maybe_arg orelse return error.MissingArg), | |
| 213 | .update => { | |
| 214 | var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined; | |
| 215 | const name = switch (try contents_r.readSliceShort(&name_buffer)) { | |
| 216 | 0 => switch (update_num) { | |
| 217 | 0 => "initial update", | |
| 218 | else => |num| std.mem.print(&name_buffer, "update {d}", .{num}) catch | |
| 219 | &name_buffer, | |
| 220 | }, | |
| 221 | else => |name_len| name_buffer[0..name_len], | |
| 222 | }; | |
| 223 | _ = try contents_r.discardRemaining(); | |
| 224 | try stderr.print("update({q})\n", .{name}); | |
| 225 | update_mtime = update_mtime.addDuration(.fromSeconds(2)); | |
| 226 | update_num += 1; | |
| 227 | }, | |
| 228 | } | |
| 229 | std.debug.assert(try contents_r.discardRemaining() == 0); | |
| 230 | } else |err| switch (err) { | |
| 231 | else => |e| return e, | |
| 232 | error.EndOfStream => if (skip_delimiter) return error.MissingDelimiter, | |
| 233 | } | |
| 234 | } | |
| 235 | const DelimitedReader = struct { | |
| 236 | const Io = std.Io; | |
| 237 | ||
| 238 | unlimited: *Io.Reader, | |
| 239 | remaining: Io.Limit, | |
| 240 | delimiter: []const u8, | |
| 241 | interface: Io.Reader, | |
| 242 | ||
| 243 | pub fn init(reader: *Io.Reader, delimiter: []const u8, buffer: []u8) DelimitedReader { | |
| 244 | return .{ | |
| 245 | .unlimited = reader, | |
| 246 | .remaining = .nothing, | |
| 247 | .delimiter = delimiter, | |
| 248 | .interface = .{ | |
| 249 | .vtable = &.{ | |
| 250 | .stream = stream, | |
| 251 | .discard = discard, | |
| 252 | }, | |
| 253 | .buffer = buffer, | |
| 254 | .seek = 0, | |
| 255 | .end = 0, | |
| 256 | }, | |
| 257 | }; | |
| 258 | } | |
| 259 | fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize { | |
| 260 | const d: *DelimitedReader = @fieldParentPtr("interface", r); | |
| 261 | const block = try d.unlimited.peekGreedy(d.delimiter.len); | |
| 262 | d.remaining = .limited(std.mem.findPos(u8, block, d.remaining.toInt().?, d.delimiter) orelse | |
| 263 | block.len - d.delimiter.len + 1); | |
| 264 | if (d.remaining == .nothing) return error.EndOfStream; | |
| 265 | const n = try d.unlimited.stream(w, limit.min(d.remaining)); | |
| 266 | d.remaining = d.remaining.subtract(n).?; | |
| 267 | return n; | |
| 268 | } | |
| 269 | fn discard(r: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize { | |
| 270 | const d: *DelimitedReader = @fieldParentPtr("interface", r); | |
| 271 | const block = try d.unlimited.peekGreedy(d.delimiter.len); | |
| 272 | d.remaining = .limited(std.mem.findPos(u8, block, d.remaining.toInt().?, d.delimiter) orelse | |
| 273 | block.len - d.delimiter.len + 1); | |
| 274 | if (d.remaining == .nothing) return error.EndOfStream; | |
| 275 | const n = try d.unlimited.discard(limit.min(d.remaining)); | |
| 276 | d.remaining = d.remaining.subtract(n).?; | |
| 277 | return n; | |
| 278 | } | |
| 279 | }; |
test/standalone/build.zig+1| ... | ... | @@ -44,6 +44,7 @@ pub fn build(b: *std.Build) void { |
| 44 | 44 | "../../tools/generate_linux_syscalls.zig", |
| 45 | 45 | "../../tools/process_headers.zig", |
| 46 | 46 | "../../tools/migrate_langref.zig", |
| 47 | "../../tools/runner-check.zig", | |
| 47 | 48 | "../../tools/unskip_spirv_tests.zig", |
| 48 | 49 | "../../tools/update-linux-headers.zig", |
| 49 | 50 | "../../tools/update_clang_options.zig", |
test/tests.zig+86-1| ... | ... | @@ -3365,7 +3365,7 @@ pub fn addIncrementalTests( |
| 3365 | 3365 | |
| 3366 | 3366 | var it = try dir.walk(b.graph.arena); |
| 3367 | 3367 | while (try it.next(io)) |entry| { |
| 3368 | if (std.mem.endsWith(u8, entry.basename, ".swp")) continue; | |
| 3368 | if (isEditorFileName(entry.basename)) continue; | |
| 3369 | 3369 | |
| 3370 | 3370 | for (options.test_filters) |test_filter| { |
| 3371 | 3371 | if (std.mem.find(u8, entry.path, test_filter)) |_| break; |
| ... | ... | @@ -3435,6 +3435,91 @@ pub fn addIncrementalTests( |
| 3435 | 3435 | } |
| 3436 | 3436 | } |
| 3437 | 3437 | |
| 3438 | pub fn addNewIncrementalTests( | |
| 3439 | b: *std.Build, | |
| 3440 | runner: *std.Build.Step.Compile, | |
| 3441 | options: IncrementalTestOptions, | |
| 3442 | ) !*Step { | |
| 3443 | const tests_step = b.step("test-new-incremental", "Run the new incremental compilation test cases"); | |
| 3444 | ||
| 3445 | const tests_path = b.path("test/incremental2"); | |
| 3446 | b.dependOnDirectoryContents(tests_path); | |
| 3447 | ||
| 3448 | var tests_dir = try b.root.openDir(b.graph.io, "test/incremental2", .{ .iterate = true }); | |
| 3449 | defer tests_dir.close(b.graph.io); | |
| 3450 | var test_it = tests_dir.iterate(); | |
| 3451 | while (try test_it.next(b.graph.io)) |@"test"| { | |
| 3452 | const test_path = tests_path.path(b, @"test".name); | |
| 3453 | switch (@"test".kind) { | |
| 3454 | else => continue, | |
| 3455 | .file => if (isEditorFileName(@"test".name)) continue, | |
| 3456 | .directory => {}, | |
| 3457 | } | |
| 3458 | ||
| 3459 | for (incremental_targets) |test_target| { | |
| 3460 | const resolved_target = b.resolveTargetQuery(test_target.target); | |
| 3461 | ||
| 3462 | if (options.skip_non_native and !isNative(&resolved_target, &b.graph.host.result)) | |
| 3463 | continue; | |
| 3464 | ||
| 3465 | const target = &resolved_target.result; | |
| 3466 | ||
| 3467 | if (options.skip_wasm and target.cpu.arch.isWasm()) continue; | |
| 3468 | ||
| 3469 | if (options.skip_freebsd and target.os.tag == .freebsd) continue; | |
| 3470 | if (options.skip_netbsd and target.os.tag == .netbsd) continue; | |
| 3471 | if (options.skip_openbsd and target.os.tag == .openbsd) continue; | |
| 3472 | if (options.skip_windows and target.os.tag == .windows) continue; | |
| 3473 | if (options.skip_darwin and target.os.tag.isDarwin()) continue; | |
| 3474 | if (options.skip_linux and target.os.tag == .linux) continue; | |
| 3475 | ||
| 3476 | if (options.skip_llvm and test_target.backend == .llvm) continue; | |
| 3477 | ||
| 3478 | const target_str = b.fmt("{s}-{t}", .{ | |
| 3479 | resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"), | |
| 3480 | test_target.backend, | |
| 3481 | }); | |
| 3482 | ||
| 3483 | if (options.test_target_filters.len > 0) { | |
| 3484 | for (options.test_target_filters) |filter| { | |
| 3485 | if (std.mem.find(u8, target_str, filter) != null) break; | |
| 3486 | } else continue; | |
| 3487 | } | |
| 3488 | ||
| 3489 | const run = b.addRunArtifact(runner); | |
| 3490 | run.setName(@"test".name); | |
| 3491 | run.enableProtocolMode(); | |
| 3492 | ||
| 3493 | switch (@"test".kind) { | |
| 3494 | else => continue, | |
| 3495 | .file => run.addFileArg(test_path), | |
| 3496 | .directory => run.addDirectoryArg(test_path), | |
| 3497 | } | |
| 3498 | run.addPrefixedFileArg("--zig=", .zig_exe); | |
| 3499 | run.addPrefixedDirectoryArg("--lib=", .zig_lib); | |
| 3500 | _ = run.addPrefixedOutputDirectoryArg("--src=", "src"); | |
| 3501 | run.addArgs(&.{ "--target", target_str }); | |
| 3502 | ||
| 3503 | run.addArg("--quiet"); // don't fill stderr telling us about skipped tests etc | |
| 3504 | ||
| 3505 | run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" }); | |
| 3506 | run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" }); | |
| 3507 | run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" }); | |
| 3508 | run.addThirdPartyEnabledArgWasmtime(.{ .enabled = "-fwasmtime" }); | |
| 3509 | run.addThirdPartyEnabledArgWine(.{ .enabled = "-fwine" }); | |
| 3510 | ||
| 3511 | tests_step.dependOn(&run.step); | |
| 3512 | } | |
| 3513 | } | |
| 3514 | ||
| 3515 | return tests_step; | |
| 3516 | } | |
| 3517 | ||
| 3518 | fn isEditorFileName(name: []const u8) bool { | |
| 3519 | return (std.mem.startsWith(u8, name, "#") and std.mem.endsWith(u8, name, "#")) or | |
| 3520 | std.mem.endsWith(u8, name, "~") or std.mem.endsWith(u8, name, ".swp"); | |
| 3521 | } | |
| 3522 | ||
| 3438 | 3523 | pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step { |
| 3439 | 3524 | const step = b.step("test-llvm-ir", "Run the LLVM IR tests"); |
| 3440 | 3525 |
tools/runner-check.zig created+151| ... | ... | @@ -0,0 +1,151 @@ |
| 1 | const std = @import("std"); | |
| 2 | pub fn main(init: std.process.Init) !void { | |
| 3 | const arena = init.arena.allocator(); | |
| 4 | ||
| 5 | var test_path_arg: ?[]const u8 = null; | |
| 6 | var zig_path_arg: ?[]const u8 = null; | |
| 7 | var lib_path_arg: ?[]const u8 = null; | |
| 8 | var keep_src = false; | |
| 9 | ||
| 10 | var arg_it = try init.minimal.args.iterateAllocator(arena); | |
| 11 | std.debug.assert(arg_it.skip()); | |
| 12 | while (arg_it.next()) |arg| { | |
| 13 | if (std.mem.eql(u8, arg, "--zig")) { | |
| 14 | zig_path_arg = arg_it.next() orelse fail("missing arg after '{s}'", .{arg}); | |
| 15 | } else if (std.mem.cutPrefix(u8, arg, "--zig=")) |zig_path| { | |
| 16 | zig_path_arg = zig_path; | |
| 17 | } else if (std.mem.eql(u8, arg, "--lib")) { | |
| 18 | lib_path_arg = arg_it.next() orelse fail("missing arg after '{s}'", .{arg}); | |
| 19 | } else if (std.mem.cutPrefix(u8, arg, "--lib=")) |lib_path| { | |
| 20 | lib_path_arg = lib_path; | |
| 21 | } else if (std.mem.eql(u8, arg, "--keep-src")) { | |
| 22 | keep_src = true; | |
| 23 | } else { | |
| 24 | if (test_path_arg) |_| fail("unknown arg '{s}'", .{arg}); | |
| 25 | test_path_arg = arg; | |
| 26 | } | |
| 27 | } | |
| 28 | ||
| 29 | const test_path = test_path_arg orelse fail("missing 'path/to/test'", .{}); | |
| 30 | const zig_path = zig_path_arg orelse fail("missing '--zig=path/to/zig'", .{}); | |
| 31 | const lib_path = lib_path_arg orelse fail("missing '--lib=path/to/lib'", .{}); | |
| 32 | ||
| 33 | const test_file = try std.Io.Dir.cwd().openFile(init.io, test_path, .{ | |
| 34 | .allow_directory = true, | |
| 35 | }); | |
| 36 | const zig_file = try std.Io.Dir.cwd().openFile(init.io, zig_path, .{}); | |
| 37 | defer zig_file.close(init.io); | |
| 38 | const lib_dir = try std.Io.Dir.cwd().openDir(init.io, lib_path, .{}); | |
| 39 | defer lib_dir.close(init.io); | |
| 40 | ||
| 41 | const src_dir_path = "src_" ++ std.fmt.hex(rand_int: { | |
| 42 | var rand_int: u64 = undefined; | |
| 43 | init.io.random(@ptrCast(&rand_int)); | |
| 44 | break :rand_int rand_int; | |
| 45 | }); | |
| 46 | var src_dir = try std.Io.Dir.cwd().createDirPathOpen(init.io, src_dir_path, .{}); | |
| 47 | defer { | |
| 48 | src_dir.close(init.io); | |
| 49 | if (!keep_src) std.Io.Dir.cwd().deleteTree(init.io, src_dir_path) catch |err| { | |
| 50 | std.log.warn("failed to delete tree '{s}': {t}", .{ src_dir_path, err }); | |
| 51 | }; | |
| 52 | } | |
| 53 | ||
| 54 | var child = try std.process.spawn(init.io, .{ | |
| 55 | .argv = &.{ | |
| 56 | zig_path, | |
| 57 | "run", | |
| 58 | try std.fs.path.resolveAlloc(arena, &.{ lib_path, "..", "test", "src", "runner.zig" }), | |
| 59 | }, | |
| 60 | .stdin = .pipe, | |
| 61 | .stdout = .pipe, | |
| 62 | .inherit_dirs = &.{ lib_dir, src_dir }, | |
| 63 | .inherit_files = &.{ zig_file, test_file }, | |
| 64 | }); | |
| 65 | ||
| 66 | var stdout_buffer: [512]u8 = undefined; | |
| 67 | var stdout_reader = child.stdout.?.readerStreaming(init.io, &stdout_buffer); | |
| 68 | var stdin_buffer: [512]u8 = undefined; | |
| 69 | var stdin_writer = child.stdin.?.writerStreaming(init.io, &stdin_buffer); | |
| 70 | var client: std.zig.Client = .{ | |
| 71 | .in = &stdout_reader.interface, | |
| 72 | .out = &stdin_writer.interface, | |
| 73 | }; | |
| 74 | { | |
| 75 | const Arg = std.zig.Client.Message.Arg; | |
| 76 | var args: std.ArrayList(u8) = .initBuffer(try arena.alloc(u8, 0 + | |
| 77 | @sizeOf(Arg) + @sizeOf(std.Io.File.Handle) + | |
| 78 | @sizeOf(Arg) + "--zig=\x00".len + | |
| 79 | @sizeOf(Arg) + @sizeOf(std.Io.File.Handle) + | |
| 80 | @sizeOf(Arg) + "--lib=\x00".len + | |
| 81 | @sizeOf(Arg) + @sizeOf(std.Io.Dir.Handle) + | |
| 82 | @sizeOf(Arg) + "--src=\x00".len + | |
| 83 | @sizeOf(Arg) + @sizeOf(std.Io.Dir.Handle))); | |
| 84 | ||
| 85 | args.appendAssumeCapacity(@backingInt(@as(Arg, switch ((try test_file.stat(init.io)).kind) { | |
| 86 | else => unreachable, | |
| 87 | .file => .input_file, | |
| 88 | .directory => .input_dir, | |
| 89 | }))); | |
| 90 | args.appendSliceAssumeCapacity(@ptrCast(&test_file.handle)); | |
| 91 | ||
| 92 | args.appendAssumeCapacity(@backingInt(Arg.prefix)); | |
| 93 | args.appendSliceAssumeCapacity("--zig="); | |
| 94 | args.appendAssumeCapacity(0); | |
| 95 | ||
| 96 | args.appendAssumeCapacity(@backingInt(Arg.input_file)); | |
| 97 | args.appendSliceAssumeCapacity(@ptrCast(&zig_file.handle)); | |
| 98 | ||
| 99 | args.appendAssumeCapacity(@backingInt(Arg.prefix)); | |
| 100 | args.appendSliceAssumeCapacity("--lib="); | |
| 101 | args.appendAssumeCapacity(0); | |
| 102 | ||
| 103 | args.appendAssumeCapacity(@backingInt(Arg.input_dir)); | |
| 104 | args.appendSliceAssumeCapacity(@ptrCast(&lib_dir.handle)); | |
| 105 | ||
| 106 | args.appendAssumeCapacity(@backingInt(Arg.prefix)); | |
| 107 | args.appendSliceAssumeCapacity("--src="); | |
| 108 | args.appendAssumeCapacity(0); | |
| 109 | ||
| 110 | args.appendAssumeCapacity(@backingInt(Arg.output_dir)); | |
| 111 | args.appendSliceAssumeCapacity(@ptrCast(&src_dir.handle)); | |
| 112 | ||
| 113 | std.debug.assert(args.unusedCapacitySlice().len == 0); | |
| 114 | ||
| 115 | try client.serveMessageHeader(.{ | |
| 116 | .tag = .args, | |
| 117 | .bytes_len = @intCast(args.items.len), | |
| 118 | }); | |
| 119 | try client.out.writeAll(args.items); | |
| 120 | ||
| 121 | try client.serveBodylessMessage(.query_test_metadata); | |
| 122 | while (true) { | |
| 123 | const hdr = try client.receiveMessage(); | |
| 124 | switch (hdr.tag) { | |
| 125 | else => try client.in.discardAll(hdr.bytes_len), | |
| 126 | .zig_version => { | |
| 127 | const body = try arena.alloc(u8, hdr.bytes_len); | |
| 128 | try client.in.readSliceAll(body); | |
| 129 | if (!std.mem.eql(u8, @import("builtin").zig_version_string, body)) return fail( | |
| 130 | "zig version mismatch build runner vs compiler: '{s}' vs '{s}'", | |
| 131 | .{ @import("builtin").zig_version_string, body }, | |
| 132 | ); | |
| 133 | }, | |
| 134 | .test_metadata => { | |
| 135 | try client.in.discardAll(hdr.bytes_len); | |
| 136 | try client.serveRunTest(0); | |
| 137 | }, | |
| 138 | .test_results => { | |
| 139 | try client.in.discardAll(hdr.bytes_len); | |
| 140 | break; | |
| 141 | }, | |
| 142 | } | |
| 143 | } | |
| 144 | try client.serveBodylessMessage(.exit); | |
| 145 | } | |
| 146 | _ = try child.wait(init.io); | |
| 147 | } | |
| 148 | fn fail(comptime fmt: []const u8, args: anytype) noreturn { | |
| 149 | std.log.err(fmt, args); | |
| 150 | std.process.exit(1); | |
| 151 | } |