Skip to content

Commit bcc8cd3

Browse files
committed
feat: Add rust_lint_group and cargo_lints rule to define lint groups (bazelbuild#2993)
Chatted about this previously in [Slack](https://bazelbuild.slack.com/archives/CSV56UT0F/p1718030356910019). The goal with this PR is to make it easier to define and share lint configurations for your build. The PR adds two new rules, `rust_lint_group` and `cargo_lints`. It also adds a "lints" attr to `rust_library` and `rust_binary` rules that expects a new `LintsInfo` provider. * `rust_lint_group` allows you to define Rust, Clippy, and Rustdoc lints in a `BUILD` file. * `cargo_lints` automatically generates a set of lints by reading a crate's `Cargo.toml`, and optionally the workspace's Cargo.toml for workspace inheritance. Then the rustc, clippy, and rustdoc actions are all updated to check for the `LintsInfo` provider and appends the correct arguments so the lints take effect. Honestly this is my first large change to a set of Bazel rules, so I definitely could have done something wrong here! The change is split into two commits, the first introduces `rust_lint_group` which IMO is relatively straight forward. Some attributes are defined on a rule which are then formatted into command line flags and passed around with a provider. The second commit adds `cargo_lints` and is much larger, a few things worth considering: * I was back and forth a bit on using a `repository_rule` or a regular `rule`. While the `repository_rule` maps well to a Cargo Workspace and you'd only need to define it once, not everyone uses workspaces and so I figured a regular `rule` was more general. * Parsing a `Cargo.toml` is done via a new Rust binary called `cargo_toml_info`. I tried to keep the external dependencies on this binary to a minimum, it only has one at the moment which is [`cargo_toml`](https://docs.rs/cargo_toml/latest/cargo_toml/) and I based this change largely off of bazelbuild#2772. I tried to make the tool general though so other Cargo metadata rules could use it in the future. There aren't any! I wasn't sure where the best place to start was, any guidance here is appreciated!
1 parent ffdf608 commit bcc8cd3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3374
-25
lines changed

.bazelci/presubmit.yml

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ single_rust_channel_targets: &single_rust_channel_targets
2525
# These tests are expected to fail as they require both a nightly and stable toolchain.
2626
- "-//test/unit/channel_transitions/..."
2727
- "-//test/unpretty/..."
28+
single_rust_channel_min_version_targets: &single_rust_channel_min_version_targets
29+
# START - Copied from 'single_rust_channel_targets'.
30+
# TODO: Figure out how to do proper list inheritence.
31+
- "--"
32+
- "//..."
33+
# TODO: Remove this and replace `cargo_bootstrap_repository` with a
34+
# http_archive for a release: https://github.com/cross-rs/cross/issues/1356
35+
- "-//crate_universe/tools/cross_installer/..."
36+
# These tests are expected to fail as they require both a nightly and stable toolchain.
37+
- "-//test/unit/channel_transitions/..."
38+
- "-//test/unpretty/..."
39+
# END - Copied from 'single_rust_channel_targets'.
40+
#
41+
# These tests exercise behavior only available versions of Rust >1.80
42+
- "-//test/unit/lint_flags/..."
2843
default_linux_targets: &default_linux_targets
2944
- "--"
3045
- "//..."
@@ -297,16 +312,16 @@ tasks:
297312
name: "Min Rust Version"
298313
platform: ubuntu2004
299314
shell_commands: *min_rust_version_shell_commands
300-
build_targets: *single_rust_channel_targets
301-
test_targets: *single_rust_channel_targets
315+
build_targets: *single_rust_channel_min_version_targets
316+
test_targets: *single_rust_channel_min_version_targets
302317
ubuntu2004_min_rust_version_with_aspects:
303318
name: "Min Rust Version With Aspects"
304319
platform: ubuntu2004
305320
shell_commands: *min_rust_version_shell_commands
306321
build_flags: *aspects_flags
307-
build_targets: *single_rust_channel_targets
322+
build_targets: *single_rust_channel_min_version_targets
308323
test_flags: *aspects_flags
309-
test_targets: *single_rust_channel_targets
324+
test_targets: *single_rust_channel_min_version_targets
310325
ubuntu2004_stable_toolchain:
311326
name: "Only Stable Toolchain"
312327
platform: ubuntu2004

MODULE.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ use_repo(
158158
"rules_rust_wasm_bindgen_cli",
159159
)
160160

161+
cargo_internal_deps = use_extension("//cargo/private:internal_extensions.bzl", "i")
162+
use_repo(
163+
cargo_internal_deps,
164+
"rrcti__cargo_toml-0.20.5",
165+
)
166+
161167
rust = use_extension("//rust:extensions.bzl", "rust")
162168
rust.toolchain(edition = "2021")
163169
use_repo(rust, "rust_toolchains")

WORKSPACE.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ load("@rules_rust//bindgen:transitive_repositories.bzl", "rust_bindgen_transitiv
4545

4646
rust_bindgen_transitive_dependencies()
4747

48+
load("@rules_rust//cargo:deps.bzl", "cargo_dependencies")
49+
50+
cargo_dependencies()
51+
4852
load("@rules_rust//tools/rust_analyzer:deps.bzl", "rust_analyzer_dependencies")
4953

5054
rust_analyzer_dependencies()

cargo/defs.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,15 @@ load(
1313
"//cargo/private:cargo_dep_env.bzl",
1414
_cargo_dep_env = "cargo_dep_env",
1515
)
16+
load(
17+
"//cargo/private:cargo_lints.bzl",
18+
_extract_cargo_lints = "extract_cargo_lints",
19+
)
1620

1721
cargo_bootstrap_repository = _cargo_bootstrap_repository
1822
cargo_env = _cargo_env
1923

2024
cargo_build_script = _cargo_build_script
2125
cargo_dep_env = _cargo_dep_env
26+
27+
extract_cargo_lints = _extract_cargo_lints

cargo/deps.bzl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""
2+
The dependencies for running the cargo_toml_info binary.
3+
"""
4+
5+
load("//cargo/private/cargo_toml_info/3rdparty/crates:defs.bzl", "crate_repositories")
6+
7+
def cargo_dependencies():
8+
"""Define dependencies of the `cargo` Bazel tools"""
9+
return crate_repositories()

cargo/private/cargo_lints.bzl

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Rule used to retrieve the lints specified in the [lints section] of a `Cargo.toml`.
3+
4+
[lints section](https://doc.rust-lang.org/cargo/reference/manifest.html#the-lints-section)
5+
"""
6+
7+
# buildifier: disable=bzl-visibility
8+
load("//rust/private:providers.bzl", "LintsInfo")
9+
10+
def _extract_cargo_lints(ctx):
11+
# Cargo.toml's to read from.
12+
inputs = [ctx.file.manifest]
13+
args = ctx.actions.args()
14+
15+
args.add("--manifest_toml={0}".format(ctx.file.manifest.path))
16+
if ctx.attr.workspace:
17+
inputs.append(ctx.file.workspace)
18+
args.add("--workspace_toml={0}".format(ctx.file.workspace.path))
19+
args.add("lints")
20+
21+
# Files to output our formatted arguments into.
22+
rustc_lints_out = ctx.actions.declare_file(ctx.label.name + ".rustc" + ".lints")
23+
clippy_lints_out = ctx.actions.declare_file(ctx.label.name + ".clippy" + ".lints")
24+
rustdoc_lints_out = ctx.actions.declare_file(ctx.label.name + ".rustdoc" + ".lints")
25+
26+
args.add(rustc_lints_out)
27+
args.add(clippy_lints_out)
28+
args.add(rustdoc_lints_out)
29+
30+
outputs = [rustc_lints_out, clippy_lints_out, rustdoc_lints_out]
31+
32+
ctx.actions.run(
33+
outputs = outputs,
34+
executable = ctx.file._cargo_toml_info,
35+
inputs = inputs,
36+
arguments = [args],
37+
mnemonic = "CargoLints",
38+
progress_message = "Reading Cargo metadata to get Lints for {}".format(ctx.attr.name),
39+
)
40+
41+
return [
42+
DefaultInfo(files = depset(outputs), runfiles = ctx.runfiles(outputs)),
43+
LintsInfo(
44+
rustc_lint_flags = [],
45+
rustc_lint_files = [rustc_lints_out],
46+
clippy_lint_flags = [],
47+
clippy_lint_files = [clippy_lints_out],
48+
rustdoc_lint_flags = [],
49+
rustdoc_lint_files = [rustdoc_lints_out],
50+
),
51+
]
52+
53+
extract_cargo_lints = rule(
54+
implementation = _extract_cargo_lints,
55+
attrs = {
56+
"manifest": attr.label(
57+
allow_single_file = True,
58+
mandatory = True,
59+
doc = "Cargo.toml to read lints from.",
60+
),
61+
"workspace": attr.label(
62+
allow_single_file = True,
63+
doc = "Workspace Cargo.toml that the manifest Cargo.toml inherits from.",
64+
),
65+
"_cargo_toml_info": attr.label(
66+
allow_single_file = True,
67+
executable = True,
68+
default = Label("//cargo/private/cargo_toml_info:cargo_toml_info"),
69+
cfg = "exec",
70+
),
71+
},
72+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
load("//crate_universe:defs.bzl", "crate", "crates_vendor")
2+
3+
crates_vendor(
4+
name = "crates_vendor",
5+
cargo_lockfile = "Cargo.Bazel.lock",
6+
mode = "remote",
7+
packages = {
8+
"cargo_toml": crate.spec(version = "0.20.5"),
9+
},
10+
repository_name = "rrcti",
11+
tags = ["manual"],
12+
)

cargo/private/cargo_toml_info/3rdparty/Cargo.Bazel.lock

Lines changed: 155 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
###############################################################################
2+
# @generated
3+
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
4+
# regenerate this file, run the following:
5+
#
6+
# bazel run @@//cargo/private/cargo_toml_info/3rdparty:crates_vendor
7+
###############################################################################
8+
9+
package(default_visibility = ["//visibility:public"])
10+
11+
exports_files(
12+
[
13+
"cargo-bazel.json",
14+
"crates.bzl",
15+
"defs.bzl",
16+
] + glob(
17+
include = ["*.bazel"],
18+
allow_empty = True,
19+
),
20+
)
21+
22+
filegroup(
23+
name = "srcs",
24+
srcs = glob(
25+
include = [
26+
"*.bazel",
27+
"*.bzl",
28+
],
29+
allow_empty = True,
30+
),
31+
)
32+
33+
# Workspace Member Dependencies
34+
alias(
35+
name = "cargo_toml",
36+
actual = "@rrcti__cargo_toml-0.20.5//:cargo_toml",
37+
tags = ["manual"],
38+
)

0 commit comments

Comments
 (0)