Download .github/scripts/verify_bazel_clippy_lints.py from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 7.15 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/.github/scripts/verify_bazel_clippy_lints.py
- Command line
-
hf download hf://SaylorTwift/codex/.github/scripts/verify_bazel_clippy_lints.py
-
curl -L -o verify_bazel_clippy_lints.py https://huggingface.co/SaylorTwift/codex/resolve/main/.github/scripts/verify_bazel_clippy_lints.py
7.15 kB
| #!/usr/bin/env python3 | |
| from __future__ import annotations | |
| import argparse | |
| import re | |
| import sys | |
| import tomllib | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[2] | |
| DEFAULT_CARGO_TOML = ROOT / "codex-rs" / "Cargo.toml" | |
| DEFAULT_BAZELRC = ROOT / ".bazelrc" | |
| BAZEL_CLIPPY_FLAG_PREFIX = "build:clippy --@rules_rust//rust/settings:clippy_flag=" | |
| BAZEL_SPECIAL_FLAGS = {"-Dwarnings"} | |
| VALID_LEVELS = {"allow", "warn", "deny", "forbid"} | |
| LONG_FLAG_RE = re.compile( | |
| r"^--(?P<level>allow|warn|deny|forbid)=clippy::(?P<lint>[a-z0-9_]+)$" | |
| ) | |
| SHORT_FLAG_RE = re.compile(r"^-(?P<level>[AWDF])clippy::(?P<lint>[a-z0-9_]+)$") | |
| SHORT_LEVEL_NAMES = { | |
| "A": "allow", | |
| "W": "warn", | |
| "D": "deny", | |
| "F": "forbid", | |
| } | |
| def main() -> int: | |
| parser = argparse.ArgumentParser( | |
| description=( | |
| "Verify that Bazel clippy flags in .bazelrc stay in sync with " | |
| "codex-rs/Cargo.toml [workspace.lints.clippy]." | |
| ) | |
| ) | |
| parser.add_argument( | |
| "--cargo-toml", | |
| type=Path, | |
| default=DEFAULT_CARGO_TOML, | |
| help="Path to the workspace Cargo.toml to inspect.", | |
| ) | |
| parser.add_argument( | |
| "--bazelrc", | |
| type=Path, | |
| default=DEFAULT_BAZELRC, | |
| help="Path to the .bazelrc file to inspect.", | |
| ) | |
| args = parser.parse_args() | |
| cargo_toml = args.cargo_toml.resolve() | |
| bazelrc = args.bazelrc.resolve() | |
| cargo_lints = load_workspace_clippy_lints(cargo_toml) | |
| bazel_lints = load_bazel_clippy_lints(bazelrc) | |
| missing = sorted(cargo_lints.keys() - bazel_lints.keys()) | |
| extra = sorted(bazel_lints.keys() - cargo_lints.keys()) | |
| mismatched = sorted( | |
| lint | |
| for lint in cargo_lints.keys() & bazel_lints.keys() | |
| if cargo_lints[lint] != bazel_lints[lint] | |
| ) | |
| if missing or extra or mismatched: | |
| print_sync_error( | |
| cargo_toml=cargo_toml, | |
| bazelrc=bazelrc, | |
| cargo_lints=cargo_lints, | |
| bazel_lints=bazel_lints, | |
| missing=missing, | |
| extra=extra, | |
| mismatched=mismatched, | |
| ) | |
| return 1 | |
| print( | |
| "Bazel clippy flags in " | |
| f"{display_path(bazelrc)} match " | |
| f"{display_path(cargo_toml)} [workspace.lints.clippy]." | |
| ) | |
| return 0 | |
| def load_workspace_clippy_lints(cargo_toml: Path) -> dict[str, str]: | |
| workspace = tomllib.loads(cargo_toml.read_text())["workspace"] | |
| clippy_lints = workspace["lints"]["clippy"] | |
| parsed: dict[str, str] = {} | |
| for lint, level in clippy_lints.items(): | |
| if not isinstance(level, str): | |
| raise SystemExit( | |
| f"expected string lint level for clippy::{lint} in {cargo_toml}, got {level!r}" | |
| ) | |
| normalized = level.strip().lower() | |
| if normalized not in VALID_LEVELS: | |
| raise SystemExit( | |
| f"unsupported lint level {level!r} for clippy::{lint} in {cargo_toml}" | |
| ) | |
| parsed[lint] = normalized | |
| return parsed | |
| def load_bazel_clippy_lints(bazelrc: Path) -> dict[str, str]: | |
| parsed: dict[str, str] = {} | |
| line_numbers: dict[str, int] = {} | |
| for lineno, line in enumerate(bazelrc.read_text().splitlines(), start=1): | |
| if not line.startswith(BAZEL_CLIPPY_FLAG_PREFIX): | |
| continue | |
| flag = line.removeprefix(BAZEL_CLIPPY_FLAG_PREFIX).strip() | |
| if flag in BAZEL_SPECIAL_FLAGS: | |
| continue | |
| parsed_flag = parse_bazel_lint_flag(flag) | |
| if parsed_flag is None: | |
| continue | |
| lint, level = parsed_flag | |
| if lint in parsed: | |
| raise SystemExit( | |
| f"duplicate Bazel clippy entry for clippy::{lint} at " | |
| f"{bazelrc}:{line_numbers[lint]} and {bazelrc}:{lineno}" | |
| ) | |
| parsed[lint] = level | |
| line_numbers[lint] = lineno | |
| return parsed | |
| def parse_bazel_lint_flag(flag: str) -> tuple[str, str] | None: | |
| long_match = LONG_FLAG_RE.match(flag) | |
| if long_match: | |
| return long_match["lint"], long_match["level"] | |
| short_match = SHORT_FLAG_RE.match(flag) | |
| if short_match: | |
| return short_match["lint"], SHORT_LEVEL_NAMES[short_match["level"]] | |
| return None | |
| def print_sync_error( | |
| *, | |
| cargo_toml: Path, | |
| bazelrc: Path, | |
| cargo_lints: dict[str, str], | |
| bazel_lints: dict[str, str], | |
| missing: list[str], | |
| extra: list[str], | |
| mismatched: list[str], | |
| ) -> None: | |
| cargo_toml_display = display_path(cargo_toml) | |
| bazelrc_display = display_path(bazelrc) | |
| example_manifest = find_workspace_lints_example_manifest() | |
| print( | |
| "ERROR: Bazel clippy flags are out of sync with Cargo workspace clippy lints.", | |
| file=sys.stderr, | |
| ) | |
| print(file=sys.stderr) | |
| print( | |
| f"Cargo defines the source of truth in {cargo_toml_display} " | |
| "[workspace.lints.clippy].", | |
| file=sys.stderr, | |
| ) | |
| if example_manifest is not None: | |
| print( | |
| "Cargo applies those lint levels to member crates that opt into " | |
| f"`[lints] workspace = true`, for example {example_manifest}.", | |
| file=sys.stderr, | |
| ) | |
| print( | |
| "Bazel clippy does not ingest Cargo lint levels automatically, and " | |
| "`clippy.toml` can configure lint behavior but cannot set allow/warn/deny/forbid.", | |
| file=sys.stderr, | |
| ) | |
| print( | |
| f"Update {bazelrc_display} so its `build:clippy` " | |
| "`clippy_flag` entries match Cargo.", | |
| file=sys.stderr, | |
| ) | |
| if missing: | |
| print(file=sys.stderr) | |
| print("Missing Bazel entries:", file=sys.stderr) | |
| for lint in missing: | |
| print(f" {render_bazelrc_line(lint, cargo_lints[lint])}", file=sys.stderr) | |
| if mismatched: | |
| print(file=sys.stderr) | |
| print("Mismatched lint levels:", file=sys.stderr) | |
| for lint in mismatched: | |
| cargo_level = cargo_lints[lint] | |
| bazel_level = bazel_lints[lint] | |
| print( | |
| f" clippy::{lint}: Cargo has {cargo_level}, Bazel has {bazel_level}", | |
| file=sys.stderr, | |
| ) | |
| print( | |
| f" expected: {render_bazelrc_line(lint, cargo_level)}", | |
| file=sys.stderr, | |
| ) | |
| if extra: | |
| print(file=sys.stderr) | |
| print("Extra Bazel entries with no Cargo counterpart:", file=sys.stderr) | |
| for lint in extra: | |
| print(f" {render_bazelrc_line(lint, bazel_lints[lint])}", file=sys.stderr) | |
| def render_bazelrc_line(lint: str, level: str) -> str: | |
| return f"{BAZEL_CLIPPY_FLAG_PREFIX}--{level}=clippy::{lint}" | |
| def display_path(path: Path) -> str: | |
| try: | |
| return str(path.relative_to(ROOT)) | |
| except ValueError: | |
| return str(path) | |
| def find_workspace_lints_example_manifest() -> str | None: | |
| for cargo_toml in sorted((ROOT / "codex-rs").glob("**/Cargo.toml")): | |
| if cargo_toml == DEFAULT_CARGO_TOML: | |
| continue | |
| data = tomllib.loads(cargo_toml.read_text()) | |
| if data.get("lints", {}).get("workspace") is True: | |
| return str(cargo_toml.relative_to(ROOT)) | |
| return None | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |