authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-14 01:28:28-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-26 19:08:50-04:00
logf63e8e802f5dc2aebe888c0051f685cab6b2571e
tree625df3909db9fdaf74cc21d481e0f16b67df3edf
parent11958a306f30268b17454a25bc365e67aad84efd

Build: implement discovered inputs


4 files changed, 372 insertions(+), 266 deletions(-)

lib/compiler/Maker/Step/Run.zig+310-252
...@@ -207,6 +207,7 @@ pub fn make(...@@ -207,6 +207,7 @@ pub fn make(
207 var owned_files: std.bit_set.Dynamic = .{};207 var owned_files: std.bit_set.Dynamic = .{};
208 var inherit_files: std.ArrayList(Io.File) = .empty;208 var inherit_files: std.ArrayList(Io.File) = .empty;
209 var protocol_args: std.ArrayList(u8) = .empty;209 var protocol_args: std.ArrayList(u8) = .empty;
210 var input_dirs: std.ArrayList(Cache.Path) = .empty;
210 defer {211 defer {
211 for (inherit_dirs.items, 0..) |inherit_dir, inherit_dir_index|212 for (inherit_dirs.items, 0..) |inherit_dir, inherit_dir_index|
212 if (owned_dirs.isSet(inherit_dir_index)) inherit_dir.close(io);213 if (owned_dirs.isSet(inherit_dir_index)) inherit_dir.close(io);
...@@ -217,6 +218,7 @@ pub fn make(...@@ -217,6 +218,7 @@ pub fn make(
217 owned_files.deinit(gpa);218 owned_files.deinit(gpa);
218 inherit_files.deinit(gpa);219 inherit_files.deinit(gpa);
219 protocol_args.deinit(gpa);220 protocol_args.deinit(gpa);
221 input_dirs.deinit(gpa);
220 }222 }
221 switch (conf_run.flags.stdio) {223 switch (conf_run.flags.stdio) {
222 .infer_from_args, .inherit, .check => {},224 .infer_from_args, .inherit, .check => {},
...@@ -228,257 +230,264 @@ pub fn make(...@@ -228,257 +230,264 @@ pub fn make(
228 argv_list.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{graph.random_seed}));230 argv_list.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{graph.random_seed}));
229 argv_list.appendAssumeCapacity("--listen=-");231 argv_list.appendAssumeCapacity("--listen=-");
230 },232 },
231 .protocol => for (conf_run.args.slice[1..]) |arg_index| {233 .protocol => {
232 const arg = arg_index.get(conf);234 try input_dirs.append(gpa, if (conf_run.cwd.value) |lazy_cwd|
233 switch (arg.flags.tag) {235 try maker.resolveLazyPathIndex(arena, lazy_cwd, run_index)
234 .string => {236 else
235 const string = arg.prefix.value.?.slice(conf);237 .cwd());
236238 for (conf_run.args.slice[1..]) |arg_index| {
237 man.hash.addBytesZ(string);239 const arg = arg_index.get(conf);
238240 switch (arg.flags.tag) {
239 try protocol_args.ensureUnusedCapacity(gpa, 1 + string.len + 1);241 .string => {
240 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));242 const string = arg.prefix.value.?.slice(conf);
241 protocol_args.appendSliceAssumeCapacity(string);243
242 protocol_args.appendAssumeCapacity(0);244 man.hash.addBytesZ(string);
243 },245
244 .path_file => {246 try protocol_args.ensureUnusedCapacity(gpa, 1 + string.len + 1);
245 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";247 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));
246 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";248 protocol_args.appendSliceAssumeCapacity(string);
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);249 protocol_args.appendAssumeCapacity(0);
445 }250 },
446 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_dir));251 .path_file => {
447252 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
448 // Add a placeholder into the argument list because we need the253 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
449 // manifest hash to be updated with all arguments before the254 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
450 // object directory is computed.255
451 try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, false);256 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
452 try inherit_dirs.ensureUnusedCapacity(gpa, 1);257 try inherit_files.ensureUnusedCapacity(gpa, 1);
453 try output_placeholders.append(gpa, .{258 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
454 .index = @intCast(inherit_dirs.items.len),259 return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err });
455 .offset = @intCast(protocol_args.items.len),260 inherit_files.appendAssumeCapacity(file);
456 .arg_index = arg_index,261
457 });262 man.hash.addBytesZ(prefix);
458 _ = inherit_dirs.addOneAssumeCapacity();263 _ = try man.addInputPath(file_path, .{});
264 man.hash.addBytesZ(suffix);
265
266 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
267 1 + @sizeOf(Io.File.Handle) +
268 1 + suffix.len + 1);
269 if (prefix.len > 0) {
270 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
271 protocol_args.appendSliceAssumeCapacity(prefix);
272 protocol_args.appendAssumeCapacity(0);
273 }
274 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file));
275 const file_handle: *align(1) Io.File.Handle =
276 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
277 file_handle.* = file.handle;
278 if (suffix.len > 0) {
279 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
280 protocol_args.appendSliceAssumeCapacity(prefix);
281 protocol_args.appendAssumeCapacity(0);
282 }
283 },
284 .path_directory => {
285 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
286 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
287 const dir_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
288 try input_dirs.append(gpa, dir_path);
289
290 const has_sub_path = dir_path.sub_path.len > 0;
291 try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, has_sub_path);
292 try inherit_dirs.ensureUnusedCapacity(gpa, 1);
293 const dir = if (has_sub_path)
294 dir_path.root_dir.handle.openDir(io, dir_path.sub_path, .{
295 .iterate = true,
296 }) catch |err| return step.fail(maker, "unable to open input dir {qf}: {t}", .{ dir_path, err })
297 else
298 dir_path.root_dir.handle;
299 inherit_dirs.appendAssumeCapacity(dir);
300
301 man.hash.addBytesZ(prefix);
302 man.hash.addOptionalBytes(dir_path.root_dir.path);
303 man.hash.addBytes(dir_path.sub_path);
304 man.hash.addBytesZ(suffix);
305
306 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
307 1 + @sizeOf(Io.Dir.Handle) +
308 1 + suffix.len + 1);
309 if (prefix.len > 0) {
310 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
311 protocol_args.appendSliceAssumeCapacity(prefix);
312 protocol_args.appendAssumeCapacity(0);
313 }
314 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_dir));
315 const dir_handle: *align(1) Io.Dir.Handle =
316 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle)));
317 dir_handle.* = dir.handle;
318 if (suffix.len > 0) {
319 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
320 protocol_args.appendSliceAssumeCapacity(prefix);
321 protocol_args.appendAssumeCapacity(0);
322 }
323 },
324 .file_content => {
325 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
326 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
327 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
328
329 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
330 try inherit_files.ensureUnusedCapacity(gpa, 1);
331 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
332 return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err });
333 inherit_files.appendAssumeCapacity(file);
334
335 man.hash.addBytesZ(prefix);
336 _ = try man.addInputPath(file_path, .{});
337 man.hash.addBytesZ(suffix);
338
339 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
340 1 + @sizeOf(Io.File.Handle) +
341 1 + suffix.len + 1);
342 if (prefix.len > 0) {
343 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
344 protocol_args.appendSliceAssumeCapacity(prefix);
345 protocol_args.appendAssumeCapacity(0);
346 }
347 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file_content));
348 const file_handle: *align(1) Io.File.Handle =
349 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
350 file_handle.* = file.handle;
351 if (suffix.len > 0) {
352 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
353 protocol_args.appendSliceAssumeCapacity(prefix);
354 protocol_args.appendAssumeCapacity(0);
355 }
356 },
357 .artifact => {
358 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
359 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
360 const producer_index = arg.producer.value.?;
361 const producer_step = producer_index.ptr(conf);
362 const producer = producer_step.extended.get(conf.extra).compile;
363 const producer_make_comp_step = maker.stepByIndex(producer_index);
364 const producer_make_comp = &producer_make_comp_step.extended.compile;
365
366 const file_path = producer_make_comp.installed_path orelse
367 maker.generatedPath(producer.generated_bin.value.?);
368
369 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
370 try inherit_files.ensureUnusedCapacity(gpa, 1);
371 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
372 return step.fail(maker, "unable to open input artifact {qf}: {t}", .{ file_path, err });
373 inherit_files.appendAssumeCapacity(file);
374
375 man.hash.addBytesZ(prefix);
376 _ = try man.addInputPath(file_path, .{});
377 man.hash.addBytesZ(suffix);
378
379 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
380 1 + @sizeOf(Io.File.Handle) +
381 1 + suffix.len + 1);
382 if (prefix.len > 0) {
383 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
384 protocol_args.appendSliceAssumeCapacity(prefix);
385 protocol_args.appendAssumeCapacity(0);
386 }
387 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file));
388 const file_handle: *align(1) Io.File.Handle =
389 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
390 file_handle.* = file.handle;
391 if (suffix.len > 0) {
392 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
393 protocol_args.appendSliceAssumeCapacity(prefix);
394 protocol_args.appendAssumeCapacity(0);
395 }
396 },
397 .output_file => {
398 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
399 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
400 const basename = arg.basename.value.?.slice(conf);
401
402 man.hash.addBytesZ(prefix);
403 man.hash.addBytesZ(basename);
404 man.hash.addBytesZ(suffix);
405 assert(!arg.flags.dep_file);
406
407 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
408 1 + @sizeOf(Io.File.Handle) +
409 1 + suffix.len + 1);
410 if (prefix.len > 0) {
411 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
412 protocol_args.appendSliceAssumeCapacity(prefix);
413 protocol_args.appendAssumeCapacity(0);
414 }
415 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_file));
416
417 // Add a placeholder into the argument list because we need the
418 // manifest hash to be updated with all arguments before the
419 // object directory is computed.
420 try owned_files.resize(gpa, owned_files.bit_length + 1, false);
421 try inherit_files.ensureUnusedCapacity(gpa, 1);
422 try output_placeholders.append(gpa, .{
423 .index = @intCast(inherit_files.items.len),
424 .offset = @intCast(protocol_args.items.len),
425 .arg_index = arg_index,
426 });
427 _ = inherit_files.addOneAssumeCapacity();
459428
460 _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle));429 _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle));
461 if (suffix.len > 0) {430 if (suffix.len > 0) {
462 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));431 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
463 protocol_args.appendSliceAssumeCapacity(prefix);432 protocol_args.appendSliceAssumeCapacity(prefix);
464 protocol_args.appendAssumeCapacity(0);433 protocol_args.appendAssumeCapacity(0);
465 }434 }
466 },435 },
467 .passthru => if (maker.run_args) |run_args| {436 .output_directory => {
468 man.hash.addListOfBytes(run_args);437 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
438 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
439 const basename = arg.basename.value.?.slice(conf);
440
441 man.hash.addBytesZ(prefix);
442 man.hash.addBytesZ(basename);
443 man.hash.addBytesZ(suffix);
444 assert(!arg.flags.dep_file);
445
446 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
447 1 + @sizeOf(Io.Dir.Handle) +
448 1 + suffix.len + 1);
449 if (prefix.len > 0) {
450 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
451 protocol_args.appendSliceAssumeCapacity(prefix);
452 protocol_args.appendAssumeCapacity(0);
453 }
454 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_dir));
455
456 // Add a placeholder into the argument list because we need the
457 // manifest hash to be updated with all arguments before the
458 // object directory is computed.
459 try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, false);
460 try inherit_dirs.ensureUnusedCapacity(gpa, 1);
461 try output_placeholders.append(gpa, .{
462 .index = @intCast(inherit_dirs.items.len),
463 .offset = @intCast(protocol_args.items.len),
464 .arg_index = arg_index,
465 });
466 _ = inherit_dirs.addOneAssumeCapacity();
469467
470 for (run_args) |run_arg| {468 _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle));
471 try protocol_args.ensureUnusedCapacity(gpa, 1 + run_arg.len + 1);469 if (suffix.len > 0) {
472 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));470 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
473 protocol_args.appendSliceAssumeCapacity(run_arg);471 protocol_args.appendSliceAssumeCapacity(prefix);
474 protocol_args.appendAssumeCapacity(0);472 protocol_args.appendAssumeCapacity(0);
475 }473 }
476 },474 },
477 .enable_darling => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value),475 .passthru => if (maker.run_args) |run_args| {
478 .enable_qemu => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value),476 man.hash.addListOfBytes(run_args);
479 .enable_rosetta => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value),477
480 .enable_wasmtime => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value),478 for (run_args) |run_arg| {
481 .enable_wine => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value),479 try protocol_args.ensureUnusedCapacity(gpa, 1 + run_arg.len + 1);
480 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));
481 protocol_args.appendSliceAssumeCapacity(run_arg);
482 protocol_args.appendAssumeCapacity(0);
483 }
484 },
485 .enable_darling => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value),
486 .enable_qemu => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value),
487 .enable_rosetta => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value),
488 .enable_wasmtime => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value),
489 .enable_wine => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value),
490 }
482 }491 }
483 },492 },
484 }493 }
...@@ -561,7 +570,7 @@ pub fn make(...@@ -561,7 +570,7 @@ pub fn make(
561 .args = protocol_args.items,570 .args = protocol_args.items,
562 } },571 } },
563 });572 });
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);573 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, &.{}, &.{}, &.{}, &.{}, null, has_side_effects, output_dir_path, null);
565 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);574 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);
566 return;575 return;
567 }576 }
...@@ -581,7 +590,22 @@ pub fn make(...@@ -581,7 +590,22 @@ pub fn make(
581 .args = protocol_args.items,590 .args = protocol_args.items,
582 } },591 } },
583 });592 });
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);593 try runCommand(
594 arena,
595 run,
596 run_index,
597 maker,
598 progress_node,
599 argv_list.items,
600 inherit_dirs.items,
601 inherit_files.items,
602 protocol_args.items,
603 input_dirs.items,
604 &man,
605 has_side_effects,
606 tmp_dir_path,
607 null,
608 );
585609
586 for (output_placeholders.items) |placeholder| {610 for (output_placeholders.items) |placeholder| {
587 const arg = placeholder.arg_index.get(conf);611 const arg = placeholder.arg_index.get(conf);
...@@ -720,6 +744,8 @@ fn waitZigTest(...@@ -720,6 +744,8 @@ fn waitZigTest(
720 child: *process.Child,744 child: *process.Child,
721 progress_node: std.Progress.Node,745 progress_node: std.Progress.Node,
722 protocol_args: []const u8,746 protocol_args: []const u8,
747 input_dirs: []const Cache.Path,
748 man: ?*Cache.Manifest,
723 multi_reader: *Io.File.MultiReader,749 multi_reader: *Io.File.MultiReader,
724 opt_metadata: *?TestMetadata,750 opt_metadata: *?TestMetadata,
725 results: *Step.TestResults,751 results: *Step.TestResults,
...@@ -900,6 +926,16 @@ fn waitZigTest(...@@ -900,6 +926,16 @@ fn waitZigTest(
900926
901 requestNextTest(&client, md, &sub_prog_node) catch |err| return .{ .write_failed = err };927 requestNextTest(&client, md, &sub_prog_node) catch |err| return .{ .write_failed = err };
902 },928 },
929 .discovered_inputs => while (body_r.takeEnum(
930 std.zig.Server.Message.InputDir,
931 .little,
932 )) |input_dir| try man.?.addDiscoveredPath(.{ .discovered_path = .{
933 .unresolved = try input_dirs[@backingInt(input_dir)]
934 .join(arena, try body_r.takeSentinel(0)),
935 } }) else |err| switch (err) {
936 else => |e| return e,
937 error.EndOfStream => {},
938 },
903 }939 }
904 }940 }
905}941}
...@@ -1463,6 +1499,8 @@ fn evalZigTest(...@@ -1463,6 +1499,8 @@ fn evalZigTest(
1463 progress_node: std.Progress.Node,1499 progress_node: std.Progress.Node,
1464 spawn_options: process.SpawnOptions,1500 spawn_options: process.SpawnOptions,
1465 protocol_args: []const u8,1501 protocol_args: []const u8,
1502 input_dirs: []const Cache.Path,
1503 man: ?*Cache.Manifest,
1466 fuzz_context: ?FuzzContext,1504 fuzz_context: ?FuzzContext,
1467) !void {1505) !void {
1468 if (fuzz_context != null) {1506 if (fuzz_context != null) {
...@@ -1512,6 +1550,8 @@ fn evalZigTest(...@@ -1512,6 +1550,8 @@ fn evalZigTest(
1512 &child,1550 &child,
1513 progress_node,1551 progress_node,
1514 protocol_args,1552 protocol_args,
1553 input_dirs,
1554 man,
1515 &multi_reader,1555 &multi_reader,
1516 &test_metadata,1556 &test_metadata,
1517 &test_results,1557 &test_results,
...@@ -1932,7 +1972,7 @@ pub fn rerunInFuzzMode(...@@ -1932,7 +1972,7 @@ pub fn rerunInFuzzMode(
1932 var rand_int: u64 = undefined;1972 var rand_int: u64 = undefined;
1933 io.random(@ptrCast(&rand_int));1973 io.random(@ptrCast(&rand_int));
1934 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);1974 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
1935 try runCommand(arena, run, run_index, maker, prog_node, argv_list.items, &.{}, &.{}, &.{}, has_side_effects, tmp_dir_path, .{1975 try runCommand(arena, run, run_index, maker, prog_node, argv_list.items, &.{}, &.{}, &.{}, &.{}, null, has_side_effects, tmp_dir_path, .{
1936 .fuzz = fuzz,1976 .fuzz = fuzz,
1937 });1977 });
1938}1978}
...@@ -2084,6 +2124,8 @@ fn runCommand(...@@ -2084,6 +2124,8 @@ fn runCommand(
2084 inherit_dirs: []const Io.Dir,2124 inherit_dirs: []const Io.Dir,
2085 inherit_files: []const Io.File,2125 inherit_files: []const Io.File,
2086 protocol_args: []const u8,2126 protocol_args: []const u8,
2127 input_dirs: []const Cache.Path,
2128 man: ?*Cache.Manifest,
2087 has_side_effects: bool,2129 has_side_effects: bool,
2088 output_dir_path: []const u8,2130 output_dir_path: []const u8,
2089 fuzz_context: ?FuzzContext,2131 fuzz_context: ?FuzzContext,
...@@ -2153,6 +2195,8 @@ fn runCommand(...@@ -2153,6 +2195,8 @@ fn runCommand(
2153 inherit_dirs,2195 inherit_dirs,
2154 inherit_files,2196 inherit_files,
2155 protocol_args,2197 protocol_args,
2198 input_dirs,
2199 man,
2156 has_side_effects,2200 has_side_effects,
2157 fuzz_context,2201 fuzz_context,
2158 ) catch |err| term: {2202 ) catch |err| term: {
...@@ -2308,6 +2352,8 @@ fn runCommand(...@@ -2308,6 +2352,8 @@ fn runCommand(
2308 inherit_dirs,2352 inherit_dirs,
2309 inherit_files,2353 inherit_files,
2310 protocol_args,2354 protocol_args,
2355 input_dirs,
2356 man,
2311 has_side_effects,2357 has_side_effects,
2312 fuzz_context,2358 fuzz_context,
2313 ) catch |e| {2359 ) catch |e| {
...@@ -2569,6 +2615,8 @@ fn spawnChildAndCollect(...@@ -2569,6 +2615,8 @@ fn spawnChildAndCollect(
2569 inherit_dirs: []const Io.Dir,2615 inherit_dirs: []const Io.Dir,
2570 inherit_files: []const Io.File,2616 inherit_files: []const Io.File,
2571 protocol_args: []const u8,2617 protocol_args: []const u8,
2618 input_dirs: []const Cache.Path,
2619 man: ?*Cache.Manifest,
2572 has_side_effects: bool,2620 has_side_effects: bool,
2573 fuzz_context: ?FuzzContext,2621 fuzz_context: ?FuzzContext,
2574) !?EvalGenericResult {2622) !?EvalGenericResult {
...@@ -2675,7 +2723,17 @@ fn spawnChildAndCollect(...@@ -2675,7 +2723,17 @@ fn spawnChildAndCollect(
2675 .zig_test, .protocol => {2723 .zig_test, .protocol => {
2676 try setColorEnvironmentVariables(&conf_run, environ_map, graph.stderr_mode.?);2724 try setColorEnvironmentVariables(&conf_run, environ_map, graph.stderr_mode.?);
2677 const started: Io.Clock.Timestamp = .now(io, .awake);2725 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) {2726 const result = evalZigTest(
2727 run,
2728 run_index,
2729 maker,
2730 progress_node,
2731 spawn_options,
2732 protocol_args,
2733 input_dirs,
2734 man,
2735 fuzz_context,
2736 ) catch |err| switch (err) {
2679 error.Canceled => |e| return e,2737 error.Canceled => |e| return e,
2680 else => |e| e,2738 else => |e| e,
2681 };2739 };
lib/std/zig/Client.zig+4-3
...@@ -60,6 +60,7 @@ pub const Message = struct {...@@ -60,6 +60,7 @@ pub const Message = struct {
60 start_fuzzing,60 start_fuzzing,
61 /// The message body has the same format as in Server.61 /// The message body has the same format as in Server.
62 new_fuzz_input,62 new_fuzz_input,
63 /// Body is a sequence of Arg
63 args,64 args,
6465
65 /// Asks the server to run a list of steps.66 /// Asks the server to run a list of steps.
...@@ -72,13 +73,13 @@ pub const Message = struct {...@@ -72,13 +73,13 @@ pub const Message = struct {
7273
73 pub const Arg = enum(u8) {74 pub const Arg = enum(u8) {
74 /// Trailing:75 /// Trailing:
75 /// * string: [:0]const u8,76 /// * string: [:0]u8,
76 string,77 string,
77 /// Trailing:78 /// Trailing:
78 /// * string: [:0]const u8,79 /// * string: [:0]u8,
79 prefix,80 prefix,
80 /// Trailing:81 /// Trailing:
81 /// * string: [:0]const u8,82 /// * string: [:0]u8,
82 suffix,83 suffix,
83 /// Trailing:84 /// Trailing:
84 /// * handle: Handle,85 /// * handle: Handle,
lib/std/zig/Server.zig+12
...@@ -74,6 +74,10 @@ pub const Message = struct {...@@ -74,6 +74,10 @@ pub const Message = struct {
74 broadcast_fuzz_input,74 broadcast_fuzz_input,
75 /// Body is a TimeReport.75 /// Body is a TimeReport.
76 time_report,76 time_report,
77 /// Body is a sequence of:
78 /// - root_dir: InputDir,
79 /// - sub_path: [:0]u8,
80 discovered_inputs,
7781
78 /// The first message sent by the server over the build system protocol.82 /// The first message sent by the server over the build system protocol.
79 /// Body is a `Handshake`.83 /// Body is a `Handshake`.
...@@ -212,6 +216,14 @@ pub const Message = struct {...@@ -212,6 +216,14 @@ pub const Message = struct {
212 reserved: u7 = 0,216 reserved: u7 = 0,
213 };217 };
214 };218 };
219
220 /// A reference to one of the `.input_dir`s from the `.args` message.
221 pub const InputDir = enum(u32) {
222 /// Server cwd relative path, or absolute path.
223 cwd,
224 /// Numbered in the order that `.input_dir`s appear in the `.args` message.
225 _,
226 };
215};227};
216228
217pub fn receiveMessage(s: *Server) !InMessage.Header {229pub fn receiveMessage(s: *Server) !InMessage.Header {
test/src/runner.zig+46-11
...@@ -1,6 +1,9 @@...@@ -1,6 +1,9 @@
1const std = @import("std");1const std = @import("std");
2const Args = struct {2const Args = struct {
3 test_dir: ?std.Io.Dir,3 @"test": ?struct {
4 input_dir: std.zig.Server.Message.InputDir,
5 dir: std.Io.Dir,
6 },
4 manifest_file: ?std.Io.File,7 manifest_file: ?std.Io.File,
5 zig_file: ?std.Io.File,8 zig_file: ?std.Io.File,
6 lib_dir: ?std.Io.Dir,9 lib_dir: ?std.Io.Dir,
...@@ -19,7 +22,7 @@ pub fn main(init: std.process.Init) !void {...@@ -19,7 +22,7 @@ pub fn main(init: std.process.Init) !void {
19 };22 };
20 try server.serveStringMessage(.zig_version, @import("builtin").zig_version_string);23 try server.serveStringMessage(.zig_version, @import("builtin").zig_version_string);
21 var args: Args = .{24 var args: Args = .{
22 .test_dir = null,25 .@"test" = null,
23 .manifest_file = null,26 .manifest_file = null,
24 .zig_file = null,27 .zig_file = null,
25 .lib_dir = null,28 .lib_dir = null,
...@@ -39,12 +42,13 @@ pub fn main(init: std.process.Init) !void {...@@ -39,12 +42,13 @@ pub fn main(init: std.process.Init) !void {
39 const args_body = try init.arena.allocator().alloc(u8, hdr.bytes_len);42 const args_body = try init.arena.allocator().alloc(u8, hdr.bytes_len);
40 try server.in.readSliceAll(args_body);43 try server.in.readSliceAll(args_body);
41 var state: enum { positional, zig, lib, src } = .positional;44 var state: enum { positional, zig, lib, src } = .positional;
45 var input_dir: std.zig.Server.Message.InputDir = .cwd;
42 var args_body_offset: usize = 0;46 var args_body_offset: usize = 0;
43 while (args_body.len - args_body_offset > 0) {47 while (args_body.len - args_body_offset > 0) {
44 const arg: std.zig.Client.Message.Arg =48 const arg: std.zig.Client.Message.Arg =
45 @fromBackingInt(args_body[args_body_offset]);49 @fromBackingInt(args_body[args_body_offset]);
46 args_body_offset += 1;50 args_body_offset += 1;
47 switch (arg) {51 arg: switch (arg) {
48 .string => {52 .string => {
49 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;53 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
50 const string = args_body[args_body_offset..end];54 const string = args_body[args_body_offset..end];
...@@ -66,7 +70,11 @@ pub fn main(init: std.process.Init) !void {...@@ -66,7 +70,11 @@ pub fn main(init: std.process.Init) !void {
66 continue;70 continue;
67 },71 },
68 .suffix => unreachable,72 .suffix => unreachable,
69 .input_dir, .output_dir => {73 .input_dir => {
74 input_dir = @fromBackingInt(@backingInt(input_dir) + 1);
75 continue :arg .output_dir;
76 },
77 .output_dir => {
70 const dir_handle: *align(1) const std.Io.Dir.Handle = @ptrCast(78 const dir_handle: *align(1) const std.Io.Dir.Handle = @ptrCast(
71 args_body[args_body_offset..][0..@sizeOf(std.Io.Dir.Handle)],79 args_body[args_body_offset..][0..@sizeOf(std.Io.Dir.Handle)],
72 );80 );
...@@ -76,10 +84,21 @@ pub fn main(init: std.process.Init) !void {...@@ -76,10 +84,21 @@ pub fn main(init: std.process.Init) !void {
76 };84 };
77 switch (state) {85 switch (state) {
78 .positional => {86 .positional => {
79 std.debug.assert(args.test_dir == null);87 std.debug.assert(args.@"test" == null);
80 args.test_dir = dir;88 args.@"test" = .{ .input_dir = input_dir, .dir = dir };
81 std.debug.assert(args.manifest_file == null);89 std.debug.assert(args.manifest_file == null);
82 args.manifest_file = try dir.openFile(init.io, "manifest", .{});90 const manifest_path = "manifest";
91 args.manifest_file = try dir.openFile(init.io, manifest_path, .{});
92
93 try server.serveMessageHeader(.{
94 .tag = .discovered_inputs,
95 .bytes_len = @sizeOf(std.zig.Server.Message.InputDir) +
96 manifest_path.len + 1,
97 });
98 try server.out.writeInt(u32, @backingInt(input_dir), .little);
99 try server.out.writeAll(manifest_path);
100 try server.out.writeByte(0);
101 try server.out.flush();
83 },102 },
84 .zig => unreachable,103 .zig => unreachable,
85 .lib => {104 .lib => {
...@@ -125,7 +144,7 @@ pub fn main(init: std.process.Init) !void {...@@ -125,7 +144,7 @@ pub fn main(init: std.process.Init) !void {
125 .run_test => {144 .run_test => {
126 const test_index = try server.receiveBody_u32();145 const test_index = try server.receiveBody_u32();
127 try server.serveBodylessMessage(.test_started);146 try server.serveBodylessMessage(.test_started);
128 const test_result = runTest(init.io, &stderr.interface, &args);147 const test_result = runTest(init.io, &stderr.interface, &server, &args);
129 try stderr.flush();148 try stderr.flush();
130 try server.serveTestResults(.{149 try server.serveTestResults(.{
131 .index = test_index,150 .index = test_index,
...@@ -146,7 +165,12 @@ pub fn main(init: std.process.Init) !void {...@@ -146,7 +165,12 @@ pub fn main(init: std.process.Init) !void {
146 }165 }
147 }166 }
148}167}
149fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void {168fn runTest(
169 io: std.Io,
170 stderr: *std.Io.Writer,
171 server: *std.zig.Server,
172 args: *const Args,
173) anyerror!void {
150 const manifest_file = args.manifest_file orelse return error.MissingManifestArg;174 const manifest_file = args.manifest_file orelse return error.MissingManifestArg;
151 const src_dir = args.src_dir orelse return error.MissingSrcDir;175 const src_dir = args.src_dir orelse return error.MissingSrcDir;
152 var manifest_buffer: [512]u8 = undefined;176 var manifest_buffer: [512]u8 = undefined;
...@@ -179,6 +203,7 @@ fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void...@@ -179,6 +203,7 @@ fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void
179 else => {},203 else => {},
180 .delete => break :contents_r .ending,204 .delete => break :contents_r .ending,
181 }205 }
206
182 const contents_path = contents_path: {207 const contents_path = contents_path: {
183 const line_rest = line_it.rest();208 const line_rest = line_it.rest();
184 if (line_rest.len > 0) break :contents_path line_rest;209 if (line_rest.len > 0) break :contents_path line_rest;
...@@ -191,8 +216,18 @@ fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void...@@ -191,8 +216,18 @@ fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void
191 skip_delimiter = true;216 skip_delimiter = true;
192 break :contents_r &contents_impl.dr.interface;217 break :contents_r &contents_impl.dr.interface;
193 }218 }
194 const test_dir = args.test_dir orelse return error.ContentsFileInFileTest;219
195 contents_file = try test_dir.openFile(io, contents_path, .{});220 const @"test" = args.@"test" orelse return error.ContentsFileInFileTest;
221 try server.serveMessageHeader(.{
222 .tag = .discovered_inputs,
223 .bytes_len = @intCast(@sizeOf(std.zig.Server.Message.InputDir) + contents_path.len + 1),
224 });
225 try server.out.writeInt(u32, @backingInt(@"test".input_dir), .little);
226 try server.out.writeAll(contents_path);
227 try server.out.writeByte(0);
228 try server.out.flush();
229
230 contents_file = try @"test".dir.openFile(io, contents_path, .{});
196 contents_impl = .{ .fr = contents_file.?.reader(io, &.{}) };231 contents_impl = .{ .fr = contents_file.?.reader(io, &.{}) };
197 break :contents_r &contents_impl.fr.interface;232 break :contents_r &contents_impl.fr.interface;
198 };233 };