From cffbbff8bdff7198ba1b166c360f7f62116680ef Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Tue, 25 Apr 2023 12:13:58 +0200 Subject: [PATCH 1/2] replaced check-exercises.pu with check-exercises.zig --- tools/check-exercises.py | 97 ---------------------------------- tools/check-exercises.zig | 108 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 97 deletions(-) delete mode 100755 tools/check-exercises.py create mode 100644 tools/check-exercises.zig diff --git a/tools/check-exercises.py b/tools/check-exercises.py deleted file mode 100755 index fa0b5cb..0000000 --- a/tools/check-exercises.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python - -import difflib -import io -import os -import os.path -import subprocess -import sys - - -IGNORE = subprocess.DEVNULL -PIPE = subprocess.PIPE - -EXERCISES_PATH = "exercises" -HEALED_PATH = "patches/healed" -PATCHES_PATH = "patches/patches" - - -# Heals all the exercises. -def heal(): - maketree(HEALED_PATH) - - with os.scandir(EXERCISES_PATH) as it: - for entry in it: - name = entry.name - - original_path = entry.path - patch_path = os.path.join(PATCHES_PATH, patch_name(name)) - output_path = os.path.join(HEALED_PATH, name) - - patch(original_path, patch_path, output_path) - - -# Yields all the healed exercises that are not correctly formatted. -def check_healed(): - term = subprocess.run( - ["zig", "fmt", "--check", HEALED_PATH], stdout=PIPE, text=True - ) - if term.stdout == "" and term.returncode != 0: - term.check_returncode() - - stream = io.StringIO(term.stdout) - for line in stream: - yield line.strip() - - -def main(): - heal() - - # Show the unified diff between the original example and the correctly - # formatted one. - for i, original in enumerate(check_healed()): - if i > 0: - print() - - name = os.path.basename(original) - print(f"checking exercise {name}...\n") - - from_file = open(original) - to_file = zig_fmt_file(original) - - diff = difflib.unified_diff( - from_file.readlines(), to_file.readlines(), name, name + "-fmt" - ) - sys.stderr.writelines(diff) - - -def maketree(path): - return os.makedirs(path, exist_ok=True) - - -# Returns path with the patch extension. -def patch_name(path): - name, _ = os.path.splitext(path) - - return name + ".patch" - - -# Applies patch to original, and write the file to output. -def patch(original, patch, output): - subprocess.run( - ["patch", "-i", patch, "-o", output, original], stdout=IGNORE, check=True - ) - - -# Formats the Zig file at path, and returns the possibly reformatted file as a -# file object. -def zig_fmt_file(path): - with open(path) as stdin: - term = subprocess.run( - ["zig", "fmt", "--stdin"], stdin=stdin, stdout=PIPE, check=True, text=True - ) - - return io.StringIO(term.stdout) - - -main() diff --git a/tools/check-exercises.zig b/tools/check-exercises.zig new file mode 100644 index 0000000..8bfeb34 --- /dev/null +++ b/tools/check-exercises.zig @@ -0,0 +1,108 @@ +const std = @import("std"); +const print = std.debug.print; +const string = []const u8; + +const cwd = std.fs.cwd(); +const Dir = std.fs.Dir; +const Allocator = std.mem.Allocator; + +const EXERCISES_PATH = "exercises"; +const HEALED_PATH = "patches/healed"; +const TEMP_PATH = "patches/healed/tmp"; +const PATCHES_PATH = "patches/patches"; + +// Heals all the exercises. +fn heal(alloc: Allocator) !void { + try cwd.makePath(HEALED_PATH); + + const org_path = try cwd.realpathAlloc(alloc, EXERCISES_PATH); + const patch_path = try cwd.realpathAlloc(alloc, PATCHES_PATH); + const healed_path = try cwd.realpathAlloc(alloc, HEALED_PATH); + + var idir = try cwd.openIterableDir(EXERCISES_PATH, Dir.OpenDirOptions{}); + defer idir.close(); + + var it = idir.iterate(); + while (try it.next()) |entry| { + + // create filenames + const healed_file = try concat(alloc, &.{ healed_path, "/", entry.name }); + const patch_file = try concat(alloc, &.{ patch_path, "/", try patch_name(alloc, entry.name) }); + + // patch file + const result = try std.ChildProcess.exec(.{ + .allocator = alloc, + .argv = &.{ "patch", "-i", patch_file, "-o", healed_file, entry.name }, + .cwd = org_path, + }); + + print("{s}", .{result.stderr}); + } +} + +// Yields all the healed exercises that are not correctly formatted. +fn check_healed(alloc: Allocator) !void { + try cwd.makePath(TEMP_PATH); + + const temp_path = try cwd.realpathAlloc(alloc, TEMP_PATH); + const healed_path = try cwd.realpathAlloc(alloc, HEALED_PATH); + + var idir = try cwd.openIterableDir(HEALED_PATH, Dir.OpenDirOptions{}); + defer idir.close(); + + var it = idir.iterate(); + while (try it.next()) |entry| { + + // Check the healed file + const result = try std.ChildProcess.exec(.{ + .allocator = alloc, + .argv = &.{ "zig", "fmt", "--check", entry.name }, + .cwd = healed_path, + }); + + // Is there something to fix? + if (result.stdout.len > 0) { + const temp_file = try concat(alloc, &.{ temp_path, "/", entry.name }); + const healed_file = try concat(alloc, &.{ healed_path, "/", entry.name }); + try std.fs.copyFileAbsolute(healed_file, temp_file, std.fs.CopyFileOptions{}); + + // Formats the temp file + _ = try std.ChildProcess.exec(.{ + .allocator = alloc, + .argv = &.{ "zig", "fmt", entry.name }, + .cwd = temp_path, + }); + + // Show the differences + const diff = try std.ChildProcess.exec(.{ + .allocator = alloc, + .argv = &.{ "diff", "-c", healed_file, entry.name }, + .cwd = temp_path, + }); + + print("{s}", .{diff.stdout}); + try std.fs.deleteFileAbsolute(temp_file); + } + } +} + +fn concat(alloc: Allocator, slices: []const string) !string { + const buf = try std.mem.concat(alloc, u8, slices); + return buf; +} + +fn patch_name(alloc: Allocator, path: string) !string { + var filename = path; + const index = std.mem.lastIndexOfScalar(u8, path, '.') orelse return path; + if (index > 0) filename = path[0..index]; + return try concat(alloc, &.{ filename, ".patch" }); +} + +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + const alloc = arena.allocator(); + + try heal(alloc); + try check_healed(alloc); +} From 213d0712a532292106515882295bd54a7e0a9326 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Tue, 25 Apr 2023 21:35:18 +0200 Subject: [PATCH 2/2] replaced update-patches.py with update-patches.zig --- tools/update-patches.py | 68 ------------------------------ tools/update-patches.zig | 90 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 68 deletions(-) delete mode 100755 tools/update-patches.py create mode 100644 tools/update-patches.zig diff --git a/tools/update-patches.py b/tools/update-patches.py deleted file mode 100755 index 76a1c46..0000000 --- a/tools/update-patches.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -import os -import os.path -import subprocess - - -IGNORE = subprocess.DEVNULL - -EXERCISES_PATH = "exercises" -ANSWERS_PATH = "answers" -PATCHES_PATH = "patches/patches" - - -# Heals all the exercises. -def heal(): - maketree(ANSWERS_PATH) - - with os.scandir(EXERCISES_PATH) as it: - for entry in it: - name = entry.name - - original_path = entry.path - patch_path = os.path.join(PATCHES_PATH, patch_name(name)) - output_path = os.path.join(ANSWERS_PATH, name) - - patch(original_path, patch_path, output_path) - - -def main(): - heal() - - with os.scandir(EXERCISES_PATH) as it: - for entry in it: - name = entry.name - - broken_path = entry.path - healed_path = os.path.join(ANSWERS_PATH, name) - patch_path = os.path.join(PATCHES_PATH, patch_name(name)) - - with open(patch_path, "w") as file: - term = subprocess.run( - ["diff", broken_path, healed_path], - stdout=file, - text=True, - ) - assert term.returncode == 1 - - -def maketree(path): - return os.makedirs(path, exist_ok=True) - - -# Returns path with the patch extension. -def patch_name(path): - name, _ = os.path.splitext(path) - - return name + ".patch" - - -# Applies patch to original, and write the file to output. -def patch(original, patch, output): - subprocess.run( - ["patch", "-i", patch, "-o", output, original], stdout=IGNORE, check=True - ) - - -main() diff --git a/tools/update-patches.zig b/tools/update-patches.zig new file mode 100644 index 0000000..618d2bf --- /dev/null +++ b/tools/update-patches.zig @@ -0,0 +1,90 @@ +const std = @import("std"); +const print = std.debug.print; +const string = []const u8; + +const cwd = std.fs.cwd(); +const Dir = std.fs.Dir; +const Allocator = std.mem.Allocator; + +const EXERCISES_PATH = "exercises"; +const ANSWERS_PATH = "answers"; +const PATCHES_PATH = "patches/patches"; + +// Heals all the exercises. +fn heal(alloc: Allocator) !void { + try cwd.makePath(ANSWERS_PATH); + + const org_path = try cwd.realpathAlloc(alloc, EXERCISES_PATH); + const patch_path = try cwd.realpathAlloc(alloc, PATCHES_PATH); + const healed_path = try cwd.realpathAlloc(alloc, ANSWERS_PATH); + + var idir = try cwd.openIterableDir(EXERCISES_PATH, Dir.OpenDirOptions{}); + defer idir.close(); + + var it = idir.iterate(); + while (try it.next()) |entry| { + + // create filenames + const healed_file = try concat(alloc, &.{ healed_path, "/", entry.name }); + const patch_file = try concat(alloc, &.{ patch_path, "/", try patch_name(alloc, entry.name) }); + + // patch the file + const result = try std.ChildProcess.exec(.{ + .allocator = alloc, + .argv = &.{ "patch", "-i", patch_file, "-o", healed_file, entry.name }, + .cwd = org_path, + }); + + print("{s}", .{result.stderr}); + } +} + +// Creates new patch files for every exercise +fn update(alloc: Allocator) !void { + const org_path = try cwd.realpathAlloc(alloc, EXERCISES_PATH); + const healed_path = try cwd.realpathAlloc(alloc, ANSWERS_PATH); + const patch_path = try cwd.realpathAlloc(alloc, PATCHES_PATH); + + var idir = try cwd.openIterableDir(EXERCISES_PATH, Dir.OpenDirOptions{}); + defer idir.close(); + + var it = idir.iterate(); + while (try it.next()) |entry| { + + // create diff + const org_file = try concat(alloc, &.{ org_path, "/", entry.name }); + const healed_file = try concat(alloc, &.{ healed_path, "/", entry.name }); + const result = try std.ChildProcess.exec(.{ + .allocator = alloc, + .argv = &.{ "diff", org_file, healed_file }, + }); + std.debug.assert(result.term.Exited == 1); + + // write diff to file + const patch_file = try concat(alloc, &.{ patch_path, "/", try patch_name(alloc, entry.name) }); + var file = try std.fs.cwd().createFile(patch_file, .{ .read = false }); + defer file.close(); + try file.writer().print("{s}", .{result.stdout}); + } +} + +fn concat(alloc: Allocator, slices: []const string) !string { + const buf = try std.mem.concat(alloc, u8, slices); + return buf; +} + +fn patch_name(alloc: Allocator, path: string) !string { + var filename = path; + const index = std.mem.lastIndexOfScalar(u8, path, '.') orelse return path; + if (index > 0) filename = path[0..index]; + return try concat(alloc, &.{ filename, ".patch" }); +} + +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + const alloc = arena.allocator(); + + try heal(alloc); + try update(alloc); +}