check-exercises.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #!/usr/bin/env python
  2. import difflib
  3. import io
  4. import os
  5. import os.path
  6. import subprocess
  7. import sys
  8. IGNORE = subprocess.DEVNULL
  9. PIPE = subprocess.PIPE
  10. EXERCISES_PATH = "exercises"
  11. HEALED_PATH = "patches/healed"
  12. PATCHES_PATH = "patches/patches"
  13. # Heals all the exercises.
  14. def heal():
  15. maketree(HEALED_PATH)
  16. with os.scandir(EXERCISES_PATH) as it:
  17. for entry in it:
  18. name = entry.name
  19. original_path = entry.path
  20. patch_path = os.path.join(PATCHES_PATH, patch_name(name))
  21. output_path = os.path.join(HEALED_PATH, name)
  22. patch(original_path, patch_path, output_path)
  23. # Yields all the healed exercises that are not correctly formatted.
  24. def check_healed():
  25. term = subprocess.run(
  26. ["zig", "fmt", "--check", HEALED_PATH], stdout=PIPE, text=True
  27. )
  28. if term.stdout == "" and term.returncode != 0:
  29. term.check_returncode()
  30. stream = io.StringIO(term.stdout)
  31. for line in stream:
  32. yield line.strip()
  33. def main():
  34. heal()
  35. # Show the unified diff between the original example and the correctly
  36. # formatted one.
  37. for i, original in enumerate(check_healed()):
  38. if i > 0:
  39. print()
  40. name = os.path.basename(original)
  41. print(f"checking exercise {name}...\n")
  42. from_file = open(original)
  43. to_file = zig_fmt_file(original)
  44. diff = difflib.unified_diff(
  45. from_file.readlines(), to_file.readlines(), name, name + "-fmt"
  46. )
  47. sys.stderr.writelines(diff)
  48. def maketree(path):
  49. return os.makedirs(path, exist_ok=True)
  50. # Returns path with the patch extension.
  51. def patch_name(path):
  52. name, _ = os.path.splitext(path)
  53. return name + ".patch"
  54. # Applies patch to original, and write the file to output.
  55. def patch(original, patch, output):
  56. subprocess.run(
  57. ["patch", "-i", patch, "-o", output, original], stdout=IGNORE, check=True
  58. )
  59. # Formats the Zig file at path, and returns the possibly reformatted file as a
  60. # file object.
  61. def zig_fmt_file(path):
  62. with open(path) as stdin:
  63. term = subprocess.run(
  64. ["zig", "fmt", "--stdin"], stdin=stdin, stdout=PIPE, check=True, text=True
  65. )
  66. return io.StringIO(term.stdout)
  67. main()