blob: bfb340152350d4ddc819a45790abbd3742d65298 [file]
#!/usr/bin/env python3
# Copyright 2025 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Run clang-format with the right settings."""
import functools
from pathlib import Path
import platform
import subprocess
import sys
from typing import Iterable
import libdot
@functools.cache
def get_manifest_name() -> str:
"""The path on the server for this program."""
osname = platform.system()
try:
shortname = {
"Linux": "linux",
"Darwin": "mac",
"Windows": "win",
}[osname]
except KeyError as e:
raise RuntimeError(f"Unknown OS {osname}") from e
return f"clang-format/{shortname}"
@functools.cache
def get_manifest_spec() -> libdot.Artifact:
"""Get the manifest entry for this file."""
return libdot.fetch_manifest_lookup(
libdot.DIR / "fetch.json", get_manifest_name()
)
@functools.cache
def binary_path() -> Path:
"""Get path to the local binary."""
spec = get_manifest_spec()
objname = spec.url.rsplit("/", 1)[-1]
sfx = ".exe" if platform.system() == "Windows" else ""
return libdot.BIN_DIR / f".clang-format.{objname}{sfx}"
def setup() -> None:
"""Download & update our copy."""
path = binary_path()
if path.exists():
return
for p in libdot.BIN_DIR.glob(".clang-format.*"):
p.unlink()
# Download & unpack the archive.
libdot.fetch_manifest_spec(get_manifest_spec(), path)
path.chmod(0o755)
def run(argv: Iterable[str] = (), **kwargs) -> subprocess.CompletedProcess:
"""Run the tool directly."""
setup()
cmd = [binary_path()] + list(argv)
return libdot.run(cmd, **kwargs)
def perform(
argv: Iterable[str] = (),
paths: Iterable[str] = (),
fix: bool = False,
gerrit_comments_file: bool = None,
) -> None:
"""Run high level tool logic."""
del gerrit_comments_file
argv = list(argv)
paths = list(paths)
argv += ["-style=file"]
if fix:
argv += ["-i"]
else:
argv += ["--dry-run"]
# TODO(vapier): Add support for Gerrit comments.
result = run(argv + paths, check=False)
return result.returncode == 0
def get_parser() -> libdot.ArgumentParser:
"""Get a command line parser."""
parser = libdot.ArgumentParser(description=__doc__, short_options=False)
parser.add_argument(
"--fix",
action="store_true",
help="Fix formatting issues.",
)
return parser
def main(argv: list[str]) -> int:
"""The main func!"""
parser = get_parser()
opts, args = parser.parse_known_args(argv)
return 0 if perform(args, fix=opts.fix) else 1
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))