authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-15 21:43:52+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-16 22:42:29+01:00
log8e72a25285b5e782ee44828b6d1904d91fb16a29
treefbf331a2dab8368be364a289972b59cbfc13d33a
parent9064907b34128d66ffae8d15e075eddab7af0153

doctest: handle relative paths correctly

Evaluate all child processes in the temporary directory, and use `std.fs.path.relative` to make every other path relative to that child cwd instead of our cwd. Resolves: #22119

1 files changed, 27 insertions(+), 15 deletions(-)

tools/doctest.zig+27-15
...@@ -89,7 +89,18 @@ pub fn main() !void {...@@ -89,7 +89,18 @@ pub fn main() !void {
89 const out = bw.writer();89 const out = bw.writer();
9090
91 try printSourceBlock(arena, out, source, fs.path.basename(input_path));91 try printSourceBlock(arena, out, source, fs.path.basename(input_path));
92 try printOutput(arena, out, code, input_path, zig_path, opt_zig_lib_dir, tmp_dir_path);92 try printOutput(
93 arena,
94 out,
95 code,
96 tmp_dir_path,
97 try std.fs.path.relative(arena, tmp_dir_path, zig_path),
98 try std.fs.path.relative(arena, tmp_dir_path, input_path),
99 if (opt_zig_lib_dir) |zig_lib_dir|
100 try std.fs.path.relative(arena, tmp_dir_path, zig_lib_dir)
101 else
102 null,
103 );
93104
94 try bw.flush();105 try bw.flush();
95}106}
...@@ -98,10 +109,14 @@ fn printOutput(...@@ -98,10 +109,14 @@ fn printOutput(
98 arena: Allocator,109 arena: Allocator,
99 out: anytype,110 out: anytype,
100 code: Code,111 code: Code,
101 input_path: []const u8,112 /// Relative to this process' cwd.
113 tmp_dir_path: []const u8,
114 /// Relative to `tmp_dir_path`.
102 zig_exe: []const u8,115 zig_exe: []const u8,
116 /// Relative to `tmp_dir_path`.
117 input_path: []const u8,
118 /// Relative to `tmp_dir_path`.
103 opt_zig_lib_dir: ?[]const u8,119 opt_zig_lib_dir: ?[]const u8,
104 tmp_dir_path: []const u8,
105) !void {120) !void {
106 var env_map = try process.getEnvMap(arena);121 var env_map = try process.getEnvMap(arena);
107 try env_map.put("CLICOLOR_FORCE", "1");122 try env_map.put("CLICOLOR_FORCE", "1");
...@@ -304,7 +319,7 @@ fn printOutput(...@@ -304,7 +319,7 @@ fn printOutput(
304 },319 },
305 }320 }
306 }321 }
307 const result = run(arena, &env_map, null, test_args.items) catch322 const result = run(arena, &env_map, tmp_dir_path, test_args.items) catch
308 fatal("test failed", .{});323 fatal("test failed", .{});
309 const escaped_stderr = try escapeHtml(arena, result.stderr);324 const escaped_stderr = try escapeHtml(arena, result.stderr);
310 const escaped_stdout = try escapeHtml(arena, result.stdout);325 const escaped_stdout = try escapeHtml(arena, result.stdout);
...@@ -339,6 +354,7 @@ fn printOutput(...@@ -339,6 +354,7 @@ fn printOutput(
339 .allocator = arena,354 .allocator = arena,
340 .argv = test_args.items,355 .argv = test_args.items,
341 .env_map = &env_map,356 .env_map = &env_map,
357 .cwd = tmp_dir_path,
342 .max_output_bytes = max_doc_file_size,358 .max_output_bytes = max_doc_file_size,
343 });359 });
344 switch (result.term) {360 switch (result.term) {
...@@ -395,6 +411,7 @@ fn printOutput(...@@ -395,6 +411,7 @@ fn printOutput(
395 .allocator = arena,411 .allocator = arena,
396 .argv = test_args.items,412 .argv = test_args.items,
397 .env_map = &env_map,413 .env_map = &env_map,
414 .cwd = tmp_dir_path,
398 .max_output_bytes = max_doc_file_size,415 .max_output_bytes = max_doc_file_size,
399 });416 });
400 switch (result.term) {417 switch (result.term) {
...@@ -432,10 +449,7 @@ fn printOutput(...@@ -432,10 +449,7 @@ fn printOutput(
432 zig_exe, "build-obj",449 zig_exe, "build-obj",
433 "--color", "on",450 "--color", "on",
434 "--name", code_name,451 "--name", code_name,
435 input_path,452 input_path, try std.fmt.allocPrint(arena, "-femit-bin={s}", .{name_plus_obj_ext}),
436 try std.fmt.allocPrint(arena, "-femit-bin={s}{c}{s}", .{
437 tmp_dir_path, fs.path.sep, name_plus_obj_ext,
438 }),
439 });453 });
440 if (opt_zig_lib_dir) |zig_lib_dir| {454 if (opt_zig_lib_dir) |zig_lib_dir| {
441 try build_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir });455 try build_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir });
...@@ -465,6 +479,7 @@ fn printOutput(...@@ -465,6 +479,7 @@ fn printOutput(
465 .allocator = arena,479 .allocator = arena,
466 .argv = build_args.items,480 .argv = build_args.items,
467 .env_map = &env_map,481 .env_map = &env_map,
482 .cwd = tmp_dir_path,
468 .max_output_bytes = max_doc_file_size,483 .max_output_bytes = max_doc_file_size,
469 });484 });
470 switch (result.term) {485 switch (result.term) {
...@@ -489,7 +504,7 @@ fn printOutput(...@@ -489,7 +504,7 @@ fn printOutput(
489 const colored_stderr = try termColor(arena, escaped_stderr);504 const colored_stderr = try termColor(arena, escaped_stderr);
490 try shell_out.print("\n{s} ", .{colored_stderr});505 try shell_out.print("\n{s} ", .{colored_stderr});
491 } else {506 } else {
492 _ = run(arena, &env_map, null, build_args.items) catch fatal("example failed to compile", .{});507 _ = run(arena, &env_map, tmp_dir_path, build_args.items) catch fatal("example failed to compile", .{});
493 }508 }
494 try shell_out.writeAll("\n");509 try shell_out.writeAll("\n");
495 },510 },
...@@ -505,10 +520,7 @@ fn printOutput(...@@ -505,10 +520,7 @@ fn printOutput(
505520
506 try test_args.appendSlice(&[_][]const u8{521 try test_args.appendSlice(&[_][]const u8{
507 zig_exe, "build-lib",522 zig_exe, "build-lib",
508 input_path,523 input_path, try std.fmt.allocPrint(arena, "-femit-bin={s}", .{bin_basename}),
509 try std.fmt.allocPrint(arena, "-femit-bin={s}{s}{s}", .{
510 tmp_dir_path, fs.path.sep_str, bin_basename,
511 }),
512 });524 });
513 if (opt_zig_lib_dir) |zig_lib_dir| {525 if (opt_zig_lib_dir) |zig_lib_dir| {
514 try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir });526 try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir });
...@@ -542,7 +554,7 @@ fn printOutput(...@@ -542,7 +554,7 @@ fn printOutput(
542 try test_args.append(option);554 try test_args.append(option);
543 try shell_out.print("{s} ", .{option});555 try shell_out.print("{s} ", .{option});
544 }556 }
545 const result = run(arena, &env_map, null, test_args.items) catch fatal("test failed", .{});557 const result = run(arena, &env_map, tmp_dir_path, test_args.items) catch fatal("test failed", .{});
546 const escaped_stderr = try escapeHtml(arena, result.stderr);558 const escaped_stderr = try escapeHtml(arena, result.stderr);
547 const escaped_stdout = try escapeHtml(arena, result.stdout);559 const escaped_stdout = try escapeHtml(arena, result.stdout);
548 try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout });560 try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout });
...@@ -1076,7 +1088,7 @@ fn in(slice: []const u8, number: u8) bool {...@@ -1076,7 +1088,7 @@ fn in(slice: []const u8, number: u8) bool {
1076fn run(1088fn run(
1077 allocator: Allocator,1089 allocator: Allocator,
1078 env_map: *process.EnvMap,1090 env_map: *process.EnvMap,
1079 cwd: ?[]const u8,1091 cwd: []const u8,
1080 args: []const []const u8,1092 args: []const []const u8,
1081) !process.Child.RunResult {1093) !process.Child.RunResult {
1082 const result = try process.Child.run(.{1094 const result = try process.Child.run(.{