From: Kirill Isakov Date: Sun, 3 Apr 2022 11:14:55 +0000 (+0600) Subject: Update old Python code X-Git-Url: https://git.tinc-vpn.org/git/browse?a=commitdiff_plain;h=2ded4a80352dfbbd17b35ae0eafcbdc62243d574;p=tinc Update old Python code - reformat old Python scripts with black - fix pylint warnings - fix mypy warnings - wrap all linters in lint.py - replace reformat.py with lint.py --fix - add new linting command: `ninja -C build lint` --- diff --git a/.astylerc b/.astylerc index 8d504221..31b2482f 100644 --- a/.astylerc +++ b/.astylerc @@ -2,13 +2,13 @@ --convert-tabs --exclude=subprojects --exclude=build --i --j --f --A2 --U --p --xg --k3 --w +--ignore-exclude-errors +--add-braces +--break-blocks +--style=attach +--unpad-paren +--pad-oper +--pad-return-type +--align-pointer=name +--indent-preproc-define --formatted diff --git a/lint.py b/lint.py new file mode 100755 index 00000000..076b3e71 --- /dev/null +++ b/lint.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +"""Run linters on project code. Add --fix to autofix files with linters that support it.""" + +import sys +import subprocess as subp +from glob import glob +from os import path, environ, chdir + +DRY = "--fix" not in sys.argv or environ.get("CI") +HEADER = "#" * 24 + +if DRY: + MSG = """ +You're running linters in non-destructive readonly mode. +Some of them support automated fixes (like reformatting code). +To apply them, run `lint.py --fix` or `ninja -C build reformat`. +""" + print(MSG, file=sys.stderr) + +source_root = path.dirname(path.realpath(__file__)) +source_root = environ.get("MESON_SOURCE_ROOT", source_root) +chdir(source_root) + +# It's best not to use globs that cover everything in the project — if integration +# tests are run with a large --repeat value, test working directory can reach +# enormous sizes, and linters either get very slow, or start crashing. +linters = ( + [ + "astyle", + "--recursive", + "--options=.astylerc", + "--dry-run" if DRY else "--formatted", + "./*.c", + "./*.h", + ], + ["shfmt", "-d" if DRY else "-w", "-i", "2", "-s", "."], + ["black", "--check" if DRY else ".", "."], + ["pylint", "."], + ["mypy", "--exclude", "build", "."], + ["shellcheck", "-x", *glob(".ci/**/*.sh", recursive=True)], +) + +failed: bool = False + +for cmd in linters: + exe = cmd[0] + print(f"{HEADER} Running linter '{exe}' {HEADER}") + + try: + res = subp.run( + cmd, + check=False, + stdout=subp.PIPE, + encoding="utf-8", + ) + failed = ( + failed + or bool(res.returncode) + or (exe == "astyle" and "Formatted " in res.stdout) + ) + print(res.stdout) + except FileNotFoundError as e: + print(f"Warning: linter {exe} is missing", file=sys.stderr) + +sys.exit(int(failed)) diff --git a/meson.build b/meson.build index 488230e8..85d16122 100644 --- a/meson.build +++ b/meson.build @@ -139,6 +139,12 @@ if os_name == 'linux' and not opt_systemd.disabled() endif run_target('reformat', command: [ - find_program('python3'), - '@SOURCE_ROOT@/reformat.py', + python, + '@SOURCE_ROOT@/lint.py', + '--fix', +]) + +run_target('lint', command: [ + python, + '@SOURCE_ROOT@/lint.py', ]) diff --git a/reformat.py b/reformat.py deleted file mode 100755 index 256e482c..00000000 --- a/reformat.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 - -from os import path, environ -from sys import stderr -import subprocess as subp -import glob - -source_root = path.dirname(path.realpath(__file__)) -source_root = environ.get("MESON_SOURCE_ROOT", source_root) - -astyle_cmd = [ - "astyle", - "--options=.astylerc", - "--recursive", - "*.c", - "*.h", -] - -shfmt_cmd = [ - "shfmt", - "-i", "2", - "-s", - "-w", -] - -for path in "**/*.sh", "**/*.test", ".ci/**/*.sh": - shfmt_cmd.extend(glob.glob(path, root_dir=source_root, recursive=True)) - -for cmd in astyle_cmd, shfmt_cmd: - try: - result = subp.run(cmd, cwd=source_root, check=True) - except FileNotFoundError as e: - print("Warning: missing", cmd[0], file=stderr) diff --git a/version.py b/version.py index b4fb38af..3213e327 100755 --- a/version.py +++ b/version.py @@ -1,30 +1,39 @@ #!/usr/bin/env python3 +"""Print current tinc version for using in build scripts. + +First try to determine the latest version using git tags. If this fails (because +the .git directory is missing, git is not installed, or for some other reason), +fall back to using the VERSION file. If it is not present or could not be read, +use 'unknown'. +""" + from os import path, environ from sys import argv, stderr import subprocess as subp +import typing as T -prefix = "release-" -source_root = path.dirname(path.realpath(__file__)) -source_root = environ.get("MESON_SOURCE_ROOT", source_root) +PREFIX = "release-" +SOURCE_ROOT = path.dirname(path.realpath(__file__)) +SOURCE_ROOT = environ.get("MESON_SOURCE_ROOT", SOURCE_ROOT) cmd = [ "git", "--git-dir", - path.join(source_root, ".git"), + path.join(SOURCE_ROOT, ".git"), "describe", "--always", "--tags", - "--match=" + prefix + "*", + "--match=" + PREFIX + "*", ] if "short" in argv: cmd.append("--abbrev=0") -version = None +version: T.Optional[str] = None try: - result = subp.run(cmd, stdout=subp.PIPE, encoding="utf-8") + result = subp.run(cmd, stdout=subp.PIPE, encoding="utf-8", check=False) if not result.returncode: version = result.stdout except FileNotFoundError: @@ -32,11 +41,11 @@ except FileNotFoundError: if not version: try: - with open(path.join(source_root, "VERSION"), "r") as f: + with open(path.join(SOURCE_ROOT, "VERSION"), "r", encoding="utf-8") as f: version = f.read().strip() except OSError as e: print("could not read version from file", e, file=stderr) -elif version.startswith(prefix): - version = version[len(prefix):].strip() +elif version.startswith(PREFIX): + version = version[len(PREFIX) :].strip() print(version if version else "unknown", end="")