1
+ use protobuf_codegen;
1
2
use std:: process:: { self , Command } ;
2
3
use std:: {
3
4
env,
@@ -116,18 +117,31 @@ const PROTOS: &[(&str, &[&str], &str, &str)] = &[
116
117
( "proto/proto" , & [ "google/rpc" ] , "proto/src/proto" , "google/rpc" ) ,
117
118
] ;
118
119
119
- const NAMING_PATCH : & [ ( & str , & [ ( & str , & str ) ] ) ] = & [ (
120
- "health/src/proto/protobuf/health.rs" ,
121
- & [
122
- ( "HealthCheckResponse_ServingStatus" , "ServingStatus" ) ,
123
- // Order is important.
124
- ( "NOT_SERVING" , "NotServing" ) ,
125
- ( "SERVICE_UNKNOWN" , "ServiceUnknown" ) ,
126
- ( "UNKNOWN" , "Unknown" ) ,
127
- ( "SERVING" , "Serving" ) ,
128
- ( "rustfmt_skip" , "rustfmt::skip" ) ,
129
- ] ,
130
- ) ] ;
120
+ const NAMING_PATCH : & [ ( & str , & [ ( & str , & str ) ] ) ] = & [
121
+ (
122
+ "health/src/proto/protobuf/health.rs" ,
123
+ & [
124
+ ( "HealthCheckResponse_ServingStatus" , "ServingStatus" ) ,
125
+ // Order is important.
126
+ ( "NOT_SERVING" , "NotServing" ) ,
127
+ ( "SERVICE_UNKNOWN" , "ServiceUnknown" ) ,
128
+ ( "UNKNOWN" , "Unknown" ) ,
129
+ ( "SERVING" , "Serving" ) ,
130
+ ( "rustfmt_skip" , "rustfmt::skip" ) ,
131
+ ] ,
132
+ ) ,
133
+ (
134
+ "health/src/proto/protobuf_v3/health.rs" ,
135
+ & [
136
+ // Order is important.
137
+ ( "NOT_SERVING" , "NotServing" ) ,
138
+ ( "SERVICE_UNKNOWN" , "ServiceUnknown" ) ,
139
+ ( "UNKNOWN" , "Unknown" ) ,
140
+ ( "SERVING" , "Serving" ) ,
141
+ ( "rustfmt_skip" , "rustfmt::skip" ) ,
142
+ ] ,
143
+ ) ,
144
+ ] ;
131
145
132
146
fn modify ( path : impl AsRef < Path > , f : impl FnOnce ( & mut String ) ) {
133
147
let path = path. as_ref ( ) ;
@@ -140,21 +154,16 @@ fn modify(path: impl AsRef<Path>, f: impl FnOnce(&mut String)) {
140
154
File :: create ( path) . unwrap ( ) . write_all ( content. as_bytes ( ) ) . unwrap ( ) ;
141
155
}
142
156
143
- fn generate_protobuf ( protoc : & Path , include : & str , inputs : & [ & str ] , out_dir : & str ) {
157
+ /// If out_dir already exists, deletes and recreates it.
158
+ fn delete_and_mkdir ( out_dir : & str ) {
144
159
if Path :: new ( out_dir) . exists ( ) {
145
160
fs:: remove_dir_all ( out_dir) . unwrap ( ) ;
146
161
}
147
162
fs:: create_dir_all ( out_dir) . unwrap ( ) ;
163
+ }
148
164
149
- // TODO: update rust-protobuf to allow specifying protoc explicitly.
150
- protoc_rust:: run ( protoc_rust:: Args {
151
- out_dir,
152
- includes : & [ include] ,
153
- input : inputs,
154
- customize : protoc_rust:: Customize :: default ( ) ,
155
- } )
156
- . unwrap ( ) ;
157
-
165
+ /// Builds grpcio-compiler and uses it to generate _grpc.rs files. Used in both protobufv2 and v3.
166
+ fn run_gen_grpc ( protoc : & Path , include : & str , inputs : & [ & str ] , out_dir : & str ) {
158
167
exec ( cargo ( ) . args ( & [ "build" , "-p" , "grpcio-compiler" ] ) ) ;
159
168
let mut c = cmd ( protoc) ;
160
169
c. arg ( format ! ( "-I{}" , include) )
@@ -164,38 +173,101 @@ fn generate_protobuf(protoc: &Path, include: &str, inputs: &[&str], out_dir: &st
164
173
c. arg ( i) ;
165
174
}
166
175
exec ( & mut c) ;
176
+ }
167
177
178
+ // Does string replacements on predefined files. Used with protobuf v2 and v3.
179
+ fn apply_naming_patch ( ) {
168
180
for ( path, name_fixes) in NAMING_PATCH {
169
181
modify ( path, |content| {
170
182
for ( old, new) in * name_fixes {
171
183
* content = content. replace ( old, new) ;
172
184
}
173
185
} ) ;
174
186
}
187
+ }
188
+
189
+ /// Loops over all _grpc.rs files in out_dir, and if a corresponding .rs file exists, links it by adding a "use" statement.
190
+ fn link_pb_with_grpc_rs ( out_dir : & str ) {
191
+ for f in fs:: read_dir ( out_dir) . unwrap ( ) {
192
+ let path = f. unwrap ( ) . path ( ) ;
193
+ let file_name = path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
194
+ if !file_name. ends_with ( "_grpc.rs" ) {
195
+ continue ;
196
+ }
197
+ // remove _grpc
198
+ let pb_file_name = format ! ( "{}.rs" , & file_name[ ..file_name. len( ) - 8 ] ) ;
199
+ let pb_path = path. with_file_name ( pb_file_name) ;
200
+ // remove .rs
201
+ let module_name = & file_name[ ..file_name. len ( ) - 3 ] ;
202
+ modify ( pb_path, |content| {
203
+ content. push_str ( & format ! ( "\n pub use super::{}::*;\n " , module_name) ) ;
204
+ } ) ;
205
+ }
206
+ }
207
+
208
+ /// Removes the protobuf version constraint in all .rs files in out_dir.
209
+ /// note: now that we have distinct protobuf v2 and v3 generated files, not sure this step is necessary or good practice anymore
210
+ fn remove_protobuf_version_constraint ( out_dir : & str ) {
211
+ for f in fs:: read_dir ( out_dir) . unwrap ( ) {
212
+ let path = f. unwrap ( ) . path ( ) ;
213
+ if path. extension ( ) . unwrap ( ) == "rs" {
214
+ modify ( path, |content| {
215
+ * content = remove_match ( & content, |l| l. contains ( "::protobuf::VERSION" ) ) ;
216
+ } ) ;
217
+ }
218
+ }
219
+ }
220
+
221
+ fn generate_protobuf ( protoc : & Path , include : & str , inputs : & [ & str ] , out_dir : & str ) {
222
+ delete_and_mkdir ( out_dir) ;
223
+
224
+ // TODO: update rust-protobuf to allow specifying protoc explicitly.
225
+ protoc_rust:: run ( protoc_rust:: Args {
226
+ out_dir,
227
+ includes : & [ include] ,
228
+ input : inputs,
229
+ customize : protoc_rust:: Customize :: default ( ) ,
230
+ } )
231
+ . unwrap ( ) ;
232
+
233
+ run_gen_grpc ( protoc, include, inputs, out_dir) ;
234
+ apply_naming_patch ( ) ;
235
+ link_pb_with_grpc_rs ( out_dir) ;
236
+ // note: now that we have distinct protobuf v2 and v3 generated files, not sure this step is necessary or good practice anymore
237
+ remove_protobuf_version_constraint ( out_dir) ;
238
+ }
239
+
240
+ fn generate_protobufv3 ( protoc : & Path , include : & str , inputs : & [ & str ] , out_dir : & str ) {
241
+ delete_and_mkdir ( out_dir) ;
242
+
243
+ let _ = protobuf_codegen:: Codegen :: new ( )
244
+ . protoc ( )
245
+ . includes ( [ include] )
246
+ . inputs ( inputs)
247
+ . out_dir ( out_dir)
248
+ . run ( ) ;
249
+
250
+ run_gen_grpc ( protoc, include, inputs, out_dir) ;
251
+ apply_naming_patch ( ) ;
175
252
176
253
for f in fs:: read_dir ( out_dir) . unwrap ( ) {
177
254
let p = f. unwrap ( ) ;
178
255
if p. path ( ) . extension ( ) . unwrap ( ) == "rs" {
179
- let file_name = p. path ( ) . file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
180
- if file_name. ends_with ( "_grpc.rs" ) {
181
- let pb_path = p. path ( ) . with_file_name ( format ! ( "{}.rs" , & file_name[ ..file_name. len( ) - 8 ] ) ) ;
182
- modify ( pb_path, |content| {
183
- content. push_str ( & format ! ( "\n pub use super::{}::*;\n " , & file_name[ ..file_name. len( ) - 3 ] ) ) ;
184
- } ) ;
185
- }
186
256
modify ( p. path ( ) , |content| {
187
- * content = remove_match ( & content, |l| l . contains ( "::protobuf::VERSION" ) ) ;
257
+ * content = content. replace ( "::protobuf::" , "::protobufv3::" ) ;
188
258
} ) ;
189
259
}
190
260
}
261
+
262
+ link_pb_with_grpc_rs ( out_dir) ;
263
+ // note: now that we have distinct protobuf v2 and v3 generated files, not sure this step is necessary or good practice anymore
264
+ remove_protobuf_version_constraint ( out_dir) ;
191
265
}
192
266
193
267
fn generate_prost ( protoc : & Path , include : & str , inputs : & [ & str ] , out_dir : & str ) {
194
268
env:: set_var ( "PROTOC" , protoc) ;
195
- if Path :: new ( out_dir) . exists ( ) {
196
- fs:: remove_dir_all ( out_dir) . unwrap ( ) ;
197
- }
198
- fs:: create_dir_all ( out_dir) . unwrap ( ) ;
269
+ delete_and_mkdir ( out_dir) ;
270
+
199
271
exec (
200
272
cargo ( )
201
273
. args ( & [
@@ -242,7 +314,18 @@ fn codegen() {
242
314
& inputs_ref,
243
315
& format ! ( "{}/protobuf/{}" , out_dir, package) ,
244
316
) ;
245
- generate_prost ( & protoc, include, & inputs_ref, & format ! ( "{}/prost/{}" , out_dir, package) ) ;
317
+ generate_protobufv3 (
318
+ & protoc,
319
+ include,
320
+ & inputs_ref,
321
+ & format ! ( "{}/protobuf_v3/{}" , out_dir, package) ,
322
+ ) ;
323
+ generate_prost (
324
+ & protoc,
325
+ include,
326
+ & inputs_ref,
327
+ & format ! ( "{}/prost/{}" , out_dir, package) ,
328
+ ) ;
246
329
}
247
330
exec ( cargo ( ) . args ( & [ "fmt" , "--all" ] ) )
248
331
}
0 commit comments