GitHub CI: update list of container images
[tinc] / lint.py
1 #!/usr/bin/env python3
2
3 """Run linters on project code. Add --fix to autofix files with linters that support it."""
4
5 import sys
6 import subprocess as subp
7 from glob import glob
8 from os import path, environ, chdir
9
10 DRY = "--fix" not in sys.argv or environ.get("CI")
11 HEADER = "#" * 24
12
13 if DRY:
14     MSG = """
15 You're running linters in non-destructive readonly mode.
16 Some of them support automated fixes (like reformatting code).
17 To apply them, run `lint.py --fix` or `ninja -C build reformat`.
18 """
19     print(MSG, file=sys.stderr)
20
21 source_root = path.dirname(path.realpath(__file__))
22 source_root = environ.get("MESON_SOURCE_ROOT", source_root)
23 chdir(source_root)
24
25 # It's best not to use globs that cover everything in the project — if integration
26 # tests are run with a large --repeat value, test working directory can reach
27 # enormous sizes, and linters either get very slow, or start crashing.
28 linters = (
29     [
30         "astyle",
31         "--recursive",
32         "--options=.astylerc",
33         "--dry-run" if DRY else "--formatted",
34         "./*.c",
35         "./*.h",
36     ],
37     ["shfmt", "-d" if DRY else "-w", "-i", "2", "-s", "."],
38     ["black", "--check" if DRY else ".", "."],
39     ["pylint", "."],
40     ["mypy", "--exclude", "build", "."],
41     ["shellcheck", "-x", *glob(".ci/**/*.sh", recursive=True)],
42     ["markflow", "--line-length", "80", "--check" if DRY else "--verbose", ".", ".ci"],
43 )
44
45 failed: bool = False
46
47 for cmd in linters:
48     exe = cmd[0]
49     print(f"{HEADER} Running linter '{exe}' {HEADER}")
50
51     try:
52         res = subp.run(
53             cmd,
54             check=False,
55             stdout=subp.PIPE,
56             encoding="utf-8",
57         )
58         failed = (
59             failed
60             or bool(res.returncode)
61             or (exe == "astyle" and "Formatted  " in res.stdout)
62         )
63         print(res.stdout)
64     except FileNotFoundError as e:
65         print(f"Warning: linter {exe} is missing", file=sys.stderr)
66
67 sys.exit(int(failed))