diff --git a/.gitignore b/.gitignore index 22ed0324..00faa555 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .vscode .idea target -/test /benchmark/output diff --git a/Cargo.lock b/Cargo.lock index fa437e5b..e538d067 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -360,9 +360,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -766,12 +766,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1368,7 +1368,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.1", "hyper-util", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -1725,9 +1725,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.165" +version = "0.2.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e" +checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" [[package]] name = "libgit2-sys" @@ -2379,9 +2379,9 @@ dependencies = [ [[package]] name = "pilota-build" -version = "0.11.26" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19d09b73001664056629c68a5aad55b9ec83f222cb951c77506292a2b89e2bd" +checksum = "ba01ed6ca5328ba34f19a26de53f8a8f058cc0ce0412bebe466c61a10587eec9" dependencies = [ "ahash", "anyhow", @@ -2934,9 +2934,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "aws-lc-rs", "log", @@ -3234,9 +3234,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3362,9 +3362,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791" +checksum = "4c33cd241af0f2e9e3b5c32163b873b29956890b5342e6745b917ce9d490f4af" dependencies = [ "core-foundation-sys", "libc", @@ -3615,7 +3615,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "tokio", ] @@ -3823,9 +3823,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -3835,9 +3835,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -3982,7 +3982,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "serde", "serde_json", @@ -4066,7 +4066,7 @@ dependencies = [ "once_cell", "pin-project", "rand", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "rustls-pki-types", "socket2", @@ -4082,7 +4082,7 @@ dependencies = [ [[package]] name = "volo-build" -version = "0.10.17" +version = "0.10.18" dependencies = [ "ahash", "anyhow", @@ -4112,7 +4112,7 @@ dependencies = [ [[package]] name = "volo-cli" -version = "0.10.4" +version = "0.10.5" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 579918fc..d4fc7543 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,12 +27,12 @@ rust-version = "1.80.0" pilota = "0.11" pilota-build = "0.11" pilota-thrift-parser = "0.11" -# pilota = { git = "https://github.com/cloudwego/pilota", branch = "main" } -# pilota-build = { git = "https://github.com/cloudwego/pilota", branch = "main" } -# pilota-thrift-parser = { git = "https://github.com/cloudwego/pilota", branch = "main" } +# pilota = { git = "https://github.com/cloudwego/pilota.git", branch = "main" } +# pilota-build = { git = "https://github.com/cloudwego/pilota.git", branch = "main" } +# pilota-thrift-parser = { git = "https://github.com/cloudwego/pilota.git", branch = "main" } motore = "0.4" -# motore = { git = "https://github.com/cloudwego/motore", branch = "main" } +# motore = { git = "https://github.com/cloudwego/motore.git", branch = "main" } metainfo = "0.7" diff --git a/examples/volo-gen/volo.yml b/examples/volo-gen/volo.yml index ce0210e4..58fe48e3 100644 --- a/examples/volo-gen/volo.yml +++ b/examples/volo-gen/volo.yml @@ -22,6 +22,7 @@ entries: thrift: filename: thrift_gen.rs protocol: thrift + split_generated_files: true services: - idl: source: local diff --git a/scripts/volo-cli-test.sh b/scripts/volo-cli-test.sh index e3236c77..1ebbcf7e 100644 --- a/scripts/volo-cli-test.sh +++ b/scripts/volo-cli-test.sh @@ -43,13 +43,22 @@ append_volo_dep_item() { echo "$1 = { path = \"$VOLO_DIR/$1\" }" >> Cargo.toml } +append_pilota_dep_item() { + echo "$1 = { git = \"https://github.com/cloudwego/pilota.git\", branch = \"main\" }" >> Cargo.toml +} + patch_cargo_toml() { echo "[patch.crates-io]" >> Cargo.toml + append_volo_dep_item volo append_volo_dep_item volo-build append_volo_dep_item volo-thrift append_volo_dep_item volo-grpc append_volo_dep_item volo-http + + append_pilota_dep_item pilota + append_pilota_dep_item pilota-build + append_pilota_dep_item pilota-thrift-parser } thrift_test() { diff --git a/tests/code-generation-workspace-split/.gitignore b/tests/code-generation-workspace-split/.gitignore new file mode 100644 index 00000000..ebffaa3e --- /dev/null +++ b/tests/code-generation-workspace-split/.gitignore @@ -0,0 +1,5 @@ +common +rpc_article +rpc_author +rpc_image +Cargo.lock diff --git a/tests/code-generation-workspace-split/Cargo.toml b/tests/code-generation-workspace-split/Cargo.toml new file mode 100644 index 00000000..e99a92dc --- /dev/null +++ b/tests/code-generation-workspace-split/Cargo.toml @@ -0,0 +1,37 @@ +[[bin]] +bench = false +name = "gen" +test = false + +[dependencies.pilota-build] +version = "*" + +[dependencies.volo-build] +workspace = true + +[package] +edition = "2021" +name = "code-generation-workspace-split" +publish = false +version = "0.0.0" + +[workspace] +members = [] + +[workspace.dependencies] +anyhow = "1" +async-trait = "0.1" +lazy_static = "1" +serde = "1" + +[workspace.dependencies.pilota] +version = "*" + +[workspace.dependencies.volo] +path = "../../volo" + +[workspace.dependencies.volo-build] +path = "../../volo-build" + +[workspace.dependencies.volo-thrift] +path = "../../volo-thrift" diff --git a/tests/code-generation-workspace-split/src/bin/gen.rs b/tests/code-generation-workspace-split/src/bin/gen.rs new file mode 100644 index 00000000..b5dc6991 --- /dev/null +++ b/tests/code-generation-workspace-split/src/bin/gen.rs @@ -0,0 +1,7 @@ +use volo_build::plugin::SerdePlugin; + +fn main() { + volo_build::workspace::Builder::thrift() + .plugin(SerdePlugin) + .gen() +} diff --git a/tests/code-generation-workspace-split/thrift/article.thrift b/tests/code-generation-workspace-split/thrift/article.thrift new file mode 100644 index 00000000..164efc8e --- /dev/null +++ b/tests/code-generation-workspace-split/thrift/article.thrift @@ -0,0 +1,34 @@ +include "image.thrift" +include "author.thrift" +include "common.thrift" + +namespace rs article + +enum Status { + NORMAL = 0, + DELETED = 1, +} + +struct Article { + 1: required i64 id, + 2: required string title, + 3: required string content, + 4: required author.Author author, + 5: required Status status, + 6: required list images, + 7: required common.CommonData common_data, +} + +struct GetArticleRequest { + 1: required i64 id, +} + +struct GetArticleResponse { + 1: required Article article, +} + +service ArticleService { + GetArticleResponse GetArticle(1: GetArticleRequest req), +} + +service articleService {} \ No newline at end of file diff --git a/tests/code-generation-workspace-split/thrift/author.thrift b/tests/code-generation-workspace-split/thrift/author.thrift new file mode 100644 index 00000000..9af3823e --- /dev/null +++ b/tests/code-generation-workspace-split/thrift/author.thrift @@ -0,0 +1,24 @@ +include "image.thrift" +include "common.thrift" + +namespace rs author + +struct Author { + 1: required i64 id, + 2: required string username, + 3: required string email, + 4: required image.Image avatar, + 5: required common.CommonData common_data, +} + +struct GetAuthorRequest { + 1: required i64 id, +} + +struct GetAuthorResponse { + 1: required Author author, +} + +service AuthorService { + GetAuthorResponse GetAuthor(1: GetAuthorRequest req), +} \ No newline at end of file diff --git a/tests/code-generation-workspace-split/thrift/cdn.thrift b/tests/code-generation-workspace-split/thrift/cdn.thrift new file mode 100644 index 00000000..c6847a3c --- /dev/null +++ b/tests/code-generation-workspace-split/thrift/cdn.thrift @@ -0,0 +1,9 @@ +include "common.thrift" + +namespace rs article.image.cdn + +struct CDN { + 1: required i64 id, + 2: required string url, + 3: required common.CommonData common_data, +} \ No newline at end of file diff --git a/tests/code-generation-workspace-split/thrift/common.thrift b/tests/code-generation-workspace-split/thrift/common.thrift new file mode 100644 index 00000000..517116f1 --- /dev/null +++ b/tests/code-generation-workspace-split/thrift/common.thrift @@ -0,0 +1,7 @@ +namespace rs common + +struct CommonData { + 1: required i64 id, + 2: required string name, + 3: required string description, +} \ No newline at end of file diff --git a/tests/code-generation-workspace-split/thrift/image.thrift b/tests/code-generation-workspace-split/thrift/image.thrift new file mode 100644 index 00000000..b1d4ec86 --- /dev/null +++ b/tests/code-generation-workspace-split/thrift/image.thrift @@ -0,0 +1,23 @@ +include "common.thrift" +include "cdn.thrift" + +namespace rs article.image + +struct Image { + 1: required i64 id, + 2: required string url, + 3: required cdn.CDN cdn, + 4: required common.CommonData common_data, +} + +struct GetImageRequest { + 1: required i64 id, +} + +struct GetImageResponse { + 1: required Image image, +} + +service ImageService { + GetImageResponse GetImage(1: GetImageRequest req), +} \ No newline at end of file diff --git a/tests/code-generation-workspace-split/volo.workspace.yml b/tests/code-generation-workspace-split/volo.workspace.yml new file mode 100644 index 00000000..ee974a99 --- /dev/null +++ b/tests/code-generation-workspace-split/volo.workspace.yml @@ -0,0 +1,33 @@ +common_crate_name: "common" # common_crate_name = "common" by default +touch_all: true +dedups: [] # remove the repeated structure generation in one entry +special_namings: [] +split_generated_files: true +# repos: # exsit if non-local +# { repo }: # repo = extract the name from url by default +# url: { git } # url = repo git url +# ref: { ref } # ref = "HEAD" by default +# lock: { commit hash } # lock is the last commit hash +services: + - idl: + source: local + # repo: { repo } # required for git source + path: thrift/article.thrift # git path must be relative to the repo root dir + # includes: { includes list } # required for protobuf + codegen_option: + touch: [] + keep_unknown_fields: false # A->B->C, B could use this to transfer the unknown fields which is needed by A and C. + config: + crate_name: rpc_article + - idl: + source: local + path: thrift/author.thrift + codegen_option: + config: + crate_name: rpc_author + - idl: + source: local + path: thrift/image.thrift + codegen_option: + config: + crate_name: rpc_image diff --git a/tests/code-generation/volo.yml b/tests/code-generation/volo.yml index 77cf2c76..efeaa979 100644 --- a/tests/code-generation/volo.yml +++ b/tests/code-generation/volo.yml @@ -3,6 +3,7 @@ entries: proto: filename: proto_gen.rs protocol: protobuf + split_generated_files: true repos: protobuf: url: https://github.com/protocolbuffers/protobuf.git @@ -18,6 +19,7 @@ entries: thrift: filename: thrift_gen.rs protocol: thrift + split_generated_files: true repos: thrift: url: https://github.com/apache/thrift.git diff --git a/volo-build/Cargo.toml b/volo-build/Cargo.toml index 01f4a26f..671227f7 100644 --- a/volo-build/Cargo.toml +++ b/volo-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "volo-build" -version = "0.10.17" +version = "0.10.18" edition.workspace = true homepage.workspace = true repository.workspace = true diff --git a/volo-build/src/config_builder.rs b/volo-build/src/config_builder.rs index 60bb0637..0ac4d72f 100644 --- a/volo-build/src/config_builder.rs +++ b/volo-build/src/config_builder.rs @@ -125,6 +125,17 @@ impl InnerBuilder { } } + pub fn split_generated_files(self, split_generated_files: bool) -> Self { + match self { + InnerBuilder::Protobuf(inner) => { + InnerBuilder::Protobuf(inner.split_generated_files(split_generated_files)) + } + InnerBuilder::Thrift(inner) => { + InnerBuilder::Thrift(inner.split_generated_files(split_generated_files)) + } + } + } + pub fn common_crate_name(self, name: FastStr) -> Self { match self { InnerBuilder::Protobuf(inner) => InnerBuilder::Protobuf(inner.common_crate_name(name)), @@ -192,6 +203,7 @@ impl ConfigBuilder { .add_services(service_builders) .ignore_unused(!entry.common_option.touch_all) .special_namings(entry.common_option.special_namings) + .split_generated_files(entry.common_option.split_generated_files) .dedup(entry.common_option.dedups) .write()?; diff --git a/volo-build/src/lib.rs b/volo-build/src/lib.rs index 322dddb8..4694fc8d 100644 --- a/volo-build/src/lib.rs +++ b/volo-build/src/lib.rs @@ -112,6 +112,13 @@ impl Builder { self } + pub fn split_generated_files(mut self, split_generated_files: bool) -> Self { + self.pilota_builder = self + .pilota_builder + .split_generated_files(split_generated_files); + self + } + pub fn special_namings(mut self, namings: impl IntoIterator) -> Self { self.pilota_builder = self.pilota_builder.special_namings(namings); self diff --git a/volo-build/src/model.rs b/volo-build/src/model.rs index e0566971..8c266bf0 100644 --- a/volo-build/src/model.rs +++ b/volo-build/src/model.rs @@ -22,6 +22,8 @@ pub struct CommonOption { pub dedups: Vec, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub special_namings: Vec, + #[serde(default, skip_serializing_if = "is_false")] + pub split_generated_files: bool, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/volo-build/src/thrift_backend.rs b/volo-build/src/thrift_backend.rs index df411fde..100cf627 100644 --- a/volo-build/src/thrift_backend.rs +++ b/volo-build/src/thrift_backend.rs @@ -1,7 +1,10 @@ +use std::{io::Write, path::Path}; + use itertools::Itertools; use pilota_build::{ codegen::thrift::DecodeHelper, db::RirDatabase, + middle::context::Mode, rir::{self, Method}, tags::RustWrapperArc, CodegenBackend, Context, DefId, IdentName, Symbol, ThriftBackend, @@ -15,7 +18,7 @@ pub struct VoloThriftBackend { } impl VoloThriftBackend { - fn codegen_service_anonymous_type(&self, stream: &mut String, def_id: DefId) { + fn codegen_service_anonymous_type(&self, stream: &mut String, def_id: DefId, base_dir: &Path) { let service_name = self.cx().rust_name(def_id); let methods = self.cx().service_methods(def_id); let methods_names = methods.iter().map(|m| &**m.name).collect::>(); @@ -48,7 +51,7 @@ impl VoloThriftBackend { let res_recv_name = format!("{service_name}ResponseRecv"); let res_send_name = format!("{service_name}ResponseSend"); - let req_impl = { + let (req_recv_impl, req_send_impl) = { let mk_decode = |is_async: bool, is_send: bool| { let helper = DecodeHelper::new(is_async); let mut match_methods = String::new(); @@ -94,7 +97,7 @@ impl VoloThriftBackend { match_size = "_ => unreachable!(),".to_string(); } - format! { + let recv_impl = format! { r#"impl ::volo_thrift::EntryMessage for {req_recv_name} {{ fn encode(&self, __protocol: &mut T) -> ::core::result::Result<(), ::pilota::thrift::ThriftException> {{ match self {{ @@ -119,9 +122,11 @@ impl VoloThriftBackend { {match_size} }} }} - }} + }}"# + }; - impl ::volo_thrift::EntryMessage for {req_send_name} {{ + let send_impl = format! { + r#"impl ::volo_thrift::EntryMessage for {req_send_name} {{ fn encode(&self, __protocol: &mut T) -> ::core::result::Result<(), ::pilota::thrift::ThriftException> {{ match self {{ {match_encode} @@ -146,10 +151,12 @@ impl VoloThriftBackend { }} }} }}"# - } + }; + + (recv_impl, send_impl) }; - let res_impl = { + let (res_recv_impl, res_send_impl) = { let mk_decode = |is_async: bool, is_send: bool| { let helper = DecodeHelper::new(is_async); let mut match_methods = String::new(); @@ -195,7 +202,8 @@ impl VoloThriftBackend { let send_decode_async = mk_decode(true, true); let recv_decode = mk_decode(false, false); let recv_decode_async = mk_decode(true, false); - format! { + + let recv_impl = format! { r#"impl ::volo_thrift::EntryMessage for {res_recv_name} {{ fn encode(&self, __protocol: &mut T) -> ::core::result::Result<(), ::pilota::thrift::ThriftException> {{ match self {{ @@ -220,9 +228,11 @@ impl VoloThriftBackend { {match_size} }} }} - }} + }}"# + }; - impl ::volo_thrift::EntryMessage for {res_send_name} {{ + let send_impl = format! { + r#"impl ::volo_thrift::EntryMessage for {res_send_name} {{ fn encode(&self, __protocol: &mut T) -> ::core::result::Result<(), ::pilota::thrift::ThriftException> {{ match self {{ {match_encode} @@ -247,7 +257,9 @@ impl VoloThriftBackend { }} }} }}"# - } + }; + + (recv_impl, send_impl) }; let req_recv_variants = crate::join_multi_strs!( ",", @@ -267,8 +279,74 @@ impl VoloThriftBackend { ",", |variant_names, result_send_names| -> "{variant_names}({result_send_names})" ); - stream.push_str(&format! { - r#"#[derive(Debug, Clone)] + + if self.cx().split { + let req_recv_stream = format! { + r#"#[derive(Debug, Clone)] + pub enum {req_recv_name} {{ + {req_recv_variants} + }} + + {req_recv_impl} + "# + }; + + let req_send_stream = format! { + r#"#[derive(Debug, Clone)] + pub enum {req_send_name} {{ + {req_send_variants} + }} + + {req_send_impl} + "# + }; + + let res_recv_stream = format! { + r#"#[derive(Debug, Clone)] + pub enum {res_recv_name} {{ + {res_recv_variants} + }} + {res_recv_impl} + "# + }; + + let res_send_stream = format! { + r#"#[derive(Debug, Clone)] + pub enum {res_send_name} {{ + {res_send_variants} + }} + + {res_send_impl} + "# + }; + + Self::write_item( + stream, + base_dir, + format!("enum_{}.rs", &req_recv_name), + req_recv_stream, + ); + Self::write_item( + stream, + base_dir, + format!("enum_{}.rs", &res_recv_name), + res_recv_stream, + ); + Self::write_item( + stream, + base_dir, + format!("enum_{}.rs", &req_send_name), + req_send_stream, + ); + Self::write_item( + stream, + base_dir, + format!("enum_{}.rs", &res_send_name), + res_send_stream, + ); + } else { + stream.push_str(&format! { + r#"#[derive(Debug, Clone)] pub enum {req_recv_name} {{ {req_recv_variants} }} @@ -288,9 +366,27 @@ impl VoloThriftBackend { {res_send_variants} }} - {req_impl} - {res_impl}"# - }); + {req_recv_impl} + {req_send_impl} + {res_recv_impl} + {res_send_impl} + "# + }); + } + } + + fn write_item(stream: &mut String, base_dir: &Path, name: String, impl_str: String) { + let req_recv_buf = base_dir.join(&name); + let req_recv_file = req_recv_buf.as_path(); + Self::write_file(req_recv_file, impl_str); + stream.push_str(format!("include!(\"{}\");", &name).as_str()); + } + + fn write_file(path: &Path, stream: String) { + let mut req_file_writer = std::io::BufWriter::new(std::fs::File::create(path).unwrap()); + req_file_writer.write_all(stream.as_bytes()).unwrap(); + req_file_writer.flush().unwrap(); + pilota_build::fmt::fmt_file(path); } fn method_ty_path(&self, service_name: &Symbol, method: &Method, suffix: &str) -> FastStr { @@ -371,6 +467,50 @@ impl pilota_build::CodegenBackend for VoloThriftBackend { let mut client_methods = Vec::new(); let mut oneshot_client_methods = Vec::new(); + let path = self.cx().item_path(def_id); + let path = path.as_ref(); + + // Locate directory based on the full item path + let base_dir = match self.cx().mode.as_ref() { + // In a workspace mode, the base directory is next to the `.rs` file for the service + Mode::Workspace(info) => { + let mut dir = info.dir.clone(); + if path.is_empty() { + dir + } else { + dir.push(path[0].0.as_str()); + if path.len() > 1 { + dir.push("src"); + for segment in path.iter().skip(1) { + dir.push(Path::new(segment.0.as_str())); + } + } + dir + } + } + // In single file mode, the files directory is the root + // The base directory path is the root + the item path + Mode::SingleFile { file_path } => { + let mut dir = file_path.clone(); + dir.pop(); + for segment in path { + dir.push(Path::new(segment.0.as_str())); + } + dir + } + }; + + let base_dir = if let Some(suffix) = self.cx().names.get(&def_id) { + format!("{}_{suffix}", base_dir.display()) + } else { + base_dir.display().to_string() + }; + let base_dir = Path::new(&base_dir); + + if self.cx().split { + std::fs::create_dir_all(base_dir).expect("Failed to create base directory"); + } + all_methods.iter().for_each(|m| { let name = self.cx().rust_name(m.def_id); let resp_type = self.cx().codegen_item_ty(m.ret.kind.clone()); @@ -530,12 +670,35 @@ impl pilota_build::CodegenBackend for VoloThriftBackend { {user_handler} )),"#); - stream.push_str(&format! { + let mut mod_rs_stream = String::new(); + + let server_string = format! { r#"pub struct {server_name} {{ inner: S, // handler }} - pub struct {mk_client_name}; + impl {server_name} where S: {service_name} + ::core::marker::Send + ::core::marker::Sync + 'static {{ + pub fn new(inner: S) -> ::volo_thrift::server::Server>>, ::volo_thrift::tracing::DefaultProvider> {{ + ::volo_thrift::server::Server::new(Self {{ + inner, + }}) + }} + }} + + impl ::volo::service::Service<::volo_thrift::context::ServerContext, {req_recv_name}> for {server_name} where T: {service_name} + Send + Sync + 'static {{ + type Response = {res_send_name}; + type Error = ::volo_thrift::ServerError; + + async fn call<'s, 'cx>(&'s self, _cx: &'cx mut ::volo_thrift::context::ServerContext, req: {req_recv_name}) -> ::std::result::Result {{ + match req {{ + {handler} + }} + }} + }}"# + }; + + let client_string = format! { + r#" pub struct {mk_client_name}; pub type {client_name} = {generic_client_name}<::volo::service::BoxCloneService<::volo_thrift::context::ClientContext, {req_send_name}, ::std::option::Option<{res_recv_name}>, ::volo_thrift::ClientError>>; @@ -580,29 +743,44 @@ impl pilota_build::CodegenBackend for VoloThriftBackend { {{ ::volo_thrift::client::ClientBuilder::new(service_name, {mk_client_name}) }} - }} - + }}"# + }; - impl {server_name} where S: {service_name} + ::core::marker::Send + ::core::marker::Sync + 'static {{ - pub fn new(inner: S) -> ::volo_thrift::server::Server>>, ::volo_thrift::tracing::DefaultProvider> {{ - ::volo_thrift::server::Server::new(Self {{ - inner, - }}) - }} - }} + if self.cx().split { + Self::write_item( + &mut mod_rs_stream, + base_dir, + format!("service_{}Server.rs", service_name), + server_string, + ); + Self::write_item( + &mut mod_rs_stream, + base_dir, + format!("service_{}Client.rs", service_name), + client_string, + ); + } else { + stream.push_str(&server_string); + stream.push_str(&client_string); + } - impl ::volo::service::Service<::volo_thrift::context::ServerContext, {req_recv_name}> for {server_name} where T: {service_name} + Send + Sync + 'static {{ - type Response = {res_send_name}; - type Error = ::volo_thrift::ServerError; + if self.cx().split { + self.codegen_service_anonymous_type(&mut mod_rs_stream, def_id, base_dir); + } else { + self.codegen_service_anonymous_type(stream, def_id, base_dir); + } - async fn call<'s, 'cx>(&'s self, _cx: &'cx mut ::volo_thrift::context::ServerContext, req: {req_recv_name}) -> ::std::result::Result {{ - match req {{ - {handler} - }} - }} - }}"# - }); - self.codegen_service_anonymous_type(stream, def_id); + if self.cx().split { + let mod_rs_file_path = base_dir.join("mod.rs"); + Self::write_file(&mod_rs_file_path, mod_rs_stream); + stream.push_str( + format!( + "include!(\"{}/mod.rs\");", + base_dir.file_name().unwrap().to_str().unwrap() + ) + .as_str(), + ); + } } fn codegen_service_method(&self, _service_def_id: DefId, method: &Method) -> String { @@ -698,7 +876,7 @@ impl pilota_build::CodegenBackend for VoloThriftBackend { fn rust_name(cx: &Context, def_id: DefId) -> FastStr { let name = cx.rust_name(def_id); - if cx.names.contains(&def_id) { + if cx.names.contains_key(&def_id) { name.0 } else { name.0.upper_camel_ident() diff --git a/volo-build/src/workspace.rs b/volo-build/src/workspace.rs index 425b8cc4..9d17a294 100644 --- a/volo-build/src/workspace.rs +++ b/volo-build/src/workspace.rs @@ -106,6 +106,7 @@ where .dedup(config.common_option.dedups) .special_namings(config.common_option.special_namings) .common_crate_name(config.common_crate_name) + .split_generated_files(config.common_option.split_generated_files) .pilota_builder .compile_with_config(idl_services, pilota_build::Output::Workspace(work_dir)); } @@ -148,6 +149,13 @@ where self } + pub fn split_generated_files(mut self, split_generated_files: bool) -> Self { + self.pilota_builder = self + .pilota_builder + .split_generated_files(split_generated_files); + self + } + pub fn touch( mut self, items: impl IntoIterator>)>, diff --git a/volo-cli/Cargo.toml b/volo-cli/Cargo.toml index c5d4278a..f6def44e 100644 --- a/volo-cli/Cargo.toml +++ b/volo-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "volo-cli" -version = "0.10.4" +version = "0.10.5" edition.workspace = true homepage.workspace = true repository.workspace = true diff --git a/volo-cli/src/migrate.rs b/volo-cli/src/migrate.rs index 49ea9dd4..69cf69e5 100644 --- a/volo-cli/src/migrate.rs +++ b/volo-cli/src/migrate.rs @@ -49,6 +49,7 @@ impl CliCommand for Migrate { touch_all: old_entry.touch_all, dedups: Vec::new(), special_namings: Vec::new(), + split_generated_files: false, }, };