| ... | ... | @@ -2,14 +2,41 @@ const std = @import("std"); |
| 2 | 2 | const fatal = std.process.fatal; |
| 3 | 3 | const Allocator = std.mem.Allocator; |
| 4 | 4 | |
| 5 | const usage = "usage: incr-check <zig binary path> <input file> [-fno-emit-bin] [--zig-lib-dir lib]"; |
| 6 | |
| 5 | 7 | pub fn main() !void { |
| 6 | 8 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 7 | 9 | defer arena_instance.deinit(); |
| 8 | 10 | const arena = arena_instance.allocator(); |
| 9 | 11 | |
| 10 | | const args = try std.process.argsAlloc(arena); |
| 11 | | const zig_exe = args[1]; |
| 12 | | const input_file_name = args[2]; |
| 12 | var opt_zig_exe: ?[]const u8 = null; |
| 13 | var opt_input_file_name: ?[]const u8 = null; |
| 14 | var opt_lib_dir: ?[]const u8 = null; |
| 15 | var no_bin = false; |
| 16 | |
| 17 | var arg_it = try std.process.argsWithAllocator(arena); |
| 18 | _ = arg_it.skip(); |
| 19 | while (arg_it.next()) |arg| { |
| 20 | if (arg.len > 0 and arg[0] == '-') { |
| 21 | if (std.mem.eql(u8, arg, "-fno-emit-bin")) { |
| 22 | no_bin = true; |
| 23 | } else if (std.mem.eql(u8, arg, "--zig-lib-dir")) { |
| 24 | opt_lib_dir = arg_it.next() orelse fatal("expected arg after '--zig-lib-dir'\n{s}", .{usage}); |
| 25 | } else { |
| 26 | fatal("unknown option '{s}'\n{s}", .{ arg, usage }); |
| 27 | } |
| 28 | continue; |
| 29 | } |
| 30 | if (opt_zig_exe == null) { |
| 31 | opt_zig_exe = arg; |
| 32 | } else if (opt_input_file_name == null) { |
| 33 | opt_input_file_name = arg; |
| 34 | } else { |
| 35 | fatal("unknown argument '{s}'\n{s}", .{ arg, usage }); |
| 36 | } |
| 37 | } |
| 38 | const zig_exe = opt_zig_exe orelse fatal("missing path to zig\n{s}", .{usage}); |
| 39 | const input_file_name = opt_input_file_name orelse fatal("missing input file\n{s}", .{usage}); |
| 13 | 40 | |
| 14 | 41 | const input_file_bytes = try std.fs.cwd().readFileAlloc(arena, input_file_name, std.math.maxInt(u32)); |
| 15 | 42 | const case = try Case.parse(arena, input_file_bytes); |
| ... | ... | @@ -24,13 +51,12 @@ pub fn main() !void { |
| 24 | 51 | const child_prog_node = prog_node.start("zig build-exe", 0); |
| 25 | 52 | defer child_prog_node.end(); |
| 26 | 53 | |
| 27 | | var child = std.process.Child.init(&.{ |
| 54 | var child_args: std.ArrayListUnmanaged([]const u8) = .{}; |
| 55 | try child_args.appendSlice(arena, &.{ |
| 28 | 56 | // Convert incr-check-relative path to subprocess-relative path. |
| 29 | 57 | try std.fs.path.relative(arena, tmp_dir_path, zig_exe), |
| 30 | 58 | "build-exe", |
| 31 | 59 | case.root_source_file, |
| 32 | | "-fno-llvm", |
| 33 | | "-fno-lld", |
| 34 | 60 | "-fincremental", |
| 35 | 61 | "-target", |
| 36 | 62 | case.target_query, |
| ... | ... | @@ -39,8 +65,17 @@ pub fn main() !void { |
| 39 | 65 | "--global-cache-dir", |
| 40 | 66 | ".global_cache", |
| 41 | 67 | "--listen=-", |
| 42 | | }, arena); |
| 68 | }); |
| 69 | if (opt_lib_dir) |lib_dir| { |
| 70 | try child_args.appendSlice(arena, &.{ "--zig-lib-dir", lib_dir }); |
| 71 | } |
| 72 | if (no_bin) { |
| 73 | try child_args.append(arena, "-fno-emit-bin"); |
| 74 | } else { |
| 75 | try child_args.appendSlice(arena, &.{ "-fno-llvm", "-fno-lld" }); |
| 76 | } |
| 43 | 77 | |
| 78 | var child = std.process.Child.init(child_args.items, arena); |
| 44 | 79 | child.stdin_behavior = .Pipe; |
| 45 | 80 | child.stdout_behavior = .Pipe; |
| 46 | 81 | child.stderr_behavior = .Pipe; |
| ... | ... | @@ -65,6 +100,8 @@ pub fn main() !void { |
| 65 | 100 | defer poller.deinit(); |
| 66 | 101 | |
| 67 | 102 | for (case.updates) |update| { |
| 103 | var update_node = prog_node.start(update.name, 0); |
| 104 | defer update_node.end(); |
| 68 | 105 | eval.write(update); |
| 69 | 106 | try eval.requestUpdate(); |
| 70 | 107 | try eval.check(&poller, update); |
| ... | ... | @@ -138,7 +175,17 @@ const Eval = struct { |
| 138 | 175 | const stderr_data = try stderr.toOwnedSlice(); |
| 139 | 176 | fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); |
| 140 | 177 | } |
| 141 | | try eval.checkErrorOutcome(update, result_error_bundle); |
| 178 | if (result_error_bundle.errorMessageCount() == 0) { |
| 179 | // Empty bundle indicates successful update in a `-fno-emit-bin` build. |
| 180 | // We can't do a full success check since we don't have a binary, but let's |
| 181 | // at least check that no errors were expected. |
| 182 | switch (update.outcome) { |
| 183 | .unknown, .stdout, .exit_code => {}, |
| 184 | .compile_errors => fatal("expected compile errors but compilation incorrectly succeeded", .{}), |
| 185 | } |
| 186 | } else { |
| 187 | try eval.checkErrorOutcome(update, result_error_bundle); |
| 188 | } |
| 142 | 189 | // This message indicates the end of the update. |
| 143 | 190 | stdout.discard(body.len); |
| 144 | 191 | return; |
| ... | ... | @@ -357,6 +404,11 @@ const Case = struct { |
| 357 | 404 | fatal("line {d}: bad string literal: {s}", .{ line_n, @errorName(err) }); |
| 358 | 405 | }, |
| 359 | 406 | }; |
| 407 | } else if (std.mem.eql(u8, key, "expect_error")) { |
| 408 | if (updates.items.len == 0) fatal("line {d}: expect directive before update", .{line_n}); |
| 409 | const last_update = &updates.items[updates.items.len - 1]; |
| 410 | if (last_update.outcome != .unknown) fatal("line {d}: conflicting expect directive", .{line_n}); |
| 411 | last_update.outcome = .{ .compile_errors = &.{} }; |
| 360 | 412 | } else { |
| 361 | 413 | fatal("line {d}: unrecognized key '{s}'", .{ line_n, key }); |
| 362 | 414 | } |