Skip to content

Commit af29e2a

Browse files
committed
ci: build Rust bindings inside devcontainer
Add Rust toolchain (rustup, clippy, rustfmt, gcc, musl-dev) to the devcontainer Dockerfile. Rust builds alongside Go and Python as part of proto-local. Pass PROTO_DEPS_DIR to cargo so build.rs finds validate.proto from the container's proto deps. local build still fetches validate.proto from net Signed-off-by: Mikhail Malyshev <mike.malyshev@gmail.com>
1 parent 5799d1c commit af29e2a

File tree

4 files changed

+44
-7
lines changed

4 files changed

+44
-7
lines changed

.devcontainer/Dockerfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ ARG PROTO_GEN_VALIDATE_VERSION=7b06248484ceeaa947e93ca2747eccf336a88ecc # v1.2.1
1212
ARG GOOGLEAPIS_VERSION=376467058c288ad34dd7aafa892a95883e4acd0c # master
1313
ARG PROTO_DEPS_DIR=/proto/.proto_deps
1414

15-
RUN apk add --no-cache bash curl git make graphviz ttf-freefont
15+
RUN apk add --no-cache bash curl git make graphviz ttf-freefont gcc musl-dev
1616

1717

1818
RUN arch="$(uname -m)" && \
@@ -70,3 +70,7 @@ RUN mkdir -p $(go env GOPATH)
7070
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v${PROTOC_GEN_GO_VERSION} && mv /root/go/bin/protoc-gen-go /usr/local/bin/protoc-gen-go
7171
RUN go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@${OPENAPI_VERSION} && mv /root/go/bin/protoc-gen-openapiv2 /usr/local/bin/protoc-gen-openapiv2
7272
RUN go install github.com/envoyproxy/protoc-gen-validate@${PROTO_GEN_VALIDATE_VERSION} && mv /root/go/bin/protoc-gen-validate /usr/local/bin/protoc-gen-validate
73+
74+
# Install Rust toolchain (for prost-build based protobuf bindings)
75+
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal --component clippy,rustfmt
76+
ENV PATH="/root/.cargo/bin:${PATH}"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.cache/
22
swagger/
33
rust/target/
4+
rust/proto-deps/

Makefile

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,17 @@ go-vet:
4646
python: proto-api-python
4747

4848
rust:
49-
cd rust && cargo build --release
49+
cd rust && PROTO_DEPS_DIR=$(PROTO_DEPS_DIR) cargo build --release
5050
@echo Rust bindings built successfully
5151

5252
rust-test:
53-
cd rust && cargo test
54-
cd rust && cargo test --examples
53+
cd rust && PROTO_DEPS_DIR=$(PROTO_DEPS_DIR) cargo test
5554

5655
rust-clean:
5756
cd rust && cargo clean
5857

5958
rust-check:
60-
cd rust && cargo check
61-
cd rust && cargo clippy -- -D warnings
59+
cd rust && PROTO_DEPS_DIR=$(PROTO_DEPS_DIR) cargo clippy -- -D warnings
6260
cd rust && cargo fmt --check
6361

6462
proto-api-%:

rust/build.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use prost_build::Config;
22
use std::path::Path;
3+
use std::process::Command;
34

45
fn main() -> Result<(), Box<dyn std::error::Error>> {
56
let proto_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../proto");
@@ -14,6 +15,37 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
1415

1516
let proto_dir_str = proto_dir.to_str().unwrap();
1617

18+
// Extra include path for third-party proto deps (e.g., validate/validate.proto
19+
// from protoc-gen-validate, imported by register.proto).
20+
//
21+
// Resolution order:
22+
// 1. PROTO_DEPS_DIR env var (set inside devcontainer → /proto/.proto_deps)
23+
// 2. Local proto-deps/ directory (auto-fetched for local dev)
24+
let proto_deps_dir = if let Ok(d) = std::env::var("PROTO_DEPS_DIR") {
25+
Path::new(&d).join("protoc-gen-validate").to_path_buf()
26+
} else {
27+
let local = Path::new(env!("CARGO_MANIFEST_DIR")).join("proto-deps");
28+
let validate = local.join("validate").join("validate.proto");
29+
if !validate.exists() {
30+
eprintln!("Fetching validate.proto for local build...");
31+
std::fs::create_dir_all(local.join("validate")).expect("create proto-deps/validate/");
32+
let status = Command::new("curl")
33+
.args([
34+
"-sSfL",
35+
"-o",
36+
validate.to_str().unwrap(),
37+
"https://raw.githubusercontent.com/bufbuild/protoc-gen-validate/v1.2.1/validate/validate.proto",
38+
])
39+
.status()
40+
.expect("failed to run curl — install curl or use the devcontainer");
41+
if !status.success() {
42+
panic!("failed to download validate.proto (exit {})", status);
43+
}
44+
}
45+
local
46+
};
47+
let proto_deps_str = proto_deps_dir.to_str().unwrap().to_owned();
48+
1749
let mut config = Config::new();
1850

1951
// Use Bytes for all bytes fields for zero-copy efficiency
@@ -91,10 +123,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
91123
.map(|f| format!("{}/{}", proto_dir_str, f))
92124
.collect();
93125

94-
config.compile_protos(&proto_files, &[proto_dir_str])?;
126+
config.compile_protos(&proto_files, &[proto_dir_str, &proto_deps_str])?;
95127

96128
// Rerun if any proto file changes
97129
println!("cargo:rerun-if-changed={}", proto_dir_str);
130+
println!("cargo:rerun-if-changed={}", proto_deps_str);
131+
println!("cargo:rerun-if-env-changed=PROTO_DEPS_DIR");
98132
println!("cargo:rerun-if-changed=build.rs");
99133

100134
Ok(())

0 commit comments

Comments
 (0)