protobuf_build/
protobuf_impl.rs1use std::fs::File;
4use std::io::{Read, Write};
5use std::path::Path;
6use std::process::Command;
7
8use protobuf::Message;
9use regex::Regex;
10
11use crate::get_protoc;
12use crate::Builder;
13
14impl Builder {
15 pub fn generate_files(&self) {
16 let mut cmd = Command::new(get_protoc());
17 let desc_file = format!("{}/mod.desc", self.out_dir);
18 for i in &self.includes {
19 cmd.arg(format!("-I{}", i));
20 }
21 cmd.arg("--include_imports")
22 .arg("--include_source_info")
23 .arg("-o")
24 .arg(&desc_file);
25 for f in &self.files {
26 cmd.arg(f);
27 }
28 println!("executing {:?}", cmd);
29 match cmd.status() {
30 Ok(e) if e.success() => {}
31 e => panic!("failed to generate descriptor set files: {:?}", e),
32 }
33
34 let desc_bytes = std::fs::read(&desc_file).unwrap();
35 let mut desc = protobuf::descriptor::FileDescriptorSet::new();
36 desc.merge_from_bytes(&desc_bytes).unwrap();
37 desc.check_initialized().unwrap();
38
39 let mut files_to_generate = Vec::new();
40 'outer: for file in &self.files {
41 for include in &self.includes {
42 if let Ok(truncated) = Path::new(file).strip_prefix(include) {
43 files_to_generate.push(format!("{}", truncated.display()));
44 continue 'outer;
45 }
46 }
47
48 panic!(
49 "file {:?} is not found in includes {:?}",
50 file, self.includes
51 );
52 }
53
54 protobuf_codegen::gen_and_write(
55 desc.get_file(),
56 &files_to_generate,
57 Path::new(&self.out_dir),
58 &protobuf_codegen::Customize::default(),
59 )
60 .unwrap();
61 self.generate_grpcio(desc.get_file(), &files_to_generate);
62 self.import_grpcio();
63 self.replace_read_unknown_fields();
64 }
65
66 fn replace_read_unknown_fields(&self) {
69 let regex =
70 Regex::new(r"::protobuf::rt::read_proto3_enum_with_unknown_fields_into\(([^,]+), ([^,]+), &mut ([^,]+), [^\)]+\)\?").unwrap();
71 self.list_rs_files().for_each(|path| {
72 let mut text = String::new();
73 let mut f = File::open(&path).unwrap();
74 f.read_to_string(&mut text)
75 .expect("Couldn't read source file");
76
77 #[rustfmt::skip]
79 let text = {
80 regex.replace_all(
81 &text,
82 "if $1 == ::protobuf::wire_format::WireTypeVarint {\
83 $3 = $2.read_enum()?;\
84 } else {\
85 return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));\
86 }",
87 )
88 };
89 let mut out = File::create(&path).unwrap();
90 out.write_all(text.as_bytes())
91 .expect("Could not write source file");
92 });
93 }
94
95 #[cfg(feature = "grpcio-protobuf-codec")]
96 fn import_grpcio(&self) {
97 use std::collections::BTreeMap;
98 use std::fs::OpenOptions;
99
100 if !self.re_export_services {
101 return;
102 }
103
104 let paths: BTreeMap<_, _> = self
106 .list_rs_files()
107 .map(|path| (path.file_stem().unwrap().to_str().unwrap().to_owned(), path))
108 .collect();
109 for (name, path) in &paths {
110 if name.starts_with("wrapper_")
111 || *name == "mod"
112 || name.ends_with("_grpc")
113 || !paths.contains_key(&*format!("{}_grpc", name))
114 {
115 continue;
116 }
117
118 let mut out = OpenOptions::new()
119 .append(true)
120 .open(&path)
121 .expect("Couldn't open source file");
122 writeln!(out, "pub use super::{}_grpc::*;", name).expect("Could not write source file");
123 }
124 }
125
126 #[cfg(not(feature = "grpcio-protobuf-codec"))]
127 fn import_grpcio(&self) {}
128
129 #[cfg(feature = "grpcio-protobuf-codec")]
130 fn generate_grpcio(
131 &self,
132 desc: &[protobuf::descriptor::FileDescriptorProto],
133 files_to_generate: &[String],
134 ) {
135 let output_dir = std::path::Path::new(&self.out_dir);
136 let results = grpcio_compiler::codegen::gen(desc, &files_to_generate);
137 for res in results {
138 let out_file = output_dir.join(&res.name);
139 let mut f = std::fs::File::create(&out_file).unwrap();
140 f.write_all(&res.content).unwrap();
141 }
142 }
143
144 #[cfg(not(feature = "grpcio-protobuf-codec"))]
145 fn generate_grpcio(&self, _: &[protobuf::descriptor::FileDescriptorProto], _: &[String]) {}
146}