From 06ff619944a2f44d3aea60e653b39157c392f541 Mon Sep 17 00:00:00 2001 From: Adam Jacob Date: Tue, 8 Oct 2019 15:11:42 -0700 Subject: [PATCH] =?UTF-8?q?feat(build):=20Expose=20prost-build=20type=5Fat?= =?UTF-8?q?tributes=20and=20field=5Fattribu=E2=80=A6=20(#60)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Add tags to .gitignore When generating ctags/universal-ctags, a 'tags' file is generated. This commit adds any generted 'tags' file to .gitignore. * feat(build): Expose type_attribute and field_attribute This commit exposes the `type_attribute` and `field_attribute` configuration settings from Prost. These are useful to tweak/extend the generated types. For example: ``` tonic_build::configure() .out_dir(tmp) .format(false) .type_attribute(".", "#[derive(Serialize, Deserialize)]") .type_attribute(".", "#[serde(rename_all = \"camelCase\")]") .field_attribute("in", "#[serde(rename = \"in\")]") .compile(&["tests/protos/wellknown.proto"], &["tests/protos"]) .unwrap(); ``` Would add the serde `Serialize` and `Deserialize` traits, while renaming all the fields to camelCase, and having serde keep fields named `in` named `in`, rather than Prost's `in_`, to every type generated by Prost. --- .gitignore | 1 + tonic-build/src/lib.rs | 29 +++++++++++++++++++++++++++++ tonic-build/tests/wellknown.rs | 3 +++ 3 files changed, 33 insertions(+) diff --git a/.gitignore b/.gitignore index 693699042..3d69c0417 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk Cargo.lock +tags diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index d1f3d2d06..4cc7d4b0b 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -76,6 +76,8 @@ mod server; pub struct Builder { build_client: bool, build_server: bool, + field_attributes: Vec<(String, String)>, + type_attributes: Vec<(String, String)>, out_dir: Option, #[cfg(feature = "rustfmt")] format: bool, @@ -109,6 +111,24 @@ impl Builder { self } + /// Add additional attribute to matched messages, enums, and one-offs. + /// + /// Passed directly to `prost_build::Config.field_attribute`. + pub fn field_attribute, A: AsRef>(mut self, path: P, attribute: A) -> Self { + self.field_attributes + .push((path.as_ref().to_string(), attribute.as_ref().to_string())); + self + } + + /// Add additional attribute to matched messages, enums, and one-offs. + /// + /// Passed directly to `prost_build::Config.type_attribute`. + pub fn type_attribute, A: AsRef>(mut self, path: P, attribute: A) -> Self { + self.type_attributes + .push((path.as_ref().to_string(), attribute.as_ref().to_string())); + self + } + /// Compile the .proto files and execute code generation. pub fn compile>(self, protos: &[P], includes: &[P]) -> io::Result<()> { let mut config = Config::new(); @@ -122,7 +142,14 @@ impl Builder { .unwrap_or_else(|| PathBuf::from(std::env::var("OUT_DIR").unwrap())); config.out_dir(out_dir.clone()); + for (path, attr) in self.field_attributes.iter() { + config.field_attribute(path, attr); + } + for (path, attr) in self.type_attributes.iter() { + config.type_attribute(path, attr); + } config.service_generator(Box::new(ServiceGenerator::new(self))); + config.compile_protos(protos, includes)?; #[cfg(feature = "rustfmt")] @@ -144,6 +171,8 @@ pub fn configure() -> Builder { build_client: true, build_server: true, out_dir: None, + field_attributes: Vec::new(), + type_attributes: Vec::new(), #[cfg(feature = "rustfmt")] format: true, } diff --git a/tonic-build/tests/wellknown.rs b/tonic-build/tests/wellknown.rs index 921d7f51d..51aa89647 100644 --- a/tonic-build/tests/wellknown.rs +++ b/tonic-build/tests/wellknown.rs @@ -4,6 +4,9 @@ fn wellknown() { tonic_build::configure() .out_dir(tmp) .format(false) + .type_attribute(".", "#[derive(Serialize, Deserialize)]") + .type_attribute(".", "#[serde(rename_all = \"camelCase\")]") + .field_attribute("in", "#[serde(rename = \"in\")]") .compile(&["tests/protos/wellknown.proto"], &["tests/protos"]) .unwrap(); }