mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 23:05:36 +08:00
161 lines
5.8 KiB
Python
161 lines
5.8 KiB
Python
#!/bin/env python
|
|
|
|
# SPDX-FileCopyrightText: Copyright (C) 2025 swift Project Community / Contributors
|
|
# SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
|
|
|
|
"""This script runs static analysis tools only on files that have changed compared to the latest origin/main branch."""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
from subprocess import CalledProcessError
|
|
|
|
import utils
|
|
|
|
# Currently we are not checking all directories as they might need to run compilation first for Qt UIC
|
|
CHECK_DIRECTORIES = [
|
|
"src/core",
|
|
"src/misc",
|
|
"src/input",
|
|
"src/sound",
|
|
]
|
|
|
|
|
|
def _get_all_files(build_path: str) -> list[str]:
|
|
"""Get all files inside the compile commands."""
|
|
src_path = utils.get_swift_source_path()
|
|
os.chdir(src_path)
|
|
|
|
with open(os.path.join(build_path, "compile_commands.json"), 'r') as f:
|
|
commands = json.load(f)
|
|
commands = set([os.path.relpath(entry["file"], utils.get_swift_source_path()) for entry in commands])
|
|
|
|
commands = [command for command in commands if
|
|
not command.startswith("third_party") and not command.startswith(build_path)]
|
|
return commands
|
|
|
|
|
|
def _get_all_files_ci(build_path: str) -> list[str]:
|
|
"""Get all files in the compile commands and which will be checked in CI runs."""
|
|
src_path = utils.get_swift_source_path()
|
|
os.chdir(src_path)
|
|
|
|
with open(os.path.join(build_path, "compile_commands.json"), 'r') as f:
|
|
commands = json.load(f)
|
|
commands = set([os.path.relpath(entry["file"], utils.get_swift_source_path()) for entry in commands])
|
|
|
|
commands = [command for command in commands if command.startswith(tuple(CHECK_DIRECTORIES))]
|
|
return commands
|
|
|
|
|
|
def _get_changed_files_ci(build_path: str) -> set[str]:
|
|
"""Get all files in the compile commands which has changed since the last main commit and are in the included directories."""
|
|
src_path = utils.get_swift_source_path()
|
|
os.chdir(src_path)
|
|
|
|
result = subprocess.run(
|
|
['git', 'diff', '--name-only', 'origin/main'],
|
|
check=True,
|
|
stdout=subprocess.PIPE,
|
|
text=True
|
|
)
|
|
with open(os.path.join(build_path, "compile_commands.json"), 'r') as f:
|
|
commands = json.load(f)
|
|
commands = set([os.path.relpath(entry["file"], utils.get_swift_source_path()) for entry in commands])
|
|
|
|
files = set([line for line in result.stdout.splitlines() if
|
|
(line.endswith('.cpp') or line.endswith('.h')) and line.startswith(tuple(CHECK_DIRECTORIES))])
|
|
return files & commands
|
|
|
|
|
|
def _has_changed_files() -> bool:
|
|
src_path = utils.get_swift_source_path()
|
|
os.chdir(src_path)
|
|
|
|
result = subprocess.run(
|
|
['git', 'diff', '--name-only', 'origin/main'],
|
|
check=True,
|
|
stdout=subprocess.PIPE,
|
|
text=True
|
|
)
|
|
|
|
return len([line for line in result.stdout.splitlines() if
|
|
(line.endswith('.cpp') or line.endswith('.h')) and line.startswith(tuple(CHECK_DIRECTORIES))]) > 0
|
|
|
|
|
|
def run_clang_tidy(build_path: str, changed_source_files: set[str]):
|
|
print(f"Run clang-tidy on files: {changed_source_files}")
|
|
nproc = 10
|
|
try:
|
|
subprocess.run([
|
|
'xargs',
|
|
'-P', str(nproc),
|
|
'-n', '1',
|
|
'-r',
|
|
'clang-tidy',
|
|
'-p', build_path,
|
|
'--warnings-as-errors', '*',
|
|
'--quiet',
|
|
'--header-filter', f'{utils.get_swift_source_path()}/src/',
|
|
], input='\n'.join(changed_source_files), text=True, check=True)
|
|
except CalledProcessError:
|
|
print("Clang-tidy finished with errors")
|
|
exit(1)
|
|
|
|
|
|
def run_clazy(build_path: str, changed_source_files: set[str]):
|
|
print(f"Run clazy on files: {changed_source_files}")
|
|
nproc = os.cpu_count()
|
|
try:
|
|
subprocess.run([
|
|
'clazy-standalone',
|
|
'-p', build_path,
|
|
"-extra-arg", "-Werror",
|
|
"-extra-arg", "-Wno-unnecessary-virtual-specifier",
|
|
'--header-filter', f'{utils.get_swift_source_path()}/src/',
|
|
*changed_source_files
|
|
], text=True, check=True)
|
|
except CalledProcessError:
|
|
print("Clazy finished with errors")
|
|
exit(1)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(prog="swift clang-tidy helper")
|
|
parser.add_argument("--build-path", help='Path to build folder')
|
|
|
|
check_mode = parser.add_mutually_exclusive_group(required=True)
|
|
check_mode.add_argument("--all-files", action="store_true",
|
|
help="Run check on all files in the compile commands")
|
|
check_mode.add_argument("--all-files-ci", action="store_true",
|
|
help="Run check on all files in the compile commands and which will be checked in CI runs.")
|
|
check_mode.add_argument("--changed-files-ci", action="store_true",
|
|
help="Run check on all files in the compile commands which are changed since the last main commit and are in the included directories (no Qt UIC files).")
|
|
check_mode.add_argument("--check-changed-files", action="store_true",
|
|
help="Check if files have changed for evaluation. Program exits with 0 if no files changed; with 1 otherwise")
|
|
|
|
parser.add_argument("--clang-tidy", action="store_true",
|
|
help="Run clang-tidy checks")
|
|
parser.add_argument("--clazy", action="store_true",
|
|
help="Run clazy checks")
|
|
args = parser.parse_args()
|
|
|
|
if args.all_files:
|
|
source_files = _get_all_files(args.build_path)
|
|
elif args.all_files_ci:
|
|
source_files = _get_all_files_ci(args.build_path)
|
|
elif args.changed_files_ci:
|
|
source_files = _get_changed_files_ci(args.build_path)
|
|
else:
|
|
exit(1 if _has_changed_files() else 0)
|
|
|
|
if args.clang_tidy:
|
|
run_clang_tidy(args.build_path, source_files)
|
|
elif args.clazy:
|
|
run_clazy(args.build_path, source_files)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|