Browse Source

Merge pull request 'issue201-adding-progress-tracking' (#203) from zendril/exercises:issue201-adding-progress-tracking into main

Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/203
Chris Boesch 6 months ago
parent
commit
b3dd04885d
2 changed files with 68 additions and 3 deletions
  1. 5 0
      README.md
  2. 63 3
      build.zig

+ 5 - 0
README.md

@@ -173,6 +173,11 @@ zig build -Dn=19 -l
   ...
 ```
 
+To reset the progress (have it run all the exercises that have already been completed):
+```
+zig build -Dreset
+```
+
 ## What's Covered
 
 The primary goal for Ziglings is to cover the core Zig language.

+ 63 - 3
build.zig

@@ -120,6 +120,8 @@ pub const logo =
     \\
 ;
 
+const progress_filename = ".progress.txt";
+
 pub fn build(b: *Build) !void {
     if (!validate_exercises()) std.process.exit(2);
 
@@ -162,6 +164,7 @@ pub fn build(b: *Build) !void {
     const exno: ?usize = b.option(usize, "n", "Select exercise");
     const rand: ?bool = b.option(bool, "random", "Select random exercise");
     const start: ?usize = b.option(usize, "s", "Start at exercise");
+    const reset: ?bool = b.option(bool, "reset", "Reset exercise progress");
 
     const sep = std.fs.path.sep_str;
     const healed_path = if (override_healed_path) |path|
@@ -242,17 +245,62 @@ pub fn build(b: *Build) !void {
         return;
     }
 
+    if (reset) |_| {
+        std.fs.cwd().deleteFile(progress_filename) catch |err| {
+            switch (err) {
+                std.fs.Dir.DeleteFileError.FileNotFound => {},
+                else => {
+                    print("Unable to remove progress file, Error: {}\n", .{err});
+                    return err;
+                },
+            }
+        };
+
+        print("Progress reset, {s} removed.\n", .{progress_filename});
+        std.process.exit(0);
+    }
+
     // Normal build mode: verifies all exercises according to the recommended
     // order.
     const ziglings_step = b.step("ziglings", "Check all ziglings");
     b.default_step = ziglings_step;
 
     var prev_step = &header_step.step;
+
+    var starting_exercise: u32 = 0;
+
+    if (std.fs.cwd().openFile(progress_filename, .{})) |progress_file| {
+        defer progress_file.close();
+
+        const progress_file_size = try progress_file.getEndPos();
+
+        var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+        defer _ = gpa.deinit();
+        const allocator = gpa.allocator();
+        const contents = try progress_file.readToEndAlloc(allocator, progress_file_size);
+        defer allocator.free(contents);
+
+        starting_exercise = try std.fmt.parseInt(u32, contents, 10);
+    } else |err| {
+        switch (err) {
+
+            std.fs.File.OpenError.FileNotFound => {
+                // This is fine, may be the first time tests are run or progress have been reset
+            },
+            else => {
+                print("Unable to open {s}: {}\n", .{progress_filename, err});
+                return err;
+            },
+        }
+    }
+
     for (exercises) |ex| {
-        const verify_stepn = ZiglingStep.create(b, ex, work_path, .normal);
-        verify_stepn.step.dependOn(prev_step);
+        if (starting_exercise < ex.number()) {
+            const verify_stepn = ZiglingStep.create(b, ex, work_path, .normal);
+            verify_stepn.step.dependOn(prev_step);
 
-        prev_step = &verify_stepn.step;
+            prev_step = &verify_stepn.step;
+        }
     }
     ziglings_step.dependOn(prev_step);
 
@@ -403,6 +451,18 @@ const ZiglingStep = struct {
             , .{ red, reset, exercise_output, red, reset, output, red, reset });
         }
 
+        const progress = try std.fmt.allocPrint(b.allocator, "{d}", .{self.exercise.number()});
+        defer b.allocator.free(progress);
+
+        const file = try std.fs.cwd().createFile(
+            progress_filename,
+            .{ .read = true, .truncate = true },
+        );
+        defer file.close();
+
+        try file.writeAll(progress);
+        try file.sync();
+
         print("{s}PASSED:\n{s}{s}\n\n", .{ green_text, output, reset_text });
     }