Skip to content

Commit 49de586

Browse files
authored
Add rust_tonic_compile rule (#391)
## What is the goal of this PR? We added the `rust_tonic_compile` rule which compiles `.proto` files into Rust sources that depend on the `tonic` and `prost` crates. ## What are the changes implemented in this PR? We had an existing Rust binary for compiling proto files into a Tonic library - a Cargo build script in `typedb-protocol`. But Cargo users shouldn't have to run `protoc` on their machine to compile `typedb-client` (which is what happens with a Cargo build script). Rather, the `typedb-protocol` crate should contain the generated Rust gRPC + Protobuf sources. So we've created a rule, `rust_tonic_compile`, that internally runs a `rust_binary` (similarly to how many of our rules run Kotlin binaries), which uses `tonic_build` to compile `.proto` files into Rust sources, and exposes the outputs. Any `rust_library` can then depend on these generated sources. The API is similar to Java and Python (`java_grpc_compile` and `python_grpc_compile` respectively), and the `antlr` rule from `rules_antlr` behaves similarly, too. Ideally, we wouldn't need our own rule to do this, however, the Bazel rules repos that contain Rust gRPC + Protobuf rules only support the `grpc` crate, and not the more popular `tonic` crate. Moreover, all of them already have open PRs for adding such functionality: - rules-proto-grpc/rules_proto_grpc#143 - stackb/rules_proto#201 - bazelbuild/rules_rust#915 Given that our implementation is **very minimal** (~30 lines of code) it should incur a very low maintenance effort.
1 parent e2b0978 commit 49de586

File tree

4 files changed

+128
-3
lines changed

4 files changed

+128
-3
lines changed

WORKSPACE

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ workspace(name = "vaticle_dependencies")
2121
# Load @vaticle_dependencies #
2222
################################
2323

24-
# Load //build/rust
24+
# Load //builder/rust
2525
load("//builder/rust:deps.bzl", rust_deps = "deps")
2626
rust_deps()
27-
load("@rules_rust//rust:repositories.bzl", "rust_repositories")
28-
rust_repositories(version = "nightly", iso_date = "2021-07-01", edition="2018")
27+
28+
load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_register_toolchains")
29+
rules_rust_dependencies()
30+
rust_register_toolchains(edition = "2021", include_rustc_srcs = True)
2931

3032
# Load //builder/python
3133
load("//builder/python:deps.bzl", python_deps = "deps")

builder/grpc/rust/BUILD

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#
2+
# Copyright (C) 2022 Vaticle
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU Affero General Public License as
6+
# published by the Free Software Foundation, either version 3 of the
7+
# License, or (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU Affero General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU Affero General Public License
15+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
#
17+
18+
load("@rules_rust//rust:defs.bzl", "rust_binary")
19+
load("@vaticle_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test")
20+
21+
rust_binary(
22+
name = "compile",
23+
srcs = ["compile.rs"],
24+
deps = ["@vaticle_dependencies//library/crates:tonic_build"],
25+
visibility = ["//visibility:public"]
26+
)
27+
28+
checkstyle_test(
29+
name = "checkstyle",
30+
include = glob(["*"]),
31+
license_type = "agpl-header",
32+
size = "small",
33+
)

builder/grpc/rust/compile.bzl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#
2+
# Copyright (C) 2022 Vaticle
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU Affero General Public License as
6+
# published by the Free Software Foundation, either version 3 of the
7+
# License, or (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU Affero General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU Affero General Public License
15+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
#
17+
18+
def _rust_tonic_compile_impl(ctx):
19+
protos = [src[ProtoInfo].direct_sources[0] for src in ctx.attr.srcs]
20+
21+
inputs = ctx.attr.protoc.files.to_list() + protos
22+
outputs = [ctx.actions.declare_file("{}.rs".format(package)) for package in ctx.attr.packages]
23+
24+
ctx.actions.run(
25+
inputs = inputs,
26+
outputs = outputs,
27+
executable = ctx.executable._compile_script,
28+
env = {
29+
"OUT_DIR": outputs[0].dirname,
30+
"PROTOC": ctx.attr.protoc.files.to_list()[0].path,
31+
"PROTOS": ";".join([src.path for src in protos]),
32+
"PROTOS_ROOT": ctx.attr.srcs[0][ProtoInfo].proto_source_root,
33+
},
34+
mnemonic = "RustTonicCompileAction"
35+
)
36+
37+
return [DefaultInfo(files = depset(outputs))]
38+
39+
rust_tonic_compile = rule(
40+
implementation = _rust_tonic_compile_impl,
41+
attrs = {
42+
"srcs": attr.label_list(
43+
allow_files = True,
44+
mandatory = True,
45+
doc = "The .proto source files."
46+
),
47+
"packages": attr.string_list(
48+
mandatory = True,
49+
allow_empty = False,
50+
doc = "The Protobuf package names. Each package name corresponds to a single output file."
51+
),
52+
"protoc": attr.label(
53+
default = "@com_google_protobuf//:protoc",
54+
doc = "The protoc executable."
55+
),
56+
"_compile_script": attr.label(
57+
executable = True,
58+
cfg = "host",
59+
default = "@vaticle_dependencies//builder/grpc/rust:compile",
60+
),
61+
}
62+
)

builder/grpc/rust/compile.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Copyright (C) 2022 Vaticle
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as
6+
// published by the Free Software Foundation, either version 3 of the
7+
// License, or (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
//
17+
18+
use std::env;
19+
20+
fn main() -> std::io::Result<()> {
21+
let protos_raw = env::var("PROTOS").expect("PROTOS environment variable is not set");
22+
let protos: Vec<&str> = protos_raw.split(";").filter(|&str| !str.is_empty()).collect();
23+
24+
tonic_build::configure()
25+
.compile(&protos, &[
26+
env::var("PROTOS_ROOT").expect("PROTOS_ROOT environment variable is not set")
27+
])
28+
}

0 commit comments

Comments
 (0)