aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/check-exercises.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/check-exercises.py')
-rwxr-xr-xtools/check-exercises.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/tools/check-exercises.py b/tools/check-exercises.py
new file mode 100755
index 0000000..fa0b5cb
--- /dev/null
+++ b/tools/check-exercises.py
@@ -0,0 +1,97 @@
+#!/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()