summaryrefslogtreecommitdiffstatshomepage
path: root/tools/check-exercises.py
blob: fa0b5cbf4ee58223028148dc0fde5c2496d623ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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()