From ae4c44908d27abd6210454681c2c422c41d02b5b Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 23 Sep 2026 11:47:06 +0800 Subject: [PATCH 1/2] chore: remove unused legacy generator dependencies Remove the unused public grpcio Prost generator from ttrpc-compiler and its Prost 0.8 dependencies. Bump compiler and codegen versions for the API and dependency changes. Remove unused direct dependencies from the Prost generator and example manifests; keep tempfile only for compiler tests. Signed-off-by: Tim Zhang --- Cargo.toml | 4 +- codegen/Cargo.toml | 2 - compiler/CHANGELOG.md | 8 + compiler/Cargo.toml | 8 +- compiler/src/lib.rs | 2 - compiler/src/prost_codegen.rs | 559 ---------------------------------- example-prost/Cargo.toml | 3 - example/Cargo.toml | 4 - ttrpc-codegen/CHANGELOG.md | 7 + ttrpc-codegen/Cargo.toml | 2 +- 10 files changed, 21 insertions(+), 578 deletions(-) delete mode 100644 compiler/src/prost_codegen.rs diff --git a/Cargo.toml b/Cargo.toml index e9e7d175..0d083eb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,8 +29,8 @@ authors = ["The AntFin Kata Team "] # version. For example, for protobuf: # protobuf = { workspace = true } ttrpc = { version = "0.9.0", path = "./" } -ttrpc-codegen = { version = "0.6.0", path = "./ttrpc-codegen" } -ttrpc-compiler = { version = "0.8.0", path = "./compiler" } +ttrpc-codegen = { version = "0.6.1", path = "./ttrpc-codegen" } +ttrpc-compiler = { version = "0.9.0", path = "./compiler" } protobuf = "3.7.2" protobuf-codegen = "3.7.2" protobuf-parse = "3.7.2" diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 20b08fdc..127ea5fb 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -24,5 +24,3 @@ prost-types = "0.13" prost-build = "0.13" proc-macro2 = "1.0" quote = "1.0" -lazy_static = "1.4" -regex = "1.7" diff --git a/compiler/CHANGELOG.md b/compiler/CHANGELOG.md index 2ab9812a..c1883aaf 100644 --- a/compiler/CHANGELOG.md +++ b/compiler/CHANGELOG.md @@ -9,6 +9,14 @@ published crates and Git history. Release dates are crates.io publication dates. Releases are ordered by publication date because multiple version lines were maintained in parallel. +## [Unreleased] + +### Removed + +- **Breaking:** Removed the unused `prost_codegen` module, which generated + grpcio bindings, and its Prost 0.8 dependencies. Use the standalone Prost + generator in `codegen/` for ttrpc bindings. + ## [0.8.0] - 2025-07-15 ### API changes diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 2f71c06f..4d4867f0 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ttrpc-compiler" -version = "0.8.0" +version = "0.9.0" edition = { workspace = true } rust-version = { workspace = true } license = { workspace = true } @@ -15,10 +15,8 @@ homepage = "https://github.com/containerd/ttrpc-rust/tree/master/compiler" [dependencies] protobuf = { workspace = true } protobuf-codegen = { workspace = true } -prost = "0.8" -prost-build = "0.8" -prost-types = "0.8" -derive-new = "0.5" + +[dev-dependencies] tempfile = "3.0" [[bin]] diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index 857aea9b..8f86abbd 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -25,8 +25,6 @@ /// Generates ttrpc service bindings from Protocol Buffers descriptors. pub mod codegen; -/// Legacy Prost-based code generation helpers. -pub mod prost_codegen; mod util; /// Customize generated code. diff --git a/compiler/src/prost_codegen.rs b/compiler/src/prost_codegen.rs deleted file mode 100644 index ad59e7f3..00000000 --- a/compiler/src/prost_codegen.rs +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright 2019 PingCAP, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Legacy Prost-based service generation helpers. -//! -//! This module invokes `protoc` and generates Rust messages and service definitions through -//! `prost-build`. New ttrpc projects generally use the pure-Rust [`ttrpc-codegen`] pipeline. -//! -//! [`ttrpc-codegen`]: https://docs.rs/ttrpc-codegen - -use super::util::{fq_grpc, to_snake_case, MethodType}; -use derive_new::new; -use prost::Message; -use prost_build::{protoc, protoc_include, Config, Method, Service, ServiceGenerator}; -use prost_types::FileDescriptorSet; -use std::io::{Error, Read}; -use std::path::Path; -use std::{fs, io, process::Command}; - -/// Compiles Protocol Buffers files and returns the unique package names generated. -/// -/// # Errors -/// -/// Returns an error if `protoc` cannot be executed, exits unsuccessfully, produces an invalid -/// descriptor set, or generated files cannot be written to `out_dir`. -pub fn compile_protos

(protos: &[P], includes: &[P], out_dir: &str) -> io::Result> -where - P: AsRef, -{ - let mut prost_config = Config::new(); - prost_config.service_generator(Box::new(Generator)); - prost_config.out_dir(out_dir); - - // Create a file descriptor set for the protocol files. - let tmp = tempfile::Builder::new().prefix("prost-build").tempdir()?; - let descriptor_set = tmp.path().join("prost-descriptor-set"); - - let mut cmd = Command::new(protoc()); - cmd.arg("--include_imports") - .arg("--include_source_info") - .arg("-o") - .arg(&descriptor_set); - - for include in includes { - cmd.arg("-I").arg(include.as_ref()); - } - - // Set the protoc include after the user includes in case the user wants to - // override one of the built-in .protos. - cmd.arg("-I").arg(protoc_include()); - - for proto in protos { - cmd.arg(proto.as_ref()); - } - - let output = cmd.output()?; - if !output.status.success() { - return Err(Error::other(format!( - "protoc failed: {}", - String::from_utf8_lossy(&output.stderr) - ))); - } - - let mut buf = Vec::new(); - fs::File::open(descriptor_set)?.read_to_end(&mut buf)?; - let descriptor_set = FileDescriptorSet::decode(&*buf)?; - - // Get the package names from the descriptor set. - let mut packages: Vec<_> = descriptor_set - .file - .iter() - .filter_map(|f| f.package.clone()) - .collect(); - packages.sort(); - packages.dedup(); - - // FIXME(https://github.com/danburkert/prost/pull/155) - // Unfortunately we have to forget the above work and use `compile_protos` to - // actually generate the Rust code. - prost_config.compile_protos(protos, includes)?; - - Ok(packages) -} - -struct Generator; - -impl ServiceGenerator for Generator { - fn generate(&mut self, service: Service, buf: &mut String) { - generate_methods(&service, buf); - generate_client(&service, buf); - generate_server(&service, buf); - } -} - -fn generate_methods(service: &Service, buf: &mut String) { - let service_path = if service.package.is_empty() { - format!("/{}", service.proto_name) - } else { - format!("/{}.{}", service.package, service.proto_name) - }; - - for method in &service.methods { - generate_method(&service.name, &service_path, method, buf); - } -} - -fn const_method_name(service_name: &str, method: &Method) -> String { - format!( - "METHOD_{}_{}", - to_snake_case(service_name).to_uppercase(), - method.name.to_uppercase() - ) -} - -fn generate_method(service_name: &str, service_path: &str, method: &Method, buf: &mut String) { - let name = const_method_name(service_name, method); - let ty = format!( - "{}<{}, {}>", - fq_grpc("Method"), - method.input_type, - method.output_type - ); - - buf.push_str("const "); - buf.push_str(&name); - buf.push_str(": "); - buf.push_str(&ty); - buf.push_str(" = "); - generate_method_body(service_path, method, buf); -} - -fn generate_method_body(service_path: &str, method: &Method, buf: &mut String) { - let ty = fq_grpc(&MethodType::from_method(method).to_string()); - let pr_mar = format!( - "{} {{ ser: {}, de: {} }}", - fq_grpc("Marshaller"), - fq_grpc("pr_ser"), - fq_grpc("pr_de") - ); - - buf.push_str(&fq_grpc("Method")); - buf.push('{'); - generate_field_init("ty", &ty, buf); - generate_field_init( - "name", - &format!("\"{}/{}\"", service_path, method.proto_name), - buf, - ); - generate_field_init("req_mar", &pr_mar, buf); - generate_field_init("resp_mar", &pr_mar, buf); - buf.push_str("};\n"); -} - -// TODO share this code with protobuf codegen -impl MethodType { - fn from_method(method: &Method) -> MethodType { - match (method.client_streaming, method.server_streaming) { - (false, false) => MethodType::Unary, - (true, false) => MethodType::ClientStreaming, - (false, true) => MethodType::ServerStreaming, - (true, true) => MethodType::Duplex, - } - } -} - -fn generate_field_init(name: &str, value: &str, buf: &mut String) { - buf.push_str(name); - buf.push_str(": "); - buf.push_str(value); - buf.push_str(", "); -} - -fn generate_client(service: &Service, buf: &mut String) { - let client_name = format!("{}Client", service.name); - buf.push_str("#[derive(Clone)]\n"); - buf.push_str("pub struct "); - buf.push_str(&client_name); - buf.push_str(" { client: ::grpcio::Client }\n"); - - buf.push_str("impl "); - buf.push_str(&client_name); - buf.push_str(" {\n"); - generate_ctor(&client_name, buf); - generate_client_methods(service, buf); - generate_spawn(buf); - buf.push_str("}\n") -} - -fn generate_ctor(client_name: &str, buf: &mut String) { - buf.push_str("pub fn new(channel: ::grpcio::Channel) -> Self { "); - buf.push_str(client_name); - buf.push_str(" { client: ::grpcio::Client::new(channel) }"); - buf.push_str("}\n"); -} - -fn generate_client_methods(service: &Service, buf: &mut String) { - for method in &service.methods { - generate_client_method(&service.name, method, buf); - } -} - -fn generate_client_method(service_name: &str, method: &Method, buf: &mut String) { - let name = &format!( - "METHOD_{}_{}", - to_snake_case(service_name).to_uppercase(), - method.name.to_uppercase() - ); - match MethodType::from_method(method) { - MethodType::Unary => { - ClientMethod::new( - &method.name, - true, - Some(&method.input_type), - false, - vec![&method.output_type], - "unary_call", - name, - ) - .generate(buf); - ClientMethod::new( - &method.name, - false, - Some(&method.input_type), - false, - vec![&method.output_type], - "unary_call", - name, - ) - .generate(buf); - ClientMethod::new( - &method.name, - true, - Some(&method.input_type), - true, - vec![&format!( - "{}<{}>", - fq_grpc("ClientUnaryReceiver"), - method.output_type - )], - "unary_call", - name, - ) - .generate(buf); - ClientMethod::new( - &method.name, - false, - Some(&method.input_type), - true, - vec![&format!( - "{}<{}>", - fq_grpc("ClientUnaryReceiver"), - method.output_type - )], - "unary_call", - name, - ) - .generate(buf); - } - MethodType::ClientStreaming => { - ClientMethod::new( - &method.name, - true, - None, - false, - vec![ - &format!("{}<{}>", fq_grpc("ClientCStreamSender"), method.input_type), - &format!( - "{}<{}>", - fq_grpc("ClientCStreamReceiver"), - method.output_type - ), - ], - "client_streaming", - name, - ) - .generate(buf); - ClientMethod::new( - &method.name, - false, - None, - false, - vec![ - &format!("{}<{}>", fq_grpc("ClientCStreamSender"), method.input_type), - &format!( - "{}<{}>", - fq_grpc("ClientCStreamReceiver"), - method.output_type - ), - ], - "client_streaming", - name, - ) - .generate(buf); - } - MethodType::ServerStreaming => { - ClientMethod::new( - &method.name, - true, - Some(&method.input_type), - false, - vec![&format!( - "{}<{}>", - fq_grpc("ClientSStreamReceiver"), - method.output_type - )], - "server_streaming", - name, - ) - .generate(buf); - ClientMethod::new( - &method.name, - false, - Some(&method.input_type), - false, - vec![&format!( - "{}<{}>", - fq_grpc("ClientSStreamReceiver"), - method.output_type - )], - "server_streaming", - name, - ) - .generate(buf); - } - MethodType::Duplex => { - ClientMethod::new( - &method.name, - true, - None, - false, - vec![ - &format!("{}<{}>", fq_grpc("ClientDuplexSender"), method.input_type), - &format!( - "{}<{}>", - fq_grpc("ClientDuplexReceiver"), - method.output_type - ), - ], - "duplex_streaming", - name, - ) - .generate(buf); - ClientMethod::new( - &method.name, - false, - None, - false, - vec![ - &format!("{}<{}>", fq_grpc("ClientDuplexSender"), method.input_type), - &format!( - "{}<{}>", - fq_grpc("ClientDuplexReceiver"), - method.output_type - ), - ], - "duplex_streaming", - name, - ) - .generate(buf); - } - } -} - -#[derive(new)] -struct ClientMethod<'a> { - method_name: &'a str, - opt: bool, - request: Option<&'a str>, - r#async: bool, - result_types: Vec<&'a str>, - inner_method_name: &'a str, - data_name: &'a str, -} - -impl<'a> ClientMethod<'a> { - fn generate(&self, buf: &mut String) { - buf.push_str("pub fn "); - - buf.push_str(self.method_name); - if self.r#async { - buf.push_str("_async"); - } - if self.opt { - buf.push_str("_opt"); - } - - buf.push_str("(&self"); - if let Some(req) = self.request { - buf.push_str(", req: &"); - buf.push_str(req); - } - if self.opt { - buf.push_str(", opt: "); - buf.push_str(&fq_grpc("CallOption")); - } - buf.push_str(") -> "); - - buf.push_str(&fq_grpc("Result")); - buf.push('<'); - if self.result_types.len() != 1 { - buf.push('('); - } - for rt in &self.result_types { - buf.push_str(rt); - buf.push(','); - } - if self.result_types.len() != 1 { - buf.push(')'); - } - buf.push_str("> { "); - if self.opt { - self.generate_inner_body(buf); - } else { - self.generate_opt_body(buf); - } - buf.push_str(" }\n"); - } - - // Method delegates to the `_opt` version of the method. - fn generate_opt_body(&self, buf: &mut String) { - buf.push_str("self."); - buf.push_str(self.method_name); - if self.r#async { - buf.push_str("_async"); - } - buf.push_str("_opt("); - if self.request.is_some() { - buf.push_str("req, "); - } - buf.push_str(&fq_grpc("CallOption::default()")); - buf.push(')'); - } - - // Method delegates to the inner client. - fn generate_inner_body(&self, buf: &mut String) { - buf.push_str("self.client."); - buf.push_str(self.inner_method_name); - if self.r#async { - buf.push_str("_async"); - } - buf.push_str("(&"); - buf.push_str(self.data_name); - if self.request.is_some() { - buf.push_str(", req"); - } - buf.push_str(", opt)"); - } -} - -fn generate_spawn(buf: &mut String) { - buf.push_str( - "pub fn spawn(&self, f: F) \ - where F: ::futures::Future + Send + 'static {\ - self.client.spawn(f)\ - }\n", - ); -} - -fn generate_server(service: &Service, buf: &mut String) { - buf.push_str("pub trait "); - buf.push_str(&service.name); - buf.push_str(" {\n"); - generate_server_methods(service, buf); - buf.push_str("}\n"); - - buf.push_str("pub fn create_"); - buf.push_str(&to_snake_case(&service.name)); - buf.push_str("(s: S) -> "); - buf.push_str(&fq_grpc("Service")); - buf.push_str(" {\n"); - buf.push_str("let mut builder = ::grpcio::ServiceBuilder::new();\n"); - - for method in &service.methods[0..service.methods.len() - 1] { - buf.push_str("let mut instance = s.clone();\n"); - generate_method_bind(&service.name, method, buf); - } - - buf.push_str("let mut instance = s;\n"); - generate_method_bind( - &service.name, - &service.methods[service.methods.len() - 1], - buf, - ); - - buf.push_str("builder.build()\n"); - buf.push_str("}\n"); -} - -fn generate_server_methods(service: &Service, buf: &mut String) { - for method in &service.methods { - let method_type = MethodType::from_method(method); - let request_arg = match method_type { - MethodType::Unary | MethodType::ServerStreaming => { - format!("req: {}", method.input_type) - } - MethodType::ClientStreaming | MethodType::Duplex => format!( - "stream: {}<{}>", - fq_grpc("RequestStream"), - method.input_type - ), - }; - let response_type = match method_type { - MethodType::Unary => "UnarySink", - MethodType::ClientStreaming => "ClientStreamingSink", - MethodType::ServerStreaming => "ServerStreamingSink", - MethodType::Duplex => "DuplexSink", - }; - generate_server_method(method, &request_arg, response_type, buf); - } -} - -fn generate_server_method( - method: &Method, - request_arg: &str, - response_type: &str, - buf: &mut String, -) { - buf.push_str("fn "); - buf.push_str(&method.name); - buf.push_str("(&mut self, ctx: "); - buf.push_str(&fq_grpc("RpcContext")); - buf.push_str(", "); - buf.push_str(request_arg); - buf.push_str(", sink: "); - buf.push_str(&fq_grpc(response_type)); - buf.push('<'); - buf.push_str(&method.output_type); - buf.push('>'); - buf.push_str(");\n"); -} - -fn generate_method_bind(service_name: &str, method: &Method, buf: &mut String) { - let add_name = match MethodType::from_method(method) { - MethodType::Unary => "add_unary_handler", - MethodType::ClientStreaming => "add_client_streaming_handler", - MethodType::ServerStreaming => "add_server_streaming_handler", - MethodType::Duplex => "add_duplex_streaming_handler", - }; - - buf.push_str("builder = builder."); - buf.push_str(add_name); - buf.push_str("(&"); - buf.push_str(&const_method_name(service_name, method)); - buf.push_str(", move |ctx, req, resp| instance."); - buf.push_str(&method.name); - buf.push_str("(ctx, req, resp));\n"); -} diff --git a/example-prost/Cargo.toml b/example-prost/Cargo.toml index 0e814c8d..44daedff 100644 --- a/example-prost/Cargo.toml +++ b/example-prost/Cargo.toml @@ -14,11 +14,8 @@ publish = false [dependencies] prost = "0.13" -libc = "0.2.79" -byteorder = "1.3.2" log = "0.4.6" simple-logging = "2.0.2" -nix = "0.23.0" ttrpc = { path = "../", features = ["sync", "async", "prost"], default-features = false } ctrlc = { version = "3.0", features = ["termination"] } tokio = { version = "1.0.1", features = ["signal", "time"] } diff --git a/example/Cargo.toml b/example/Cargo.toml index ae070e44..2b851c36 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -13,12 +13,8 @@ publish = false [dev-dependencies] protobuf = "3.7.2" -bytes = "0.4.11" -libc = "0.2.158" -byteorder = "1.3.2" log = "0.4.6" simple-logging = "2.0.2" -nix = "0.23.0" ttrpc = { path = "../", features = ["async","rustprotobuf"] } ctrlc = { version = "3.0", features = ["termination"] } tokio = { version = "1.0.1", features = ["signal", "time", "rt-multi-thread", "macros"] } diff --git a/ttrpc-codegen/CHANGELOG.md b/ttrpc-codegen/CHANGELOG.md index 7e8f4f27..40eedd98 100644 --- a/ttrpc-codegen/CHANGELOG.md +++ b/ttrpc-codegen/CHANGELOG.md @@ -8,6 +8,13 @@ published crates and Git history. Release dates are crates.io publication dates. Releases are ordered by publication date because multiple version lines were maintained in parallel. +## [Unreleased] + +### Changed + +- Updated the `ttrpc-compiler` dependency to 0.9.0 after removing its unused + legacy Prost generator. + ## [0.6.0] - 2025-07-15 ### API changes diff --git a/ttrpc-codegen/Cargo.toml b/ttrpc-codegen/Cargo.toml index 96ee2153..3b69a057 100644 --- a/ttrpc-codegen/Cargo.toml +++ b/ttrpc-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ttrpc-codegen" -version = "0.6.0" +version = "0.6.1" edition = { workspace = true } rust-version = { workspace = true } authors = { workspace = true } From c0c3ed1bcf27bc373fbc673250de06063efda8d6 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 23 Sep 2026 15:54:14 +0800 Subject: [PATCH 2/2] codegen: rename Prost generator and directory Rename the unpublished Prost generator package to `ttrpc-codegen-prost` at 0.1.0 and move its source directory. Update the Prost example, CI, package links, and release docs. Preserve the newer generator guide while updating imports and paths. Signed-off-by: Tim Zhang --- .github/workflows/bvt.yml | 8 ++-- Cargo.toml | 2 +- README.md | 18 ++++----- RELEASE.md | 19 ++++++++++ compiler/CHANGELOG.md | 2 +- example-prost/Cargo.toml | 2 +- example-prost/README.md | 4 +- example-prost/build.rs | 2 +- src/lib.rs | 4 +- ttrpc-codegen-prost/CHANGELOG.md | 37 +++++++++++++++++++ {codegen => ttrpc-codegen-prost}/Cargo.toml | 8 ++-- {codegen => ttrpc-codegen-prost}/Makefile | 0 {codegen => ttrpc-codegen-prost}/README.md | 21 ++++++----- .../src/codegen.rs | 4 +- {codegen => ttrpc-codegen-prost}/src/lib.rs | 2 +- .../src/svcgen.rs | 0 {codegen => ttrpc-codegen-prost}/src/util.rs | 0 .../tests/codegen_proto.rs | 8 ++-- 18 files changed, 100 insertions(+), 41 deletions(-) create mode 100644 ttrpc-codegen-prost/CHANGELOG.md rename {codegen => ttrpc-codegen-prost}/Cargo.toml (89%) rename {codegen => ttrpc-codegen-prost}/Makefile (100%) rename {codegen => ttrpc-codegen-prost}/README.md (85%) rename {codegen => ttrpc-codegen-prost}/src/codegen.rs (98%) rename {codegen => ttrpc-codegen-prost}/src/lib.rs (97%) rename {codegen => ttrpc-codegen-prost}/src/svcgen.rs (100%) rename {codegen => ttrpc-codegen-prost}/src/util.rs (100%) rename {codegen => ttrpc-codegen-prost}/tests/codegen_proto.rs (84%) diff --git a/.github/workflows/bvt.yml b/.github/workflows/bvt.yml index 66f41d0d..946df530 100644 --- a/.github/workflows/bvt.yml +++ b/.github/workflows/bvt.yml @@ -23,7 +23,7 @@ jobs: run: | cargo test --workspace --features async,sync,security_extension cargo test -p ttrpc --no-default-features --features sync,async,prost - cargo test --manifest-path codegen/Cargo.toml + cargo test --manifest-path ttrpc-codegen-prost/Cargo.toml check: name: Check @@ -40,9 +40,9 @@ jobs: - name: Check run: | make check-all - # The codegen crate is a standalone workspace root, so its checks + # The ttrpc-codegen-prost crate is a standalone workspace root, so its checks # must be invoked explicitly (protoc is required for its tests). - make -C codegen check + make -C ttrpc-codegen-prost check make: name: Build @@ -63,7 +63,7 @@ jobs: make -C ttrpc-codegen make -C example build-examples make -C example-prost build-examples - make -C codegen test + make -C ttrpc-codegen-prost test # Keep bash so a native-command failure on Windows isn't masked by a # later successful command (PowerShell swallows non-zero exits). shell: bash diff --git a/Cargo.toml b/Cargo.toml index 0d083eb2..7796afd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ # they are standalone crates and intentionally kept decoupled from the # rustprotobuf-oriented workspace members above. exclude = [ - "./codegen", + "./ttrpc-codegen-prost", "./example-prost", ] resolver = "2" diff --git a/README.md b/README.md index 341032d1..8e208d6a 100644 --- a/README.md +++ b/README.md @@ -189,18 +189,18 @@ prost = "0.13" ttrpc = { path = "../ttrpc-rust", default-features = false, features = ["sync", "prost"] } [build-dependencies] -ttrpc-codegen = { path = "../ttrpc-rust/codegen" } +ttrpc-codegen-prost = { version = "0.1", path = "../ttrpc-rust/ttrpc-codegen-prost" } ``` -Adjust the paths to your checkout. The Prost generator in `codegen/` is a separate -crate from the rust-protobuf generator in `ttrpc-codegen/`; select the appropriate -path. The two protobuf backend features are mutually exclusive. Because disabling +Adjust the paths to your checkout. The `ttrpc-codegen-prost` package is separate +from the rust-protobuf `ttrpc-codegen` package; its first release is planned as +version 0.1. The two protobuf backend features are mutually exclusive. Because disabling default features also disables `sync`, list the runtime features explicitly. Use `.prost()` in `build.rs`. Set `Customize::async_all = true` for async bindings and enable the runtime's `async` feature; generated async bindings also require `async-trait` in your application. Streaming requires async bindings. The -[Prost generator guide](./codegen/README.md) includes a complete dependency setup, +[Prost generator guide](./ttrpc-codegen-prost/README.md) includes a complete dependency setup, service definition, build script, and generated-module import. Generated Rust files and modules follow the protobuf package rather than the @@ -230,7 +230,7 @@ you inspect the Prost APIs and fails on documentation warnings. The generator's own documentation is built separately: ```bash -RUSTDOCFLAGS="-D warnings" cargo doc --manifest-path codegen/Cargo.toml --no-deps --open +RUSTDOCFLAGS="-D warnings" cargo doc --manifest-path ttrpc-codegen-prost/Cargo.toml --no-deps --open ``` ## Transport addresses @@ -253,7 +253,7 @@ ttrpc does not provide TLS. If you expose TCP beyond a trusted boundary, secure | [`ttrpc-codegen`](https://crates.io/crates/ttrpc-codegen) | Build-script API for parsing `.proto` files and generating Rust code | | [`ttrpc-compiler`](https://crates.io/crates/ttrpc-compiler) | Service code generator and `protoc` plugin | | [`example`](https://github.com/containerd/ttrpc-rust/tree/master/example) | End-to-end unary and streaming examples using rust-protobuf | -| [Prost generator](./codegen) | Standalone build-script generator using Prost and `protoc` | +| [`ttrpc-codegen-prost`](./ttrpc-codegen-prost) | Standalone build-script generator using Prost and `protoc` | | [`example-prost`](./example-prost) | Standalone unary and streaming examples using Prost | ## Compatibility @@ -276,8 +276,8 @@ make test make check-all # The Prost generator is a separate workspace -make -C codegen test -make -C codegen check +make -C ttrpc-codegen-prost test +make -C ttrpc-codegen-prost check ``` ## Project details diff --git a/RELEASE.md b/RELEASE.md index d752951e..b208e581 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -10,10 +10,12 @@ This document describes the steps to release a new version of the crate or wasi- * `./CHANGELOG.md` for `ttrpc`. * `./compiler/CHANGELOG.md` for `ttrpc-compiler`. * `./ttrpc-codegen/CHANGELOG.md` for `ttrpc-codegen`. + * `./ttrpc-codegen-prost/CHANGELOG.md` for `ttrpc-codegen-prost`. 2. Bump package and dependency versions in: * `./compiler/Cargo.toml`: Bump the package version as needed. * `./ttrpc-codegen/Cargo.toml`: Bump the package version as needed. * `./Cargo.toml`: Bump package version as needed. Then bump the workspace dependencies version to match the respective crates versions. + * `./ttrpc-codegen-prost/Cargo.toml`: Bump `ttrpc-codegen-prost` as needed and update its dependency version in `./example-prost/Cargo.toml`. 3. Commit the changes and get them merged in the repo. 4. Dry run the `cargo publish` command as follows: ```bash @@ -30,3 +32,20 @@ This document describes the steps to release a new version of the crate or wasi- 1. `ttrpc-compiler` 2. `ttrpc-codegen` 3. `ttrpc` + +### Standalone Prost Generator + +`ttrpc-codegen-prost` lives in `ttrpc-codegen-prost/` and is a separate workspace. It is +not included in the root workspace publish commands above. Validate and +publish it separately when selected for release: + +```bash +cargo test --manifest-path ttrpc-codegen-prost/Cargo.toml +cargo build --manifest-path example-prost/Cargo.toml --examples +cargo publish --manifest-path ttrpc-codegen-prost/Cargo.toml --dry-run --locked +# After the dry run succeeds and the release changes are merged: +cargo publish --manifest-path ttrpc-codegen-prost/Cargo.toml --locked +``` + +Keep its package version and release notes independent from the +rust-protobuf `ttrpc-codegen` package. diff --git a/compiler/CHANGELOG.md b/compiler/CHANGELOG.md index c1883aaf..117d0f67 100644 --- a/compiler/CHANGELOG.md +++ b/compiler/CHANGELOG.md @@ -15,7 +15,7 @@ lines were maintained in parallel. - **Breaking:** Removed the unused `prost_codegen` module, which generated grpcio bindings, and its Prost 0.8 dependencies. Use the standalone Prost - generator in `codegen/` for ttrpc bindings. + generator in `ttrpc-codegen-prost/` for ttrpc bindings. ## [0.8.0] - 2025-07-15 diff --git a/example-prost/Cargo.toml b/example-prost/Cargo.toml index 44daedff..29a05d97 100644 --- a/example-prost/Cargo.toml +++ b/example-prost/Cargo.toml @@ -23,7 +23,7 @@ async-trait = "0.1.42" rand = "0.8.5" [build-dependencies] -ttrpc-codegen = { path = "../codegen" } +ttrpc-codegen-prost = { version = "0.1.0", path = "../ttrpc-codegen-prost" } [[example]] name = "client" diff --git a/example-prost/README.md b/example-prost/README.md index 286f7e89..743ad6af 100644 --- a/example-prost/README.md +++ b/example-prost/README.md @@ -1,7 +1,7 @@ # Prost examples These examples use the local ttrpc runtime and the standalone Prost generator in -[`codegen/`](../codegen). They share the `.proto` definitions in +[`ttrpc-codegen-prost/`](../ttrpc-codegen-prost). They share the `.proto` definitions in [`example/protocols/protos/`](../example/protocols/protos) with the rust-protobuf examples. `build.rs` generates sync and async bindings when Cargo builds them. @@ -37,7 +37,7 @@ enabled together with `prost`. Generated message and service APIs follow protobuf package names. The checked-in module glue re-exports the generated `grpc` and streaming packages under the -names used by the example sources. See the [generator guide](../codegen/README.md) +names used by the example sources. See the [generator guide](../ttrpc-codegen-prost/README.md) for adding Prost generation to your own application. ## Build and validate diff --git a/example-prost/build.rs b/example-prost/build.rs index 68eb327c..fb077a42 100644 --- a/example-prost/build.rs +++ b/example-prost/build.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use ttrpc_codegen::{Codegen, Customize}; +use ttrpc_codegen_prost::{Codegen, Customize}; // The schemas are shared with the rust-protobuf based `example` crate; this // crate only provides the Prost-generated Rust bindings. diff --git a/src/lib.rs b/src/lib.rs index 6394dcb0..f829b646 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ //! ``` //! //! Adjust the path to your checkout. Install `protoc` for the runtime build and application -//! code generation, and use the separate [Prost generator] in `codegen/`. Its builder uses +//! code generation, and use the separate [Prost generator] in `ttrpc-codegen-prost/`. Its builder uses //! `.prost()` and supports `Customize::async_all` for async and streaming bindings. //! Generated Rust modules follow the protobuf package name; see the [Prost examples] for //! sync, async, and streaming applications. Both backends use the same ttrpc wire protocol. @@ -185,7 +185,7 @@ //! their framing protocols are different even when their service definitions match. //! //! [client, server, and streaming examples]: https://github.com/containerd/ttrpc-rust/tree/master/example -//! [Prost generator]: https://github.com/containerd/ttrpc-rust/tree/master/codegen +//! [Prost generator]: https://github.com/containerd/ttrpc-rust/tree/master/ttrpc-codegen-prost //! [Prost examples]: https://github.com/containerd/ttrpc-rust/tree/master/example-prost //! [ttrpc]: https://github.com/containerd/ttrpc //! [`ttrpc-codegen`]: https://docs.rs/ttrpc-codegen diff --git a/ttrpc-codegen-prost/CHANGELOG.md b/ttrpc-codegen-prost/CHANGELOG.md new file mode 100644 index 00000000..f9e933a7 --- /dev/null +++ b/ttrpc-codegen-prost/CHANGELOG.md @@ -0,0 +1,37 @@ +# Changelog + +All notable changes to the `ttrpc-codegen-prost` crate are documented here. +The format is based on [Keep a Changelog]. + +## [Unreleased] + +The first release is being prepared as `0.1.0`. + +### Added + +- Added a standalone Prost 0.13 generator with a fluent `Codegen` builder, + an explicit `.prost()` backend selector, and `Customize` options. ([#286]) +- Generate synchronous, asynchronous, client-streaming, server-streaming, + and bidirectional ttrpc service bindings. ([#286]) +- Support `OUT_DIR` as the default destination, module declarations through + `mod.rs` or `_include.rs`, and optional Serde derives on generated messages. + ([#286]) +- Added standalone generator tests and sync, async, and streaming examples. + Building generated bindings requires `protoc` and the runtime's `prost` + feature with default features disabled. ([#286]) + +### Changed + +- Renamed the unpublished Prost package from `ttrpc-codegen` version `1.0.0` + to `ttrpc-codegen-prost` version `0.1.0`. Rust imports now use + `ttrpc_codegen_prost`; the rust-protobuf `ttrpc-codegen` package retains + its existing name and version line. + +### Fixed + +- Avoid writing the generated-file header multiple times when several proto + descriptors share the same output package file. ([#286]) + +[Keep a Changelog]: https://keepachangelog.com/en/2.0.0/ +[Unreleased]: https://github.com/containerd/ttrpc-rust/commits/master/ttrpc-codegen-prost +[#286]: https://github.com/containerd/ttrpc-rust/pull/286 diff --git a/codegen/Cargo.toml b/ttrpc-codegen-prost/Cargo.toml similarity index 89% rename from codegen/Cargo.toml rename to ttrpc-codegen-prost/Cargo.toml index 127ea5fb..9d7825b0 100644 --- a/codegen/Cargo.toml +++ b/ttrpc-codegen-prost/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "ttrpc-codegen" -version = "1.0.0" +name = "ttrpc-codegen-prost" +version = "0.1.0" edition = "2021" rust-version = "1.85" authors = ["The Ant Group Kata Team "] @@ -8,8 +8,8 @@ license = "Apache-2.0" keywords = ["codegen", "ttrpc", "protobuf"] description = "Rust codegen for ttrpc using prost crate" categories = ["network-programming", "development-tools::build-utils"] -repository = "https://github.com/containerd/ttrpc-rust/tree/master/codegen" -homepage = "https://github.com/containerd/ttrpc-rust/tree/master/codegen" +repository = "https://github.com/containerd/ttrpc-rust/tree/master/ttrpc-codegen-prost" +homepage = "https://github.com/containerd/ttrpc-rust/tree/master/ttrpc-codegen-prost" readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/codegen/Makefile b/ttrpc-codegen-prost/Makefile similarity index 100% rename from codegen/Makefile rename to ttrpc-codegen-prost/Makefile diff --git a/codegen/README.md b/ttrpc-codegen-prost/README.md similarity index 85% rename from codegen/README.md rename to ttrpc-codegen-prost/README.md index 902e949c..063239a8 100644 --- a/codegen/README.md +++ b/ttrpc-codegen-prost/README.md @@ -1,8 +1,11 @@ -# ttrpc code generation with Prost +# ttrpc-codegen-prost This standalone crate generates Prost messages and ttrpc clients, server traits, and service registration helpers from `.proto` files. It requires `protoc` on `PATH` and uses Prost 0.13. The runtime must also use the `prost` backend. +The separate `ttrpc-codegen` package continues to use rust-protobuf. This +generator was previously an unpublished package with the same name; its first +release is planned as `ttrpc-codegen-prost` 0.1.0. ## Build a service @@ -32,12 +35,12 @@ prost = "0.13" ttrpc = { path = "../ttrpc-rust", default-features = false, features = ["sync", "prost"] } [build-dependencies] -ttrpc-codegen = { path = "../ttrpc-rust/codegen" } +ttrpc-codegen-prost = { version = "0.1", path = "../ttrpc-rust/ttrpc-codegen-prost" } ``` -The `codegen/` directory contains the Prost generator; `ttrpc-codegen/` contains -the rust-protobuf generator. Their package names currently match, so use the -explicit path above to select this generator from the checkout. +The `ttrpc-codegen-prost/` directory contains the Prost generator; +`ttrpc-codegen/` contains the rust-protobuf generator. Use the local path above +until the Prost generator is published. Define `proto/greeter.proto`: @@ -56,7 +59,7 @@ service Greeter { Generate the bindings in `build.rs`: ```rust -use ttrpc_codegen::{Codegen, Customize}; +use ttrpc_codegen_prost::{Codegen, Customize}; fn main() { println!("cargo:rerun-if-changed=proto/greeter.proto"); @@ -140,15 +143,15 @@ This crate has its own workspace. Run its checks explicitly from the repository root: ```bash -make -C codegen test -make -C codegen check +make -C ttrpc-codegen-prost test +make -C ttrpc-codegen-prost check ``` `check` runs formatting, strict Clippy, and strict API documentation generation. To open the generator documentation directly: ```bash -RUSTDOCFLAGS="-D warnings" cargo doc --manifest-path codegen/Cargo.toml --no-deps --open +RUSTDOCFLAGS="-D warnings" cargo doc --manifest-path ttrpc-codegen-prost/Cargo.toml --no-deps --open ``` The runtime's Prost and security extension documentation is a separate build diff --git a/codegen/src/codegen.rs b/ttrpc-codegen-prost/src/codegen.rs similarity index 98% rename from codegen/src/codegen.rs rename to ttrpc-codegen-prost/src/codegen.rs index 313ade5b..f5f98ad7 100644 --- a/codegen/src/codegen.rs +++ b/ttrpc-codegen-prost/src/codegen.rs @@ -64,7 +64,7 @@ impl Customize { /// # Examples /// /// ```no_run -/// use ttrpc_codegen::{Codegen, Customize}; +/// use ttrpc_codegen_prost::{Codegen, Customize}; /// /// # fn main() -> std::io::Result<()> { /// Codegen::new() @@ -223,7 +223,7 @@ impl CodegenImpl { _ => continue, }; let header = format!( - r#"// This file is generated by ttrpc-codegen {}. Do not edit + r#"// This file is generated by ttrpc-codegen-prost {}. Do not edit // @generated "#, diff --git a/codegen/src/lib.rs b/ttrpc-codegen-prost/src/lib.rs similarity index 97% rename from codegen/src/lib.rs rename to ttrpc-codegen-prost/src/lib.rs index bab1230f..1ea778d2 100644 --- a/codegen/src/lib.rs +++ b/ttrpc-codegen-prost/src/lib.rs @@ -15,7 +15,7 @@ //! See the [setup guide] for a complete build script and application configuration, //! and the [examples] for working clients and servers. //! -//! [setup guide]: https://github.com/containerd/ttrpc-rust/blob/master/codegen/README.md +//! [setup guide]: https://github.com/containerd/ttrpc-rust/blob/master/ttrpc-codegen-prost/README.md //! [examples]: https://github.com/containerd/ttrpc-rust/tree/master/example-prost mod codegen; diff --git a/codegen/src/svcgen.rs b/ttrpc-codegen-prost/src/svcgen.rs similarity index 100% rename from codegen/src/svcgen.rs rename to ttrpc-codegen-prost/src/svcgen.rs diff --git a/codegen/src/util.rs b/ttrpc-codegen-prost/src/util.rs similarity index 100% rename from codegen/src/util.rs rename to ttrpc-codegen-prost/src/util.rs diff --git a/codegen/tests/codegen_proto.rs b/ttrpc-codegen-prost/tests/codegen_proto.rs similarity index 84% rename from codegen/tests/codegen_proto.rs rename to ttrpc-codegen-prost/tests/codegen_proto.rs index 0ca4d511..27cc4b3c 100644 --- a/codegen/tests/codegen_proto.rs +++ b/ttrpc-codegen-prost/tests/codegen_proto.rs @@ -1,5 +1,5 @@ use std::path::PathBuf; -use ttrpc_codegen::{Codegen, Customize}; +use ttrpc_codegen_prost::{Codegen, Customize}; #[test] fn generate_from_shared_protos() { @@ -9,7 +9,7 @@ fn generate_from_shared_protos() { dir.join("agent.proto"), dir.join("oci.proto"), ]; - let out = std::env::temp_dir().join("ttrpc-codegen-test/grpc-out"); + let out = std::env::temp_dir().join("ttrpc-codegen-prost-test/grpc-out"); std::fs::create_dir_all(&out).unwrap(); Codegen::new() .out_dir(&out) @@ -30,7 +30,7 @@ fn generate_async_from_shared_protos() { dir.join("oci.proto"), dir.join("streaming.proto"), ]; - let out = std::env::temp_dir().join("ttrpc-codegen-test/grpc-async-out"); + let out = std::env::temp_dir().join("ttrpc-codegen-prost-test/grpc-async-out"); std::fs::create_dir_all(&out).unwrap(); Codegen::new() .out_dir(&out) @@ -53,7 +53,7 @@ fn generate_async_no_streaming() { dir.join("agent.proto"), dir.join("oci.proto"), ]; - let out = std::env::temp_dir().join("ttrpc-codegen-test/grpc-async-nostream"); + let out = std::env::temp_dir().join("ttrpc-codegen-prost-test/grpc-async-nostream"); std::fs::create_dir_all(&out).unwrap(); Codegen::new() .out_dir(&out)