From 59e28987dab53acfb268d30e5f19f02aa20bd70d Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Thu, 6 Apr 2023 12:47:08 +0200 Subject: [PATCH] build: restore the exercise chain The new parallel build support in Zig broke the exercise chain, so that each esercise check is no longer strictly serialized. 1. Add the Dexno option, in order to isolate the chain starting from a named exercise from the normal chain, thus simplify the code. The current code have an additional issue: it added 4 x n steps, making reading the help message or the list of steps very hard. Add only the `install`, `uninstall`, `zigling`, `test` and `start` steps. The last three steps match the old steps `n`, `n_test` and `n_start`. The default step is zigling (note the singular form). The `install` step override the builtin install step, showing a custom description and matches the old `n_install` step. The uninstall step was added for consistency, so that the description is consistent. Setup a new chain starting at `zig build -Dexno=n start` so that it is stricly serialized. The behavior should be the same as the old one. 2. Handle the code for all the exercises separately. Add only the `ziglings step`, making it the default step, in addition to the install and uninstall steps. Setup a new chain starting at the first exercise, to that it is strictly serialized. The behavior should be the same as the old one. The current code has a know issue: the messages from the ZiglingStep and the ones from the compiler compilation progress are interleaved, but each message is written atomically, due to the use of `std.debug.getStderrMutex()`. Update the README.md file. Closes #202 --- README.md | 11 ++----- build.zig | 92 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 600790b..f23f536 100644 --- a/README.md +++ b/README.md @@ -50,18 +50,11 @@ $ git clone https://github.com/ratfactor/ziglings $ cd ziglings ``` -Then run `zig build 1` and follow the instructions to begin! +Then run `zig build` and follow the instructions to begin! ```bash -$ zig build 1 +$ zig build ``` -## :warning: Attention -Due to Zig's new build system, exercises can currently only be run manually with their number! - -```bash -$ zig build xy -``` -We hope to be able to offer this again soon in the automatic way. ## A Note About Versions diff --git a/build.zig b/build.zig index e3533aa..391c260 100644 --- a/build.zig +++ b/build.zig @@ -51,6 +51,11 @@ const Exercise = struct { while (self.main_file[start_index] == '0') start_index += 1; return self.main_file[start_index..end_index.?]; } + + /// Returns the exercise key as an integer. + pub fn number(self: Exercise) usize { + return std.fmt.parseInt(usize, self.key(), 10) catch unreachable; + } }; const exercises = [_]Exercise{ @@ -534,17 +539,21 @@ pub fn build(b: *Build) !void { \\ ; + const use_healed = b.option(bool, "healed", "Run exercises from patches/healed") orelse false; + const exno: ?usize = b.option(usize, "n", "Select exercise"); + const header_step = PrintStep.create(b, logo, std.io.getStdErr()); - const verify_all = b.step("ziglings", "Check all ziglings"); - verify_all.dependOn(&header_step.step); - b.default_step = verify_all; + if (exno) |i| { + const ex = blk: { + for (exercises) |ex| { + if (ex.number() == i) break :blk ex; + } - var prev_chain_verify = verify_all; + print("unknown exercise number: {}\n", .{i}); + std.os.exit(1); + }; - const use_healed = b.option(bool, "healed", "Run exercises from patches/healed") orelse false; - - for (exercises) |ex| { const base_name = ex.baseName(); const file_path = std.fs.path.join(b.allocator, &[_][]const u8{ if (use_healed) "patches/healed" else "exercises", ex.main_file, @@ -553,31 +562,64 @@ pub fn build(b: *Build) !void { const build_step = b.addExecutable(.{ .name = base_name, .root_source_file = .{ .path = file_path } }); build_step.install(); + const run_step = build_step.run(); + + const test_step = b.step("test", b.fmt("Run {s} without checking output", .{ex.main_file})); + test_step.dependOn(&run_step.step); + + const install_step = b.step("install", b.fmt("Install {s} to prefix path", .{ex.main_file})); + install_step.dependOn(b.getInstallStep()); + + const uninstall_step = b.step("uninstall", b.fmt("Uninstall {s} from prefix path", .{ex.main_file})); + uninstall_step.dependOn(b.getUninstallStep()); + const verify_step = ZiglingStep.create(b, ex, use_healed); - const key = ex.key(); + const zigling_step = b.step("zigling", b.fmt("Check the solution of {s}", .{ex.main_file})); + zigling_step.dependOn(&verify_step.step); + b.default_step = zigling_step; - const named_test = b.step(b.fmt("{s}_test", .{key}), b.fmt("Run {s} without checking output", .{ex.main_file})); - const run_step = build_step.run(); - named_test.dependOn(&run_step.step); + const start_step = b.step("start", b.fmt("Check all solutions starting at {s}", .{ex.main_file})); - const named_install = b.step(b.fmt("{s}_install", .{key}), b.fmt("Copy {s} to prefix path", .{ex.main_file})); - named_install.dependOn(&build_step.install_step.?.step); + var prev_step = verify_step; + for (exercises) |exn| { + const n = exn.number(); + if (n > i) { + const verify_stepn = ZiglingStep.create(b, exn, use_healed); + verify_stepn.step.dependOn(&prev_step.step); - const named_verify = b.step(key, b.fmt("Check {s} only", .{ex.main_file})); - named_verify.dependOn(&verify_step.step); + prev_step = verify_stepn; + } + } + start_step.dependOn(&prev_step.step); - const chain_verify = b.allocator.create(Step) catch unreachable; - chain_verify.* = Step.init(Step.Options{ .id = .custom, .name = b.fmt("chain {s}", .{key}), .owner = b }); - chain_verify.dependOn(&verify_step.step); - - const named_chain = b.step(b.fmt("{s}_start", .{key}), b.fmt("Check all solutions starting at {s}", .{ex.main_file})); - named_chain.dependOn(&header_step.step); - named_chain.dependOn(chain_verify); - - prev_chain_verify.dependOn(chain_verify); - prev_chain_verify = chain_verify; + return; } + + const ziglings_step = b.step("ziglings", "Check all ziglings"); + ziglings_step.dependOn(&header_step.step); + b.default_step = ziglings_step; + + var prev_step: *Step = undefined; + for (exercises, 0..) |ex, i| { + const base_name = ex.baseName(); + const file_path = std.fs.path.join(b.allocator, &[_][]const u8{ + if (use_healed) "patches/healed" else "exercises", ex.main_file, + }) catch unreachable; + + const build_step = b.addExecutable(.{ .name = base_name, .root_source_file = .{ .path = file_path } }); + build_step.install(); + + const verify_stepn = ZiglingStep.create(b, ex, use_healed); + if (i == 0) { + prev_step = &verify_stepn.step; + } else { + verify_stepn.step.dependOn(prev_step); + + prev_step = &verify_stepn.step; + } + } + ziglings_step.dependOn(prev_step); } var use_color_escapes = false;