├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── example ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs └── src │ ├── client.rs │ ├── protos │ ├── .gitignore │ ├── example │ │ └── diner.proto │ └── mod.rs │ └── server.rs ├── install_dependencies.sh ├── rustfmt.toml ├── src └── lib.rs └── test └── assets └── protos ├── foo └── bar │ └── baz.proto └── helloworld.proto /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | /Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | env: 7 | - PROTOBUF_VERSION=3.0.0 8 | - PROTOBUF_VERSION=3.5.1 9 | - PROTOBUF_VERSION=3.6.1 10 | matrix: 11 | allow_failures: 12 | - rust: nightly 13 | before_install: 14 | - ./install_dependencies.sh 15 | script: 16 | - PATH=/home/travis/bin:$PATH cargo test 17 | - PATH=/home/travis/bin:$PATH cargo build --manifest-path example/Cargo.toml 18 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "protoc-grpcio" 3 | version = "4.0.0" 4 | authors = ["Matt Pelland "] 5 | license = "Apache-2.0" 6 | keywords = ["compiler", "grpc", "protobuf", "grpc-rs"] 7 | repository = "https://github.com/mtp401/protoc-grpcio" 8 | documentation = "https://docs.rs/protoc-grpcio" 9 | description = """ 10 | API for programatically invoking the grpcio (grpc-rs) gRPC compiler 11 | """ 12 | 13 | [badges] 14 | maintenance = { status = "actively-developed" } 15 | travis-ci = { repository = "mtp401/protoc-grpcio" } 16 | 17 | [dependencies] 18 | anyhow = "1" 19 | grpcio-compiler = "0.7" 20 | tempfile = "3.1" 21 | protobuf = "2.18" 22 | protobuf-codegen = "2.18" 23 | protoc = "2.18" 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018. Matt Pelland 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # protoc-grpcio 2 | [![crates.io](https://img.shields.io/crates/v/protoc-grpcio.svg)](https://crates.io/crates/protoc-grpcio) 3 | [![Build Status](https://travis-ci.org/mtp401/protoc-grpcio.svg?branch=master)](https://travis-ci.org/mtp401/protoc-grpcio) 4 | [![License](https://img.shields.io/crates/l/protoc-grpcio.svg)](https://github.com/mtp401/protoc-grpcio/blob/master/LICENSE) 5 | 6 | A programmatic API to the 7 | [grpc-rs compiler](https://github.com/pingcap/grpc-rs). 8 | 9 | ## Requirements 10 | 11 | - You must have Google's Protocol Buffer compiler (`protoc`) installed and in 12 | `PATH`. 13 | 14 | ## Example `build.rs` 15 | 16 | For a project laid out like so: 17 | ``` 18 | $ tree 19 | . 20 | ├── build.rs 21 | ├── Cargo.toml 22 | └── src 23 | ├── client.rs 24 | ├── protos 25 | │   ├── example 26 | │   │   └── diner.proto 27 | │   └── mod.rs 28 | └── server.rs 29 | 30 | 3 directories, 7 files 31 | ``` 32 | 33 | The `build.rs` might look like: 34 | ```rust 35 | extern crate protoc_grpcio; 36 | 37 | fn main() { 38 | let proto_root = "src/protos"; 39 | println!("cargo:rerun-if-changed={}", proto_root); 40 | protoc_grpcio::compile_grpc_protos( 41 | &["example/diner.proto"], 42 | &[proto_root], 43 | &proto_root, 44 | None 45 | ).expect("Failed to compile gRPC definitions!"); 46 | } 47 | ``` 48 | 49 | ## Example `Cargo.toml` 50 | 51 | And the `Cargo.toml` might look like: 52 | ```toml 53 | [package] 54 | # ... 55 | build = "build.rs" 56 | 57 | [lib] 58 | name = "protos" 59 | path = "src/protos/mod.rs" 60 | 61 | [[bin]] 62 | name = "server" 63 | path = "src/server.rs" 64 | 65 | [[bin]] 66 | name = "client" 67 | path = "src/client.rs" 68 | 69 | [dependencies] 70 | futures = "0.1.16" 71 | grpcio = "0.4.3" 72 | protobuf = "~2" 73 | 74 | [build-dependencies] 75 | protoc-grpcio = "1.0.2" 76 | ``` 77 | 78 | You can inspect this example under [`example/`](example) by compiling and running the example 79 | server in one shell session: 80 | ``` 81 | cargo run --manifest-path example/Cargo.toml --bin server 82 | ... 83 | Finished dev [unoptimized + debuginfo] target(s) in 27.97 secs 84 | Running `example/target/debug/server` 85 | listening on 127.0.0.1:34431 86 | ``` 87 | 88 | And then running the client in another: 89 | ``` 90 | $ cargo run --manifest-path example/Cargo.toml --bin client 34431 91 | ... 92 | Finished dev [unoptimized + debuginfo] target(s) in 1.28 secs 93 | Running `example/target/debug/client 34431` 94 | Ate items: SPAM items: EGGS and got charged $0.30 95 | ``` 96 | 97 | ## Credits 98 | 99 | Credit to both the TiKV project developers for 100 | ([grpc-rs](https://github.com/pingcap/grpc-rs)) and Stepan Koltsov 101 | (@stepancheg, [rust-protobuf](https://github.com/stepancheg/rust-protobuf)) 102 | for their amazing work bringing Protocol Buffers and gRPC support to Rust. 103 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /example/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anyhow" 16 | version = "1.0.71" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" 19 | 20 | [[package]] 21 | name = "autocfg" 22 | version = "1.1.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 25 | 26 | [[package]] 27 | name = "bindgen" 28 | version = "0.51.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" 31 | dependencies = [ 32 | "bitflags", 33 | "cexpr", 34 | "cfg-if 0.1.10", 35 | "clang-sys", 36 | "lazy_static", 37 | "peeking_take_while", 38 | "proc-macro2", 39 | "quote", 40 | "regex", 41 | "rustc-hash", 42 | "shlex", 43 | ] 44 | 45 | [[package]] 46 | name = "bitflags" 47 | version = "1.3.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 50 | 51 | [[package]] 52 | name = "cc" 53 | version = "1.0.79" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" 56 | 57 | [[package]] 58 | name = "cexpr" 59 | version = "0.3.6" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d" 62 | dependencies = [ 63 | "nom", 64 | ] 65 | 66 | [[package]] 67 | name = "cfg-if" 68 | version = "0.1.10" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 71 | 72 | [[package]] 73 | name = "cfg-if" 74 | version = "1.0.0" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 77 | 78 | [[package]] 79 | name = "clang-sys" 80 | version = "0.28.1" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853" 83 | dependencies = [ 84 | "glob", 85 | "libc", 86 | "libloading", 87 | ] 88 | 89 | [[package]] 90 | name = "cloudabi" 91 | version = "0.0.3" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 94 | dependencies = [ 95 | "bitflags", 96 | ] 97 | 98 | [[package]] 99 | name = "cmake" 100 | version = "0.1.50" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 103 | dependencies = [ 104 | "cc", 105 | ] 106 | 107 | [[package]] 108 | name = "either" 109 | version = "1.8.1" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 112 | 113 | [[package]] 114 | name = "errno" 115 | version = "0.3.1" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" 118 | dependencies = [ 119 | "errno-dragonfly", 120 | "libc", 121 | "windows-sys", 122 | ] 123 | 124 | [[package]] 125 | name = "errno-dragonfly" 126 | version = "0.1.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 129 | dependencies = [ 130 | "cc", 131 | "libc", 132 | ] 133 | 134 | [[package]] 135 | name = "example" 136 | version = "0.0.1" 137 | dependencies = [ 138 | "futures", 139 | "grpcio", 140 | "protobuf", 141 | "protoc-grpcio", 142 | ] 143 | 144 | [[package]] 145 | name = "fastrand" 146 | version = "1.9.0" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" 149 | dependencies = [ 150 | "instant", 151 | ] 152 | 153 | [[package]] 154 | name = "futures" 155 | version = "0.3.28" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" 158 | dependencies = [ 159 | "futures-channel", 160 | "futures-core", 161 | "futures-executor", 162 | "futures-io", 163 | "futures-sink", 164 | "futures-task", 165 | "futures-util", 166 | ] 167 | 168 | [[package]] 169 | name = "futures-channel" 170 | version = "0.3.28" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" 173 | dependencies = [ 174 | "futures-core", 175 | "futures-sink", 176 | ] 177 | 178 | [[package]] 179 | name = "futures-core" 180 | version = "0.3.28" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 183 | 184 | [[package]] 185 | name = "futures-executor" 186 | version = "0.3.28" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" 189 | dependencies = [ 190 | "futures-core", 191 | "futures-task", 192 | "futures-util", 193 | ] 194 | 195 | [[package]] 196 | name = "futures-io" 197 | version = "0.3.28" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" 200 | 201 | [[package]] 202 | name = "futures-macro" 203 | version = "0.3.28" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" 206 | dependencies = [ 207 | "proc-macro2", 208 | "quote", 209 | "syn", 210 | ] 211 | 212 | [[package]] 213 | name = "futures-sink" 214 | version = "0.3.28" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 217 | 218 | [[package]] 219 | name = "futures-task" 220 | version = "0.3.28" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 223 | 224 | [[package]] 225 | name = "futures-util" 226 | version = "0.3.28" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 229 | dependencies = [ 230 | "futures-channel", 231 | "futures-core", 232 | "futures-io", 233 | "futures-macro", 234 | "futures-sink", 235 | "futures-task", 236 | "memchr", 237 | "pin-project-lite", 238 | "pin-utils", 239 | "slab", 240 | ] 241 | 242 | [[package]] 243 | name = "glob" 244 | version = "0.3.1" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 247 | 248 | [[package]] 249 | name = "grpcio" 250 | version = "0.6.0" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "63fac32f9f74fa1fd78215d04b47f134c1ee5a535c237a54d52bf18cf65ac983" 253 | dependencies = [ 254 | "futures", 255 | "grpcio-sys", 256 | "libc", 257 | "log", 258 | "parking_lot", 259 | "protobuf", 260 | ] 261 | 262 | [[package]] 263 | name = "grpcio-compiler" 264 | version = "0.7.0" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "f1f1abac9f330ac9ee0950220c10eea84d66479cede4836f0b924407fecf093c" 267 | dependencies = [ 268 | "protobuf", 269 | ] 270 | 271 | [[package]] 272 | name = "grpcio-sys" 273 | version = "0.6.0" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "12d4e9309f1151c9ebcd07622858c4a504b6ea6cd2821524fe74ccde8ea830d7" 276 | dependencies = [ 277 | "bindgen", 278 | "cc", 279 | "cmake", 280 | "libc", 281 | "libz-sys", 282 | "pkg-config", 283 | "walkdir", 284 | ] 285 | 286 | [[package]] 287 | name = "hermit-abi" 288 | version = "0.3.1" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" 291 | 292 | [[package]] 293 | name = "instant" 294 | version = "0.1.12" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 297 | dependencies = [ 298 | "cfg-if 1.0.0", 299 | ] 300 | 301 | [[package]] 302 | name = "io-lifetimes" 303 | version = "1.0.11" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 306 | dependencies = [ 307 | "hermit-abi", 308 | "libc", 309 | "windows-sys", 310 | ] 311 | 312 | [[package]] 313 | name = "lazy_static" 314 | version = "1.4.0" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 317 | 318 | [[package]] 319 | name = "libc" 320 | version = "0.2.146" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" 323 | 324 | [[package]] 325 | name = "libloading" 326 | version = "0.5.2" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" 329 | dependencies = [ 330 | "cc", 331 | "winapi", 332 | ] 333 | 334 | [[package]] 335 | name = "libz-sys" 336 | version = "1.1.9" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" 339 | dependencies = [ 340 | "cc", 341 | "libc", 342 | "pkg-config", 343 | "vcpkg", 344 | ] 345 | 346 | [[package]] 347 | name = "linux-raw-sys" 348 | version = "0.3.8" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 351 | 352 | [[package]] 353 | name = "lock_api" 354 | version = "0.3.4" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" 357 | dependencies = [ 358 | "scopeguard", 359 | ] 360 | 361 | [[package]] 362 | name = "log" 363 | version = "0.4.19" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 366 | 367 | [[package]] 368 | name = "memchr" 369 | version = "2.5.0" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 372 | 373 | [[package]] 374 | name = "nom" 375 | version = "4.2.3" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" 378 | dependencies = [ 379 | "memchr", 380 | "version_check", 381 | ] 382 | 383 | [[package]] 384 | name = "once_cell" 385 | version = "1.18.0" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 388 | 389 | [[package]] 390 | name = "parking_lot" 391 | version = "0.10.2" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" 394 | dependencies = [ 395 | "lock_api", 396 | "parking_lot_core", 397 | ] 398 | 399 | [[package]] 400 | name = "parking_lot_core" 401 | version = "0.7.3" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "b93f386bb233083c799e6e642a9d73db98c24a5deeb95ffc85bf281255dffc98" 404 | dependencies = [ 405 | "cfg-if 0.1.10", 406 | "cloudabi", 407 | "libc", 408 | "redox_syscall 0.1.57", 409 | "smallvec", 410 | "winapi", 411 | ] 412 | 413 | [[package]] 414 | name = "peeking_take_while" 415 | version = "0.1.2" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 418 | 419 | [[package]] 420 | name = "pin-project-lite" 421 | version = "0.2.9" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 424 | 425 | [[package]] 426 | name = "pin-utils" 427 | version = "0.1.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 430 | 431 | [[package]] 432 | name = "pkg-config" 433 | version = "0.3.27" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 436 | 437 | [[package]] 438 | name = "proc-macro2" 439 | version = "1.0.60" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" 442 | dependencies = [ 443 | "unicode-ident", 444 | ] 445 | 446 | [[package]] 447 | name = "protobuf" 448 | version = "2.28.0" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" 451 | 452 | [[package]] 453 | name = "protobuf-codegen" 454 | version = "2.28.0" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6" 457 | dependencies = [ 458 | "protobuf", 459 | ] 460 | 461 | [[package]] 462 | name = "protoc" 463 | version = "2.28.0" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "a0218039c514f9e14a5060742ecd50427f8ac4f85a6dc58f2ddb806e318c55ee" 466 | dependencies = [ 467 | "log", 468 | "which", 469 | ] 470 | 471 | [[package]] 472 | name = "protoc-grpcio" 473 | version = "4.0.0" 474 | dependencies = [ 475 | "anyhow", 476 | "grpcio-compiler", 477 | "protobuf", 478 | "protobuf-codegen", 479 | "protoc", 480 | "tempfile", 481 | ] 482 | 483 | [[package]] 484 | name = "quote" 485 | version = "1.0.28" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" 488 | dependencies = [ 489 | "proc-macro2", 490 | ] 491 | 492 | [[package]] 493 | name = "redox_syscall" 494 | version = "0.1.57" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 497 | 498 | [[package]] 499 | name = "redox_syscall" 500 | version = "0.3.5" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 503 | dependencies = [ 504 | "bitflags", 505 | ] 506 | 507 | [[package]] 508 | name = "regex" 509 | version = "1.8.4" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" 512 | dependencies = [ 513 | "aho-corasick", 514 | "memchr", 515 | "regex-syntax", 516 | ] 517 | 518 | [[package]] 519 | name = "regex-syntax" 520 | version = "0.7.2" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" 523 | 524 | [[package]] 525 | name = "rustc-hash" 526 | version = "1.1.0" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 529 | 530 | [[package]] 531 | name = "rustix" 532 | version = "0.37.20" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" 535 | dependencies = [ 536 | "bitflags", 537 | "errno", 538 | "io-lifetimes", 539 | "libc", 540 | "linux-raw-sys", 541 | "windows-sys", 542 | ] 543 | 544 | [[package]] 545 | name = "same-file" 546 | version = "1.0.6" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 549 | dependencies = [ 550 | "winapi-util", 551 | ] 552 | 553 | [[package]] 554 | name = "scopeguard" 555 | version = "1.1.0" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 558 | 559 | [[package]] 560 | name = "shlex" 561 | version = "0.1.1" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" 564 | 565 | [[package]] 566 | name = "slab" 567 | version = "0.4.8" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 570 | dependencies = [ 571 | "autocfg", 572 | ] 573 | 574 | [[package]] 575 | name = "smallvec" 576 | version = "1.10.0" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 579 | 580 | [[package]] 581 | name = "syn" 582 | version = "2.0.18" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" 585 | dependencies = [ 586 | "proc-macro2", 587 | "quote", 588 | "unicode-ident", 589 | ] 590 | 591 | [[package]] 592 | name = "tempfile" 593 | version = "3.6.0" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" 596 | dependencies = [ 597 | "autocfg", 598 | "cfg-if 1.0.0", 599 | "fastrand", 600 | "redox_syscall 0.3.5", 601 | "rustix", 602 | "windows-sys", 603 | ] 604 | 605 | [[package]] 606 | name = "unicode-ident" 607 | version = "1.0.9" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" 610 | 611 | [[package]] 612 | name = "vcpkg" 613 | version = "0.2.15" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 616 | 617 | [[package]] 618 | name = "version_check" 619 | version = "0.1.5" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" 622 | 623 | [[package]] 624 | name = "walkdir" 625 | version = "2.3.3" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" 628 | dependencies = [ 629 | "same-file", 630 | "winapi-util", 631 | ] 632 | 633 | [[package]] 634 | name = "which" 635 | version = "4.4.0" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" 638 | dependencies = [ 639 | "either", 640 | "libc", 641 | "once_cell", 642 | ] 643 | 644 | [[package]] 645 | name = "winapi" 646 | version = "0.3.9" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 649 | dependencies = [ 650 | "winapi-i686-pc-windows-gnu", 651 | "winapi-x86_64-pc-windows-gnu", 652 | ] 653 | 654 | [[package]] 655 | name = "winapi-i686-pc-windows-gnu" 656 | version = "0.4.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 659 | 660 | [[package]] 661 | name = "winapi-util" 662 | version = "0.1.5" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 665 | dependencies = [ 666 | "winapi", 667 | ] 668 | 669 | [[package]] 670 | name = "winapi-x86_64-pc-windows-gnu" 671 | version = "0.4.0" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 674 | 675 | [[package]] 676 | name = "windows-sys" 677 | version = "0.48.0" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 680 | dependencies = [ 681 | "windows-targets", 682 | ] 683 | 684 | [[package]] 685 | name = "windows-targets" 686 | version = "0.48.0" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" 689 | dependencies = [ 690 | "windows_aarch64_gnullvm", 691 | "windows_aarch64_msvc", 692 | "windows_i686_gnu", 693 | "windows_i686_msvc", 694 | "windows_x86_64_gnu", 695 | "windows_x86_64_gnullvm", 696 | "windows_x86_64_msvc", 697 | ] 698 | 699 | [[package]] 700 | name = "windows_aarch64_gnullvm" 701 | version = "0.48.0" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 704 | 705 | [[package]] 706 | name = "windows_aarch64_msvc" 707 | version = "0.48.0" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 710 | 711 | [[package]] 712 | name = "windows_i686_gnu" 713 | version = "0.48.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 716 | 717 | [[package]] 718 | name = "windows_i686_msvc" 719 | version = "0.48.0" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 722 | 723 | [[package]] 724 | name = "windows_x86_64_gnu" 725 | version = "0.48.0" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 728 | 729 | [[package]] 730 | name = "windows_x86_64_gnullvm" 731 | version = "0.48.0" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 734 | 735 | [[package]] 736 | name = "windows_x86_64_msvc" 737 | version = "0.48.0" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 740 | -------------------------------------------------------------------------------- /example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example" 3 | version = "0.0.1" 4 | authors = ["John Doe "] 5 | publish = false 6 | 7 | [lib] 8 | name = "protos" 9 | path = "src/protos/mod.rs" 10 | 11 | [[bin]] 12 | name = "server" 13 | path = "src/server.rs" 14 | 15 | [[bin]] 16 | name = "client" 17 | path = "src/client.rs" 18 | 19 | [dependencies] 20 | futures = "0.3.5" 21 | grpcio = "0.6.0" 22 | protobuf = "~2" 23 | 24 | [build-dependencies] 25 | protoc-grpcio = { path = ".." } 26 | -------------------------------------------------------------------------------- /example/build.rs: -------------------------------------------------------------------------------- 1 | extern crate protoc_grpcio; 2 | 3 | fn main() { 4 | let proto_root = "src/protos"; 5 | println!("cargo:rerun-if-changed={}", proto_root); 6 | protoc_grpcio::compile_grpc_protos(&["example/diner.proto"], &[proto_root], &proto_root, None) 7 | .expect("Failed to compile gRPC definitions!"); 8 | } 9 | -------------------------------------------------------------------------------- /example/src/client.rs: -------------------------------------------------------------------------------- 1 | extern crate grpcio; 2 | extern crate protos; 3 | 4 | use std::env; 5 | use std::sync::Arc; 6 | 7 | use grpcio::{ChannelBuilder, EnvBuilder}; 8 | 9 | use protos::diner::{Item, Order}; 10 | use protos::diner_grpc::DinerClient; 11 | 12 | fn main() { 13 | let args = env::args().collect::>(); 14 | if args.len() != 2 { 15 | panic!("Expected exactly one argument, the port to connect to.") 16 | } 17 | let port = args[1] 18 | .parse::() 19 | .unwrap_or_else(|_| panic!("{} is not a valid port number", args[1])); 20 | 21 | let env = Arc::new(EnvBuilder::new().build()); 22 | let ch = ChannelBuilder::new(env).connect(format!("localhost:{}", port).as_str()); 23 | let client = DinerClient::new(ch); 24 | 25 | let mut order = Order::new(); 26 | order.set_items(vec![Item::SPAM, Item::EGGS]); 27 | let check = client.eat(&order).expect("RPC Failed!"); 28 | println!("Ate {:?} and got charged ${:.2}", order, check.get_total()); 29 | } 30 | -------------------------------------------------------------------------------- /example/src/protos/.gitignore: -------------------------------------------------------------------------------- 1 | *.rs 2 | !mod.rs 3 | -------------------------------------------------------------------------------- /example/src/protos/example/diner.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package example; 4 | 5 | service Diner { 6 | rpc Eat(Order) returns (Check) {} 7 | } 8 | 9 | enum Item { 10 | SPAM = 0; 11 | EGGS = 1; 12 | HAM = 2; 13 | } 14 | 15 | message Order { 16 | repeated Item items = 1; 17 | } 18 | 19 | message Check { 20 | double total = 1; 21 | } 22 | -------------------------------------------------------------------------------- /example/src/protos/mod.rs: -------------------------------------------------------------------------------- 1 | extern crate futures; 2 | extern crate grpcio; 3 | extern crate protobuf; 4 | 5 | pub mod diner; 6 | pub mod diner_grpc; 7 | -------------------------------------------------------------------------------- /example/src/server.rs: -------------------------------------------------------------------------------- 1 | extern crate futures; 2 | extern crate grpcio; 3 | extern crate protos; 4 | 5 | use std::io::Read; 6 | use std::sync::Arc; 7 | use std::{io, thread}; 8 | 9 | use futures::prelude::*; 10 | use grpcio::{Environment, RpcContext, ServerBuilder, UnarySink}; 11 | 12 | use protos::diner::{Check, Item, Order}; 13 | use protos::diner_grpc::{self, Diner}; 14 | use futures::channel::oneshot; 15 | use futures::executor::block_on; 16 | 17 | #[derive(Clone)] 18 | struct DinerService; 19 | 20 | impl Diner for DinerService { 21 | fn eat(&mut self, ctx: RpcContext, order: Order, sink: UnarySink) { 22 | println!("Received Order {{ {:?} }}", order); 23 | let mut check = Check::new(); 24 | check.set_total(order.get_items().iter().fold(0.0, |total, &item| { 25 | total + match item { 26 | Item::SPAM => 0.05, 27 | Item::EGGS => 0.25, 28 | Item::HAM => 1.0, 29 | } 30 | })); 31 | let f = sink 32 | .success(check.clone()) 33 | .map_err(move |err| eprintln!("Failed to reply: {:?}", err)) 34 | .map(move |_| println!("Responded with Check {{ {:?} }}", check)); 35 | ctx.spawn(f) 36 | } 37 | } 38 | 39 | fn main() { 40 | let env = Arc::new(Environment::new(1)); 41 | let service = diner_grpc::create_diner(DinerService); 42 | let mut server = ServerBuilder::new(env) 43 | .register_service(service) 44 | .bind("127.0.0.1", 0) 45 | .build() 46 | .unwrap(); 47 | server.start(); 48 | for (ref host, port) in server.bind_addrs() { 49 | println!("listening on {}:{}", host, port); 50 | } 51 | let (tx, rx) = oneshot::channel(); 52 | thread::spawn(move || { 53 | println!("Press ENTER to exit..."); 54 | let _ = io::stdin().read(&mut [0]).unwrap(); 55 | tx.send(()) 56 | }); 57 | let _ = block_on(rx); 58 | let _ = block_on(server.shutdown()); 59 | } 60 | -------------------------------------------------------------------------------- /install_dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function install_protobuf { 4 | local install_prefix="${INSTALL_PREFIX:-/home/travis}" 5 | local protobuf_version="${PROTOBUF_VERSION:-3.5.1}" 6 | local protobuf_dir="protobuf-${protobuf_version}" 7 | local protobuf_archive_name="protobuf-cpp-${protobuf_version}.tar.gz" 8 | local protobuf_url="https://github.com/google/protobuf/releases/download/v${protobuf_version}/${protobuf_archive_name}" 9 | local build_dir="/tmp" 10 | 11 | set -e 12 | 13 | if [ ! -e "${install_prefix}/bin/protoc" ]; then 14 | if [ ! -e "${build_dir}/${protobuf_archive_name}" ]; then 15 | mkdir -p "${build_dir}/download" 16 | wget -q -P "${build_dir}/download" "${protobuf_url}" 17 | mv "${build_dir}/download/${protobuf_archive_name}" "${build_dir}" 18 | fi 19 | tar -C "${build_dir}" -zxvf "${build_dir}/${protobuf_archive_name}" 20 | pushd "${build_dir}/${protobuf_dir}" 21 | ./configure --prefix="${install_prefix}" 22 | make 23 | make install 24 | popd 25 | fi 26 | 27 | set +e 28 | } 29 | 30 | install_protobuf 31 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # line length 2 | error_on_line_overflow = true 3 | max_width = 100 4 | 5 | # comments 6 | comment_width = 100 7 | wrap_comments = false # rustfmt is broken currently and doesn't softwrap 8 | normalize_comments = true 9 | 10 | # commas 11 | trailing_comma = "Never" 12 | match_block_trailing_comma = true 13 | 14 | # code 15 | use_try_shorthand = true 16 | binop_separator = "Back" 17 | format_strings = false # rustfmt string handling is horribly busted 18 | 19 | # imports 20 | reorder_imports = true 21 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018. Matthew Pelland . 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | // 14 | // Parts of this work are derived from the `protoc-rust-grpc` crate by 15 | // Stepan Koltsov . 16 | // 17 | // Copyright 2016, Stepan Koltsov . 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // See the License for the specific language governing permissions and 28 | // limitations under the License. 29 | #![deny(warnings)] 30 | #![warn(missing_docs)] 31 | //! An API for programmatically invoking the grpcio gRPC compiler in the same vein as the 32 | //! [rust-protoc-grpc](https://crates.io/crates/protoc-rust-grpc) crate from Stepan Koltsov. 33 | 34 | extern crate grpcio_compiler; 35 | 36 | #[macro_use] 37 | extern crate anyhow; 38 | 39 | extern crate tempfile; 40 | 41 | extern crate protobuf; 42 | extern crate protobuf_codegen; 43 | extern crate protoc; 44 | 45 | use std::convert::AsRef; 46 | use std::fs::File; 47 | use std::io::{Read, Write}; 48 | use std::iter::Iterator; 49 | use std::path::{Path, PathBuf}; 50 | use std::vec::Vec; 51 | 52 | use anyhow::Context; 53 | 54 | use tempfile::NamedTempFile; 55 | 56 | use protobuf::{compiler_plugin, descriptor, Message}; 57 | use protobuf_codegen::Customize; 58 | use protoc::{DescriptorSetOutArgs, Protoc}; 59 | 60 | /// Custom error type used throughout this crate. 61 | pub type CompileError = ::anyhow::Error; 62 | /// Custom result type used throughout this crate. 63 | pub type CompileResult = Result; 64 | 65 | fn stringify_paths(paths: Paths) -> CompileResult> 66 | where 67 | Paths: IntoIterator, 68 | Paths::Item: AsRef, 69 | { 70 | paths 71 | .into_iter() 72 | .map(|input| match input.as_ref().to_str() { 73 | Some(s) => Ok(s.to_owned()), 74 | None => Err(format_err!( 75 | "failed to convert {:?} to string", 76 | input.as_ref() 77 | )), 78 | }) 79 | .collect() 80 | } 81 | 82 | fn write_out_generated_files

( 83 | generation_results: Vec, 84 | output_dir: P, 85 | ) -> CompileResult<()> 86 | where 87 | P: AsRef, 88 | { 89 | for result in generation_results { 90 | let file = output_dir.as_ref().join(result.name); 91 | File::create(&file) 92 | .context(format!("failed to create {:?}", &file))? 93 | .write_all(&result.content) 94 | .context(format!("failed to write {:?}", &file))?; 95 | } 96 | 97 | Ok(()) 98 | } 99 | 100 | fn absolutize

(path: P) -> CompileResult 101 | where 102 | P: AsRef, 103 | { 104 | let p = path.as_ref(); 105 | if p.is_relative() { 106 | match std::env::current_dir() { 107 | Ok(cwd) => Ok(cwd.join(p)), 108 | Err(err) => Err(format_err!( 109 | "Failed to determine CWD needed to absolutize a relative path: {:?}", 110 | err 111 | )), 112 | } 113 | } else { 114 | Ok(PathBuf::from(p)) 115 | } 116 | } 117 | 118 | fn normalize( 119 | paths: Paths, 120 | bases: Bases, 121 | ) -> CompileResult<(Vec, Vec, Vec)> 122 | where 123 | Paths: IntoIterator, 124 | Paths::Item: AsRef, 125 | Bases: IntoIterator, 126 | Bases::Item: AsRef, 127 | { 128 | let absolutized_bases = bases 129 | .into_iter() 130 | .map(absolutize) 131 | .collect::>>()?; 132 | 133 | // We deal with the following cases: 134 | // a.) absolute paths 135 | // b.) paths relative to CWD 136 | // c.) paths relative to bases 137 | // 138 | // We take the strategy of transforming the relative path cases (b & c) into absolute paths (a) 139 | // and use the strip_prefix API from there. 140 | 141 | let absolutized_paths = paths 142 | .into_iter() 143 | .map(|p| { 144 | let rel_path = p.as_ref().to_path_buf(); 145 | let absolute_path = absolutize(&rel_path)?; 146 | Ok((rel_path, absolute_path)) 147 | }) 148 | // TODO(John Sirois): Use `.flatten()` pending https://github.com/rust-lang/rust/issues/48213 149 | .flat_map(|r: CompileResult<(PathBuf, PathBuf)>| r) 150 | .map(|(rel_path, abs_path)| { 151 | if abs_path.exists() { 152 | // Case a or b. 153 | Ok(abs_path) 154 | } else { 155 | // Case c. 156 | for b in &absolutized_bases { 157 | let absolutized_path = b.join(&rel_path); 158 | if absolutized_path.exists() { 159 | return Ok(absolutized_path); 160 | } 161 | } 162 | Err(format_err!( 163 | "Failed to find the absolute path of input {:?}", 164 | rel_path 165 | )) 166 | } 167 | }) 168 | .collect::>>()?; 169 | 170 | let relativized_paths: Vec = absolutized_paths 171 | .iter() 172 | .map(|p| { 173 | for b in &absolutized_bases { 174 | if let Ok(rel_path) = p.strip_prefix(&b) { 175 | return Ok(PathBuf::from(rel_path)); 176 | } 177 | } 178 | Err(format_err!( 179 | "The input path {:?} is not contained by any of the include paths {:?}", 180 | p, 181 | absolutized_bases 182 | )) 183 | }) 184 | .collect::>>()?; 185 | 186 | Ok((absolutized_bases, absolutized_paths, relativized_paths)) 187 | } 188 | 189 | /// Compiles a list a gRPC definitions to rust modules. 190 | /// 191 | /// # Arguments 192 | /// 193 | /// * `inputs` - A list of protobuf definition paths to compile. Paths can be specified as absolute, 194 | /// relative to the CWD or relative to one of the `includes` paths. Note that the directory each 195 | /// member of `inputs` is found under must be included in the `includes` parameter. 196 | /// * `includes` - A list of of include directory paths to pass to `protoc`. Include paths can be 197 | /// specified either as absolute or relative to the CWD. Note that the directory each member of 198 | /// `inputs` is found under must be included in this parameter. 199 | /// * `output` - Directory to place the generated rust modules into. 200 | /// * `customizations` - An Option allowing customization options to be 201 | /// passed to protobuf_codegen 202 | pub fn compile_grpc_protos( 203 | inputs: Inputs, 204 | includes: Includes, 205 | output: Output, 206 | customizations: Option, 207 | ) -> CompileResult<()> 208 | where 209 | Inputs: IntoIterator, 210 | Inputs::Item: AsRef, 211 | Includes: IntoIterator, 212 | Includes::Item: AsRef, 213 | Output: AsRef, 214 | { 215 | let protoc = Protoc::from_env_path(); 216 | 217 | protoc 218 | .check() 219 | .context("failed to find `protoc`, `protoc` must be availabe in `PATH`")?; 220 | 221 | let (absolutized_includes, absolutized_paths, relativized_inputs) = 222 | normalize(inputs, includes)?; 223 | let stringified_inputs_absolute = stringify_paths(absolutized_paths)?; 224 | let stringified_inputs = stringify_paths(relativized_inputs)?; 225 | let stringified_includes = stringify_paths(absolutized_includes)?; 226 | 227 | let descriptor_set = NamedTempFile::new()?; 228 | 229 | protoc 230 | .write_descriptor_set(DescriptorSetOutArgs { 231 | out: match descriptor_set.as_ref().to_str() { 232 | Some(s) => s, 233 | None => bail!("failed to convert descriptor set path to string"), 234 | }, 235 | input: stringified_inputs_absolute 236 | .iter() 237 | .map(String::as_str) 238 | .collect::>() 239 | .as_slice(), 240 | includes: stringified_includes 241 | .iter() 242 | .map(String::as_str) 243 | .collect::>() 244 | .as_slice(), 245 | include_imports: true, 246 | }) 247 | .context("failed to write descriptor set")?; 248 | 249 | let mut serialized_descriptor_set = Vec::new(); 250 | File::open(&descriptor_set) 251 | .context("failed to open descriptor set")? 252 | .read_to_end(&mut serialized_descriptor_set) 253 | .context("failed to read descriptor set")?; 254 | 255 | let descriptor_set = 256 | descriptor::FileDescriptorSet::parse_from_bytes(&serialized_descriptor_set) 257 | .context("failed to parse descriptor set")?; 258 | 259 | let customize = customizations.unwrap_or_default(); 260 | 261 | write_out_generated_files( 262 | grpcio_compiler::codegen::gen(descriptor_set.get_file(), stringified_inputs.as_slice()), 263 | &output, 264 | ) 265 | .context("failed to write generated grpc definitions")?; 266 | 267 | write_out_generated_files( 268 | protobuf_codegen::gen( 269 | descriptor_set.get_file(), 270 | stringified_inputs.as_slice(), 271 | &customize, 272 | ), 273 | &output, 274 | ) 275 | .context("failed to write out generated protobuf definitions")?; 276 | 277 | Ok(()) 278 | } 279 | 280 | #[cfg(test)] 281 | mod tests { 282 | use super::*; 283 | use std::path::PathBuf; 284 | use tempfile::tempdir; 285 | 286 | fn assert_compile_grpc_protos(input: Input, expected_outputs: Output) 287 | where 288 | Input: AsRef, 289 | Output: IntoIterator + Copy, 290 | Output::Item: AsRef, 291 | { 292 | let rel_include_path = PathBuf::from("test/assets/protos"); 293 | let abs_include_path = Path::new(env!("CARGO_MANIFEST_DIR")).join(&rel_include_path); 294 | for include_path in &[&rel_include_path, &abs_include_path] { 295 | for inputs in &[vec![input.as_ref()], vec![&include_path.join(&input)]] { 296 | let temp_dir = tempdir().unwrap(); 297 | compile_grpc_protos(inputs, &[include_path], &temp_dir, None).unwrap(); 298 | 299 | for output in expected_outputs { 300 | assert!(temp_dir.as_ref().join(output).is_file()); 301 | } 302 | } 303 | } 304 | } 305 | 306 | #[test] 307 | fn test_compile_grpc_protos() { 308 | assert_compile_grpc_protos("helloworld.proto", &["helloworld_grpc.rs", "helloworld.rs"]) 309 | } 310 | 311 | #[test] 312 | fn test_compile_grpc_protos_subdir() { 313 | assert_compile_grpc_protos("foo/bar/baz.proto", &["baz_grpc.rs", "baz.rs"]) 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /test/assets/protos/foo/bar/baz.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package foo.bar; 4 | 5 | message Foo { 6 | int64 value = 1; 7 | } 8 | 9 | message Bar { 10 | double value = 1; 11 | } 12 | 13 | service Baz { 14 | rpc Qux(Foo) returns (Bar) {} 15 | } 16 | -------------------------------------------------------------------------------- /test/assets/protos/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | option objc_class_prefix = "HLW"; 21 | 22 | package helloworld; 23 | 24 | // The greeting service definition. 25 | service Greeter { 26 | // Sends a greeting 27 | rpc SayHello (HelloRequest) returns (HelloReply) {} 28 | } 29 | 30 | // The request message containing the user's name. 31 | message HelloRequest { 32 | string name = 1; 33 | } 34 | 35 | // The response message containing the greetings 36 | message HelloReply { 37 | string message = 1; 38 | } 39 | --------------------------------------------------------------------------------