summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rwxr-xr-xtools/check-exercises.py97
-rw-r--r--tools/check-exercises.zig108
-rwxr-xr-xtools/update-patches.py68
-rw-r--r--tools/update-patches.zig90
4 files changed, 198 insertions, 165 deletions
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);
+}
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);
+}