blob: b920cda42f6ac5c00f6f0f264ad541f2398bdb77 [file] [log] [blame]
# 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",
"compiled_tool_path",
"get_build_dir",
"get_fuchsia_dir",
"os_exec",
)
def _clippy(ctx):
"""Parses Clippy linter results produced by the build."""
files = [
f
for f in ctx.scm.affected_files()
if f.endswith(".rs")
]
if not files:
return
exe = compiled_tool_path(ctx, "clippy-reporter")
res = os_exec(ctx, [
exe,
"-checkout-dir",
get_fuchsia_dir(ctx),
"-build-dir",
get_build_dir(ctx),
"-files-json",
ctx.io.tempfile(json.encode(files)),
]).wait()
for finding in json.decode(res.stdout):
end_col = finding["end_col"]
if finding["line"] == finding["end_line"] and finding["col"] >= finding["end_col"]:
# TODO(olivernewman): Remove this debug statement and handling once
# col >= end_col instances are fixed.
print(
"WARNING: Clippy finding has col >= end_col: %s",
finding,
) # allow-print
end_col = None
ctx.emit.finding(
message = finding["message"],
level = "warning",
filepath = finding["path"],
line = finding["line"],
end_line = finding["end_line"],
col = finding["col"],
end_col = end_col,
replacements = finding["replacements"],
)
def _rustfmt(ctx):
"""Runs rustfmt on a Rust code base.
Args:
ctx: A ctx instance.
"""
rust_files = [
f
for f in ctx.scm.affected_files()
if f.endswith(".rs") and
not f.startswith("third_party/") and
# fidlgen_banjo Rust templates have an ".rs" extension but are not
# valid Rust.
not f.startswith("src/devices/tools/fidlgen_banjo/src/backends/templates/rust")
]
if not rust_files:
return
base_cmd = [
"%s/prebuilt/third_party/rust/%s/bin/rustfmt" % (
get_fuchsia_dir(ctx),
cipd_platform_name(ctx),
),
"--config-path",
"rustfmt.toml",
"--unstable-features",
"--skip-children",
]
res = os_exec(ctx, base_cmd + ["--check", "--files-with-diff"] + rust_files, ok_retcodes = [0, 1]).wait()
unformatted = res.stdout.splitlines()
if res.retcode and not unformatted:
fail("rustfmt failed:\n%s" % res.stderr)
procs = []
for f in unformatted:
filepath = f[len(ctx.scm.root) + 1:]
procs.append((
filepath,
os_exec(ctx, base_cmd + ["--emit", "stdout", filepath]),
))
for filepath, proc in procs:
output = proc.wait().stdout
# First two lines are file name and a blank line.
formatted = "\n".join(output.split("\n")[2:])
ctx.emit.finding(
# Switch to "error" if it's decided that rustfmt should be enforced
# in presubmit.
level = "warning",
message = FORMATTER_MSG,
filepath = filepath,
replacements = [formatted],
)
def register_rust_checks():
shac.register_check(shac.check(_clippy))
shac.register_check(shac.check(_rustfmt, formatter = True))