build.zig 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. const std = @import("std");
  2. const builtin = @import("builtin");
  3. pub fn build(b: *std.Build) !void {
  4. const target = b.standardTargetOptions(.{});
  5. const optimize = b.standardOptimizeOption(.{});
  6. const zigup_exe_native = blk: {
  7. const exe = addZigupExe(b, target, optimize);
  8. b.installArtifact(exe);
  9. const run_cmd = b.addRunArtifact(exe);
  10. run_cmd.step.dependOn(b.getInstallStep());
  11. const run_step = b.step("run", "Run the app");
  12. run_step.dependOn(&run_cmd.step);
  13. if (b.args) |args| {
  14. run_cmd.addArgs(args);
  15. }
  16. break :blk exe;
  17. };
  18. const test_step = b.step("test", "test the executable");
  19. addTests(b, target, zigup_exe_native, test_step, .{
  20. .make_build_steps = true,
  21. });
  22. const unzip_step = b.step(
  23. "unzip",
  24. "Build/install the unzip cmdline tool",
  25. );
  26. {
  27. const unzip = b.addExecutable(.{
  28. .name = "unzip",
  29. .root_source_file = b.path("unzip.zig"),
  30. .target = target,
  31. .optimize = optimize,
  32. });
  33. const install = b.addInstallArtifact(unzip, .{});
  34. unzip_step.dependOn(&install.step);
  35. }
  36. const zip_step = b.step(
  37. "zip",
  38. "Build/install the zip cmdline tool",
  39. );
  40. {
  41. const zip = b.addExecutable(.{
  42. .name = "zip",
  43. .root_source_file = b.path("zip.zig"),
  44. .target = target,
  45. .optimize = optimize,
  46. });
  47. const install = b.addInstallArtifact(zip, .{});
  48. zip_step.dependOn(&install.step);
  49. }
  50. const host_zip_exe = b.addExecutable(.{
  51. .name = "zip",
  52. .root_source_file = b.path("zip.zig"),
  53. .target = b.host,
  54. });
  55. const ci_step = b.step("ci", "The build/test step to run on the CI");
  56. ci_step.dependOn(b.getInstallStep());
  57. ci_step.dependOn(test_step);
  58. ci_step.dependOn(unzip_step);
  59. ci_step.dependOn(zip_step);
  60. try ci(b, ci_step, host_zip_exe);
  61. }
  62. fn addZigupExe(
  63. b: *std.Build,
  64. target: std.Build.ResolvedTarget,
  65. optimize: std.builtin.Mode,
  66. ) *std.Build.Step.Compile {
  67. const win32exelink_mod: ?*std.Build.Module = blk: {
  68. if (target.result.os.tag == .windows) {
  69. const exe = b.addExecutable(.{
  70. .name = "win32exelink",
  71. .root_source_file = b.path("win32exelink.zig"),
  72. .target = target,
  73. .optimize = optimize,
  74. });
  75. break :blk b.createModule(.{
  76. .root_source_file = exe.getEmittedBin(),
  77. });
  78. }
  79. break :blk null;
  80. };
  81. const exe = b.addExecutable(.{
  82. .name = "zigup",
  83. .root_source_file = b.path("zigup.zig"),
  84. .target = target,
  85. .optimize = optimize,
  86. });
  87. if (target.result.os.tag == .windows) {
  88. exe.root_module.addImport("win32exelink", win32exelink_mod.?);
  89. }
  90. return exe;
  91. }
  92. fn ci(
  93. b: *std.Build,
  94. ci_step: *std.Build.Step,
  95. host_zip_exe: *std.Build.Step.Compile,
  96. ) !void {
  97. const ci_targets = [_][]const u8{
  98. "x86_64-linux",
  99. "x86_64-macos",
  100. "x86_64-windows",
  101. "aarch64-linux",
  102. "aarch64-macos",
  103. "aarch64-windows",
  104. "arm-linux",
  105. "riscv64-linux",
  106. "powerpc-linux",
  107. "powerpc64le-linux",
  108. };
  109. const make_archive_step = b.step("archive", "Create CI archives");
  110. ci_step.dependOn(make_archive_step);
  111. for (ci_targets) |ci_target_str| {
  112. const target = b.resolveTargetQuery(try std.Target.Query.parse(
  113. .{ .arch_os_abi = ci_target_str },
  114. ));
  115. const optimize: std.builtin.OptimizeMode =
  116. // Compile in ReleaseSafe on Windows for faster extraction
  117. if (target.result.os.tag == .windows) .ReleaseSafe else .Debug;
  118. const zigup_exe = addZigupExe(b, target, optimize);
  119. const zigup_exe_install = b.addInstallArtifact(zigup_exe, .{
  120. .dest_dir = .{ .override = .{ .custom = ci_target_str } },
  121. });
  122. ci_step.dependOn(&zigup_exe_install.step);
  123. const target_test_step = b.step(b.fmt("test-{s}", .{ci_target_str}), "");
  124. addTests(b, target, zigup_exe, target_test_step, .{
  125. .make_build_steps = false,
  126. // This doesn't seem to be working, so we're only adding these tests
  127. // as a dependency if we see the arch is compatible beforehand
  128. .failing_to_execute_foreign_is_an_error = false,
  129. });
  130. const os_compatible = (builtin.os.tag == target.result.os.tag);
  131. const arch_compatible = (builtin.cpu.arch == target.result.cpu.arch);
  132. if (os_compatible and arch_compatible) {
  133. ci_step.dependOn(target_test_step);
  134. }
  135. if (builtin.os.tag == .linux) {
  136. make_archive_step.dependOn(makeCiArchiveStep(b, ci_target_str, target.result, zigup_exe_install, host_zip_exe));
  137. }
  138. }
  139. }
  140. fn makeCiArchiveStep(
  141. b: *std.Build,
  142. ci_target_str: []const u8,
  143. target: std.Target,
  144. exe_install: *std.Build.Step.InstallArtifact,
  145. host_zip_exe: *std.Build.Step.Compile,
  146. ) *std.Build.Step {
  147. const install_path = b.getInstallPath(.prefix, ".");
  148. if (target.os.tag == .windows) {
  149. const out_zip_file = b.pathJoin(&.{
  150. install_path,
  151. b.fmt("zigup-{s}.zip", .{ci_target_str}),
  152. });
  153. const zip = b.addRunArtifact(host_zip_exe);
  154. zip.addArg(out_zip_file);
  155. zip.addArg("zigup.exe");
  156. zip.addArg("zigup.pdb");
  157. zip.cwd = .{ .cwd_relative = b.getInstallPath(
  158. exe_install.dest_dir.?,
  159. ".",
  160. ) };
  161. zip.step.dependOn(&exe_install.step);
  162. return &zip.step;
  163. }
  164. const targz = b.pathJoin(&.{
  165. install_path,
  166. b.fmt("zigup-{s}.tar.gz", .{ci_target_str}),
  167. });
  168. const tar = b.addSystemCommand(&.{
  169. "tar",
  170. "-czf",
  171. targz,
  172. "zigup",
  173. });
  174. tar.cwd = .{ .cwd_relative = b.getInstallPath(
  175. exe_install.dest_dir.?,
  176. ".",
  177. ) };
  178. tar.step.dependOn(&exe_install.step);
  179. return &tar.step;
  180. }
  181. const SharedTestOptions = struct {
  182. make_build_steps: bool,
  183. failing_to_execute_foreign_is_an_error: bool = true,
  184. };
  185. fn addTests(
  186. b: *std.Build,
  187. target: std.Build.ResolvedTarget,
  188. zigup_exe: *std.Build.Step.Compile,
  189. test_step: *std.Build.Step,
  190. shared_options: SharedTestOptions,
  191. ) void {
  192. const runtest_exe = b.addExecutable(.{
  193. .name = "runtest",
  194. .root_source_file = b.path("runtest.zig"),
  195. .target = target,
  196. });
  197. const tests: Tests = .{
  198. .b = b,
  199. .test_step = test_step,
  200. .zigup_exe = zigup_exe,
  201. .runtest_exe = runtest_exe,
  202. .shared_options = shared_options,
  203. };
  204. tests.addWithClean(.{
  205. .name = "test-usage-h",
  206. .argv = &.{"-h"},
  207. .check = .{ .expect_stderr_match = "Usage" },
  208. });
  209. tests.addWithClean(.{
  210. .name = "test-usage-help",
  211. .argv = &.{"--help"},
  212. .check = .{ .expect_stderr_match = "Usage" },
  213. });
  214. tests.addWithClean(.{
  215. .name = "test-fetch-index",
  216. .argv = &.{"fetch-index"},
  217. .checks = &.{
  218. .{ .expect_stdout_match = "master" },
  219. .{ .expect_stdout_match = "version" },
  220. .{ .expect_stdout_match = "0.13.0" },
  221. },
  222. });
  223. tests.addWithClean(.{
  224. .name = "test-no-default",
  225. .argv = &.{"default"},
  226. .check = .{ .expect_stdout_exact = "<no-default>\n" },
  227. });
  228. tests.addWithClean(.{
  229. .name = "test-default-master-not-fetched",
  230. .argv = &.{ "default", "master" },
  231. .check = .{ .expect_stderr_match = "master has not been fetched" },
  232. });
  233. tests.addWithClean(.{
  234. .name = "test-default-0.7.0-not-fetched",
  235. .argv = &.{ "default", "0.7.0" },
  236. .check = .{ .expect_stderr_match = "error: compiler '0.7.0' is not installed\n" },
  237. });
  238. tests.addWithClean(.{
  239. .name = "test-bad-version",
  240. .argv = &.{ "THIS_ZIG_VERSION_DOES_NOT_EXIT" },
  241. .checks = &.{
  242. .{ .expect_stderr_match = "error: download '" },
  243. .{ .expect_stderr_match = "' failed: " },
  244. },
  245. });
  246. // NOTE: this test will eventually break when these builds are cleaned up,
  247. // we should support downloading from bazel and use that instead since
  248. // it should be more permanent
  249. tests.addWithClean(.{
  250. .name = "test-dev-version",
  251. .argv = &.{ "0.14.0-dev.2465+70de2f3a7" },
  252. .check = .{ .expect_stdout_exact = "" },
  253. });
  254. const _7 = tests.add(.{
  255. .name = "test-7",
  256. .argv = &.{"0.7.0"},
  257. .check = .{ .expect_stdout_match = "" },
  258. });
  259. tests.addWithClean(.{
  260. .name = "test-already-fetched-7",
  261. .env = _7,
  262. .argv = &.{ "fetch", "0.7.0" },
  263. .check = .{ .expect_stderr_match = "already installed" },
  264. });
  265. tests.addWithClean(.{
  266. .name = "test-get-default-7",
  267. .env = _7,
  268. .argv = &.{"default"},
  269. .check = .{ .expect_stdout_exact = "0.7.0\n" },
  270. });
  271. tests.addWithClean(.{
  272. .name = "test-get-default-7-no-path",
  273. .env = _7,
  274. .add_path = false,
  275. .argv = &.{ "default", "0.7.0" },
  276. .check = .{ .expect_stderr_match = " is not in PATH" },
  277. });
  278. // verify we print a nice error message if we can't update the symlink
  279. // because it's a directory
  280. tests.addWithClean(.{
  281. .name = "test-get-default-7-path-link-is-directory",
  282. .env = _7,
  283. .setup_option = "path-link-is-directory",
  284. .argv = &.{ "default", "0.7.0" },
  285. .checks = switch (builtin.os.tag) {
  286. .windows => &.{
  287. .{ .expect_stderr_match = "unable to create the exe link, the path '" },
  288. .{ .expect_stderr_match = "' is a directory" },
  289. },
  290. else => &.{
  291. .{ .expect_stderr_match = "unable to update/overwrite the 'zig' PATH symlink, the file '" },
  292. .{ .expect_stderr_match = "' already exists and is not a symlink" },
  293. },
  294. },
  295. });
  296. const _7_and_8 = tests.add(.{
  297. .name = "test-fetch-8",
  298. .env = _7,
  299. .argv = &.{ "fetch", "0.8.0" },
  300. });
  301. tests.addWithClean(.{
  302. .name = "test-get-default-7-after-fetch-8",
  303. .env = _7_and_8,
  304. .argv = &.{"default"},
  305. .check = .{ .expect_stdout_exact = "0.7.0\n" },
  306. });
  307. tests.addWithClean(.{
  308. .name = "test-already-fetched-8",
  309. .env = _7_and_8,
  310. .argv = &.{ "fetch", "0.8.0" },
  311. .check = .{ .expect_stderr_match = "already installed" },
  312. });
  313. const _7_and_default_8 = tests.add(.{
  314. .name = "test-set-default-8",
  315. .env = _7_and_8,
  316. .argv = &.{ "default", "0.8.0" },
  317. .check = .{ .expect_stdout_exact = "" },
  318. });
  319. tests.addWithClean(.{
  320. .name = "test-7-after-default-8",
  321. .env = _7_and_default_8,
  322. .argv = &.{"0.7.0"},
  323. .check = .{ .expect_stdout_exact = "" },
  324. });
  325. const master_7_and_8 = tests.add(.{
  326. .name = "test-master",
  327. .env = _7_and_8,
  328. .argv = &.{"master"},
  329. .check = .{ .expect_stdout_exact = "" },
  330. });
  331. tests.addWithClean(.{
  332. .name = "test-already-fetched-master",
  333. .env = master_7_and_8,
  334. .argv = &.{ "fetch", "master" },
  335. .check = .{ .expect_stderr_match = "already installed" },
  336. });
  337. tests.addWithClean(.{
  338. .name = "test-default-after-master",
  339. .env = master_7_and_8,
  340. .argv = &.{"default"},
  341. // master version could be anything so we won't check
  342. });
  343. tests.addWithClean(.{
  344. .name = "test-default-master",
  345. .env = master_7_and_8,
  346. .argv = &.{ "default", "master" },
  347. });
  348. tests.addWithClean(.{
  349. .name = "test-default-not-in-path",
  350. .add_path = false,
  351. .env = master_7_and_8,
  352. .argv = &.{ "default", "master" },
  353. .check = .{ .expect_stderr_match = " is not in PATH" },
  354. });
  355. // verify that we get an error if there is another compiler in the path
  356. tests.addWithClean(.{
  357. .name = "test-default-master-with-another-zig",
  358. .setup_option = "another-zig",
  359. .env = master_7_and_8,
  360. .argv = &.{ "default", "master" },
  361. .checks = &.{
  362. .{ .expect_stderr_match = "error: zig compiler '" },
  363. .{ .expect_stderr_match = "' is higher priority in PATH than the path-link '" },
  364. },
  365. });
  366. {
  367. const default8 = tests.add(.{
  368. .name = "test-default8-with-another-zig",
  369. .setup_option = "another-zig",
  370. .env = master_7_and_8,
  371. .argv = &.{ "default", "0.8.0" },
  372. .checks = &.{
  373. .{ .expect_stderr_match = "error: zig compiler '" },
  374. .{ .expect_stderr_match = "' is higher priority in PATH than the path-link '" },
  375. },
  376. });
  377. // default compiler should still be set
  378. tests.addWithClean(.{
  379. .name = "test-default8-even-with-another-zig",
  380. .env = default8,
  381. .argv = &.{ "default" },
  382. .check = .{ .expect_stdout_exact = "0.8.0\n" },
  383. });
  384. }
  385. tests.addWithClean(.{
  386. .name = "test-list",
  387. .env = master_7_and_8,
  388. .argv = &.{"list"},
  389. .checks = &.{
  390. .{ .expect_stdout_match = "0.7.0\n" },
  391. .{ .expect_stdout_match = "0.8.0\n" },
  392. },
  393. });
  394. {
  395. const default_8 = tests.add(.{
  396. .name = "test-8-with-master",
  397. .env = master_7_and_8,
  398. .argv = &.{"0.8.0"},
  399. .check = .{ .expect_stdout_exact = "" },
  400. });
  401. tests.addWithClean(.{
  402. .name = "test-default-8",
  403. .env = default_8,
  404. .argv = &.{"default"},
  405. .check = .{ .expect_stdout_exact = "0.8.0\n" },
  406. });
  407. }
  408. tests.addWithClean(.{
  409. .name = "test-run-8",
  410. .env = master_7_and_8,
  411. .argv = &.{ "run", "0.8.0", "version" },
  412. .check = .{ .expect_stdout_exact = "0.8.0\n" },
  413. });
  414. tests.addWithClean(.{
  415. .name = "test-run-doesnotexist",
  416. .env = master_7_and_8,
  417. .argv = &.{ "run", "doesnotexist", "version" },
  418. .check = .{ .expect_stderr_exact = "error: compiler 'doesnotexist' does not exist, fetch it first with: zigup fetch doesnotexist\n" },
  419. });
  420. tests.addWithClean(.{
  421. .name = "test-clean-default-master",
  422. .env = master_7_and_8,
  423. .argv = &.{"clean"},
  424. .checks = &.{
  425. .{ .expect_stderr_match = "keeping '" },
  426. .{ .expect_stderr_match = "' (is default compiler)\n" },
  427. .{ .expect_stderr_match = "deleting '" },
  428. .{ .expect_stderr_match = "0.7.0'\n" },
  429. .{ .expect_stderr_match = "0.8.0'\n" },
  430. .{ .expect_stdout_exact = "" },
  431. },
  432. });
  433. {
  434. const default7 = tests.add(.{
  435. .name = "test-set-default-7",
  436. .env = master_7_and_8,
  437. .argv = &.{ "default", "0.7.0" },
  438. .checks = &.{
  439. .{ .expect_stdout_exact = "" },
  440. },
  441. });
  442. tests.addWithClean(.{
  443. .name = "test-clean-default-7",
  444. .env = default7,
  445. .argv = &.{"clean"},
  446. .checks = &.{
  447. .{ .expect_stderr_match = "keeping '" },
  448. .{ .expect_stderr_match = "' (it is master)\n" },
  449. .{ .expect_stderr_match = "keeping '0.7.0' (is default compiler)\n" },
  450. .{ .expect_stderr_match = "deleting '" },
  451. .{ .expect_stderr_match = "0.8.0'\n" },
  452. .{ .expect_stdout_exact = "" },
  453. },
  454. });
  455. }
  456. {
  457. const keep8 = tests.add(.{
  458. .name = "test-keep8",
  459. .env = master_7_and_8,
  460. .argv = &.{ "keep", "0.8.0" },
  461. .check = .{ .expect_stdout_exact = "" },
  462. });
  463. {
  464. const keep8_default_7 = tests.add(.{
  465. .name = "test-set-default-7-keep8",
  466. .env = keep8,
  467. .argv = &.{ "default", "0.7.0" },
  468. .checks = &.{
  469. .{ .expect_stdout_exact = "" },
  470. },
  471. });
  472. tests.addWithClean(.{
  473. .name = "test-clean-default-7-keep8",
  474. .env = keep8_default_7,
  475. .argv = &.{"clean"},
  476. .checks = &.{
  477. .{ .expect_stderr_match = "keeping '" },
  478. .{ .expect_stderr_match = "' (it is master)\n" },
  479. .{ .expect_stderr_match = "keeping '0.7.0' (is default compiler)\n" },
  480. .{ .expect_stderr_match = "keeping '0.8.0' (has keep file)\n" },
  481. .{ .expect_stdout_exact = "" },
  482. },
  483. });
  484. tests.addWithClean(.{
  485. .name = "test-clean-master",
  486. .env = keep8_default_7,
  487. .argv = &.{"clean", "master"},
  488. .checks = &.{
  489. .{ .expect_stderr_match = "deleting '" },
  490. .{ .expect_stderr_match = "master'\n" },
  491. .{ .expect_stdout_exact = "" },
  492. },
  493. });
  494. }
  495. const after_clean = tests.add(.{
  496. .name = "test-clean-keep8",
  497. .env = keep8,
  498. .argv = &.{"clean"},
  499. .checks = &.{
  500. .{ .expect_stderr_match = "keeping '" },
  501. .{ .expect_stderr_match = "' (is default compiler)\n" },
  502. .{ .expect_stderr_match = "keeping '0.8.0' (has keep file)\n" },
  503. .{ .expect_stderr_match = "deleting '" },
  504. .{ .expect_stderr_match = "0.7.0'\n" },
  505. },
  506. });
  507. tests.addWithClean(.{
  508. .name = "test-set-default-7-after-clean",
  509. .env = after_clean,
  510. .argv = &.{ "default", "0.7.0" },
  511. .checks = &.{
  512. .{ .expect_stderr_match = "error: compiler '0.7.0' is not installed\n" },
  513. },
  514. });
  515. const default8 = tests.add(.{
  516. .name = "test-set-default-8-after-clean",
  517. .env = after_clean,
  518. .argv = &.{ "default", "0.8.0" },
  519. .checks = &.{
  520. .{ .expect_stdout_exact = "" },
  521. },
  522. });
  523. tests.addWithClean(.{
  524. .name = "test-clean8-as-default",
  525. .env = default8,
  526. .argv = &.{ "clean", "0.8.0" },
  527. .checks = &.{
  528. .{ .expect_stderr_match = "error: cannot clean '0.8.0' (is default compiler)\n" },
  529. },
  530. });
  531. const after_clean8 = tests.add(.{
  532. .name = "test-clean8",
  533. .env = after_clean,
  534. .argv = &.{ "clean", "0.8.0" },
  535. .checks = &.{
  536. .{ .expect_stderr_match = "deleting '" },
  537. .{ .expect_stderr_match = "0.8.0'\n" },
  538. .{ .expect_stdout_exact = "" },
  539. },
  540. });
  541. tests.addWithClean(.{
  542. .name = "test-clean-after-clean8",
  543. .env = after_clean8,
  544. .argv = &.{"clean"},
  545. .checks = &.{
  546. .{ .expect_stderr_match = "keeping '" },
  547. .{ .expect_stderr_match = "' (is default compiler)\n" },
  548. .{ .expect_stdout_exact = "" },
  549. },
  550. });
  551. }
  552. }
  553. const native_exe_ext = builtin.os.tag.exeFileExt(builtin.cpu.arch);
  554. const TestOptions = struct {
  555. name: []const u8,
  556. add_path: bool = true,
  557. env: ?std.Build.LazyPath = null,
  558. setup_option: []const u8 = "no-extra-setup",
  559. argv: []const []const u8,
  560. check: ?std.Build.Step.Run.StdIo.Check = null,
  561. checks: []const std.Build.Step.Run.StdIo.Check = &.{},
  562. };
  563. const Tests = struct {
  564. b: *std.Build,
  565. test_step: *std.Build.Step,
  566. zigup_exe: *std.Build.Step.Compile,
  567. runtest_exe: *std.Build.Step.Compile,
  568. shared_options: SharedTestOptions,
  569. fn addWithClean(tests: Tests, opt: TestOptions) void {
  570. _ = tests.addCommon(opt, .yes_clean);
  571. }
  572. fn add(tests: Tests, opt: TestOptions) std.Build.LazyPath {
  573. return tests.addCommon(opt, .no_clean);
  574. }
  575. fn addCommon(tests: Tests, opt: TestOptions, clean_opt: enum { no_clean, yes_clean }) std.Build.LazyPath {
  576. const b = tests.b;
  577. const run = std.Build.Step.Run.create(b, b.fmt("run {s}", .{opt.name}));
  578. run.failing_to_execute_foreign_is_an_error = tests.shared_options.failing_to_execute_foreign_is_an_error;
  579. run.addArtifactArg(tests.runtest_exe);
  580. run.addArg(opt.name);
  581. run.addArg(if (opt.add_path) "--with-path" else "--no-path");
  582. if (opt.env) |env| {
  583. run.addDirectoryArg(env);
  584. } else {
  585. run.addArg("--no-input-environment");
  586. }
  587. const out_env = run.addOutputDirectoryArg(opt.name);
  588. run.addArg(opt.setup_option);
  589. run.addFileArg(tests.zigup_exe.getEmittedBin());
  590. run.addArgs(opt.argv);
  591. if (opt.check) |check| {
  592. run.addCheck(check);
  593. }
  594. for (opt.checks) |check| {
  595. run.addCheck(check);
  596. }
  597. const test_step: *std.Build.Step = switch (clean_opt) {
  598. .no_clean => &run.step,
  599. .yes_clean => &CleanDir.create(tests.b, out_env).step,
  600. };
  601. if (tests.shared_options.make_build_steps) {
  602. b.step(opt.name, "").dependOn(test_step);
  603. }
  604. tests.test_step.dependOn(test_step);
  605. return out_env;
  606. }
  607. };
  608. const CleanDir = struct {
  609. step: std.Build.Step,
  610. dir_path: std.Build.LazyPath,
  611. pub fn create(owner: *std.Build, path: std.Build.LazyPath) *CleanDir {
  612. const clean_dir = owner.allocator.create(CleanDir) catch @panic("OOM");
  613. clean_dir.* = .{
  614. .step = std.Build.Step.init(.{
  615. .id = .custom,
  616. .name = owner.fmt("CleanDir {s}", .{path.getDisplayName()}),
  617. .owner = owner,
  618. .makeFn = make,
  619. }),
  620. .dir_path = path.dupe(owner),
  621. };
  622. path.addStepDependencies(&clean_dir.step);
  623. return clean_dir;
  624. }
  625. fn make(step: *std.Build.Step, prog_node: std.Progress.Node) !void {
  626. _ = prog_node;
  627. const b = step.owner;
  628. const clean_dir: *CleanDir = @fieldParentPtr("step", step);
  629. try b.build_root.handle.deleteTree(clean_dir.dir_path.getPath(b));
  630. }
  631. };