blob: e984cb4d7e94fefc618b1c11a59482db935c1257 [file] [edit]
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
load("./common.star", "FORMATTER_MSG", "cipd_platform_name", "get_fuchsia_dir", "os_exec")
def _python_format(ctx):
"""Formats Python code using autoflake, isort and black on a Python code base.
Args:
ctx: A ctx instance.
"""
py_files = ctx.scm.affected_files(glob = ["*.py", "!third_party", "!*_pb2.py"])
if not py_files:
return
# Format tools make conflicting code style changes. To ensure consistent formatting:
# 1. Run Autoflake to remove unused imports and variables.
# 2. Run isort to sort imports on the autoflake formatted code.
# 3. Run black on the isort formatted code to enforce its code style guidelines.
fuchsia_dir = get_fuchsia_dir(ctx)
platform = cipd_platform_name(ctx)
python_bin = "%s/prebuilt/third_party/python3/%s/bin/python3" % (
fuchsia_dir,
platform,
)
autoflake_path = "%s/third_party/pylibs/autoflake/main.py" % fuchsia_dir
isort_path = "%s/third_party/pylibs/isort/main.py" % fuchsia_dir
black_path = "%s/prebuilt/third_party/black/%s/black" % (
fuchsia_dir,
platform,
)
pyproject_toml = "%s/pyproject.toml" % fuchsia_dir
procs = []
for f in py_files:
procs.append(
(
f,
os_exec(
ctx,
[
python_bin,
"scripts/shac/python_format.py",
"--python",
python_bin,
"--autoflake",
autoflake_path,
"--isort",
isort_path,
"--black",
black_path,
"--pyproject-toml",
pyproject_toml,
f,
],
raise_on_failure = False,
),
),
)
errors = []
for filepath, proc in procs:
original = str(ctx.io.read_file(filepath))
res = proc.wait()
if res.retcode != 0:
errors.append("python_format failed on %s:\n%s" % (filepath, res.stderr))
continue
formatted = res.stdout
if formatted != original:
ctx.emit.finding(
level = "error",
message = FORMATTER_MSG,
filepath = filepath,
replacements = [formatted],
)
if errors:
fail("\n".join(errors))
def _py_shebangs(ctx):
"""Validates that all Python script shebangs specify the vendored Python interpeter.
Scripts can opt out of this by adding a comment with
"allow-non-vendored-python" in a line after the shebang.
"""
ignore_paths = (
"build/bazel/",
"build/bazel_sdk/",
"infra/",
"integration/",
"vendor/",
"third_party/",
)
for path in ctx.scm.affected_files(glob = "*.py"):
if path.startswith(ignore_paths):
continue
lines = str(ctx.io.read_file(path, 4096)).splitlines()
if not lines:
continue
first_line = lines[0]
want_shebang = "#!/usr/bin/env fuchsia-vendored-python"
if first_line.startswith("#!") and first_line != want_shebang:
if len(lines) > 1 and lines[1].startswith("# allow-non-vendored-python"):
continue
ctx.emit.finding(
level = "warning",
message = "Use fuchsia-vendored-python in shebangs for Python scripts.",
filepath = path,
line = 1,
replacements = [want_shebang + "\n"],
)
def register_python_checks():
shac.register_check(shac.check(_python_format, formatter = True))
shac.register_check(_py_shebangs)