mirror of
https://codeberg.org/ziglings/exercises.git
synced 2026-06-08 07:50:00 +00:00
Some deprecated functions removed and a progress bar added.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# Ziglings
|
# Ziglings
|
||||||
|
|
||||||
Welcome to Ziglings! This project contains a series of tiny
|
Welcome to Ziglings! This project contains a series of tiny
|
||||||
broken programs (and one nasty surprise). By fixing them, you'll
|
broken programs (and one nasty surprise). By fixing them, you'll
|
||||||
learn how to read and write [Zig](https://ziglang.org/) code.
|
learn how to read and write [Zig](https://ziglang.org/) code.
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
88
build.zig
88
build.zig
@@ -15,7 +15,7 @@ const print = std.debug.print;
|
|||||||
// 1) Getting Started
|
// 1) Getting Started
|
||||||
// 2) Version Changes
|
// 2) Version Changes
|
||||||
comptime {
|
comptime {
|
||||||
const required_zig = "0.16.0";
|
const required_zig = "0.16.0-dev.2915";
|
||||||
const current_zig = builtin.zig_version;
|
const current_zig = builtin.zig_version;
|
||||||
const min_zig = std.SemanticVersion.parse(required_zig) catch unreachable;
|
const min_zig = std.SemanticVersion.parse(required_zig) catch unreachable;
|
||||||
if (current_zig.order(min_zig) == .lt) {
|
if (current_zig.order(min_zig) == .lt) {
|
||||||
@@ -205,7 +205,8 @@ pub fn build(b: *Build) !void {
|
|||||||
break :blk seed;
|
break :blk seed;
|
||||||
});
|
});
|
||||||
const rnd = prng.random();
|
const rnd = prng.random();
|
||||||
const ex = exercises[rnd.intRangeLessThan(usize, 0, exercises.len)];
|
const num = rnd.intRangeLessThan(usize, 0, exercises.len);
|
||||||
|
const ex = exercises[num];
|
||||||
|
|
||||||
print("random exercise: {s}\n", .{ex.main_file});
|
print("random exercise: {s}\n", .{ex.main_file});
|
||||||
|
|
||||||
@@ -270,11 +271,9 @@ pub fn build(b: *Build) !void {
|
|||||||
|
|
||||||
const progress_file_size = try progress_file.length(io);
|
const progress_file_size = try progress_file.length(io);
|
||||||
|
|
||||||
var gpa = std.heap.DebugAllocator(.{}){};
|
var gpa = b.allocator;
|
||||||
defer _ = gpa.deinit();
|
const contents = try gpa.alloc(u8, progress_file_size);
|
||||||
const allocator = gpa.allocator();
|
defer gpa.free(contents);
|
||||||
const contents = try allocator.alloc(u8, progress_file_size);
|
|
||||||
defer allocator.free(contents);
|
|
||||||
var file_buffer: [1024]u8 = undefined;
|
var file_buffer: [1024]u8 = undefined;
|
||||||
var file_reader = progress_file.reader(io, &file_buffer);
|
var file_reader = progress_file.reader(io, &file_buffer);
|
||||||
// try file_reader.interface.readSliceAll(contents);
|
// try file_reader.interface.readSliceAll(contents);
|
||||||
@@ -346,6 +345,26 @@ const ZiglingStep = struct {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn printProgress(num: usize, max: usize) void {
|
||||||
|
const bar_width: u32 = 60;
|
||||||
|
|
||||||
|
const filled_len_u64 = (@as(u64, num) * bar_width) / max;
|
||||||
|
const filled_len = @as(u32, @intCast(filled_len_u64));
|
||||||
|
|
||||||
|
var bar_buf: [bar_width]u8 = undefined;
|
||||||
|
|
||||||
|
for (0..bar_width) |n| {
|
||||||
|
const ord = std.math.order(n, filled_len);
|
||||||
|
bar_buf[n] = switch (ord) {
|
||||||
|
.lt => '#',
|
||||||
|
.eq => '>',
|
||||||
|
.gt => '-',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std.debug.print("\rProgress: [{s}] {d}/{d}\n\n", .{ &bar_buf, num, max });
|
||||||
|
}
|
||||||
|
|
||||||
fn make(step: *Step, options: Step.MakeOptions) !void {
|
fn make(step: *Step, options: Step.MakeOptions) !void {
|
||||||
// NOTE: Using exit code 2 will prevent the Zig compiler to print the message:
|
// NOTE: Using exit code 2 will prevent the Zig compiler to print the message:
|
||||||
// "error: the following build command failed with exit code 1:..."
|
// "error: the following build command failed with exit code 1:..."
|
||||||
@@ -361,6 +380,9 @@ const ZiglingStep = struct {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Progess
|
||||||
|
printProgress(self.exercise.number(), exercises.len - 1);
|
||||||
|
|
||||||
const exe_path = self.compile(options.progress_node) catch {
|
const exe_path = self.compile(options.progress_node) catch {
|
||||||
self.printErrors();
|
self.printErrors();
|
||||||
|
|
||||||
@@ -388,6 +410,7 @@ const ZiglingStep = struct {
|
|||||||
fn run(self: *ZiglingStep, exe_path: []const u8, _: std.Progress.Node) !void {
|
fn run(self: *ZiglingStep, exe_path: []const u8, _: std.Progress.Node) !void {
|
||||||
resetLine();
|
resetLine();
|
||||||
const b = self.step.owner;
|
const b = self.step.owner;
|
||||||
|
const gpa = b.allocator;
|
||||||
const io = b.graph.io;
|
const io = b.graph.io;
|
||||||
|
|
||||||
print("Checking: {s}\n", .{self.exercise.main_file});
|
print("Checking: {s}\n", .{self.exercise.main_file});
|
||||||
@@ -395,7 +418,7 @@ const ZiglingStep = struct {
|
|||||||
// Allow up to 1 MB of stdout capture.
|
// Allow up to 1 MB of stdout capture.
|
||||||
const max_output_bytes = 1 * 1024 * 1024;
|
const max_output_bytes = 1 * 1024 * 1024;
|
||||||
|
|
||||||
const result = Process.run(b.allocator, io, .{
|
const result = Process.run(gpa, io, .{
|
||||||
.argv = &.{exe_path},
|
.argv = &.{exe_path},
|
||||||
.cwd = .{ .path = b.build_root.path.? },
|
.cwd = .{ .path = b.build_root.path.? },
|
||||||
.stdout_limit = .limited(max_output_bytes),
|
.stdout_limit = .limited(max_output_bytes),
|
||||||
@@ -413,6 +436,7 @@ const ZiglingStep = struct {
|
|||||||
|
|
||||||
fn check_output(self: *ZiglingStep, result: Process.RunResult) !void {
|
fn check_output(self: *ZiglingStep, result: Process.RunResult) !void {
|
||||||
const b = self.step.owner;
|
const b = self.step.owner;
|
||||||
|
const gpa = b.allocator;
|
||||||
const io = b.graph.io;
|
const io = b.graph.io;
|
||||||
|
|
||||||
// Make sure it exited cleanly.
|
// Make sure it exited cleanly.
|
||||||
@@ -438,7 +462,7 @@ const ZiglingStep = struct {
|
|||||||
|
|
||||||
// NOTE: exercise.output can never contain a CR character.
|
// NOTE: exercise.output can never contain a CR character.
|
||||||
// See https://ziglang.org/documentation/master/#Source-Encoding.
|
// See https://ziglang.org/documentation/master/#Source-Encoding.
|
||||||
const output = trimLines(b.allocator, raw_output) catch @panic("OOM");
|
const output = trimLines(gpa, raw_output) catch @panic("OOM");
|
||||||
|
|
||||||
// Validate the output.
|
// Validate the output.
|
||||||
var exercise_output = self.exercise.output;
|
var exercise_output = self.exercise.output;
|
||||||
@@ -486,8 +510,8 @@ const ZiglingStep = struct {
|
|||||||
, .{ red, reset, exercise_output, red, reset, output, red, reset });
|
, .{ red, reset, exercise_output, red, reset, output, red, reset });
|
||||||
}
|
}
|
||||||
|
|
||||||
const progress = try std.fmt.allocPrint(b.allocator, "{d}", .{self.exercise.number()});
|
const progress = try std.fmt.allocPrint(gpa, "{d}", .{self.exercise.number()});
|
||||||
defer b.allocator.free(progress);
|
defer gpa.free(progress);
|
||||||
|
|
||||||
const file = try std.Io.Dir.cwd().createFile(
|
const file = try std.Io.Dir.cwd().createFile(
|
||||||
io,
|
io,
|
||||||
@@ -526,43 +550,44 @@ const ZiglingStep = struct {
|
|||||||
print("Compiling: {s}\n", .{self.exercise.main_file});
|
print("Compiling: {s}\n", .{self.exercise.main_file});
|
||||||
|
|
||||||
const b = self.step.owner;
|
const b = self.step.owner;
|
||||||
|
const gpa = b.allocator;
|
||||||
const exercise_path = self.exercise.main_file;
|
const exercise_path = self.exercise.main_file;
|
||||||
const path = join(b.allocator, &.{ self.work_path, exercise_path }) catch
|
const path = join(gpa, &.{ self.work_path, exercise_path }) catch
|
||||||
@panic("OOM");
|
@panic("OOM");
|
||||||
|
|
||||||
var zig_args = std.array_list.Managed([]const u8).init(b.allocator);
|
var zig_args = std.ArrayList([]const u8).initCapacity(gpa, 10) catch @panic("OOM");
|
||||||
defer zig_args.deinit();
|
defer zig_args.deinit(gpa);
|
||||||
|
|
||||||
zig_args.append(b.graph.zig_exe) catch @panic("OOM");
|
zig_args.append(gpa, b.graph.zig_exe) catch @panic("OOM");
|
||||||
|
|
||||||
const cmd = switch (self.exercise.kind) {
|
const cmd = switch (self.exercise.kind) {
|
||||||
.exe => "build-exe",
|
.exe => "build-exe",
|
||||||
.@"test" => "test",
|
.@"test" => "test",
|
||||||
};
|
};
|
||||||
zig_args.append(cmd) catch @panic("OOM");
|
zig_args.append(gpa, cmd) catch @panic("OOM");
|
||||||
|
|
||||||
// Enable C support for exercises that use C functions.
|
// Enable C support for exercises that use C functions.
|
||||||
if (self.exercise.link_libc) {
|
if (self.exercise.link_libc) {
|
||||||
zig_args.append("-lc") catch @panic("OOM");
|
zig_args.append(gpa, "-lc") catch @panic("OOM");
|
||||||
zig_args.append("-fllvm") catch @panic("OOM");
|
zig_args.append(gpa, "-fllvm") catch @panic("OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b.reference_trace) |rt| {
|
if (b.reference_trace) |rt| {
|
||||||
zig_args.append(b.fmt("-freference-trace={}", .{rt})) catch @panic("OOM");
|
zig_args.append(gpa, b.fmt("-freference-trace={}", .{rt})) catch @panic("OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
zig_args.append(b.pathFromRoot(path)) catch @panic("OOM");
|
zig_args.append(gpa, b.pathFromRoot(path)) catch @panic("OOM");
|
||||||
|
|
||||||
zig_args.append("--cache-dir") catch @panic("OOM");
|
zig_args.append(gpa, "--cache-dir") catch @panic("OOM");
|
||||||
zig_args.append(b.pathFromRoot(b.cache_root.path.?)) catch @panic("OOM");
|
zig_args.append(gpa, b.pathFromRoot(b.cache_root.path.?)) catch @panic("OOM");
|
||||||
|
|
||||||
zig_args.append("--listen=-") catch @panic("OOM");
|
zig_args.append(gpa, "--listen=-") catch @panic("OOM");
|
||||||
|
|
||||||
//
|
//
|
||||||
// NOTE: After many changes in zig build system, we need to create the cache path manually.
|
// NOTE: After many changes in zig build system, we need to create the cache path manually.
|
||||||
// See https://github.com/ziglang/zig/pull/21115
|
// See https://github.com/ziglang/zig/pull/21115
|
||||||
// Maybe there is a better way (in the future).
|
// Maybe there is a better way (in the future).
|
||||||
const exe_dir = try self.step.evalZigProcess(zig_args.items, prog_node, false, null, b.allocator);
|
const exe_dir = try self.step.evalZigProcess(zig_args.items, prog_node, false, null, gpa);
|
||||||
const exe_name = switch (self.exercise.kind) {
|
const exe_name = switch (self.exercise.kind) {
|
||||||
.exe => self.exercise.name(),
|
.exe => self.exercise.name(),
|
||||||
.@"test" => "test",
|
.@"test" => "test",
|
||||||
@@ -628,21 +653,22 @@ fn resetLine() void {
|
|||||||
|
|
||||||
/// Removes trailing whitespace for each line in buf, also ensuring that there
|
/// Removes trailing whitespace for each line in buf, also ensuring that there
|
||||||
/// are no trailing LF characters at the end.
|
/// are no trailing LF characters at the end.
|
||||||
pub fn trimLines(allocator: std.mem.Allocator, buf: []const u8) ![]const u8 {
|
pub fn trimLines(gpa: std.mem.Allocator, buf: []const u8) ![]const u8 {
|
||||||
var list = try std.array_list.Aligned(u8, null).initCapacity(allocator, buf.len);
|
var list = try std.ArrayList(u8).initCapacity(gpa, buf.len);
|
||||||
|
errdefer list.deinit(gpa);
|
||||||
|
|
||||||
var iter = std.mem.splitSequence(u8, buf, " \n");
|
var iter = std.mem.splitSequence(u8, buf, " \n");
|
||||||
while (iter.next()) |line| {
|
while (iter.next()) |line| {
|
||||||
// TODO: trimming CR characters is probably not necessary.
|
// TODO: trimming CR characters is probably not necessary.
|
||||||
const data = std.mem.trimEnd(u8, line, " \r");
|
const data = std.mem.trimEnd(u8, line, " \r");
|
||||||
try list.appendSlice(allocator, data);
|
try list.appendSlice(gpa, data);
|
||||||
try list.append(allocator, '\n');
|
try list.append(gpa, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = try list.toOwnedSlice(allocator); // TODO: probably not necessary
|
// Calls deinit()
|
||||||
|
const result = try list.toOwnedSlice(gpa);
|
||||||
|
|
||||||
// Remove the trailing LF character, that is always present in the exercise
|
// Remove the trailing LF character, that is always present in the exercise output.
|
||||||
// output.
|
|
||||||
return std.mem.trimEnd(u8, result, "\n");
|
return std.mem.trimEnd(u8, result, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user