summaryrefslogtreecommitdiffstats
path: root/tools/codespell.py
blob: 042bbf49214fc837030783ddf0a47eacb6feecb7 (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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import itertools
import logging
import os
import subprocess
import sys
import typing

import githelper


def run_codespell_on_lines(rootdir, filename, lines, codespell_args):
    """
    Run codespell on the requested lines.

    Returns 1 if any changes were made, else 0.
    """
    logger = logging.getLogger(__name__)
    cmd = ["codespell", *codespell_args, "--", filename]
    logger.debug("Running command: %r", cmd)

    try:
        subprocess.check_output(cmd)
    except subprocess.CalledProcessError as e:
        output = e.output.decode().strip()
    else:
        return 0

    result = 0
    for line in output.splitlines():
        matched_fname_with_line = line.partition(": ")[0]
        matched_fname, _, linenum = matched_fname_with_line.rpartition(":")
        assert matched_fname == filename
        if int(linenum) in lines:
            result = 1
            print(line)

    return result


def main(argv: typing.Optional[typing.List[str]] = None) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--from-ref", help="use changes changes since commit")
    parser.add_argument("--to-ref", help="use changes until commit")
    parser.add_argument("--files", nargs="*", help="only check these files")
    parser.add_argument(
        "-v", "--verbose", action="store_true", help="Be verbose"
    )
    args, codespell_args = parser.parse_known_args(argv)

    logging.basicConfig(
        format="[%(levelname)s] %(message)s",
        level=logging.DEBUG if args.verbose else logging.INFO,
    )

    if not args.from_ref:
        args.from_ref = os.getenv("PRE_COMMIT_FROM_REF") or os.getenv(
            "PRE_COMMIT_SOURCE"
        )

    if not args.to_ref:
        args.to_ref = os.getenv("PRE_COMMIT_TO_REF") or os.getenv(
            "PRE_COMMIT_ORIGIN"
        )

    # Filter filenames
    rootdir = githelper.get_toplevel_path()

    files_with_added_lines = githelper.get_changed_lines(
        from_ref=args.from_ref,
        to_ref=args.to_ref,
        filter_lines=lambda line: line.added,
        include_files=args.files,
    )

    result = 0
    for filename, file_lines in itertools.groupby(
        files_with_added_lines, key=lambda line: line.sourcefile
    ):
        lines = set(line.number for line in file_lines)
        result |= run_codespell_on_lines(
            rootdir,
            filename,
            lines,
            [arg for arg in codespell_args if arg != "--"],
        )

    return result


if __name__ == "__main__":
    sys.exit(main())