Files
mongo/buildscripts/buildifier.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

135 lines
4.9 KiB
Python
Raw Normal View History

import argparse
import json
import os
import pathlib
import platform
import subprocess
from simple_report import put_report, try_combine_reports, make_report
mongo_dir = pathlib.Path(__file__).parents[1]
def find_all_failed(bin_path: str) -> list[str]:
# TODO(SERVER-81039): Remove once third_party libs can be compiled from the root directory.
ignored_paths = []
with open(os.path.join(mongo_dir, ".bazelignore"), "r") as file:
for line in file.readlines():
contents = line.split("#")[0].strip()
if contents:
ignored_paths.append(contents)
process = subprocess.run([bin_path, "--format=json", "--mode=check", "-r", "./"], check=True,
capture_output=True)
buildifier_results = json.loads(process.stdout)
if buildifier_results["success"]:
return []
return [
result["filename"] for result in buildifier_results["files"]
if (not result["formatted"] and \
not any(result["filename"].startswith(ignored_path) for ignored_path in ignored_paths))
]
def lint_all(bin_path: str, generate_report: bool):
files = find_all_failed(bin_path)
lint(bin_path, files, generate_report)
def fix_all(bin_path: str):
files = find_all_failed(bin_path)
fix(bin_path, files)
def lint(bin_path: str, files: list[str], generate_report: bool):
for file in files:
process = subprocess.run([bin_path, "--format=json", "--mode=check", file], check=True,
capture_output=True)
result = json.loads(process.stdout)
if result["success"]:
continue
# This purposefully gives a exit code of 4 when there is a diff
process = subprocess.run([bin_path, "--mode=diff", file], capture_output=True,
encoding='utf-8')
if process.returncode not in (0, 4):
raise RuntimeError()
diff = process.stdout
print(f"{file} has linting errors")
print(diff)
if generate_report:
header = (
"There are linting errors in this file, fix them with one of the following commands:\n"
"python3 buildscripts/buildifier.py fix-all\n"
f"python3 buildscripts/buildifier.py fix {file}\n\n")
report = make_report(f"{file} warnings", json.dumps(result, indent=2), 1)
try_combine_reports(report)
put_report(report)
report = make_report(f"{file} diff", header + diff, 1)
try_combine_reports(report)
put_report(report)
print("Done linting files")
def fix(bin_path: str, files: list[str]):
for file in files:
subprocess.run([bin_path, "--mode=fix", file], check=True)
print("Done fixing files")
def main():
parser = argparse.ArgumentParser(description='buildifier wrapper')
parser.add_argument(
"--binary-dir", "-b", type=str,
help="Path to the buildifier binary, defaults to looking in the current directory.",
default="")
parser.add_argument(
"--generate-report", action="store_true",
help="Whether or not a report of the lint errors should be generated for evergreen.",
default=False)
parser.set_defaults(subcommand=None)
sub = parser.add_subparsers(title="buildifier subcommands", help="sub-command help")
lint_all_parser = sub.add_parser("lint-all", help="Lint all files")
lint_all_parser.set_defaults(subcommand="lint-all")
fix_all_parser = sub.add_parser("fix-all", help="Fix all files")
fix_all_parser.set_defaults(subcommand="fix-all")
lint_parser = sub.add_parser("lint", help="Lint specified list of files")
lint_parser.add_argument("files", nargs="+")
lint_parser.set_defaults(subcommand="lint")
lint_parser = sub.add_parser("fix", help="Fix specified list of files")
lint_parser.add_argument("files", nargs="+")
lint_parser.set_defaults(subcommand="fix")
args = parser.parse_args()
assert os.path.abspath(os.curdir) == str(
mongo_dir.absolute()), "buildifier.py must be run from the root of the mongo repo"
binary_name = "buildifier.exe" if platform.system() == "Windows" else "buildifier"
if args.binary_dir:
binary_path = os.path.join(args.binary_dir, binary_name)
else:
binary_path = os.path.join(os.curdir, binary_name)
subcommand = args.subcommand
if subcommand == "lint-all":
lint_all(binary_path, args.generate_report)
elif subcommand == "fix-all":
fix_all(binary_path)
elif subcommand == "lint":
lint(binary_path, args.files, args.generate_report)
elif subcommand == "fix":
fix(binary_path, args.files)
else:
# we purposefully do not use sub.choices.keys() so it does not print as a dict_keys object
choices = [key for key in sub.choices]
raise RuntimeError(f"One of the following subcommands must be specified: {choices}")
if __name__ == "__main__":
main()