exercises/tools/check-exercises.py

98 lines
2.2 KiB
Python
Raw Normal View History

#!/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()