Merge pull request #254 from chrboesch/tools
Replacing Python-Tools with Zig-Tools
This commit is contained in:
commit
232002f30f
4 changed files with 198 additions and 165 deletions
|
@ -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
tools/check-exercises.zig
Normal file
108
tools/check-exercises.zig
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -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
tools/update-patches.zig
Normal file
90
tools/update-patches.zig
Normal file
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in a new issue