runtest.zig 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. const builtin = @import("builtin");
  2. const std = @import("std");
  3. const fixdeletetree = @import("fixdeletetree.zig");
  4. const exe_ext = builtin.os.tag.exeFileExt(builtin.cpu.arch);
  5. pub fn main() !void {
  6. var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
  7. const arena = arena_instance.allocator();
  8. const all_args = try std.process.argsAlloc(arena);
  9. if (all_args.len < 7) @panic("not enough cmdline args");
  10. const test_name = all_args[1];
  11. const add_path_option = all_args[2];
  12. const in_env_dir = all_args[3];
  13. const out_env_dir = all_args[4];
  14. const setup_option = all_args[5];
  15. const zigup_exe = all_args[6];
  16. const zigup_args = all_args[7..];
  17. const add_path = blk: {
  18. if (std.mem.eql(u8, add_path_option, "--with-path")) break :blk true;
  19. if (std.mem.eql(u8, add_path_option, "--no-path")) break :blk false;
  20. std.log.err("expected '--with-path' or '--no-path' but got '{s}'", .{add_path_option});
  21. std.process.exit(0xff);
  22. };
  23. try fixdeletetree.deleteTree(std.fs.cwd(), out_env_dir);
  24. try std.fs.cwd().makeDir(out_env_dir);
  25. // make a file named after the test so we can find this directory in the cache
  26. _ = test_name;
  27. // {
  28. // const test_marker_file = try std.fs.path.join(arena, &.{ out_env_dir, test_name});
  29. // defer arena.free(test_marker_file);
  30. // var file = try std.fs.cwd().createFile(test_marker_file, .{});
  31. // defer file.close();
  32. // try file.writer().print("this file marks this directory as the output for test: {s}\n", .{test_name});
  33. // }
  34. const path_link = try std.fs.path.join(arena, &.{ out_env_dir, "zig" ++ exe_ext });
  35. const install_dir = try std.fs.path.join(arena, &.{ out_env_dir, "install" });
  36. if (std.mem.eql(u8, in_env_dir, "--no-input-environment")) {
  37. try std.fs.cwd().makeDir(install_dir);
  38. } else {
  39. try copyEnvDir(arena, in_env_dir, out_env_dir, in_env_dir, out_env_dir);
  40. }
  41. var maybe_second_bin_dir: ?[]const u8 = null;
  42. if (std.mem.eql(u8, setup_option, "no-extra-setup")) {
  43. // nothing extra to setup
  44. } else if (std.mem.eql(u8, setup_option, "path-link-is-directory")) {
  45. if (std.fs.cwd().access(path_link, .{})) {
  46. try std.fs.cwd().deleteFile(path_link);
  47. } else |err| switch (err) {
  48. error.FileNotFound => {},
  49. else => |e| return e,
  50. }
  51. try std.fs.cwd().makeDir(path_link);
  52. } else if (std.mem.eql(u8, setup_option, "another-zig")) {
  53. maybe_second_bin_dir = try std.fs.path.join(arena, &.{ out_env_dir, "bin2" });
  54. try std.fs.cwd().makeDir(maybe_second_bin_dir.?);
  55. const fake_zig = try std.fs.path.join(arena, &.{
  56. maybe_second_bin_dir.?,
  57. "zig" ++ comptime builtin.target.exeFileExt(),
  58. });
  59. defer arena.free(fake_zig);
  60. var file = try std.fs.cwd().createFile(fake_zig, .{});
  61. defer file.close();
  62. try file.writer().writeAll("a fake executable");
  63. } else {
  64. std.log.err("unknown setup option '{s}'", .{setup_option});
  65. std.process.exit(0xff);
  66. }
  67. var argv = std.ArrayList([]const u8).init(arena);
  68. try argv.append(zigup_exe);
  69. try argv.append("--path-link");
  70. try argv.append(path_link);
  71. try argv.append("--install-dir");
  72. try argv.append(install_dir);
  73. try argv.appendSlice(zigup_args);
  74. var child = std.process.Child.init(argv.items, arena);
  75. if (add_path) {
  76. var env_map = try std.process.getEnvMap(arena);
  77. // make sure the directory with our path-link comes first in PATH
  78. var new_path = std.ArrayList(u8).init(arena);
  79. if (maybe_second_bin_dir) |second_bin_dir| {
  80. try new_path.appendSlice(second_bin_dir);
  81. try new_path.append(std.fs.path.delimiter);
  82. }
  83. try new_path.appendSlice(out_env_dir);
  84. try new_path.append(std.fs.path.delimiter);
  85. if (env_map.get("PATH")) |path| {
  86. try new_path.appendSlice(path);
  87. }
  88. try env_map.put("PATH", new_path.items);
  89. child.env_map = &env_map;
  90. } else if (maybe_second_bin_dir) |_| @panic("invalid config");
  91. try child.spawn();
  92. const result = try child.wait();
  93. switch (result) {
  94. .Exited => |c| std.process.exit(c),
  95. else => |sig| {
  96. std.log.err("zigup terminated from '{s}' with {}", .{ @tagName(result), sig });
  97. std.process.exit(0xff);
  98. },
  99. }
  100. }
  101. fn copyEnvDir(
  102. allocator: std.mem.Allocator,
  103. in_root: []const u8,
  104. out_root: []const u8,
  105. in_path: []const u8,
  106. out_path: []const u8,
  107. ) !void {
  108. var in_dir = try std.fs.cwd().openDir(in_path, .{ .iterate = true });
  109. defer in_dir.close();
  110. var it = in_dir.iterate();
  111. while (try it.next()) |entry| {
  112. const in_sub_path = try std.fs.path.join(allocator, &.{ in_path, entry.name });
  113. defer allocator.free(in_sub_path);
  114. const out_sub_path = try std.fs.path.join(allocator, &.{ out_path, entry.name });
  115. defer allocator.free(out_sub_path);
  116. switch (entry.kind) {
  117. .directory => {
  118. try std.fs.cwd().makeDir(out_sub_path);
  119. try copyEnvDir(allocator, in_root, out_root, in_sub_path, out_sub_path);
  120. },
  121. .file => try std.fs.cwd().copyFile(in_sub_path, std.fs.cwd(), out_sub_path, .{}),
  122. .sym_link => {
  123. var target_buf: [std.fs.max_path_bytes]u8 = undefined;
  124. const in_target = try std.fs.cwd().readLink(in_sub_path, &target_buf);
  125. var out_target_buf: [std.fs.max_path_bytes]u8 = undefined;
  126. const out_target = blk: {
  127. if (std.fs.path.isAbsolute(in_target)) {
  128. if (!std.mem.startsWith(u8, in_target, in_root)) std.debug.panic(
  129. "expected symlink target to start with '{s}' but got '{s}'",
  130. .{ in_root, in_target },
  131. );
  132. break :blk try std.fmt.bufPrint(
  133. &out_target_buf,
  134. "{s}{s}",
  135. .{ out_root, in_target[in_root.len..] },
  136. );
  137. }
  138. break :blk in_target;
  139. };
  140. if (builtin.os.tag == .windows) @panic(
  141. "we got a symlink on windows?",
  142. ) else try std.posix.symlink(out_target, out_sub_path);
  143. },
  144. else => std.debug.panic("copy {}", .{entry}),
  145. }
  146. }
  147. }