Просмотр исходного кода

Merge pull request #254 from chrboesch/tools

Replacing Python-Tools with Zig-Tools
Chris Boesch 2 лет назад
Родитель
Сommit
232002f30f
4 измененных файлов с 198 добавлено и 165 удалено
  1. 0 97
      tools/check-exercises.py
  2. 108 0
      tools/check-exercises.zig
  3. 0 68
      tools/update-patches.py
  4. 90 0
      tools/update-patches.zig

+ 0 - 97
tools/check-exercises.py

@@ -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()

+ 108 - 0
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);
+}

+ 0 - 68
tools/update-patches.py

@@ -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()

+ 90 - 0
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);
+}