Files
esphome/script/clang_tidy_hash.py

66 lines
2.2 KiB
Python

"""Files that affect clang-tidy results, and a content hash over them.
``CLANG_TIDY_GLOBAL_FILES`` (plus ``SDKCONFIG_DEFAULTS_PREFIX``) is the single
source of truth for which files influence clang-tidy output. A change to any of
them can surface warnings in source files a PR didn't touch, so:
* ``script/determine-jobs.py`` runs a full clang-tidy scan when one changes, and
* ``calculate_clang_tidy_hash()`` folds them into the idedata cache key used by
``script/helpers.py`` (a content hash, unlike an mtime check, stays correct
across git checkouts).
"""
from __future__ import annotations
import hashlib
from pathlib import Path
# Root-relative paths whose contents affect clang-tidy results.
CLANG_TIDY_GLOBAL_FILES = (
".clang-tidy",
"platformio.ini",
"requirements_dev.txt",
"esphome/idf_component.yml",
)
# sdkconfig.defaults and per-target sdkconfig.defaults.<target> files flip the
# CONFIG flags that decide which variant code paths clang-tidy sees. Matched by
# this prefix at the repo root.
SDKCONFIG_DEFAULTS_PREFIX = "sdkconfig.defaults"
def read_file_bytes(path: Path) -> bytes:
"""Read bytes from a file."""
with path.open("rb") as f:
return f.read()
def get_repo_root() -> Path:
"""Get the repository root directory."""
return Path(__file__).parent.parent
def _ensure_repo_root(repo_root: Path | None) -> Path:
"""Ensure repo_root is a Path, using default if None."""
return repo_root if repo_root is not None else get_repo_root()
def calculate_clang_tidy_hash(repo_root: Path | None = None) -> str:
"""Calculate a hash of the files that affect clang-tidy results."""
repo_root = _ensure_repo_root(repo_root)
hasher = hashlib.sha256()
for name in CLANG_TIDY_GLOBAL_FILES:
path = repo_root / name
if path.exists():
hasher.update(read_file_bytes(path))
# Hash each sdkconfig.defaults* file. Include the filename so adding or
# renaming a per-target variant is detected, not just content edits.
for path in sorted(repo_root.glob(f"{SDKCONFIG_DEFAULTS_PREFIX}*")):
hasher.update(path.name.encode())
hasher.update(read_file_bytes(path))
return hasher.hexdigest()