Skip to content

Commit 76376b4

Browse files
committed
Add function for generating customisable clippy action
1 parent 8de8f2b commit 76376b4

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

Diff for: rust/private/clippy.bzl

+44-8
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,30 @@ def _clippy_aspect_impl(target, ctx):
9999
if hasattr(target[OutputGroupInfo], "clippy_checks"):
100100
return []
101101

102+
output_format = "stderr-to-file" if ctx.attr._capture_output[CaptureClippyOutputInfo].capture_output else "stderr-and-touch-file"
103+
104+
clippy_info = rust_clippy_action(target, ctx, output_format, capture_exit_code=False)
105+
106+
return [
107+
OutputGroupInfo(clippy_checks = clippy_info.output),
108+
clippy_info,
109+
]
110+
111+
def rust_clippy_action(target, ctx, output_format, capture_exit_code):
112+
"""Generate an action to run clippy.
113+
114+
Args:
115+
target (Target): The target the aspect is running on.
116+
ctx (ctx, optional): The aspect's context object.
117+
output_format (str): One of "stderr-and-touch-file", "stderr-to-file", or "json-to-file"
118+
capture_exit_code (boolean): If true, write the exit code to a file and exit 0.
119+
120+
Returns:
121+
ClippyInfo: A `ClippyInfo` provider.
122+
"""
102123
crate_info = _get_clippy_ready_crate_info(target, ctx)
103124
if not crate_info:
104-
return [ClippyInfo(output = depset([]))]
125+
return ClippyInfo(output = depset([]))
105126

106127
toolchain = find_toolchain(ctx)
107128
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
@@ -171,7 +192,7 @@ def _clippy_aspect_impl(target, ctx):
171192

172193
# For remote execution purposes, the clippy_out file must be a sibling of crate_info.output
173194
# or rustc may fail to create intermediate output files because the directory does not exist.
174-
if ctx.attr._capture_output[CaptureClippyOutputInfo].capture_output:
195+
if output_format == "stderr-to-file":
175196
clippy_out = ctx.actions.declare_file(ctx.label.name + ".clippy.out", sibling = crate_info.output)
176197
args.process_wrapper_flags.add("--stderr-file", clippy_out)
177198

@@ -181,7 +202,7 @@ def _clippy_aspect_impl(target, ctx):
181202
# If we are capturing the output, we want the build system to be able to keep going
182203
# and consume the output. Some clippy lints are denials, so we cap everything at warn.
183204
args.rustc_flags.add("--cap-lints=warn")
184-
else:
205+
elif output_format == "stderr-and-touch-file":
185206
# A marker file indicating clippy has executed successfully.
186207
# This file is necessary because "ctx.actions.run" mandates an output.
187208
clippy_out = ctx.actions.declare_file(ctx.label.name + ".clippy.ok", sibling = crate_info.output)
@@ -196,6 +217,24 @@ def _clippy_aspect_impl(target, ctx):
196217
# Bazel will consider the execution result of the aspect to be "success",
197218
# and Clippy won't be re-triggered unless the source file is modified.
198219
args.rustc_flags.add("-Dwarnings")
220+
elif output_format == "json-to-file":
221+
clippy_out = ctx.actions.declare_file(ctx.label.name + ".clippy.out", sibling = crate_info.output)
222+
args.process_wrapper_flags.add("--stderr-file", clippy_out)
223+
224+
if clippy_flags or lint_files:
225+
args.rustc_flags.add_all(clippy_flags)
226+
args.rustc_flags.add("--error-format=json")
227+
else:
228+
fail("clippy output_format must be one of stderr-to-file|stderr-and-touch-file|json-to-file but was {}".format(output_format))
229+
230+
outputs = [clippy_out]
231+
232+
if capture_exit_code:
233+
exit_code_file = ctx.actions.declare_file(ctx.label.name + ".clippy.exit_code", sibling = crate_info.output)
234+
args.process_wrapper_flags.add("--exit-code-file", exit_code_file)
235+
outputs.append(exit_code_file)
236+
else:
237+
exit_code_file = None
199238

200239
# Upstream clippy requires one of these two filenames or it silently uses
201240
# the default config. Enforce the naming so users are not confused.
@@ -208,7 +247,7 @@ def _clippy_aspect_impl(target, ctx):
208247
ctx.actions.run(
209248
executable = ctx.executable._process_wrapper,
210249
inputs = compile_inputs,
211-
outputs = [clippy_out],
250+
outputs = outputs,
212251
env = env,
213252
tools = [toolchain.clippy_driver],
214253
arguments = args.all,
@@ -217,10 +256,7 @@ def _clippy_aspect_impl(target, ctx):
217256
toolchain = "@rules_rust//rust:toolchain_type",
218257
)
219258

220-
return [
221-
OutputGroupInfo(clippy_checks = depset([clippy_out])),
222-
ClippyInfo(output = depset([clippy_out])),
223-
]
259+
return ClippyInfo(output = depset([clippy_out]), exit_code_file = exit_code_file)
224260

225261
# Example: Run the clippy checker on all targets in the codebase.
226262
# bazel build --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect \

Diff for: rust/private/providers.bzl

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ ClippyInfo = provider(
139139
doc = "Provides information on a clippy run.",
140140
fields = {
141141
"output": "File with the clippy output.",
142+
"exit_code_file": "File with clippy's exit code, or None if the action is expected to fail on failure.",
142143
},
143144
)
144145

Diff for: util/process_wrapper/options.rs

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pub(crate) struct Options {
4444
// If set, also logs all unprocessed output from the rustc output to this file.
4545
// Meant to be used to get json output out of rustc for tooling usage.
4646
pub(crate) output_file: Option<String>,
47+
// If set, output the exit code of the subprocess to this file in ASCII, and unconditionally exit 0.
48+
pub(crate) exit_code_file: Option<String>,
4749
// If set, it configures rustc to emit an rmeta file and then
4850
// quit.
4951
pub(crate) rustc_quit_on_rmeta: bool,
@@ -64,6 +66,7 @@ pub(crate) fn options() -> Result<Options, OptionError> {
6466
let mut stdout_file = None;
6567
let mut stderr_file = None;
6668
let mut output_file = None;
69+
let mut exit_code_file = None;
6770
let mut rustc_quit_on_rmeta_raw = None;
6871
let mut rustc_output_format_raw = None;
6972
let mut flags = Flags::new();
@@ -101,6 +104,11 @@ pub(crate) fn options() -> Result<Options, OptionError> {
101104
"Log all unprocessed subprocess stderr in this file.",
102105
&mut output_file,
103106
);
107+
flags.define_flag(
108+
"--exit-code-file",
109+
"Log the process's exit code to this file as ASCII. Unconditionally exit with code 0 if this is set.",
110+
&mut exit_code_file,
111+
);
104112
flags.define_flag(
105113
"--rustc-quit-on-rmeta",
106114
"If enabled, this wrapper will terminate rustc after rmeta has been emitted.",
@@ -210,6 +218,7 @@ pub(crate) fn options() -> Result<Options, OptionError> {
210218
stdout_file,
211219
stderr_file,
212220
output_file,
221+
exit_code_file,
213222
rustc_quit_on_rmeta,
214223
rustc_output_format,
215224
})

0 commit comments

Comments
 (0)