mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-09 20:04:20 +00:00
This search/replace updates all copyright notices to drop the "All rights reserved", Use "ChromiumOS" instead of "Chromium OS" and drops the trailing dots. This fulfills the request from legal and unifies our notices. ./tools/health-check has been updated to only accept this style. BUG=b:246579983 TEST=./tools/health-check Change-Id: I87a80701dc651f1baf4820e5cc42469d7c5f5bf7 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3894243 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Dennis Kempin <denniskempin@google.com>
166 lines
5 KiB
Python
166 lines
5 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright 2022 The ChromiumOS Authors
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
from dataclasses import dataclass
|
|
from fnmatch import fnmatch
|
|
from pathlib import Path
|
|
from time import time
|
|
from typing import Callable, List, NamedTuple
|
|
|
|
from impl.common import all_tracked_files, cmd, verbose
|
|
|
|
git = cmd("git")
|
|
|
|
|
|
@dataclass
|
|
class CheckContext(object):
|
|
"Information passed to each check when it's called."
|
|
|
|
# Whether or not --fix was set and checks should attempt to fix problems they encounter.
|
|
fix: bool
|
|
|
|
# Use rust nightly version for rust checks
|
|
nightly: bool
|
|
|
|
# All files that this check should cover (e.g. all python files on a python check).
|
|
all_files: List[Path]
|
|
|
|
# Those files of all_files that were modified locally.
|
|
modified_files: List[Path]
|
|
|
|
# Files that do not exist upstream and have been added locally.
|
|
new_files: List[Path]
|
|
|
|
|
|
class Check(NamedTuple):
|
|
"Metadata for each check, definining on which files it should run."
|
|
|
|
# Function to call for this check
|
|
check_function: Callable[[CheckContext], None]
|
|
|
|
# List of globs that this check should be triggered on
|
|
files: List[str] = []
|
|
|
|
python_tools: bool = False
|
|
|
|
# List of globs to exclude from this check
|
|
exclude: List[str] = []
|
|
|
|
# Whether or not this check can fix issues.
|
|
can_fix: bool = False
|
|
|
|
@property
|
|
def name(self):
|
|
name = self.check_function.__name__
|
|
if name.startswith("check_"):
|
|
return name[len("check_") :]
|
|
return name
|
|
|
|
|
|
def list_file_diff():
|
|
"""
|
|
Lists files there were modified compared to the upstream branch.
|
|
|
|
Falls back to all files tracked by git if there is no upstream branch.
|
|
"""
|
|
upstream = git("rev-parse @{u}").stdout(check=False)
|
|
if upstream:
|
|
for line in git("diff --name-status", upstream).lines():
|
|
parts = line.split("\t", 1)
|
|
file = Path(parts[1].strip())
|
|
if file.is_file():
|
|
yield (parts[0].strip(), file)
|
|
else:
|
|
print("WARNING: Not tracking a branch. Checking all files.")
|
|
for file in all_tracked_files():
|
|
yield ("M", file)
|
|
|
|
|
|
def should_run_check_on_file(check: Check, file: Path):
|
|
"Returns true if `file` should be run on `check`."
|
|
|
|
# Skip third_party except vmm_vhost.
|
|
if str(file).startswith("third_party") and not str(file).startswith("third_party/vmm_vhost"):
|
|
return False
|
|
|
|
# Skip excluded files
|
|
for glob in check.exclude:
|
|
if fnmatch(str(file), glob):
|
|
return False
|
|
|
|
# Match python tools (no file-extension, but with a python shebang line)
|
|
if check.python_tools:
|
|
if fnmatch(str(file), "tools/*") and file.suffix == "" and file.is_file():
|
|
if file.open(errors="ignore").read(32).startswith("#!/usr/bin/env python3"):
|
|
return True
|
|
|
|
# If no constraint is specified, match all files.
|
|
if not check.files and not check.python_tools:
|
|
return True
|
|
|
|
# Otherwise, match only those specified by `files`.
|
|
for glob in check.files:
|
|
if fnmatch(str(file), glob):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def run_check(check: Check, context: CheckContext):
|
|
"Runs `check` using the information in `context`. Prints status updates."
|
|
start_time = time()
|
|
if verbose():
|
|
print(f"Checking {check.name}...")
|
|
try:
|
|
check.check_function(context)
|
|
success = True
|
|
except Exception as e:
|
|
print(e)
|
|
success = False
|
|
|
|
duration = time() - start_time
|
|
print(f"Check {check.name}", "OK" if success else "FAILED", f" ({duration:.2f} s)")
|
|
return success
|
|
|
|
|
|
def run_checks(
|
|
checks_list: List[Check],
|
|
fix: bool,
|
|
run_on_all_files: bool,
|
|
nightly: bool,
|
|
):
|
|
"""
|
|
Runs all checks in checks_list.
|
|
|
|
Arguments:
|
|
fix: Tell checks to fix issues if they can (e.g. run formatter).
|
|
run_on_all_files: Do not use git delta, but run on all files.
|
|
nightly: Use nightly version of rust tooling.
|
|
"""
|
|
all_files = [*all_tracked_files()]
|
|
file_diff = [*list_file_diff()]
|
|
new_files = [f for (s, f) in file_diff if s == "A"]
|
|
if run_on_all_files:
|
|
modified_files = all_files
|
|
else:
|
|
modified_files = [f for (s, f) in file_diff if s in ("M", "A")]
|
|
|
|
failed_checks: List[Check] = []
|
|
for check in checks_list:
|
|
context = CheckContext(
|
|
fix=fix,
|
|
nightly=nightly,
|
|
all_files=[f for f in all_files if should_run_check_on_file(check, f)],
|
|
modified_files=[f for f in modified_files if should_run_check_on_file(check, f)],
|
|
new_files=[f for f in new_files if should_run_check_on_file(check, f)],
|
|
)
|
|
if context.modified_files:
|
|
if not run_check(check, context):
|
|
failed_checks.append(check)
|
|
if any(c.can_fix for c in failed_checks):
|
|
print("")
|
|
print("Some of the issues above can be fixed automatically with:")
|
|
print("./tools/health-check --fix")
|
|
return len(failed_checks) == 0
|