| ... | @@ -8,8 +8,24 @@ const Args = struct { | ... | @@ -8,8 +8,24 @@ const Args = struct { |
| 8 | zig_file: ?std.Io.File, | 8 | zig_file: ?std.Io.File, |
| 9 | lib_dir: ?std.Io.Dir, | 9 | lib_dir: ?std.Io.Dir, |
| 10 | src_dir: ?std.Io.Dir, | 10 | src_dir: ?std.Io.Dir, |
| | 11 | targets: std.ArrayList(u32), |
| | 12 | target_bytes: std.ArrayList(u8), |
| | 13 | |
| | 14 | fn deinit(args: *Args, gpa: std.mem.Allocator) void { |
| | 15 | args.targets.deinit(gpa); |
| | 16 | args.target_bytes.deinit(gpa); |
| | 17 | } |
| | 18 | |
| | 19 | fn addTarget(args: *Args, gpa: std.mem.Allocator, target: []const u8) std.mem.Allocator.Error!void { |
| | 20 | try args.target_bytes.ensureUnusedCapacity(gpa, target.len + 1); |
| | 21 | try args.targets.append(gpa, @intCast(args.target_bytes.items.len)); |
| | 22 | args.target_bytes.appendSliceAssumeCapacity(target); |
| | 23 | args.target_bytes.appendAssumeCapacity(0); |
| | 24 | } |
| 11 | }; | 25 | }; |
| 12 | pub fn main(init: std.process.Init) !void { | 26 | pub fn main(init: std.process.Init) !void { |
| | 27 | const arena = init.arena.allocator(); |
| | 28 | |
| 13 | var stdin_buffer: [512]u8 = undefined; | 29 | var stdin_buffer: [512]u8 = undefined; |
| 14 | var stdout_buffer: [512]u8 = undefined; | 30 | var stdout_buffer: [512]u8 = undefined; |
| 15 | var stderr_buffer: [512]u8 = undefined; | 31 | var stderr_buffer: [512]u8 = undefined; |
| ... | @@ -20,14 +36,19 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -20,14 +36,19 @@ pub fn main(init: std.process.Init) !void { |
| 20 | .in = &stdin.interface, | 36 | .in = &stdin.interface, |
| 21 | .out = &stdout.interface, | 37 | .out = &stdout.interface, |
| 22 | }; | 38 | }; |
| 23 | try server.serveStringMessage(.zig_version, @import("builtin").zig_version_string); | 39 | |
| 24 | var args: Args = .{ | 40 | var args: Args = .{ |
| 25 | .@"test" = null, | 41 | .@"test" = null, |
| 26 | .manifest_file = null, | 42 | .manifest_file = null, |
| 27 | .zig_file = null, | 43 | .zig_file = null, |
| 28 | .lib_dir = null, | 44 | .lib_dir = null, |
| 29 | .src_dir = null, | 45 | .src_dir = null, |
| | 46 | .targets = .empty, |
| | 47 | .target_bytes = .empty, |
| 30 | }; | 48 | }; |
| | 49 | defer args.deinit(init.gpa); |
| | 50 | |
| | 51 | try server.serveStringMessage(.zig_version, @import("builtin").zig_version_string); |
| 31 | while (true) { | 52 | while (true) { |
| 32 | const hdr = try server.receiveMessage(); | 53 | const hdr = try server.receiveMessage(); |
| 33 | switch (hdr.tag) { | 54 | switch (hdr.tag) { |
| ... | @@ -35,13 +56,11 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -35,13 +56,11 @@ pub fn main(init: std.process.Init) !void { |
| 35 | std.debug.print("unsupported message: {t}\n", .{hdr.tag}); | 56 | std.debug.print("unsupported message: {t}\n", .{hdr.tag}); |
| 36 | std.process.exit(1); | 57 | std.process.exit(1); |
| 37 | }, | 58 | }, |
| 38 | .exit => { | 59 | .exit => std.process.exit(0), |
| 39 | std.process.exit(0); | | |
| 40 | }, | | |
| 41 | .args => { | 60 | .args => { |
| 42 | const args_body = try init.arena.allocator().alloc(u8, hdr.bytes_len); | 61 | const args_body = try arena.alloc(u8, hdr.bytes_len); |
| 43 | try server.in.readSliceAll(args_body); | 62 | try server.in.readSliceAll(args_body); |
| 44 | var state: enum { positional, zig, lib, src } = .positional; | 63 | var state: enum { positional, zig, lib, src, target } = .positional; |
| 45 | var input_dir: std.zig.Server.Message.InputDir = .cwd; | 64 | var input_dir: std.zig.Server.Message.InputDir = .cwd; |
| 46 | var args_body_offset: usize = 0; | 65 | var args_body_offset: usize = 0; |
| 47 | while (args_body.len - args_body_offset > 0) { | 66 | while (args_body.len - args_body_offset > 0) { |
| ... | @@ -53,7 +72,18 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -53,7 +72,18 @@ pub fn main(init: std.process.Init) !void { |
| 53 | const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; | 72 | const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; |
| 54 | const string = args_body[args_body_offset..end]; | 73 | const string = args_body[args_body_offset..end]; |
| 55 | args_body_offset = end + 1; | 74 | args_body_offset = end + 1; |
| 56 | _ = string; | 75 | switch (state) { |
| | 76 | .positional => if (std.mem.eql(u8, string, "--target")) { |
| | 77 | state = .target; |
| | 78 | continue; |
| | 79 | } else if (std.mem.cutPrefix(u8, string, "--target=")) |target| { |
| | 80 | try args.addTarget(init.gpa, target); |
| | 81 | }, |
| | 82 | .zig => unreachable, |
| | 83 | .lib => unreachable, |
| | 84 | .src => unreachable, |
| | 85 | .target => try args.addTarget(init.gpa, string), |
| | 86 | } |
| 57 | }, | 87 | }, |
| 58 | .prefix => { | 88 | .prefix => { |
| 59 | const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; | 89 | const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; |
| ... | @@ -109,6 +139,7 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -109,6 +139,7 @@ pub fn main(init: std.process.Init) !void { |
| 109 | std.debug.assert(args.src_dir == null); | 139 | std.debug.assert(args.src_dir == null); |
| 110 | args.src_dir = dir; | 140 | args.src_dir = dir; |
| 111 | }, | 141 | }, |
| | 142 | .target => unreachable, |
| 112 | } | 143 | } |
| 113 | }, | 144 | }, |
| 114 | .input_file, .input_file_content, .output_file => { | 145 | .input_file, .input_file_content, .output_file => { |
| ... | @@ -129,22 +160,30 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -129,22 +160,30 @@ pub fn main(init: std.process.Init) !void { |
| 129 | std.debug.assert(args.zig_file == null); | 160 | std.debug.assert(args.zig_file == null); |
| 130 | args.zig_file = file; | 161 | args.zig_file = file; |
| 131 | }, | 162 | }, |
| 132 | .lib, .src => unreachable, | 163 | .lib => unreachable, |
| | 164 | .src => unreachable, |
| | 165 | .target => unreachable, |
| 133 | } | 166 | } |
| 134 | }, | 167 | }, |
| 135 | } | 168 | } |
| 136 | state = .positional; | 169 | state = .positional; |
| 137 | } | 170 | } |
| 138 | }, | 171 | }, |
| 139 | .query_test_metadata => try server.serveTestMetadata(.{ | 172 | .query_test_metadata => { |
| 140 | .names = &.{0}, | 173 | const expected_panic_msgs = try arena.alloc(u32, args.targets.items.len); |
| 141 | .expected_panic_msgs = &.{0}, | 174 | @memset(expected_panic_msgs, 0); |
| 142 | .string_bytes = "runner\x00", | 175 | try server.serveTestMetadata(.{ |
| 143 | }), | 176 | .names = args.targets.items, |
| | 177 | .expected_panic_msgs = expected_panic_msgs, |
| | 178 | .string_bytes = args.target_bytes.items, |
| | 179 | }); |
| | 180 | }, |
| 144 | .run_test => { | 181 | .run_test => { |
| 145 | const test_index = try server.receiveBody_u32(); | 182 | const test_index = try server.receiveBody_u32(); |
| | 183 | const target = |
| | 184 | std.mem.sliceTo(args.target_bytes.items[args.targets.items[test_index]..], 0); |
| 146 | try server.serveBodylessMessage(.test_started); | 185 | try server.serveBodylessMessage(.test_started); |
| 147 | const test_result = runTest(init.io, &stderr.interface, &server, &args); | 186 | const test_result = runTest(init.io, &stderr.interface, &server, &args, target); |
| 148 | try stderr.flush(); | 187 | try stderr.flush(); |
| 149 | try server.serveTestResults(.{ | 188 | try server.serveTestResults(.{ |
| 150 | .index = test_index, | 189 | .index = test_index, |
| ... | @@ -170,11 +209,13 @@ fn runTest( | ... | @@ -170,11 +209,13 @@ fn runTest( |
| 170 | stderr: *std.Io.Writer, | 209 | stderr: *std.Io.Writer, |
| 171 | server: *std.zig.Server, | 210 | server: *std.zig.Server, |
| 172 | args: *const Args, | 211 | args: *const Args, |
| 173 | ) anyerror!void { | 212 | target: []const u8, |
| | 213 | ) !void { |
| 174 | const manifest_file = args.manifest_file orelse return error.MissingManifestArg; | 214 | const manifest_file = args.manifest_file orelse return error.MissingManifestArg; |
| 175 | const src_dir = args.src_dir orelse return error.MissingSrcDir; | 215 | const src_dir = args.src_dir orelse return error.MissingSrcDir; |
| 176 | var manifest_buffer: [512]u8 = undefined; | 216 | var manifest_buffer: [512]u8 = undefined; |
| 177 | var manifest_fr = manifest_file.reader(io, &manifest_buffer); | 217 | var manifest_fr = manifest_file.reader(io, &manifest_buffer); |
| | 218 | var allow_skip = true; |
| 178 | var skip_delimiter = false; | 219 | var skip_delimiter = false; |
| 179 | var update_mtime = std.Io.Clock.real.now(io); | 220 | var update_mtime = std.Io.Clock.real.now(io); |
| 180 | var update_num: usize = 0; | 221 | var update_num: usize = 0; |
| ... | @@ -188,7 +229,7 @@ fn runTest( | ... | @@ -188,7 +229,7 @@ fn runTest( |
| 188 | continue; | 229 | continue; |
| 189 | } | 230 | } |
| 190 | const cmd = std.meta.stringToEnum( | 231 | const cmd = std.meta.stringToEnum( |
| 191 | enum { obj, exe, lib, write, delete, update, check }, | 232 | enum { skip, obj, exe, lib, write, delete, update, check }, |
| 192 | cmd_str, | 233 | cmd_str, |
| 193 | ) orelse return error.UnknownCommand; | 234 | ) orelse return error.UnknownCommand; |
| 194 | var maybe_arg = line_it.next(); | 235 | var maybe_arg = line_it.next(); |
| ... | @@ -198,38 +239,40 @@ fn runTest( | ... | @@ -198,38 +239,40 @@ fn runTest( |
| 198 | dr: DelimitedReader, | 239 | dr: DelimitedReader, |
| 199 | fr: std.Io.File.Reader, | 240 | fr: std.Io.File.Reader, |
| 200 | } = undefined; | 241 | } = undefined; |
| 201 | const contents_r: *std.Io.Reader = contents_r: { | 242 | const contents_r: *std.Io.Reader = contents_r: switch (cmd) { |
| 202 | switch (cmd) { | 243 | .skip, .delete => { |
| 203 | else => {}, | 244 | if (line_it.next()) |_| return error.UnexpectedArg; |
| 204 | .delete => break :contents_r .ending, | 245 | break :contents_r .ending; |
| 205 | } | 246 | }, |
| 206 | | 247 | else => { |
| 207 | const contents_path = contents_path: { | 248 | const contents_path = contents_path: { |
| 208 | const line_rest = line_it.rest(); | 249 | const line_rest = line_it.rest(); |
| 209 | if (line_rest.len > 0) break :contents_path line_rest; | 250 | if (line_rest.len > 0) break :contents_path line_rest; |
| 210 | const contents_path = maybe_arg orelse break :contents_r .ending; | 251 | const contents_path = maybe_arg orelse break :contents_r .ending; |
| 211 | maybe_arg = null; | 252 | maybe_arg = null; |
| 212 | break :contents_path contents_path; | 253 | break :contents_path contents_path; |
| 213 | }; | 254 | }; |
| 214 | if (std.mem.eql(u8, contents_path, "{")) { | 255 | if (std.mem.eql(u8, contents_path, "{")) { |
| 215 | contents_impl = .{ .dr = .init(&manifest_fr.interface, "#}", &.{}) }; | 256 | contents_impl = .{ .dr = .init(&manifest_fr.interface, "#}", &.{}) }; |
| 216 | skip_delimiter = true; | 257 | skip_delimiter = true; |
| 217 | break :contents_r &contents_impl.dr.interface; | 258 | break :contents_r &contents_impl.dr.interface; |
| 218 | } | 259 | } |
| 219 | | 260 | |
| 220 | const @"test" = args.@"test" orelse return error.ContentsFileInFileTest; | 261 | const @"test" = args.@"test" orelse return error.ContentsFileInFileTest; |
| 221 | try server.serveMessageHeader(.{ | 262 | try server.serveMessageHeader(.{ |
| 222 | .tag = .discovered_inputs, | 263 | .tag = .discovered_inputs, |
| 223 | .bytes_len = @intCast(@sizeOf(std.zig.Server.Message.InputDir) + contents_path.len + 1), | 264 | .bytes_len = @intCast(@sizeOf(std.zig.Server.Message.InputDir) + |
| 224 | }); | 265 | contents_path.len + 1), |
| 225 | try server.out.writeInt(u32, @backingInt(@"test".input_dir), .little); | 266 | }); |
| 226 | try server.out.writeAll(contents_path); | 267 | try server.out.writeInt(u32, @backingInt(@"test".input_dir), .little); |
| 227 | try server.out.writeByte(0); | 268 | try server.out.writeAll(contents_path); |
| 228 | try server.out.flush(); | 269 | try server.out.writeByte(0); |
| | 270 | try server.out.flush(); |
| 229 | | 271 | |
| 230 | contents_file = try @"test".dir.openFile(io, contents_path, .{}); | 272 | contents_file = try @"test".dir.openFile(io, contents_path, .{}); |
| 231 | contents_impl = .{ .fr = contents_file.?.reader(io, &.{}) }; | 273 | contents_impl = .{ .fr = contents_file.?.reader(io, &.{}) }; |
| 232 | break :contents_r &contents_impl.fr.interface; | 274 | break :contents_r &contents_impl.fr.interface; |
| | 275 | }, |
| 233 | }; | 276 | }; |
| 234 | switch (cmd) { | 277 | switch (cmd) { |
| 235 | else => { | 278 | else => { |
| ... | @@ -237,6 +280,10 @@ fn runTest( | ... | @@ -237,6 +280,10 @@ fn runTest( |
| 237 | _ = try contents_r.streamRemaining(stderr); | 280 | _ = try contents_r.streamRemaining(stderr); |
| 238 | try stderr.writeAll("\n}\n"); | 281 | try stderr.writeAll("\n}\n"); |
| 239 | }, | 282 | }, |
| | 283 | .skip => if (!allow_skip) |
| | 284 | return error.NonInitialSkipCommand // #skip must appear first |
| | 285 | else if (std.mem.eql(u8, target, maybe_arg orelse return error.MissingArg)) |
| | 286 | return error.SkipZigTest, |
| 240 | .write => { | 287 | .write => { |
| 241 | const file = try src_dir.createFile(io, maybe_arg orelse return error.MissingArg, .{}); | 288 | const file = try src_dir.createFile(io, maybe_arg orelse return error.MissingArg, .{}); |
| 242 | defer file.close(io); | 289 | defer file.close(io); |
| ... | @@ -262,6 +309,7 @@ fn runTest( | ... | @@ -262,6 +309,7 @@ fn runTest( |
| 262 | }, | 309 | }, |
| 263 | } | 310 | } |
| 264 | std.debug.assert(try contents_r.discardRemaining() == 0); | 311 | std.debug.assert(try contents_r.discardRemaining() == 0); |
| | 312 | if (cmd != .skip) allow_skip = false; |
| 265 | } else |err| switch (err) { | 313 | } else |err| switch (err) { |
| 266 | else => |e| return e, | 314 | else => |e| return e, |
| 267 | error.EndOfStream => if (skip_delimiter) return error.MissingDelimiter, | 315 | error.EndOfStream => if (skip_delimiter) return error.MissingDelimiter, |