├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-MIT ├── README.md ├── crates ├── drv-adapter │ ├── .cargo │ │ └── config.toml │ ├── Cargo.toml │ └── src │ │ └── main.rs └── proxy │ ├── Cargo.toml │ └── src │ ├── generated │ ├── build.bazel.remote.execution.v2.rs │ ├── build.bazel.semver.rs │ ├── google.api.rs │ ├── google.bytestream.rs │ ├── google.longrunning.rs │ ├── google.rpc.rs │ └── mod.rs │ ├── lib.rs │ └── main.rs ├── flake.lock ├── flake.nix ├── generator ├── Cargo.toml └── src │ └── main.rs └── remote-build.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | generator/out 3 | generator/proto 4 | test-remote-store 5 | -------------------------------------------------------------------------------- /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 = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anstream" 31 | version = "0.6.4" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" 34 | dependencies = [ 35 | "anstyle", 36 | "anstyle-parse", 37 | "anstyle-query", 38 | "anstyle-wincon", 39 | "colorchoice", 40 | "utf8parse", 41 | ] 42 | 43 | [[package]] 44 | name = "anstyle" 45 | version = "1.0.4" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" 48 | 49 | [[package]] 50 | name = "anstyle-parse" 51 | version = "0.2.3" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 54 | dependencies = [ 55 | "utf8parse", 56 | ] 57 | 58 | [[package]] 59 | name = "anstyle-query" 60 | version = "1.0.1" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" 63 | dependencies = [ 64 | "windows-sys 0.52.0", 65 | ] 66 | 67 | [[package]] 68 | name = "anstyle-wincon" 69 | version = "3.0.2" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 72 | dependencies = [ 73 | "anstyle", 74 | "windows-sys 0.52.0", 75 | ] 76 | 77 | [[package]] 78 | name = "anyhow" 79 | version = "1.0.80" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" 82 | dependencies = [ 83 | "backtrace", 84 | ] 85 | 86 | [[package]] 87 | name = "async-stream" 88 | version = "0.3.5" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" 91 | dependencies = [ 92 | "async-stream-impl", 93 | "futures-core", 94 | "pin-project-lite", 95 | ] 96 | 97 | [[package]] 98 | name = "async-stream-impl" 99 | version = "0.3.5" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" 102 | dependencies = [ 103 | "proc-macro2", 104 | "quote", 105 | "syn 2.0.46", 106 | ] 107 | 108 | [[package]] 109 | name = "async-trait" 110 | version = "0.1.74" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" 113 | dependencies = [ 114 | "proc-macro2", 115 | "quote", 116 | "syn 2.0.46", 117 | ] 118 | 119 | [[package]] 120 | name = "autocfg" 121 | version = "1.1.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 124 | 125 | [[package]] 126 | name = "axum" 127 | version = "0.6.20" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" 130 | dependencies = [ 131 | "async-trait", 132 | "axum-core", 133 | "bitflags 1.3.2", 134 | "bytes", 135 | "futures-util", 136 | "http", 137 | "http-body", 138 | "hyper", 139 | "itoa", 140 | "matchit", 141 | "memchr", 142 | "mime", 143 | "percent-encoding", 144 | "pin-project-lite", 145 | "rustversion", 146 | "serde", 147 | "sync_wrapper", 148 | "tower", 149 | "tower-layer", 150 | "tower-service", 151 | ] 152 | 153 | [[package]] 154 | name = "axum-core" 155 | version = "0.3.4" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" 158 | dependencies = [ 159 | "async-trait", 160 | "bytes", 161 | "futures-util", 162 | "http", 163 | "http-body", 164 | "mime", 165 | "rustversion", 166 | "tower-layer", 167 | "tower-service", 168 | ] 169 | 170 | [[package]] 171 | name = "backtrace" 172 | version = "0.3.69" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 175 | dependencies = [ 176 | "addr2line", 177 | "cc", 178 | "cfg-if", 179 | "libc", 180 | "miniz_oxide", 181 | "object", 182 | "rustc-demangle", 183 | ] 184 | 185 | [[package]] 186 | name = "base64" 187 | version = "0.21.5" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" 190 | 191 | [[package]] 192 | name = "bincode" 193 | version = "1.3.3" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 196 | dependencies = [ 197 | "serde", 198 | ] 199 | 200 | [[package]] 201 | name = "bitflags" 202 | version = "1.3.2" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 205 | 206 | [[package]] 207 | name = "bitflags" 208 | version = "2.4.1" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" 211 | 212 | [[package]] 213 | name = "bytes" 214 | version = "1.5.0" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" 217 | 218 | [[package]] 219 | name = "cc" 220 | version = "1.0.83" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 223 | dependencies = [ 224 | "libc", 225 | ] 226 | 227 | [[package]] 228 | name = "cfg-if" 229 | version = "1.0.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 232 | 233 | [[package]] 234 | name = "clap" 235 | version = "4.4.11" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" 238 | dependencies = [ 239 | "clap_builder", 240 | "clap_derive", 241 | ] 242 | 243 | [[package]] 244 | name = "clap_builder" 245 | version = "4.4.11" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" 248 | dependencies = [ 249 | "anstream", 250 | "anstyle", 251 | "clap_lex", 252 | "strsim", 253 | ] 254 | 255 | [[package]] 256 | name = "clap_derive" 257 | version = "4.4.7" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" 260 | dependencies = [ 261 | "heck", 262 | "proc-macro2", 263 | "quote", 264 | "syn 2.0.46", 265 | ] 266 | 267 | [[package]] 268 | name = "clap_lex" 269 | version = "0.6.0" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" 272 | 273 | [[package]] 274 | name = "colorchoice" 275 | version = "1.0.0" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 278 | 279 | [[package]] 280 | name = "drv-adapter" 281 | version = "0.1.0" 282 | dependencies = [ 283 | "aho-corasick", 284 | "anyhow", 285 | "bincode", 286 | "fs_extra", 287 | "nix-remote", 288 | "ring", 289 | "serde", 290 | "walkdir", 291 | ] 292 | 293 | [[package]] 294 | name = "either" 295 | version = "1.9.0" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 298 | 299 | [[package]] 300 | name = "equivalent" 301 | version = "1.0.1" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 304 | 305 | [[package]] 306 | name = "errno" 307 | version = "0.3.8" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 310 | dependencies = [ 311 | "libc", 312 | "windows-sys 0.52.0", 313 | ] 314 | 315 | [[package]] 316 | name = "fastrand" 317 | version = "2.0.1" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 320 | 321 | [[package]] 322 | name = "fixedbitset" 323 | version = "0.4.2" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 326 | 327 | [[package]] 328 | name = "fnv" 329 | version = "1.0.7" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 332 | 333 | [[package]] 334 | name = "fs_extra" 335 | version = "1.3.0" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" 338 | 339 | [[package]] 340 | name = "futures" 341 | version = "0.3.30" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" 344 | dependencies = [ 345 | "futures-channel", 346 | "futures-core", 347 | "futures-executor", 348 | "futures-io", 349 | "futures-sink", 350 | "futures-task", 351 | "futures-util", 352 | ] 353 | 354 | [[package]] 355 | name = "futures-channel" 356 | version = "0.3.30" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 359 | dependencies = [ 360 | "futures-core", 361 | "futures-sink", 362 | ] 363 | 364 | [[package]] 365 | name = "futures-core" 366 | version = "0.3.30" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 369 | 370 | [[package]] 371 | name = "futures-executor" 372 | version = "0.3.30" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" 375 | dependencies = [ 376 | "futures-core", 377 | "futures-task", 378 | "futures-util", 379 | ] 380 | 381 | [[package]] 382 | name = "futures-io" 383 | version = "0.3.30" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 386 | 387 | [[package]] 388 | name = "futures-macro" 389 | version = "0.3.30" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 392 | dependencies = [ 393 | "proc-macro2", 394 | "quote", 395 | "syn 2.0.46", 396 | ] 397 | 398 | [[package]] 399 | name = "futures-sink" 400 | version = "0.3.30" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 403 | 404 | [[package]] 405 | name = "futures-task" 406 | version = "0.3.30" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 409 | 410 | [[package]] 411 | name = "futures-util" 412 | version = "0.3.30" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 415 | dependencies = [ 416 | "futures-channel", 417 | "futures-core", 418 | "futures-io", 419 | "futures-macro", 420 | "futures-sink", 421 | "futures-task", 422 | "memchr", 423 | "pin-project-lite", 424 | "pin-utils", 425 | "slab", 426 | ] 427 | 428 | [[package]] 429 | name = "generator" 430 | version = "0.1.0" 431 | dependencies = [ 432 | "clap", 433 | "prost-build", 434 | "tonic-build", 435 | ] 436 | 437 | [[package]] 438 | name = "getrandom" 439 | version = "0.2.11" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" 442 | dependencies = [ 443 | "cfg-if", 444 | "libc", 445 | "wasi", 446 | ] 447 | 448 | [[package]] 449 | name = "gimli" 450 | version = "0.28.1" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 453 | 454 | [[package]] 455 | name = "h2" 456 | version = "0.3.22" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" 459 | dependencies = [ 460 | "bytes", 461 | "fnv", 462 | "futures-core", 463 | "futures-sink", 464 | "futures-util", 465 | "http", 466 | "indexmap 2.1.0", 467 | "slab", 468 | "tokio", 469 | "tokio-util", 470 | "tracing", 471 | ] 472 | 473 | [[package]] 474 | name = "hashbrown" 475 | version = "0.12.3" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 478 | 479 | [[package]] 480 | name = "hashbrown" 481 | version = "0.14.3" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 484 | 485 | [[package]] 486 | name = "heck" 487 | version = "0.4.1" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 490 | 491 | [[package]] 492 | name = "hermit-abi" 493 | version = "0.3.3" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" 496 | 497 | [[package]] 498 | name = "home" 499 | version = "0.5.5" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" 502 | dependencies = [ 503 | "windows-sys 0.48.0", 504 | ] 505 | 506 | [[package]] 507 | name = "http" 508 | version = "0.2.11" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" 511 | dependencies = [ 512 | "bytes", 513 | "fnv", 514 | "itoa", 515 | ] 516 | 517 | [[package]] 518 | name = "http-body" 519 | version = "0.4.6" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 522 | dependencies = [ 523 | "bytes", 524 | "http", 525 | "pin-project-lite", 526 | ] 527 | 528 | [[package]] 529 | name = "httparse" 530 | version = "1.8.0" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 533 | 534 | [[package]] 535 | name = "httpdate" 536 | version = "1.0.3" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 539 | 540 | [[package]] 541 | name = "hyper" 542 | version = "0.14.27" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 545 | dependencies = [ 546 | "bytes", 547 | "futures-channel", 548 | "futures-core", 549 | "futures-util", 550 | "h2", 551 | "http", 552 | "http-body", 553 | "httparse", 554 | "httpdate", 555 | "itoa", 556 | "pin-project-lite", 557 | "socket2 0.4.10", 558 | "tokio", 559 | "tower-service", 560 | "tracing", 561 | "want", 562 | ] 563 | 564 | [[package]] 565 | name = "hyper-timeout" 566 | version = "0.4.1" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" 569 | dependencies = [ 570 | "hyper", 571 | "pin-project-lite", 572 | "tokio", 573 | "tokio-io-timeout", 574 | ] 575 | 576 | [[package]] 577 | name = "indexmap" 578 | version = "1.9.3" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 581 | dependencies = [ 582 | "autocfg", 583 | "hashbrown 0.12.3", 584 | ] 585 | 586 | [[package]] 587 | name = "indexmap" 588 | version = "2.1.0" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" 591 | dependencies = [ 592 | "equivalent", 593 | "hashbrown 0.14.3", 594 | ] 595 | 596 | [[package]] 597 | name = "itertools" 598 | version = "0.11.0" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" 601 | dependencies = [ 602 | "either", 603 | ] 604 | 605 | [[package]] 606 | name = "itoa" 607 | version = "1.0.10" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 610 | 611 | [[package]] 612 | name = "libc" 613 | version = "0.2.150" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" 616 | 617 | [[package]] 618 | name = "linux-raw-sys" 619 | version = "0.4.12" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" 622 | 623 | [[package]] 624 | name = "log" 625 | version = "0.4.20" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 628 | 629 | [[package]] 630 | name = "matchit" 631 | version = "0.7.3" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" 634 | 635 | [[package]] 636 | name = "memchr" 637 | version = "2.6.4" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 640 | 641 | [[package]] 642 | name = "mime" 643 | version = "0.3.17" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 646 | 647 | [[package]] 648 | name = "miniz_oxide" 649 | version = "0.7.1" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 652 | dependencies = [ 653 | "adler", 654 | ] 655 | 656 | [[package]] 657 | name = "mio" 658 | version = "0.8.10" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" 661 | dependencies = [ 662 | "libc", 663 | "wasi", 664 | "windows-sys 0.48.0", 665 | ] 666 | 667 | [[package]] 668 | name = "multimap" 669 | version = "0.8.3" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" 672 | 673 | [[package]] 674 | name = "nix-remote" 675 | version = "0.1.1" 676 | dependencies = [ 677 | "anyhow", 678 | "clap", 679 | "num-derive", 680 | "num-traits", 681 | "serde", 682 | "serde_bytes", 683 | "tagged-serde", 684 | "thiserror", 685 | ] 686 | 687 | [[package]] 688 | name = "nix-rev2" 689 | version = "0.1.0" 690 | dependencies = [ 691 | "anyhow", 692 | "bincode", 693 | "futures", 694 | "nix-remote", 695 | "prost", 696 | "prost-types", 697 | "ring", 698 | "serde", 699 | "serde_bytes", 700 | "serde_json", 701 | "tokio", 702 | "tonic", 703 | "uuid", 704 | ] 705 | 706 | [[package]] 707 | name = "num-derive" 708 | version = "0.3.3" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" 711 | dependencies = [ 712 | "proc-macro2", 713 | "quote", 714 | "syn 1.0.109", 715 | ] 716 | 717 | [[package]] 718 | name = "num-traits" 719 | version = "0.2.17" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" 722 | dependencies = [ 723 | "autocfg", 724 | ] 725 | 726 | [[package]] 727 | name = "num_cpus" 728 | version = "1.16.0" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 731 | dependencies = [ 732 | "hermit-abi", 733 | "libc", 734 | ] 735 | 736 | [[package]] 737 | name = "object" 738 | version = "0.32.1" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" 741 | dependencies = [ 742 | "memchr", 743 | ] 744 | 745 | [[package]] 746 | name = "once_cell" 747 | version = "1.18.0" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 750 | 751 | [[package]] 752 | name = "percent-encoding" 753 | version = "2.3.1" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 756 | 757 | [[package]] 758 | name = "petgraph" 759 | version = "0.6.4" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" 762 | dependencies = [ 763 | "fixedbitset", 764 | "indexmap 2.1.0", 765 | ] 766 | 767 | [[package]] 768 | name = "pin-project" 769 | version = "1.1.3" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" 772 | dependencies = [ 773 | "pin-project-internal", 774 | ] 775 | 776 | [[package]] 777 | name = "pin-project-internal" 778 | version = "1.1.3" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" 781 | dependencies = [ 782 | "proc-macro2", 783 | "quote", 784 | "syn 2.0.46", 785 | ] 786 | 787 | [[package]] 788 | name = "pin-project-lite" 789 | version = "0.2.13" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 792 | 793 | [[package]] 794 | name = "pin-utils" 795 | version = "0.1.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 798 | 799 | [[package]] 800 | name = "ppv-lite86" 801 | version = "0.2.17" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 804 | 805 | [[package]] 806 | name = "prettyplease" 807 | version = "0.2.15" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" 810 | dependencies = [ 811 | "proc-macro2", 812 | "syn 2.0.46", 813 | ] 814 | 815 | [[package]] 816 | name = "proc-macro2" 817 | version = "1.0.74" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" 820 | dependencies = [ 821 | "unicode-ident", 822 | ] 823 | 824 | [[package]] 825 | name = "prost" 826 | version = "0.12.3" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" 829 | dependencies = [ 830 | "bytes", 831 | "prost-derive", 832 | ] 833 | 834 | [[package]] 835 | name = "prost-build" 836 | version = "0.12.3" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" 839 | dependencies = [ 840 | "bytes", 841 | "heck", 842 | "itertools", 843 | "log", 844 | "multimap", 845 | "once_cell", 846 | "petgraph", 847 | "prettyplease", 848 | "prost", 849 | "prost-types", 850 | "regex", 851 | "syn 2.0.46", 852 | "tempfile", 853 | "which", 854 | ] 855 | 856 | [[package]] 857 | name = "prost-derive" 858 | version = "0.12.3" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" 861 | dependencies = [ 862 | "anyhow", 863 | "itertools", 864 | "proc-macro2", 865 | "quote", 866 | "syn 2.0.46", 867 | ] 868 | 869 | [[package]] 870 | name = "prost-types" 871 | version = "0.12.3" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" 874 | dependencies = [ 875 | "prost", 876 | ] 877 | 878 | [[package]] 879 | name = "quote" 880 | version = "1.0.35" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 883 | dependencies = [ 884 | "proc-macro2", 885 | ] 886 | 887 | [[package]] 888 | name = "rand" 889 | version = "0.8.5" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 892 | dependencies = [ 893 | "libc", 894 | "rand_chacha", 895 | "rand_core", 896 | ] 897 | 898 | [[package]] 899 | name = "rand_chacha" 900 | version = "0.3.1" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 903 | dependencies = [ 904 | "ppv-lite86", 905 | "rand_core", 906 | ] 907 | 908 | [[package]] 909 | name = "rand_core" 910 | version = "0.6.4" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 913 | dependencies = [ 914 | "getrandom", 915 | ] 916 | 917 | [[package]] 918 | name = "redox_syscall" 919 | version = "0.4.1" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 922 | dependencies = [ 923 | "bitflags 1.3.2", 924 | ] 925 | 926 | [[package]] 927 | name = "regex" 928 | version = "1.10.2" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" 931 | dependencies = [ 932 | "aho-corasick", 933 | "memchr", 934 | "regex-automata", 935 | "regex-syntax", 936 | ] 937 | 938 | [[package]] 939 | name = "regex-automata" 940 | version = "0.4.3" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" 943 | dependencies = [ 944 | "aho-corasick", 945 | "memchr", 946 | "regex-syntax", 947 | ] 948 | 949 | [[package]] 950 | name = "regex-syntax" 951 | version = "0.8.2" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 954 | 955 | [[package]] 956 | name = "ring" 957 | version = "0.17.7" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" 960 | dependencies = [ 961 | "cc", 962 | "getrandom", 963 | "libc", 964 | "spin", 965 | "untrusted", 966 | "windows-sys 0.48.0", 967 | ] 968 | 969 | [[package]] 970 | name = "rustc-demangle" 971 | version = "0.1.23" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 974 | 975 | [[package]] 976 | name = "rustix" 977 | version = "0.38.26" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" 980 | dependencies = [ 981 | "bitflags 2.4.1", 982 | "errno", 983 | "libc", 984 | "linux-raw-sys", 985 | "windows-sys 0.52.0", 986 | ] 987 | 988 | [[package]] 989 | name = "rustversion" 990 | version = "1.0.14" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" 993 | 994 | [[package]] 995 | name = "ryu" 996 | version = "1.0.17" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 999 | 1000 | [[package]] 1001 | name = "same-file" 1002 | version = "1.0.6" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1005 | dependencies = [ 1006 | "winapi-util", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "serde" 1011 | version = "1.0.197" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" 1014 | dependencies = [ 1015 | "serde_derive", 1016 | ] 1017 | 1018 | [[package]] 1019 | name = "serde_bytes" 1020 | version = "0.11.12" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" 1023 | dependencies = [ 1024 | "serde", 1025 | ] 1026 | 1027 | [[package]] 1028 | name = "serde_derive" 1029 | version = "1.0.197" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" 1032 | dependencies = [ 1033 | "proc-macro2", 1034 | "quote", 1035 | "syn 2.0.46", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "serde_json" 1040 | version = "1.0.114" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" 1043 | dependencies = [ 1044 | "itoa", 1045 | "ryu", 1046 | "serde", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "slab" 1051 | version = "0.4.9" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1054 | dependencies = [ 1055 | "autocfg", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "socket2" 1060 | version = "0.4.10" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" 1063 | dependencies = [ 1064 | "libc", 1065 | "winapi", 1066 | ] 1067 | 1068 | [[package]] 1069 | name = "socket2" 1070 | version = "0.5.5" 1071 | source = "registry+https://github.com/rust-lang/crates.io-index" 1072 | checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" 1073 | dependencies = [ 1074 | "libc", 1075 | "windows-sys 0.48.0", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "spin" 1080 | version = "0.9.8" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1083 | 1084 | [[package]] 1085 | name = "strsim" 1086 | version = "0.10.0" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1089 | 1090 | [[package]] 1091 | name = "syn" 1092 | version = "1.0.109" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1095 | dependencies = [ 1096 | "proc-macro2", 1097 | "quote", 1098 | "unicode-ident", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "syn" 1103 | version = "2.0.46" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" 1106 | dependencies = [ 1107 | "proc-macro2", 1108 | "quote", 1109 | "unicode-ident", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "sync_wrapper" 1114 | version = "0.1.2" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 1117 | 1118 | [[package]] 1119 | name = "tagged-serde" 1120 | version = "0.1.0" 1121 | dependencies = [ 1122 | "proc-macro2", 1123 | "quote", 1124 | "syn 2.0.46", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "tempfile" 1129 | version = "3.8.1" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" 1132 | dependencies = [ 1133 | "cfg-if", 1134 | "fastrand", 1135 | "redox_syscall", 1136 | "rustix", 1137 | "windows-sys 0.48.0", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "thiserror" 1142 | version = "1.0.50" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 1145 | dependencies = [ 1146 | "thiserror-impl", 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "thiserror-impl" 1151 | version = "1.0.50" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 1154 | dependencies = [ 1155 | "proc-macro2", 1156 | "quote", 1157 | "syn 2.0.46", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "tokio" 1162 | version = "1.35.0" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" 1165 | dependencies = [ 1166 | "backtrace", 1167 | "bytes", 1168 | "libc", 1169 | "mio", 1170 | "num_cpus", 1171 | "pin-project-lite", 1172 | "socket2 0.5.5", 1173 | "tokio-macros", 1174 | "windows-sys 0.48.0", 1175 | ] 1176 | 1177 | [[package]] 1178 | name = "tokio-io-timeout" 1179 | version = "1.2.0" 1180 | source = "registry+https://github.com/rust-lang/crates.io-index" 1181 | checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" 1182 | dependencies = [ 1183 | "pin-project-lite", 1184 | "tokio", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "tokio-macros" 1189 | version = "2.2.0" 1190 | source = "registry+https://github.com/rust-lang/crates.io-index" 1191 | checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" 1192 | dependencies = [ 1193 | "proc-macro2", 1194 | "quote", 1195 | "syn 2.0.46", 1196 | ] 1197 | 1198 | [[package]] 1199 | name = "tokio-stream" 1200 | version = "0.1.14" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" 1203 | dependencies = [ 1204 | "futures-core", 1205 | "pin-project-lite", 1206 | "tokio", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "tokio-util" 1211 | version = "0.7.10" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" 1214 | dependencies = [ 1215 | "bytes", 1216 | "futures-core", 1217 | "futures-sink", 1218 | "pin-project-lite", 1219 | "tokio", 1220 | "tracing", 1221 | ] 1222 | 1223 | [[package]] 1224 | name = "tonic" 1225 | version = "0.10.2" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" 1228 | dependencies = [ 1229 | "async-stream", 1230 | "async-trait", 1231 | "axum", 1232 | "base64", 1233 | "bytes", 1234 | "h2", 1235 | "http", 1236 | "http-body", 1237 | "hyper", 1238 | "hyper-timeout", 1239 | "percent-encoding", 1240 | "pin-project", 1241 | "prost", 1242 | "tokio", 1243 | "tokio-stream", 1244 | "tower", 1245 | "tower-layer", 1246 | "tower-service", 1247 | "tracing", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "tonic-build" 1252 | version = "0.10.2" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "9d021fc044c18582b9a2408cd0dd05b1596e3ecdb5c4df822bb0183545683889" 1255 | dependencies = [ 1256 | "prettyplease", 1257 | "proc-macro2", 1258 | "prost-build", 1259 | "quote", 1260 | "syn 2.0.46", 1261 | ] 1262 | 1263 | [[package]] 1264 | name = "tower" 1265 | version = "0.4.13" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1268 | dependencies = [ 1269 | "futures-core", 1270 | "futures-util", 1271 | "indexmap 1.9.3", 1272 | "pin-project", 1273 | "pin-project-lite", 1274 | "rand", 1275 | "slab", 1276 | "tokio", 1277 | "tokio-util", 1278 | "tower-layer", 1279 | "tower-service", 1280 | "tracing", 1281 | ] 1282 | 1283 | [[package]] 1284 | name = "tower-layer" 1285 | version = "0.3.2" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 1288 | 1289 | [[package]] 1290 | name = "tower-service" 1291 | version = "0.3.2" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1294 | 1295 | [[package]] 1296 | name = "tracing" 1297 | version = "0.1.40" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1300 | dependencies = [ 1301 | "pin-project-lite", 1302 | "tracing-attributes", 1303 | "tracing-core", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "tracing-attributes" 1308 | version = "0.1.27" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 1311 | dependencies = [ 1312 | "proc-macro2", 1313 | "quote", 1314 | "syn 2.0.46", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "tracing-core" 1319 | version = "0.1.32" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1322 | dependencies = [ 1323 | "once_cell", 1324 | ] 1325 | 1326 | [[package]] 1327 | name = "try-lock" 1328 | version = "0.2.5" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1331 | 1332 | [[package]] 1333 | name = "unicode-ident" 1334 | version = "1.0.12" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1337 | 1338 | [[package]] 1339 | name = "untrusted" 1340 | version = "0.9.0" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1343 | 1344 | [[package]] 1345 | name = "utf8parse" 1346 | version = "0.2.1" 1347 | source = "registry+https://github.com/rust-lang/crates.io-index" 1348 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 1349 | 1350 | [[package]] 1351 | name = "uuid" 1352 | version = "1.7.0" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" 1355 | dependencies = [ 1356 | "getrandom", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "walkdir" 1361 | version = "2.5.0" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1364 | dependencies = [ 1365 | "same-file", 1366 | "winapi-util", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "want" 1371 | version = "0.3.1" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1374 | dependencies = [ 1375 | "try-lock", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "wasi" 1380 | version = "0.11.0+wasi-snapshot-preview1" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1383 | 1384 | [[package]] 1385 | name = "which" 1386 | version = "4.4.2" 1387 | source = "registry+https://github.com/rust-lang/crates.io-index" 1388 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 1389 | dependencies = [ 1390 | "either", 1391 | "home", 1392 | "once_cell", 1393 | "rustix", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "winapi" 1398 | version = "0.3.9" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1401 | dependencies = [ 1402 | "winapi-i686-pc-windows-gnu", 1403 | "winapi-x86_64-pc-windows-gnu", 1404 | ] 1405 | 1406 | [[package]] 1407 | name = "winapi-i686-pc-windows-gnu" 1408 | version = "0.4.0" 1409 | source = "registry+https://github.com/rust-lang/crates.io-index" 1410 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1411 | 1412 | [[package]] 1413 | name = "winapi-util" 1414 | version = "0.1.6" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 1417 | dependencies = [ 1418 | "winapi", 1419 | ] 1420 | 1421 | [[package]] 1422 | name = "winapi-x86_64-pc-windows-gnu" 1423 | version = "0.4.0" 1424 | source = "registry+https://github.com/rust-lang/crates.io-index" 1425 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1426 | 1427 | [[package]] 1428 | name = "windows-sys" 1429 | version = "0.48.0" 1430 | source = "registry+https://github.com/rust-lang/crates.io-index" 1431 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1432 | dependencies = [ 1433 | "windows-targets 0.48.5", 1434 | ] 1435 | 1436 | [[package]] 1437 | name = "windows-sys" 1438 | version = "0.52.0" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1441 | dependencies = [ 1442 | "windows-targets 0.52.0", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "windows-targets" 1447 | version = "0.48.5" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1450 | dependencies = [ 1451 | "windows_aarch64_gnullvm 0.48.5", 1452 | "windows_aarch64_msvc 0.48.5", 1453 | "windows_i686_gnu 0.48.5", 1454 | "windows_i686_msvc 0.48.5", 1455 | "windows_x86_64_gnu 0.48.5", 1456 | "windows_x86_64_gnullvm 0.48.5", 1457 | "windows_x86_64_msvc 0.48.5", 1458 | ] 1459 | 1460 | [[package]] 1461 | name = "windows-targets" 1462 | version = "0.52.0" 1463 | source = "registry+https://github.com/rust-lang/crates.io-index" 1464 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 1465 | dependencies = [ 1466 | "windows_aarch64_gnullvm 0.52.0", 1467 | "windows_aarch64_msvc 0.52.0", 1468 | "windows_i686_gnu 0.52.0", 1469 | "windows_i686_msvc 0.52.0", 1470 | "windows_x86_64_gnu 0.52.0", 1471 | "windows_x86_64_gnullvm 0.52.0", 1472 | "windows_x86_64_msvc 0.52.0", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "windows_aarch64_gnullvm" 1477 | version = "0.48.5" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1480 | 1481 | [[package]] 1482 | name = "windows_aarch64_gnullvm" 1483 | version = "0.52.0" 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" 1485 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 1486 | 1487 | [[package]] 1488 | name = "windows_aarch64_msvc" 1489 | version = "0.48.5" 1490 | source = "registry+https://github.com/rust-lang/crates.io-index" 1491 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1492 | 1493 | [[package]] 1494 | name = "windows_aarch64_msvc" 1495 | version = "0.52.0" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 1498 | 1499 | [[package]] 1500 | name = "windows_i686_gnu" 1501 | version = "0.48.5" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1504 | 1505 | [[package]] 1506 | name = "windows_i686_gnu" 1507 | version = "0.52.0" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 1510 | 1511 | [[package]] 1512 | name = "windows_i686_msvc" 1513 | version = "0.48.5" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1516 | 1517 | [[package]] 1518 | name = "windows_i686_msvc" 1519 | version = "0.52.0" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 1522 | 1523 | [[package]] 1524 | name = "windows_x86_64_gnu" 1525 | version = "0.48.5" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1528 | 1529 | [[package]] 1530 | name = "windows_x86_64_gnu" 1531 | version = "0.52.0" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 1534 | 1535 | [[package]] 1536 | name = "windows_x86_64_gnullvm" 1537 | version = "0.48.5" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1540 | 1541 | [[package]] 1542 | name = "windows_x86_64_gnullvm" 1543 | version = "0.52.0" 1544 | source = "registry+https://github.com/rust-lang/crates.io-index" 1545 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 1546 | 1547 | [[package]] 1548 | name = "windows_x86_64_msvc" 1549 | version = "0.48.5" 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" 1551 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1552 | 1553 | [[package]] 1554 | name = "windows_x86_64_msvc" 1555 | version = "0.52.0" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 1558 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["generator", "crates/proxy", "crates/drv-adapter"] 3 | resolver = "2" 4 | 5 | [workspace.dependencies] 6 | #nix-remote = { git = "https://github.com/tweag/nix-remote-rust.git" } 7 | nix-remote = { path = "../nix-remote-rust" } 8 | walkdir = "2.5" 9 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Matthew Toohey and Modus Create LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Proxy your nix builds to Bazel Remote Execution 2 | 3 | This is an experimental hack-in-progress to see what we can achieve using 4 | [nix-remote-rust](https://github.com/tweag/nix-remote-rust). 5 | -------------------------------------------------------------------------------- /crates/drv-adapter/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "x86_64-unknown-linux-musl" 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "relocation-model=static", "-C", "strip=symbols", "-C", "target-feature=+crt-static"] 6 | -------------------------------------------------------------------------------- /crates/drv-adapter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "drv-adapter" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | aho-corasick = "1.1.3" 10 | anyhow = "1.0.80" 11 | bincode = "1.3.3" 12 | fs_extra = "1.3.0" 13 | nix-remote.workspace = true 14 | ring = "0.17.7" 15 | serde = "1.0.197" 16 | walkdir.workspace = true 17 | -------------------------------------------------------------------------------- /crates/drv-adapter/src/main.rs: -------------------------------------------------------------------------------- 1 | // TODO: Set up shared lib to use between drv-adapter and proxy workspaces 2 | // - Standardize the BuildMetadata and OutputMetada structs in the shared lib, and use in both workspaces 3 | // - Write BuildMetadata and send back to the client 4 | // - fInd possible refrences to pass to the reference scanner 5 | use std::{ 6 | collections::{HashMap, HashSet}, 7 | ffi::OsStr, 8 | fs::File, 9 | io::{Cursor, Write}, 10 | os::unix::ffi::OsStrExt, 11 | os::unix::fs::PermissionsExt, 12 | path::Path, 13 | process::{exit, Command}, 14 | }; 15 | 16 | use aho_corasick::AhoCorasick; 17 | 18 | use ring::digest::{Context, Digest, SHA256}; 19 | 20 | use fs_extra::dir::CopyOptions; 21 | use nix_remote::{ 22 | nar::{DirectorySink, EntrySink, FileSink, Nar}, 23 | serialize::Tee, 24 | worker_op::Derivation, 25 | NixString, NixWriteExt, StorePath, 26 | }; 27 | use serde::{Deserialize, Serialize}; 28 | use walkdir::WalkDir; 29 | 30 | type NixHash = Vec; 31 | 32 | // FIXME: put in shared crate 33 | const METADATA_PATH: &str = "outputmetadata"; 34 | 35 | #[derive(Serialize, Deserialize)] 36 | struct OutputMetadata { 37 | references: Vec, 38 | nar_hash: NixString, 39 | nar_size: usize, 40 | } 41 | 42 | #[derive(Serialize, Deserialize)] 43 | struct BuildMetadata { 44 | // The key is the store path. 45 | metadata: HashMap, 46 | } 47 | 48 | struct HashSink { 49 | hash: Context, 50 | size: usize, 51 | } 52 | 53 | impl HashSink { 54 | fn new() -> Self { 55 | HashSink { 56 | hash: Context::new(&SHA256), 57 | size: 0, 58 | } 59 | } 60 | 61 | /// Return the digest of the hash. 62 | fn finish(self) -> (Digest, usize) { 63 | (self.hash.finish(), self.size) 64 | } 65 | } 66 | 67 | impl Write for HashSink { 68 | fn write(&mut self, buf: &[u8]) -> std::io::Result { 69 | self.hash.update(buf); 70 | self.size += buf.len(); 71 | Ok(buf.len()) 72 | } 73 | 74 | fn flush(&mut self) -> std::io::Result<()> { 75 | Ok(()) 76 | } 77 | } 78 | 79 | struct RefScanSink { 80 | hashes: AhoCorasick, 81 | hash_to_path: HashMap, 82 | seen: HashSet, 83 | tail: Vec, 84 | } 85 | 86 | impl RefScanSink { 87 | fn new(possible_paths: impl IntoIterator) -> RefScanSink { 88 | let hash_to_path: HashMap<_, _> = possible_paths 89 | .into_iter() 90 | .map(|path| (path.as_ref()[..32].to_owned(), path)) 91 | .collect(); 92 | RefScanSink { 93 | hashes: AhoCorasick::new(hash_to_path.keys()).unwrap(), 94 | hash_to_path, 95 | seen: HashSet::new(), 96 | tail: Vec::new(), 97 | } 98 | } 99 | 100 | fn scan(&mut self) { 101 | self.seen 102 | .extend(self.hashes.find_overlapping_iter(&self.tail).map(|m| { 103 | self.hash_to_path 104 | .get(&self.tail[m.range()]) 105 | .unwrap() 106 | .clone() 107 | })); 108 | } 109 | } 110 | 111 | impl Write for RefScanSink { 112 | fn write(&mut self, buf: &[u8]) -> std::io::Result { 113 | self.tail.extend_from_slice(buf); 114 | self.scan(); 115 | 116 | let tail_start = buf.len().saturating_sub(31); 117 | self.tail.drain(..tail_start); 118 | Ok(buf.len()) 119 | } 120 | 121 | fn flush(&mut self) -> std::io::Result<()> { 122 | Ok(()) 123 | } 124 | } 125 | 126 | struct Wye { 127 | w1: W1, 128 | w2: W2, 129 | } 130 | 131 | impl Wye { 132 | fn new(w1: W1, w2: W2) -> Self { 133 | Wye { w1, w2 } 134 | } 135 | } 136 | 137 | impl Write for Wye { 138 | fn write(&mut self, buf: &[u8]) -> std::io::Result { 139 | self.w1.write_all(buf)?; 140 | self.w2.write_all(buf)?; 141 | Ok(buf.len()) 142 | } 143 | 144 | fn flush(&mut self) -> std::io::Result<()> { 145 | self.w1.flush()?; 146 | self.w2.flush()?; 147 | Ok(()) 148 | } 149 | } 150 | 151 | // TODO: clean up error handling, and move to the other crate 152 | fn nar_from_filesystem<'a>(path: impl AsRef, sink: impl EntrySink<'a>) { 153 | let path = path.as_ref(); 154 | let metadata = std::fs::symlink_metadata(path).unwrap(); 155 | if metadata.is_dir() { 156 | let mut dir_sink = sink.become_directory(); 157 | let entries: Result, _> = std::fs::read_dir(path).unwrap().collect(); 158 | let mut entries = entries.unwrap(); 159 | entries.sort_by_key(|e| e.file_name()); 160 | 161 | for entry in entries { 162 | let file_name = entry.file_name(); 163 | let name = file_name.as_bytes(); 164 | let entry_sink = dir_sink.create_entry(NixString::from_bytes(name)); 165 | nar_from_filesystem(entry.path(), entry_sink); 166 | } 167 | } else if metadata.is_file() { 168 | let mut file_sink = sink.become_file(); 169 | let executable = (metadata.permissions().mode() & 0o100) != 0; 170 | // TODO: make this streaming 171 | let contents = std::fs::read(path).unwrap(); // FIXME 172 | file_sink.set_executable(executable); 173 | file_sink.add_contents(&contents); 174 | } else if metadata.is_symlink() { 175 | let target = std::fs::read_link(path).unwrap(); 176 | sink.become_symlink(NixString::from_bytes(target.into_os_string().as_bytes())); 177 | } else { 178 | panic!("not a dir, or a file, or a symlink") 179 | } 180 | } 181 | 182 | fn path_to_metadata( 183 | possible_references: impl IntoIterator, 184 | path: impl AsRef, 185 | ) -> OutputMetadata { 186 | let mut hasher = HashSink::new(); 187 | let mut ref_scanner = RefScanSink::new(possible_references); 188 | 189 | let mut out = Wye::new(&mut ref_scanner, &mut hasher); 190 | 191 | let mut nar = Nar::Target(NixString::from_bytes(b"")); 192 | nar_from_filesystem(path, &mut nar); 193 | out.write_nix(&nar).unwrap(); 194 | 195 | let (digest, nar_size) = hasher.finish(); 196 | 197 | OutputMetadata { 198 | references: ref_scanner.seen.into_iter().collect(), 199 | nar_hash: NixString::from_bytes(digest.as_ref()), 200 | nar_size, 201 | } 202 | } 203 | 204 | fn main() -> anyhow::Result<()> { 205 | // let args = std::env::args().collect::>(); 206 | // let path = &args[1]; 207 | // let out_path = &args[2]; 208 | 209 | // let mut out = File::create(out_path)?; 210 | 211 | // let mut nar = Nar::Target(NixString::from_bytes(b"")); 212 | // nar_from_filesystem(path, &mut nar); 213 | // out.write_nix(&nar).unwrap(); 214 | 215 | // Ok(()) 216 | let drv = std::fs::read("root.drv")?; 217 | let drv: Derivation = bincode::deserialize_from(Cursor::new(drv))?; 218 | 219 | let cwd = std::env::current_dir()?; 220 | 221 | // We get dumped in the worker directory, which contains a nix directory that needs 222 | // to get moved to / 223 | if Path::new("/nix").is_symlink() { 224 | // is_symlink returns true even if the symlink is broken (which is what we expect if 225 | // it's left over from an old build) 226 | eprintln!("removing /nix"); 227 | std::fs::remove_file("/nix")?; // it should be a symlink 228 | } else if Path::new("/nix").exists() { 229 | eprintln!("removing /nix recursively"); 230 | std::fs::remove_dir_all("/nix")?; 231 | } 232 | 233 | // FIXME: this is failing with "no such file or directory" 234 | //fs_extra::dir::copy(dbg!(cwd.join("nix")), "/nix", &CopyOptions::new())?; 235 | // TODO: this is a hack, but fs_extra is being annoying 236 | dbg!(Command::new("cp").args(["-r", "./nix", "/"]).status()?); 237 | 238 | eprintln!("running cmd"); 239 | let status = Command::new(dbg!(drv.builder)) 240 | .env_clear() 241 | .args(dbg!(drv.args.paths)) 242 | .env("PATH", "/path-not-set") 243 | .env("HOME", "/homeless-shelter") 244 | .env("NIX_STORE", "/nix/store") 245 | .env("NIX_BUILD_CORES", "1") 246 | .env("NIX_BUILD_TOP", &cwd) 247 | .env("TMPDIR", &cwd) 248 | .env("TEMPDIR", &cwd) 249 | .env("TMP", &cwd) 250 | .env("TEMP", &cwd) 251 | .env("PWD", &cwd) 252 | .env("NIX_LOG_FD", "2") 253 | .env("TERM", "xterm-256color") 254 | .envs(dbg!(drv.env)) 255 | .status()?; 256 | 257 | // Nix says: 258 | /* The paths that can be referenced are the input closures, the 259 | output paths, and any paths that have been built via recursive 260 | Nix calls. */ 261 | // We don't know about recursive Nix calls, so we just do the other two. 262 | // FIXME: We're not sure yet if the input_sources includes the closure... 263 | let possible_references = drv.input_sources.paths.iter().cloned().chain( 264 | drv.outputs 265 | .iter() 266 | .map(|(_name, out)| out.store_path.clone()), 267 | ); 268 | let mut metadata = BuildMetadata { 269 | metadata: HashMap::new(), 270 | }; 271 | for (_key, out) in &drv.outputs { 272 | // cp /nix/store/... nix/store 273 | let path: &OsStr = std::os::unix::ffi::OsStrExt::from_bytes(out.store_path.as_ref()); 274 | dbg!(Command::new("cp") 275 | .arg("-r") 276 | .arg(path) 277 | .arg("nix/store/") 278 | .status()?); 279 | 280 | metadata.metadata.insert( 281 | out.store_path.0.clone(), 282 | path_to_metadata(possible_references.clone(), path), 283 | ); 284 | } 285 | let out = File::create(METADATA_PATH).unwrap(); 286 | bincode::serialize_into(out, &metadata).unwrap(); 287 | 288 | if let Some(code) = status.code() { 289 | exit(code); 290 | } else { 291 | panic!("no status code"); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /crates/proxy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nix-rev2" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | 7 | [dependencies] 8 | anyhow = { version = "1.0.79", features = ["backtrace"] } 9 | bincode = { version = "1.3.3", default-features = false } 10 | futures = "0.3.30" 11 | nix-remote.workspace = true 12 | prost = "0.12.3" 13 | prost-types = "0.12.3" 14 | ring = "0.17.7" 15 | serde = { version = "1.0.194", features = ["derive"] } 16 | serde_json = "1.0.114" 17 | serde_bytes = "0.11" 18 | tokio = { version = "1.35.0", features = ["rt-multi-thread", "macros"] } 19 | tonic = "0.10.2" 20 | uuid = { version = "1.7.0", features = ["v4"] } 21 | -------------------------------------------------------------------------------- /crates/proxy/src/generated/build.bazel.semver.rs: -------------------------------------------------------------------------------- 1 | /// The full version of a given tool. 2 | #[allow(clippy::derive_partial_eq_without_eq)] 3 | #[derive(Clone, PartialEq, ::prost::Message)] 4 | pub struct SemVer { 5 | /// The major version, e.g 10 for 10.2.3. 6 | #[prost(int32, tag = "1")] 7 | pub major: i32, 8 | /// The minor version, e.g. 2 for 10.2.3. 9 | #[prost(int32, tag = "2")] 10 | pub minor: i32, 11 | /// The patch version, e.g 3 for 10.2.3. 12 | #[prost(int32, tag = "3")] 13 | pub patch: i32, 14 | /// The pre-release version. Either this field or major/minor/patch fields 15 | /// must be filled. They are mutually exclusive. Pre-release versions are 16 | /// assumed to be earlier than any released versions. 17 | #[prost(string, tag = "4")] 18 | pub prerelease: ::prost::alloc::string::String, 19 | } 20 | -------------------------------------------------------------------------------- /crates/proxy/src/generated/google.api.rs: -------------------------------------------------------------------------------- 1 | /// Defines the HTTP configuration for an API service. It contains a list of 2 | /// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method 3 | /// to one or more HTTP REST API methods. 4 | #[allow(clippy::derive_partial_eq_without_eq)] 5 | #[derive(Clone, PartialEq, ::prost::Message)] 6 | pub struct Http { 7 | /// A list of HTTP configuration rules that apply to individual API methods. 8 | /// 9 | /// **NOTE:** All service configuration rules follow "last one wins" order. 10 | #[prost(message, repeated, tag = "1")] 11 | pub rules: ::prost::alloc::vec::Vec, 12 | /// When set to true, URL path parameters will be fully URI-decoded except in 13 | /// cases of single segment matches in reserved expansion, where "%2F" will be 14 | /// left encoded. 15 | /// 16 | /// The default behavior is to not decode RFC 6570 reserved characters in multi 17 | /// segment matches. 18 | #[prost(bool, tag = "2")] 19 | pub fully_decode_reserved_expansion: bool, 20 | } 21 | /// # gRPC Transcoding 22 | /// 23 | /// gRPC Transcoding is a feature for mapping between a gRPC method and one or 24 | /// more HTTP REST endpoints. It allows developers to build a single API service 25 | /// that supports both gRPC APIs and REST APIs. Many systems, including [Google 26 | /// APIs](), 27 | /// [Cloud Endpoints](), [gRPC 28 | /// Gateway](), 29 | /// and [Envoy]() proxy support this feature 30 | /// and use it for large scale production services. 31 | /// 32 | /// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies 33 | /// how different portions of the gRPC request message are mapped to the URL 34 | /// path, URL query parameters, and HTTP request body. It also controls how the 35 | /// gRPC response message is mapped to the HTTP response body. `HttpRule` is 36 | /// typically specified as an `google.api.http` annotation on the gRPC method. 37 | /// 38 | /// Each mapping specifies a URL path template and an HTTP method. The path 39 | /// template may refer to one or more fields in the gRPC request message, as long 40 | /// as each field is a non-repeated field with a primitive (non-message) type. 41 | /// The path template controls how fields of the request message are mapped to 42 | /// the URL path. 43 | /// 44 | /// Example: 45 | /// 46 | /// service Messaging { 47 | /// rpc GetMessage(GetMessageRequest) returns (Message) { 48 | /// option (google.api.http) = { 49 | /// get: "/v1/{name=messages/*}" 50 | /// }; 51 | /// } 52 | /// } 53 | /// message GetMessageRequest { 54 | /// string name = 1; // Mapped to URL path. 55 | /// } 56 | /// message Message { 57 | /// string text = 1; // The resource content. 58 | /// } 59 | /// 60 | /// This enables an HTTP REST to gRPC mapping as below: 61 | /// 62 | /// HTTP | gRPC 63 | /// -----|----- 64 | /// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` 65 | /// 66 | /// Any fields in the request message which are not bound by the path template 67 | /// automatically become HTTP query parameters if there is no HTTP request body. 68 | /// For example: 69 | /// 70 | /// service Messaging { 71 | /// rpc GetMessage(GetMessageRequest) returns (Message) { 72 | /// option (google.api.http) = { 73 | /// get:"/v1/messages/{message_id}" 74 | /// }; 75 | /// } 76 | /// } 77 | /// message GetMessageRequest { 78 | /// message SubMessage { 79 | /// string subfield = 1; 80 | /// } 81 | /// string message_id = 1; // Mapped to URL path. 82 | /// int64 revision = 2; // Mapped to URL query parameter `revision`. 83 | /// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. 84 | /// } 85 | /// 86 | /// This enables a HTTP JSON to RPC mapping as below: 87 | /// 88 | /// HTTP | gRPC 89 | /// -----|----- 90 | /// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | 91 | /// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: 92 | /// "foo"))` 93 | /// 94 | /// Note that fields which are mapped to URL query parameters must have a 95 | /// primitive type or a repeated primitive type or a non-repeated message type. 96 | /// In the case of a repeated type, the parameter can be repeated in the URL 97 | /// as `...?param=A¶m=B`. In the case of a message type, each field of the 98 | /// message is mapped to a separate parameter, such as 99 | /// `...?foo.a=A&foo.b=B&foo.c=C`. 100 | /// 101 | /// For HTTP methods that allow a request body, the `body` field 102 | /// specifies the mapping. Consider a REST update method on the 103 | /// message resource collection: 104 | /// 105 | /// service Messaging { 106 | /// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { 107 | /// option (google.api.http) = { 108 | /// patch: "/v1/messages/{message_id}" 109 | /// body: "message" 110 | /// }; 111 | /// } 112 | /// } 113 | /// message UpdateMessageRequest { 114 | /// string message_id = 1; // mapped to the URL 115 | /// Message message = 2; // mapped to the body 116 | /// } 117 | /// 118 | /// The following HTTP JSON to RPC mapping is enabled, where the 119 | /// representation of the JSON in the request body is determined by 120 | /// protos JSON encoding: 121 | /// 122 | /// HTTP | gRPC 123 | /// -----|----- 124 | /// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: 125 | /// "123456" message { text: "Hi!" })` 126 | /// 127 | /// The special name `*` can be used in the body mapping to define that 128 | /// every field not bound by the path template should be mapped to the 129 | /// request body. This enables the following alternative definition of 130 | /// the update method: 131 | /// 132 | /// service Messaging { 133 | /// rpc UpdateMessage(Message) returns (Message) { 134 | /// option (google.api.http) = { 135 | /// patch: "/v1/messages/{message_id}" 136 | /// body: "*" 137 | /// }; 138 | /// } 139 | /// } 140 | /// message Message { 141 | /// string message_id = 1; 142 | /// string text = 2; 143 | /// } 144 | /// 145 | /// 146 | /// The following HTTP JSON to RPC mapping is enabled: 147 | /// 148 | /// HTTP | gRPC 149 | /// -----|----- 150 | /// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: 151 | /// "123456" text: "Hi!")` 152 | /// 153 | /// Note that when using `*` in the body mapping, it is not possible to 154 | /// have HTTP parameters, as all fields not bound by the path end in 155 | /// the body. This makes this option more rarely used in practice when 156 | /// defining REST APIs. The common usage of `*` is in custom methods 157 | /// which don't use the URL at all for transferring data. 158 | /// 159 | /// It is possible to define multiple HTTP methods for one RPC by using 160 | /// the `additional_bindings` option. Example: 161 | /// 162 | /// service Messaging { 163 | /// rpc GetMessage(GetMessageRequest) returns (Message) { 164 | /// option (google.api.http) = { 165 | /// get: "/v1/messages/{message_id}" 166 | /// additional_bindings { 167 | /// get: "/v1/users/{user_id}/messages/{message_id}" 168 | /// } 169 | /// }; 170 | /// } 171 | /// } 172 | /// message GetMessageRequest { 173 | /// string message_id = 1; 174 | /// string user_id = 2; 175 | /// } 176 | /// 177 | /// This enables the following two alternative HTTP JSON to RPC mappings: 178 | /// 179 | /// HTTP | gRPC 180 | /// -----|----- 181 | /// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` 182 | /// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: 183 | /// "123456")` 184 | /// 185 | /// ## Rules for HTTP mapping 186 | /// 187 | /// 1. Leaf request fields (recursive expansion nested messages in the request 188 | /// message) are classified into three categories: 189 | /// - Fields referred by the path template. They are passed via the URL path. 190 | /// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They 191 | /// are passed via the HTTP 192 | /// request body. 193 | /// - All other fields are passed via the URL query parameters, and the 194 | /// parameter name is the field path in the request message. A repeated 195 | /// field can be represented as multiple query parameters under the same 196 | /// name. 197 | /// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL 198 | /// query parameter, all fields 199 | /// are passed via URL path and HTTP request body. 200 | /// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP 201 | /// request body, all 202 | /// fields are passed via URL path and URL query parameters. 203 | /// 204 | /// ### Path template syntax 205 | /// 206 | /// Template = "/" Segments \[ Verb \] ; 207 | /// Segments = Segment { "/" Segment } ; 208 | /// Segment = "*" | "**" | LITERAL | Variable ; 209 | /// Variable = "{" FieldPath \[ "=" Segments \] "}" ; 210 | /// FieldPath = IDENT { "." IDENT } ; 211 | /// Verb = ":" LITERAL ; 212 | /// 213 | /// The syntax `*` matches a single URL path segment. The syntax `**` matches 214 | /// zero or more URL path segments, which must be the last part of the URL path 215 | /// except the `Verb`. 216 | /// 217 | /// The syntax `Variable` matches part of the URL path as specified by its 218 | /// template. A variable template must not contain other variables. If a variable 219 | /// matches a single path segment, its template may be omitted, e.g. `{var}` 220 | /// is equivalent to `{var=*}`. 221 | /// 222 | /// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` 223 | /// contains any reserved character, such characters should be percent-encoded 224 | /// before the matching. 225 | /// 226 | /// If a variable contains exactly one path segment, such as `"{var}"` or 227 | /// `"{var=*}"`, when such a variable is expanded into a URL path on the client 228 | /// side, all characters except `\[-_.~0-9a-zA-Z\]` are percent-encoded. The 229 | /// server side does the reverse decoding. Such variables show up in the 230 | /// [Discovery 231 | /// Document]() as 232 | /// `{var}`. 233 | /// 234 | /// If a variable contains multiple path segments, such as `"{var=foo/*}"` 235 | /// or `"{var=**}"`, when such a variable is expanded into a URL path on the 236 | /// client side, all characters except `\[-_.~/0-9a-zA-Z\]` are percent-encoded. 237 | /// The server side does the reverse decoding, except "%2F" and "%2f" are left 238 | /// unchanged. Such variables show up in the 239 | /// [Discovery 240 | /// Document]() as 241 | /// `{+var}`. 242 | /// 243 | /// ## Using gRPC API Service Configuration 244 | /// 245 | /// gRPC API Service Configuration (service config) is a configuration language 246 | /// for configuring a gRPC service to become a user-facing product. The 247 | /// service config is simply the YAML representation of the `google.api.Service` 248 | /// proto message. 249 | /// 250 | /// As an alternative to annotating your proto file, you can configure gRPC 251 | /// transcoding in your service config YAML files. You do this by specifying a 252 | /// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same 253 | /// effect as the proto annotation. This can be particularly useful if you 254 | /// have a proto that is reused in multiple services. Note that any transcoding 255 | /// specified in the service config will override any matching transcoding 256 | /// configuration in the proto. 257 | /// 258 | /// Example: 259 | /// 260 | /// http: 261 | /// rules: 262 | /// # Selects a gRPC method and applies HttpRule to it. 263 | /// - selector: example.v1.Messaging.GetMessage 264 | /// get: /v1/messages/{message_id}/{sub.subfield} 265 | /// 266 | /// ## Special notes 267 | /// 268 | /// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the 269 | /// proto to JSON conversion must follow the [proto3 270 | /// specification](). 271 | /// 272 | /// While the single segment variable follows the semantics of 273 | /// [RFC 6570]() Section 3.2.2 Simple String 274 | /// Expansion, the multi segment variable **does not** follow RFC 6570 Section 275 | /// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion 276 | /// does not expand special characters like `?` and `#`, which would lead 277 | /// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding 278 | /// for multi segment variables. 279 | /// 280 | /// The path variables **must not** refer to any repeated or mapped field, 281 | /// because client libraries are not capable of handling such variable expansion. 282 | /// 283 | /// The path variables **must not** capture the leading "/" character. The reason 284 | /// is that the most common use case "{var}" does not capture the leading "/" 285 | /// character. For consistency, all path variables must share the same behavior. 286 | /// 287 | /// Repeated message fields must not be mapped to URL query parameters, because 288 | /// no client library can support such complicated mapping. 289 | /// 290 | /// If an API needs to use a JSON array for request or response body, it can map 291 | /// the request or response body to a repeated field. However, some gRPC 292 | /// Transcoding implementations may not support this feature. 293 | #[allow(clippy::derive_partial_eq_without_eq)] 294 | #[derive(Clone, PartialEq, ::prost::Message)] 295 | pub struct HttpRule { 296 | /// Selects a method to which this rule applies. 297 | /// 298 | /// Refer to [selector][google.api.DocumentationRule.selector] for syntax 299 | /// details. 300 | #[prost(string, tag = "1")] 301 | pub selector: ::prost::alloc::string::String, 302 | /// The name of the request field whose value is mapped to the HTTP request 303 | /// body, or `*` for mapping all request fields not captured by the path 304 | /// pattern to the HTTP body, or omitted for not having any HTTP request body. 305 | /// 306 | /// NOTE: the referred field must be present at the top-level of the request 307 | /// message type. 308 | #[prost(string, tag = "7")] 309 | pub body: ::prost::alloc::string::String, 310 | /// Optional. The name of the response field whose value is mapped to the HTTP 311 | /// response body. When omitted, the entire response message will be used 312 | /// as the HTTP response body. 313 | /// 314 | /// NOTE: The referred field must be present at the top-level of the response 315 | /// message type. 316 | #[prost(string, tag = "12")] 317 | pub response_body: ::prost::alloc::string::String, 318 | /// Additional HTTP bindings for the selector. Nested bindings must 319 | /// not contain an `additional_bindings` field themselves (that is, 320 | /// the nesting may only be one level deep). 321 | #[prost(message, repeated, tag = "11")] 322 | pub additional_bindings: ::prost::alloc::vec::Vec, 323 | /// Determines the URL pattern is matched by this rules. This pattern can be 324 | /// used with any of the {get|put|post|delete|patch} methods. A custom method 325 | /// can be defined using the 'custom' field. 326 | #[prost(oneof = "http_rule::Pattern", tags = "2, 3, 4, 5, 6, 8")] 327 | pub pattern: ::core::option::Option, 328 | } 329 | /// Nested message and enum types in `HttpRule`. 330 | pub mod http_rule { 331 | /// Determines the URL pattern is matched by this rules. This pattern can be 332 | /// used with any of the {get|put|post|delete|patch} methods. A custom method 333 | /// can be defined using the 'custom' field. 334 | #[allow(clippy::derive_partial_eq_without_eq)] 335 | #[derive(Clone, PartialEq, ::prost::Oneof)] 336 | pub enum Pattern { 337 | /// Maps to HTTP GET. Used for listing and getting information about 338 | /// resources. 339 | #[prost(string, tag = "2")] 340 | Get(::prost::alloc::string::String), 341 | /// Maps to HTTP PUT. Used for replacing a resource. 342 | #[prost(string, tag = "3")] 343 | Put(::prost::alloc::string::String), 344 | /// Maps to HTTP POST. Used for creating a resource or performing an action. 345 | #[prost(string, tag = "4")] 346 | Post(::prost::alloc::string::String), 347 | /// Maps to HTTP DELETE. Used for deleting a resource. 348 | #[prost(string, tag = "5")] 349 | Delete(::prost::alloc::string::String), 350 | /// Maps to HTTP PATCH. Used for updating a resource. 351 | #[prost(string, tag = "6")] 352 | Patch(::prost::alloc::string::String), 353 | /// The custom pattern is used for specifying an HTTP method that is not 354 | /// included in the `pattern` field, such as HEAD, or "*" to leave the 355 | /// HTTP method unspecified for this rule. The wild-card rule is useful 356 | /// for services that provide content to Web (HTML) clients. 357 | #[prost(message, tag = "8")] 358 | Custom(super::CustomHttpPattern), 359 | } 360 | } 361 | /// A custom pattern is used for defining custom HTTP verb. 362 | #[allow(clippy::derive_partial_eq_without_eq)] 363 | #[derive(Clone, PartialEq, ::prost::Message)] 364 | pub struct CustomHttpPattern { 365 | /// The name of this custom HTTP verb. 366 | #[prost(string, tag = "1")] 367 | pub kind: ::prost::alloc::string::String, 368 | /// The path matched by this custom verb. 369 | #[prost(string, tag = "2")] 370 | pub path: ::prost::alloc::string::String, 371 | } 372 | /// The launch stage as defined by [Google Cloud Platform 373 | /// Launch Stages](). 374 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] 375 | #[repr(i32)] 376 | pub enum LaunchStage { 377 | /// Do not use this default value. 378 | Unspecified = 0, 379 | /// The feature is not yet implemented. Users can not use it. 380 | Unimplemented = 6, 381 | /// Prelaunch features are hidden from users and are only visible internally. 382 | Prelaunch = 7, 383 | /// Early Access features are limited to a closed group of testers. To use 384 | /// these features, you must sign up in advance and sign a Trusted Tester 385 | /// agreement (which includes confidentiality provisions). These features may 386 | /// be unstable, changed in backward-incompatible ways, and are not 387 | /// guaranteed to be released. 388 | EarlyAccess = 1, 389 | /// Alpha is a limited availability test for releases before they are cleared 390 | /// for widespread use. By Alpha, all significant design issues are resolved 391 | /// and we are in the process of verifying functionality. Alpha customers 392 | /// need to apply for access, agree to applicable terms, and have their 393 | /// projects allowlisted. Alpha releases don't have to be feature complete, 394 | /// no SLAs are provided, and there are no technical support obligations, but 395 | /// they will be far enough along that customers can actually use them in 396 | /// test environments or for limited-use tests -- just like they would in 397 | /// normal production cases. 398 | Alpha = 2, 399 | /// Beta is the point at which we are ready to open a release for any 400 | /// customer to use. There are no SLA or technical support obligations in a 401 | /// Beta release. Products will be complete from a feature perspective, but 402 | /// may have some open outstanding issues. Beta releases are suitable for 403 | /// limited production use cases. 404 | Beta = 3, 405 | /// GA features are open to all developers and are considered stable and 406 | /// fully qualified for production use. 407 | Ga = 4, 408 | /// Deprecated features are scheduled to be shut down and removed. For more 409 | /// information, see the "Deprecation Policy" section of our [Terms of 410 | /// Service]() 411 | /// and the [Google Cloud Platform Subject to the Deprecation 412 | /// Policy]() documentation. 413 | Deprecated = 5, 414 | } 415 | impl LaunchStage { 416 | /// String value of the enum field names used in the ProtoBuf definition. 417 | /// 418 | /// The values are not transformed in any way and thus are considered stable 419 | /// (if the ProtoBuf definition does not change) and safe for programmatic use. 420 | pub fn as_str_name(&self) -> &'static str { 421 | match self { 422 | LaunchStage::Unspecified => "LAUNCH_STAGE_UNSPECIFIED", 423 | LaunchStage::Unimplemented => "UNIMPLEMENTED", 424 | LaunchStage::Prelaunch => "PRELAUNCH", 425 | LaunchStage::EarlyAccess => "EARLY_ACCESS", 426 | LaunchStage::Alpha => "ALPHA", 427 | LaunchStage::Beta => "BETA", 428 | LaunchStage::Ga => "GA", 429 | LaunchStage::Deprecated => "DEPRECATED", 430 | } 431 | } 432 | /// Creates an enum from field names used in the ProtoBuf definition. 433 | pub fn from_str_name(value: &str) -> ::core::option::Option { 434 | match value { 435 | "LAUNCH_STAGE_UNSPECIFIED" => Some(Self::Unspecified), 436 | "UNIMPLEMENTED" => Some(Self::Unimplemented), 437 | "PRELAUNCH" => Some(Self::Prelaunch), 438 | "EARLY_ACCESS" => Some(Self::EarlyAccess), 439 | "ALPHA" => Some(Self::Alpha), 440 | "BETA" => Some(Self::Beta), 441 | "GA" => Some(Self::Ga), 442 | "DEPRECATED" => Some(Self::Deprecated), 443 | _ => None, 444 | } 445 | } 446 | } 447 | /// Required information for every language. 448 | #[allow(clippy::derive_partial_eq_without_eq)] 449 | #[derive(Clone, PartialEq, ::prost::Message)] 450 | pub struct CommonLanguageSettings { 451 | /// Link to automatically generated reference documentation. Example: 452 | /// 453 | #[deprecated] 454 | #[prost(string, tag = "1")] 455 | pub reference_docs_uri: ::prost::alloc::string::String, 456 | /// The destination where API teams want this client library to be published. 457 | #[prost(enumeration = "ClientLibraryDestination", repeated, tag = "2")] 458 | pub destinations: ::prost::alloc::vec::Vec, 459 | } 460 | /// Details about how and where to publish client libraries. 461 | #[allow(clippy::derive_partial_eq_without_eq)] 462 | #[derive(Clone, PartialEq, ::prost::Message)] 463 | pub struct ClientLibrarySettings { 464 | /// Version of the API to apply these settings to. This is the full protobuf 465 | /// package for the API, ending in the version element. 466 | /// Examples: "google.cloud.speech.v1" and "google.spanner.admin.database.v1". 467 | #[prost(string, tag = "1")] 468 | pub version: ::prost::alloc::string::String, 469 | /// Launch stage of this version of the API. 470 | #[prost(enumeration = "LaunchStage", tag = "2")] 471 | pub launch_stage: i32, 472 | /// When using transport=rest, the client request will encode enums as 473 | /// numbers rather than strings. 474 | #[prost(bool, tag = "3")] 475 | pub rest_numeric_enums: bool, 476 | /// Settings for legacy Java features, supported in the Service YAML. 477 | #[prost(message, optional, tag = "21")] 478 | pub java_settings: ::core::option::Option, 479 | /// Settings for C++ client libraries. 480 | #[prost(message, optional, tag = "22")] 481 | pub cpp_settings: ::core::option::Option, 482 | /// Settings for PHP client libraries. 483 | #[prost(message, optional, tag = "23")] 484 | pub php_settings: ::core::option::Option, 485 | /// Settings for Python client libraries. 486 | #[prost(message, optional, tag = "24")] 487 | pub python_settings: ::core::option::Option, 488 | /// Settings for Node client libraries. 489 | #[prost(message, optional, tag = "25")] 490 | pub node_settings: ::core::option::Option, 491 | /// Settings for .NET client libraries. 492 | #[prost(message, optional, tag = "26")] 493 | pub dotnet_settings: ::core::option::Option, 494 | /// Settings for Ruby client libraries. 495 | #[prost(message, optional, tag = "27")] 496 | pub ruby_settings: ::core::option::Option, 497 | /// Settings for Go client libraries. 498 | #[prost(message, optional, tag = "28")] 499 | pub go_settings: ::core::option::Option, 500 | } 501 | /// This message configures the settings for publishing [Google Cloud Client 502 | /// libraries]() 503 | /// generated from the service config. 504 | #[allow(clippy::derive_partial_eq_without_eq)] 505 | #[derive(Clone, PartialEq, ::prost::Message)] 506 | pub struct Publishing { 507 | /// A list of API method settings, e.g. the behavior for methods that use the 508 | /// long-running operation pattern. 509 | #[prost(message, repeated, tag = "2")] 510 | pub method_settings: ::prost::alloc::vec::Vec, 511 | /// Link to a *public* URI where users can report issues. Example: 512 | /// 513 | #[prost(string, tag = "101")] 514 | pub new_issue_uri: ::prost::alloc::string::String, 515 | /// Link to product home page. Example: 516 | /// 517 | #[prost(string, tag = "102")] 518 | pub documentation_uri: ::prost::alloc::string::String, 519 | /// Used as a tracking tag when collecting data about the APIs developer 520 | /// relations artifacts like docs, packages delivered to package managers, 521 | /// etc. Example: "speech". 522 | #[prost(string, tag = "103")] 523 | pub api_short_name: ::prost::alloc::string::String, 524 | /// GitHub label to apply to issues and pull requests opened for this API. 525 | #[prost(string, tag = "104")] 526 | pub github_label: ::prost::alloc::string::String, 527 | /// GitHub teams to be added to CODEOWNERS in the directory in GitHub 528 | /// containing source code for the client libraries for this API. 529 | #[prost(string, repeated, tag = "105")] 530 | pub codeowner_github_teams: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, 531 | /// A prefix used in sample code when demarking regions to be included in 532 | /// documentation. 533 | #[prost(string, tag = "106")] 534 | pub doc_tag_prefix: ::prost::alloc::string::String, 535 | /// For whom the client library is being published. 536 | #[prost(enumeration = "ClientLibraryOrganization", tag = "107")] 537 | pub organization: i32, 538 | /// Client library settings. If the same version string appears multiple 539 | /// times in this list, then the last one wins. Settings from earlier 540 | /// settings with the same version string are discarded. 541 | #[prost(message, repeated, tag = "109")] 542 | pub library_settings: ::prost::alloc::vec::Vec, 543 | /// Optional link to proto reference documentation. Example: 544 | /// 545 | #[prost(string, tag = "110")] 546 | pub proto_reference_documentation_uri: ::prost::alloc::string::String, 547 | } 548 | /// Settings for Java client libraries. 549 | #[allow(clippy::derive_partial_eq_without_eq)] 550 | #[derive(Clone, PartialEq, ::prost::Message)] 551 | pub struct JavaSettings { 552 | /// The package name to use in Java. Clobbers the java_package option 553 | /// set in the protobuf. This should be used **only** by APIs 554 | /// who have already set the language_settings.java.package_name" field 555 | /// in gapic.yaml. API teams should use the protobuf java_package option 556 | /// where possible. 557 | /// 558 | /// Example of a YAML configuration:: 559 | /// 560 | /// publishing: 561 | /// java_settings: 562 | /// library_package: com.google.cloud.pubsub.v1 563 | #[prost(string, tag = "1")] 564 | pub library_package: ::prost::alloc::string::String, 565 | /// Configure the Java class name to use instead of the service's for its 566 | /// corresponding generated GAPIC client. Keys are fully-qualified 567 | /// service names as they appear in the protobuf (including the full 568 | /// the language_settings.java.interface_names" field in gapic.yaml. API 569 | /// teams should otherwise use the service name as it appears in the 570 | /// protobuf. 571 | /// 572 | /// Example of a YAML configuration:: 573 | /// 574 | /// publishing: 575 | /// java_settings: 576 | /// service_class_names: 577 | /// - google.pubsub.v1.Publisher: TopicAdmin 578 | /// - google.pubsub.v1.Subscriber: SubscriptionAdmin 579 | #[prost(map = "string, string", tag = "2")] 580 | pub service_class_names: ::std::collections::HashMap< 581 | ::prost::alloc::string::String, 582 | ::prost::alloc::string::String, 583 | >, 584 | /// Some settings. 585 | #[prost(message, optional, tag = "3")] 586 | pub common: ::core::option::Option, 587 | } 588 | /// Settings for C++ client libraries. 589 | #[allow(clippy::derive_partial_eq_without_eq)] 590 | #[derive(Clone, PartialEq, ::prost::Message)] 591 | pub struct CppSettings { 592 | /// Some settings. 593 | #[prost(message, optional, tag = "1")] 594 | pub common: ::core::option::Option, 595 | } 596 | /// Settings for Php client libraries. 597 | #[allow(clippy::derive_partial_eq_without_eq)] 598 | #[derive(Clone, PartialEq, ::prost::Message)] 599 | pub struct PhpSettings { 600 | /// Some settings. 601 | #[prost(message, optional, tag = "1")] 602 | pub common: ::core::option::Option, 603 | } 604 | /// Settings for Python client libraries. 605 | #[allow(clippy::derive_partial_eq_without_eq)] 606 | #[derive(Clone, PartialEq, ::prost::Message)] 607 | pub struct PythonSettings { 608 | /// Some settings. 609 | #[prost(message, optional, tag = "1")] 610 | pub common: ::core::option::Option, 611 | } 612 | /// Settings for Node client libraries. 613 | #[allow(clippy::derive_partial_eq_without_eq)] 614 | #[derive(Clone, PartialEq, ::prost::Message)] 615 | pub struct NodeSettings { 616 | /// Some settings. 617 | #[prost(message, optional, tag = "1")] 618 | pub common: ::core::option::Option, 619 | } 620 | /// Settings for Dotnet client libraries. 621 | #[allow(clippy::derive_partial_eq_without_eq)] 622 | #[derive(Clone, PartialEq, ::prost::Message)] 623 | pub struct DotnetSettings { 624 | /// Some settings. 625 | #[prost(message, optional, tag = "1")] 626 | pub common: ::core::option::Option, 627 | /// Map from original service names to renamed versions. 628 | /// This is used when the default generated types 629 | /// would cause a naming conflict. (Neither name is 630 | /// fully-qualified.) 631 | /// Example: Subscriber to SubscriberServiceApi. 632 | #[prost(map = "string, string", tag = "2")] 633 | pub renamed_services: ::std::collections::HashMap< 634 | ::prost::alloc::string::String, 635 | ::prost::alloc::string::String, 636 | >, 637 | /// Map from full resource types to the effective short name 638 | /// for the resource. This is used when otherwise resource 639 | /// named from different services would cause naming collisions. 640 | /// Example entry: 641 | /// "datalabeling.googleapis.com/Dataset": "DataLabelingDataset" 642 | #[prost(map = "string, string", tag = "3")] 643 | pub renamed_resources: ::std::collections::HashMap< 644 | ::prost::alloc::string::String, 645 | ::prost::alloc::string::String, 646 | >, 647 | /// List of full resource types to ignore during generation. 648 | /// This is typically used for API-specific Location resources, 649 | /// which should be handled by the generator as if they were actually 650 | /// the common Location resources. 651 | /// Example entry: "documentai.googleapis.com/Location" 652 | #[prost(string, repeated, tag = "4")] 653 | pub ignored_resources: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, 654 | /// Namespaces which must be aliased in snippets due to 655 | /// a known (but non-generator-predictable) naming collision 656 | #[prost(string, repeated, tag = "5")] 657 | pub forced_namespace_aliases: ::prost::alloc::vec::Vec< 658 | ::prost::alloc::string::String, 659 | >, 660 | /// Method signatures (in the form "service.method(signature)") 661 | /// which are provided separately, so shouldn't be generated. 662 | /// Snippets *calling* these methods are still generated, however. 663 | #[prost(string, repeated, tag = "6")] 664 | pub handwritten_signatures: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, 665 | } 666 | /// Settings for Ruby client libraries. 667 | #[allow(clippy::derive_partial_eq_without_eq)] 668 | #[derive(Clone, PartialEq, ::prost::Message)] 669 | pub struct RubySettings { 670 | /// Some settings. 671 | #[prost(message, optional, tag = "1")] 672 | pub common: ::core::option::Option, 673 | } 674 | /// Settings for Go client libraries. 675 | #[allow(clippy::derive_partial_eq_without_eq)] 676 | #[derive(Clone, PartialEq, ::prost::Message)] 677 | pub struct GoSettings { 678 | /// Some settings. 679 | #[prost(message, optional, tag = "1")] 680 | pub common: ::core::option::Option, 681 | } 682 | /// Describes the generator configuration for a method. 683 | #[allow(clippy::derive_partial_eq_without_eq)] 684 | #[derive(Clone, PartialEq, ::prost::Message)] 685 | pub struct MethodSettings { 686 | /// The fully qualified name of the method, for which the options below apply. 687 | /// This is used to find the method to apply the options. 688 | #[prost(string, tag = "1")] 689 | pub selector: ::prost::alloc::string::String, 690 | /// Describes settings to use for long-running operations when generating 691 | /// API methods for RPCs. Complements RPCs that use the annotations in 692 | /// google/longrunning/operations.proto. 693 | /// 694 | /// Example of a YAML configuration:: 695 | /// 696 | /// publishing: 697 | /// method_settings: 698 | /// - selector: google.cloud.speech.v2.Speech.BatchRecognize 699 | /// long_running: 700 | /// initial_poll_delay: 701 | /// seconds: 60 # 1 minute 702 | /// poll_delay_multiplier: 1.5 703 | /// max_poll_delay: 704 | /// seconds: 360 # 6 minutes 705 | /// total_poll_timeout: 706 | /// seconds: 54000 # 90 minutes 707 | #[prost(message, optional, tag = "2")] 708 | pub long_running: ::core::option::Option, 709 | /// List of top-level fields of the request message, that should be 710 | /// automatically populated by the client libraries based on their 711 | /// (google.api.field_info).format. Currently supported format: UUID4. 712 | /// 713 | /// Example of a YAML configuration: 714 | /// 715 | /// publishing: 716 | /// method_settings: 717 | /// - selector: google.example.v1.ExampleService.CreateExample 718 | /// auto_populated_fields: 719 | /// - request_id 720 | #[prost(string, repeated, tag = "3")] 721 | pub auto_populated_fields: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, 722 | } 723 | /// Nested message and enum types in `MethodSettings`. 724 | pub mod method_settings { 725 | /// Describes settings to use when generating API methods that use the 726 | /// long-running operation pattern. 727 | /// All default values below are from those used in the client library 728 | /// generators (e.g. 729 | /// [Java]()). 730 | #[allow(clippy::derive_partial_eq_without_eq)] 731 | #[derive(Clone, PartialEq, ::prost::Message)] 732 | pub struct LongRunning { 733 | /// Initial delay after which the first poll request will be made. 734 | /// Default value: 5 seconds. 735 | #[prost(message, optional, tag = "1")] 736 | pub initial_poll_delay: ::core::option::Option<::prost_types::Duration>, 737 | /// Multiplier to gradually increase delay between subsequent polls until it 738 | /// reaches max_poll_delay. 739 | /// Default value: 1.5. 740 | #[prost(float, tag = "2")] 741 | pub poll_delay_multiplier: f32, 742 | /// Maximum time between two subsequent poll requests. 743 | /// Default value: 45 seconds. 744 | #[prost(message, optional, tag = "3")] 745 | pub max_poll_delay: ::core::option::Option<::prost_types::Duration>, 746 | /// Total polling timeout. 747 | /// Default value: 5 minutes. 748 | #[prost(message, optional, tag = "4")] 749 | pub total_poll_timeout: ::core::option::Option<::prost_types::Duration>, 750 | } 751 | } 752 | /// The organization for which the client libraries are being published. 753 | /// Affects the url where generated docs are published, etc. 754 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] 755 | #[repr(i32)] 756 | pub enum ClientLibraryOrganization { 757 | /// Not useful. 758 | Unspecified = 0, 759 | /// Google Cloud Platform Org. 760 | Cloud = 1, 761 | /// Ads (Advertising) Org. 762 | Ads = 2, 763 | /// Photos Org. 764 | Photos = 3, 765 | /// Street View Org. 766 | StreetView = 4, 767 | /// Shopping Org. 768 | Shopping = 5, 769 | /// Geo Org. 770 | Geo = 6, 771 | /// Generative AI - 772 | GenerativeAi = 7, 773 | } 774 | impl ClientLibraryOrganization { 775 | /// String value of the enum field names used in the ProtoBuf definition. 776 | /// 777 | /// The values are not transformed in any way and thus are considered stable 778 | /// (if the ProtoBuf definition does not change) and safe for programmatic use. 779 | pub fn as_str_name(&self) -> &'static str { 780 | match self { 781 | ClientLibraryOrganization::Unspecified => { 782 | "CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED" 783 | } 784 | ClientLibraryOrganization::Cloud => "CLOUD", 785 | ClientLibraryOrganization::Ads => "ADS", 786 | ClientLibraryOrganization::Photos => "PHOTOS", 787 | ClientLibraryOrganization::StreetView => "STREET_VIEW", 788 | ClientLibraryOrganization::Shopping => "SHOPPING", 789 | ClientLibraryOrganization::Geo => "GEO", 790 | ClientLibraryOrganization::GenerativeAi => "GENERATIVE_AI", 791 | } 792 | } 793 | /// Creates an enum from field names used in the ProtoBuf definition. 794 | pub fn from_str_name(value: &str) -> ::core::option::Option { 795 | match value { 796 | "CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED" => Some(Self::Unspecified), 797 | "CLOUD" => Some(Self::Cloud), 798 | "ADS" => Some(Self::Ads), 799 | "PHOTOS" => Some(Self::Photos), 800 | "STREET_VIEW" => Some(Self::StreetView), 801 | "SHOPPING" => Some(Self::Shopping), 802 | "GEO" => Some(Self::Geo), 803 | "GENERATIVE_AI" => Some(Self::GenerativeAi), 804 | _ => None, 805 | } 806 | } 807 | } 808 | /// To where should client libraries be published? 809 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] 810 | #[repr(i32)] 811 | pub enum ClientLibraryDestination { 812 | /// Client libraries will neither be generated nor published to package 813 | /// managers. 814 | Unspecified = 0, 815 | /// Generate the client library in a repo under github.com/googleapis, 816 | /// but don't publish it to package managers. 817 | Github = 10, 818 | /// Publish the library to package managers like nuget.org and npmjs.com. 819 | PackageManager = 20, 820 | } 821 | impl ClientLibraryDestination { 822 | /// String value of the enum field names used in the ProtoBuf definition. 823 | /// 824 | /// The values are not transformed in any way and thus are considered stable 825 | /// (if the ProtoBuf definition does not change) and safe for programmatic use. 826 | pub fn as_str_name(&self) -> &'static str { 827 | match self { 828 | ClientLibraryDestination::Unspecified => { 829 | "CLIENT_LIBRARY_DESTINATION_UNSPECIFIED" 830 | } 831 | ClientLibraryDestination::Github => "GITHUB", 832 | ClientLibraryDestination::PackageManager => "PACKAGE_MANAGER", 833 | } 834 | } 835 | /// Creates an enum from field names used in the ProtoBuf definition. 836 | pub fn from_str_name(value: &str) -> ::core::option::Option { 837 | match value { 838 | "CLIENT_LIBRARY_DESTINATION_UNSPECIFIED" => Some(Self::Unspecified), 839 | "GITHUB" => Some(Self::Github), 840 | "PACKAGE_MANAGER" => Some(Self::PackageManager), 841 | _ => None, 842 | } 843 | } 844 | } 845 | -------------------------------------------------------------------------------- /crates/proxy/src/generated/google.bytestream.rs: -------------------------------------------------------------------------------- 1 | /// Request object for ByteStream.Read. 2 | #[allow(clippy::derive_partial_eq_without_eq)] 3 | #[derive(Clone, PartialEq, ::prost::Message)] 4 | pub struct ReadRequest { 5 | /// The name of the resource to read. 6 | #[prost(string, tag = "1")] 7 | pub resource_name: ::prost::alloc::string::String, 8 | /// The offset for the first byte to return in the read, relative to the start 9 | /// of the resource. 10 | /// 11 | /// A `read_offset` that is negative or greater than the size of the resource 12 | /// will cause an `OUT_OF_RANGE` error. 13 | #[prost(int64, tag = "2")] 14 | pub read_offset: i64, 15 | /// The maximum number of `data` bytes the server is allowed to return in the 16 | /// sum of all `ReadResponse` messages. A `read_limit` of zero indicates that 17 | /// there is no limit, and a negative `read_limit` will cause an error. 18 | /// 19 | /// If the stream returns fewer bytes than allowed by the `read_limit` and no 20 | /// error occurred, the stream includes all data from the `read_offset` to the 21 | /// end of the resource. 22 | #[prost(int64, tag = "3")] 23 | pub read_limit: i64, 24 | } 25 | /// Response object for ByteStream.Read. 26 | #[allow(clippy::derive_partial_eq_without_eq)] 27 | #[derive(Clone, PartialEq, ::prost::Message)] 28 | pub struct ReadResponse { 29 | /// A portion of the data for the resource. The service **may** leave `data` 30 | /// empty for any given `ReadResponse`. This enables the service to inform the 31 | /// client that the request is still live while it is running an operation to 32 | /// generate more data. 33 | #[prost(bytes = "vec", tag = "10")] 34 | pub data: ::prost::alloc::vec::Vec, 35 | } 36 | /// Request object for ByteStream.Write. 37 | #[allow(clippy::derive_partial_eq_without_eq)] 38 | #[derive(Clone, PartialEq, ::prost::Message)] 39 | pub struct WriteRequest { 40 | /// The name of the resource to write. This **must** be set on the first 41 | /// `WriteRequest` of each `Write()` action. If it is set on subsequent calls, 42 | /// it **must** match the value of the first request. 43 | #[prost(string, tag = "1")] 44 | pub resource_name: ::prost::alloc::string::String, 45 | /// The offset from the beginning of the resource at which the data should be 46 | /// written. It is required on all `WriteRequest`s. 47 | /// 48 | /// In the first `WriteRequest` of a `Write()` action, it indicates 49 | /// the initial offset for the `Write()` call. The value **must** be equal to 50 | /// the `committed_size` that a call to `QueryWriteStatus()` would return. 51 | /// 52 | /// On subsequent calls, this value **must** be set and **must** be equal to 53 | /// the sum of the first `write_offset` and the sizes of all `data` bundles 54 | /// sent previously on this stream. 55 | /// 56 | /// An incorrect value will cause an error. 57 | #[prost(int64, tag = "2")] 58 | pub write_offset: i64, 59 | /// If `true`, this indicates that the write is complete. Sending any 60 | /// `WriteRequest`s subsequent to one in which `finish_write` is `true` will 61 | /// cause an error. 62 | #[prost(bool, tag = "3")] 63 | pub finish_write: bool, 64 | /// A portion of the data for the resource. The client **may** leave `data` 65 | /// empty for any given `WriteRequest`. This enables the client to inform the 66 | /// service that the request is still live while it is running an operation to 67 | /// generate more data. 68 | #[prost(bytes = "vec", tag = "10")] 69 | pub data: ::prost::alloc::vec::Vec, 70 | } 71 | /// Response object for ByteStream.Write. 72 | #[allow(clippy::derive_partial_eq_without_eq)] 73 | #[derive(Clone, PartialEq, ::prost::Message)] 74 | pub struct WriteResponse { 75 | /// The number of bytes that have been processed for the given resource. 76 | #[prost(int64, tag = "1")] 77 | pub committed_size: i64, 78 | } 79 | /// Request object for ByteStream.QueryWriteStatus. 80 | #[allow(clippy::derive_partial_eq_without_eq)] 81 | #[derive(Clone, PartialEq, ::prost::Message)] 82 | pub struct QueryWriteStatusRequest { 83 | /// The name of the resource whose write status is being requested. 84 | #[prost(string, tag = "1")] 85 | pub resource_name: ::prost::alloc::string::String, 86 | } 87 | /// Response object for ByteStream.QueryWriteStatus. 88 | #[allow(clippy::derive_partial_eq_without_eq)] 89 | #[derive(Clone, PartialEq, ::prost::Message)] 90 | pub struct QueryWriteStatusResponse { 91 | /// The number of bytes that have been processed for the given resource. 92 | #[prost(int64, tag = "1")] 93 | pub committed_size: i64, 94 | /// `complete` is `true` only if the client has sent a `WriteRequest` with 95 | /// `finish_write` set to true, and the server has processed that request. 96 | #[prost(bool, tag = "2")] 97 | pub complete: bool, 98 | } 99 | /// Generated client implementations. 100 | pub mod byte_stream_client { 101 | #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 102 | use tonic::codegen::*; 103 | use tonic::codegen::http::Uri; 104 | /// #### Introduction 105 | /// 106 | /// The Byte Stream API enables a client to read and write a stream of bytes to 107 | /// and from a resource. Resources have names, and these names are supplied in 108 | /// the API calls below to identify the resource that is being read from or 109 | /// written to. 110 | /// 111 | /// All implementations of the Byte Stream API export the interface defined here: 112 | /// 113 | /// * `Read()`: Reads the contents of a resource. 114 | /// 115 | /// * `Write()`: Writes the contents of a resource. The client can call `Write()` 116 | /// multiple times with the same resource and can check the status of the write 117 | /// by calling `QueryWriteStatus()`. 118 | /// 119 | /// #### Service parameters and metadata 120 | /// 121 | /// The ByteStream API provides no direct way to access/modify any metadata 122 | /// associated with the resource. 123 | /// 124 | /// #### Errors 125 | /// 126 | /// The errors returned by the service are in the Google canonical error space. 127 | #[derive(Debug, Clone)] 128 | pub struct ByteStreamClient { 129 | inner: tonic::client::Grpc, 130 | } 131 | impl ByteStreamClient { 132 | /// Attempt to create a new client by connecting to a given endpoint. 133 | pub async fn connect(dst: D) -> Result 134 | where 135 | D: TryInto, 136 | D::Error: Into, 137 | { 138 | let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; 139 | Ok(Self::new(conn)) 140 | } 141 | } 142 | impl ByteStreamClient 143 | where 144 | T: tonic::client::GrpcService, 145 | T::Error: Into, 146 | T::ResponseBody: Body + Send + 'static, 147 | ::Error: Into + Send, 148 | { 149 | pub fn new(inner: T) -> Self { 150 | let inner = tonic::client::Grpc::new(inner); 151 | Self { inner } 152 | } 153 | pub fn with_origin(inner: T, origin: Uri) -> Self { 154 | let inner = tonic::client::Grpc::with_origin(inner, origin); 155 | Self { inner } 156 | } 157 | pub fn with_interceptor( 158 | inner: T, 159 | interceptor: F, 160 | ) -> ByteStreamClient> 161 | where 162 | F: tonic::service::Interceptor, 163 | T::ResponseBody: Default, 164 | T: tonic::codegen::Service< 165 | http::Request, 166 | Response = http::Response< 167 | >::ResponseBody, 168 | >, 169 | >, 170 | , 172 | >>::Error: Into + Send + Sync, 173 | { 174 | ByteStreamClient::new(InterceptedService::new(inner, interceptor)) 175 | } 176 | /// Compress requests with the given encoding. 177 | /// 178 | /// This requires the server to support it otherwise it might respond with an 179 | /// error. 180 | #[must_use] 181 | pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { 182 | self.inner = self.inner.send_compressed(encoding); 183 | self 184 | } 185 | /// Enable decompressing responses. 186 | #[must_use] 187 | pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { 188 | self.inner = self.inner.accept_compressed(encoding); 189 | self 190 | } 191 | /// Limits the maximum size of a decoded message. 192 | /// 193 | /// Default: `4MB` 194 | #[must_use] 195 | pub fn max_decoding_message_size(mut self, limit: usize) -> Self { 196 | self.inner = self.inner.max_decoding_message_size(limit); 197 | self 198 | } 199 | /// Limits the maximum size of an encoded message. 200 | /// 201 | /// Default: `usize::MAX` 202 | #[must_use] 203 | pub fn max_encoding_message_size(mut self, limit: usize) -> Self { 204 | self.inner = self.inner.max_encoding_message_size(limit); 205 | self 206 | } 207 | /// `Read()` is used to retrieve the contents of a resource as a sequence 208 | /// of bytes. The bytes are returned in a sequence of responses, and the 209 | /// responses are delivered as the results of a server-side streaming RPC. 210 | pub async fn read( 211 | &mut self, 212 | request: impl tonic::IntoRequest, 213 | ) -> std::result::Result< 214 | tonic::Response>, 215 | tonic::Status, 216 | > { 217 | self.inner 218 | .ready() 219 | .await 220 | .map_err(|e| { 221 | tonic::Status::new( 222 | tonic::Code::Unknown, 223 | format!("Service was not ready: {}", e.into()), 224 | ) 225 | })?; 226 | let codec = tonic::codec::ProstCodec::default(); 227 | let path = http::uri::PathAndQuery::from_static( 228 | "/google.bytestream.ByteStream/Read", 229 | ); 230 | let mut req = request.into_request(); 231 | req.extensions_mut() 232 | .insert(GrpcMethod::new("google.bytestream.ByteStream", "Read")); 233 | self.inner.server_streaming(req, path, codec).await 234 | } 235 | /// `Write()` is used to send the contents of a resource as a sequence of 236 | /// bytes. The bytes are sent in a sequence of request protos of a client-side 237 | /// streaming RPC. 238 | /// 239 | /// A `Write()` action is resumable. If there is an error or the connection is 240 | /// broken during the `Write()`, the client should check the status of the 241 | /// `Write()` by calling `QueryWriteStatus()` and continue writing from the 242 | /// returned `committed_size`. This may be less than the amount of data the 243 | /// client previously sent. 244 | /// 245 | /// Calling `Write()` on a resource name that was previously written and 246 | /// finalized could cause an error, depending on whether the underlying service 247 | /// allows over-writing of previously written resources. 248 | /// 249 | /// When the client closes the request channel, the service will respond with 250 | /// a `WriteResponse`. The service will not view the resource as `complete` 251 | /// until the client has sent a `WriteRequest` with `finish_write` set to 252 | /// `true`. Sending any requests on a stream after sending a request with 253 | /// `finish_write` set to `true` will cause an error. The client **should** 254 | /// check the `WriteResponse` it receives to determine how much data the 255 | /// service was able to commit and whether the service views the resource as 256 | /// `complete` or not. 257 | pub async fn write( 258 | &mut self, 259 | request: impl tonic::IntoStreamingRequest, 260 | ) -> std::result::Result, tonic::Status> { 261 | self.inner 262 | .ready() 263 | .await 264 | .map_err(|e| { 265 | tonic::Status::new( 266 | tonic::Code::Unknown, 267 | format!("Service was not ready: {}", e.into()), 268 | ) 269 | })?; 270 | let codec = tonic::codec::ProstCodec::default(); 271 | let path = http::uri::PathAndQuery::from_static( 272 | "/google.bytestream.ByteStream/Write", 273 | ); 274 | let mut req = request.into_streaming_request(); 275 | req.extensions_mut() 276 | .insert(GrpcMethod::new("google.bytestream.ByteStream", "Write")); 277 | self.inner.client_streaming(req, path, codec).await 278 | } 279 | /// `QueryWriteStatus()` is used to find the `committed_size` for a resource 280 | /// that is being written, which can then be used as the `write_offset` for 281 | /// the next `Write()` call. 282 | /// 283 | /// If the resource does not exist (i.e., the resource has been deleted, or the 284 | /// first `Write()` has not yet reached the service), this method returns the 285 | /// error `NOT_FOUND`. 286 | /// 287 | /// The client **may** call `QueryWriteStatus()` at any time to determine how 288 | /// much data has been processed for this resource. This is useful if the 289 | /// client is buffering data and needs to know which data can be safely 290 | /// evicted. For any sequence of `QueryWriteStatus()` calls for a given 291 | /// resource name, the sequence of returned `committed_size` values will be 292 | /// non-decreasing. 293 | pub async fn query_write_status( 294 | &mut self, 295 | request: impl tonic::IntoRequest, 296 | ) -> std::result::Result< 297 | tonic::Response, 298 | tonic::Status, 299 | > { 300 | self.inner 301 | .ready() 302 | .await 303 | .map_err(|e| { 304 | tonic::Status::new( 305 | tonic::Code::Unknown, 306 | format!("Service was not ready: {}", e.into()), 307 | ) 308 | })?; 309 | let codec = tonic::codec::ProstCodec::default(); 310 | let path = http::uri::PathAndQuery::from_static( 311 | "/google.bytestream.ByteStream/QueryWriteStatus", 312 | ); 313 | let mut req = request.into_request(); 314 | req.extensions_mut() 315 | .insert( 316 | GrpcMethod::new("google.bytestream.ByteStream", "QueryWriteStatus"), 317 | ); 318 | self.inner.unary(req, path, codec).await 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /crates/proxy/src/generated/google.longrunning.rs: -------------------------------------------------------------------------------- 1 | /// This resource represents a long-running operation that is the result of a 2 | /// network API call. 3 | #[allow(clippy::derive_partial_eq_without_eq)] 4 | #[derive(Clone, PartialEq, ::prost::Message)] 5 | pub struct Operation { 6 | /// The server-assigned name, which is only unique within the same service that 7 | /// originally returns it. If you use the default HTTP mapping, the 8 | /// `name` should be a resource name ending with `operations/{unique_id}`. 9 | #[prost(string, tag = "1")] 10 | pub name: ::prost::alloc::string::String, 11 | /// Service-specific metadata associated with the operation. It typically 12 | /// contains progress information and common metadata such as create time. 13 | /// Some services might not provide such metadata. Any method that returns a 14 | /// long-running operation should document the metadata type, if any. 15 | #[prost(message, optional, tag = "2")] 16 | pub metadata: ::core::option::Option<::prost_types::Any>, 17 | /// If the value is `false`, it means the operation is still in progress. 18 | /// If `true`, the operation is completed, and either `error` or `response` is 19 | /// available. 20 | #[prost(bool, tag = "3")] 21 | pub done: bool, 22 | /// The operation result, which can be either an `error` or a valid `response`. 23 | /// If `done` == `false`, neither `error` nor `response` is set. 24 | /// If `done` == `true`, exactly one of `error` or `response` is set. 25 | #[prost(oneof = "operation::Result", tags = "4, 5")] 26 | pub result: ::core::option::Option, 27 | } 28 | /// Nested message and enum types in `Operation`. 29 | pub mod operation { 30 | /// The operation result, which can be either an `error` or a valid `response`. 31 | /// If `done` == `false`, neither `error` nor `response` is set. 32 | /// If `done` == `true`, exactly one of `error` or `response` is set. 33 | #[allow(clippy::derive_partial_eq_without_eq)] 34 | #[derive(Clone, PartialEq, ::prost::Oneof)] 35 | pub enum Result { 36 | /// The error result of the operation in case of failure or cancellation. 37 | #[prost(message, tag = "4")] 38 | Error(super::super::rpc::Status), 39 | /// The normal response of the operation in case of success. If the original 40 | /// method returns no data on success, such as `Delete`, the response is 41 | /// `google.protobuf.Empty`. If the original method is standard 42 | /// `Get`/`Create`/`Update`, the response should be the resource. For other 43 | /// methods, the response should have the type `XxxResponse`, where `Xxx` 44 | /// is the original method name. For example, if the original method name 45 | /// is `TakeSnapshot()`, the inferred response type is 46 | /// `TakeSnapshotResponse`. 47 | #[prost(message, tag = "5")] 48 | Response(::prost_types::Any), 49 | } 50 | } 51 | /// The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation]. 52 | #[allow(clippy::derive_partial_eq_without_eq)] 53 | #[derive(Clone, PartialEq, ::prost::Message)] 54 | pub struct GetOperationRequest { 55 | /// The name of the operation resource. 56 | #[prost(string, tag = "1")] 57 | pub name: ::prost::alloc::string::String, 58 | } 59 | /// The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. 60 | #[allow(clippy::derive_partial_eq_without_eq)] 61 | #[derive(Clone, PartialEq, ::prost::Message)] 62 | pub struct ListOperationsRequest { 63 | /// The name of the operation's parent resource. 64 | #[prost(string, tag = "4")] 65 | pub name: ::prost::alloc::string::String, 66 | /// The standard list filter. 67 | #[prost(string, tag = "1")] 68 | pub filter: ::prost::alloc::string::String, 69 | /// The standard list page size. 70 | #[prost(int32, tag = "2")] 71 | pub page_size: i32, 72 | /// The standard list page token. 73 | #[prost(string, tag = "3")] 74 | pub page_token: ::prost::alloc::string::String, 75 | } 76 | /// The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. 77 | #[allow(clippy::derive_partial_eq_without_eq)] 78 | #[derive(Clone, PartialEq, ::prost::Message)] 79 | pub struct ListOperationsResponse { 80 | /// A list of operations that matches the specified filter in the request. 81 | #[prost(message, repeated, tag = "1")] 82 | pub operations: ::prost::alloc::vec::Vec, 83 | /// The standard List next-page token. 84 | #[prost(string, tag = "2")] 85 | pub next_page_token: ::prost::alloc::string::String, 86 | } 87 | /// The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]. 88 | #[allow(clippy::derive_partial_eq_without_eq)] 89 | #[derive(Clone, PartialEq, ::prost::Message)] 90 | pub struct CancelOperationRequest { 91 | /// The name of the operation resource to be cancelled. 92 | #[prost(string, tag = "1")] 93 | pub name: ::prost::alloc::string::String, 94 | } 95 | /// The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation]. 96 | #[allow(clippy::derive_partial_eq_without_eq)] 97 | #[derive(Clone, PartialEq, ::prost::Message)] 98 | pub struct DeleteOperationRequest { 99 | /// The name of the operation resource to be deleted. 100 | #[prost(string, tag = "1")] 101 | pub name: ::prost::alloc::string::String, 102 | } 103 | /// The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. 104 | #[allow(clippy::derive_partial_eq_without_eq)] 105 | #[derive(Clone, PartialEq, ::prost::Message)] 106 | pub struct WaitOperationRequest { 107 | /// The name of the operation resource to wait on. 108 | #[prost(string, tag = "1")] 109 | pub name: ::prost::alloc::string::String, 110 | /// The maximum duration to wait before timing out. If left blank, the wait 111 | /// will be at most the time permitted by the underlying HTTP/RPC protocol. 112 | /// If RPC context deadline is also specified, the shorter one will be used. 113 | #[prost(message, optional, tag = "2")] 114 | pub timeout: ::core::option::Option<::prost_types::Duration>, 115 | } 116 | /// A message representing the message types used by a long-running operation. 117 | /// 118 | /// Example: 119 | /// 120 | /// rpc LongRunningRecognize(LongRunningRecognizeRequest) 121 | /// returns (google.longrunning.Operation) { 122 | /// option (google.longrunning.operation_info) = { 123 | /// response_type: "LongRunningRecognizeResponse" 124 | /// metadata_type: "LongRunningRecognizeMetadata" 125 | /// }; 126 | /// } 127 | #[allow(clippy::derive_partial_eq_without_eq)] 128 | #[derive(Clone, PartialEq, ::prost::Message)] 129 | pub struct OperationInfo { 130 | /// Required. The message name of the primary return type for this 131 | /// long-running operation. 132 | /// This type will be used to deserialize the LRO's response. 133 | /// 134 | /// If the response is in a different package from the rpc, a fully-qualified 135 | /// message name must be used (e.g. `google.protobuf.Struct`). 136 | /// 137 | /// Note: Altering this value constitutes a breaking change. 138 | #[prost(string, tag = "1")] 139 | pub response_type: ::prost::alloc::string::String, 140 | /// Required. The message name of the metadata type for this long-running 141 | /// operation. 142 | /// 143 | /// If the response is in a different package from the rpc, a fully-qualified 144 | /// message name must be used (e.g. `google.protobuf.Struct`). 145 | /// 146 | /// Note: Altering this value constitutes a breaking change. 147 | #[prost(string, tag = "2")] 148 | pub metadata_type: ::prost::alloc::string::String, 149 | } 150 | /// Generated client implementations. 151 | pub mod operations_client { 152 | #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] 153 | use tonic::codegen::*; 154 | use tonic::codegen::http::Uri; 155 | /// Manages long-running operations with an API service. 156 | /// 157 | /// When an API method normally takes long time to complete, it can be designed 158 | /// to return [Operation][google.longrunning.Operation] to the client, and the client can use this 159 | /// interface to receive the real response asynchronously by polling the 160 | /// operation resource, or pass the operation resource to another API (such as 161 | /// Google Cloud Pub/Sub API) to receive the response. Any API service that 162 | /// returns long-running operations should implement the `Operations` interface 163 | /// so developers can have a consistent client experience. 164 | #[derive(Debug, Clone)] 165 | pub struct OperationsClient { 166 | inner: tonic::client::Grpc, 167 | } 168 | impl OperationsClient { 169 | /// Attempt to create a new client by connecting to a given endpoint. 170 | pub async fn connect(dst: D) -> Result 171 | where 172 | D: TryInto, 173 | D::Error: Into, 174 | { 175 | let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; 176 | Ok(Self::new(conn)) 177 | } 178 | } 179 | impl OperationsClient 180 | where 181 | T: tonic::client::GrpcService, 182 | T::Error: Into, 183 | T::ResponseBody: Body + Send + 'static, 184 | ::Error: Into + Send, 185 | { 186 | pub fn new(inner: T) -> Self { 187 | let inner = tonic::client::Grpc::new(inner); 188 | Self { inner } 189 | } 190 | pub fn with_origin(inner: T, origin: Uri) -> Self { 191 | let inner = tonic::client::Grpc::with_origin(inner, origin); 192 | Self { inner } 193 | } 194 | pub fn with_interceptor( 195 | inner: T, 196 | interceptor: F, 197 | ) -> OperationsClient> 198 | where 199 | F: tonic::service::Interceptor, 200 | T::ResponseBody: Default, 201 | T: tonic::codegen::Service< 202 | http::Request, 203 | Response = http::Response< 204 | >::ResponseBody, 205 | >, 206 | >, 207 | , 209 | >>::Error: Into + Send + Sync, 210 | { 211 | OperationsClient::new(InterceptedService::new(inner, interceptor)) 212 | } 213 | /// Compress requests with the given encoding. 214 | /// 215 | /// This requires the server to support it otherwise it might respond with an 216 | /// error. 217 | #[must_use] 218 | pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { 219 | self.inner = self.inner.send_compressed(encoding); 220 | self 221 | } 222 | /// Enable decompressing responses. 223 | #[must_use] 224 | pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { 225 | self.inner = self.inner.accept_compressed(encoding); 226 | self 227 | } 228 | /// Limits the maximum size of a decoded message. 229 | /// 230 | /// Default: `4MB` 231 | #[must_use] 232 | pub fn max_decoding_message_size(mut self, limit: usize) -> Self { 233 | self.inner = self.inner.max_decoding_message_size(limit); 234 | self 235 | } 236 | /// Limits the maximum size of an encoded message. 237 | /// 238 | /// Default: `usize::MAX` 239 | #[must_use] 240 | pub fn max_encoding_message_size(mut self, limit: usize) -> Self { 241 | self.inner = self.inner.max_encoding_message_size(limit); 242 | self 243 | } 244 | /// Lists operations that match the specified filter in the request. If the 245 | /// server doesn't support this method, it returns `UNIMPLEMENTED`. 246 | /// 247 | /// NOTE: the `name` binding allows API services to override the binding 248 | /// to use different resource name schemes, such as `users/*/operations`. To 249 | /// override the binding, API services can add a binding such as 250 | /// `"/v1/{name=users/*}/operations"` to their service configuration. 251 | /// For backwards compatibility, the default name includes the operations 252 | /// collection id, however overriding users must ensure the name binding 253 | /// is the parent resource, without the operations collection id. 254 | pub async fn list_operations( 255 | &mut self, 256 | request: impl tonic::IntoRequest, 257 | ) -> std::result::Result< 258 | tonic::Response, 259 | tonic::Status, 260 | > { 261 | self.inner 262 | .ready() 263 | .await 264 | .map_err(|e| { 265 | tonic::Status::new( 266 | tonic::Code::Unknown, 267 | format!("Service was not ready: {}", e.into()), 268 | ) 269 | })?; 270 | let codec = tonic::codec::ProstCodec::default(); 271 | let path = http::uri::PathAndQuery::from_static( 272 | "/google.longrunning.Operations/ListOperations", 273 | ); 274 | let mut req = request.into_request(); 275 | req.extensions_mut() 276 | .insert( 277 | GrpcMethod::new("google.longrunning.Operations", "ListOperations"), 278 | ); 279 | self.inner.unary(req, path, codec).await 280 | } 281 | /// Gets the latest state of a long-running operation. Clients can use this 282 | /// method to poll the operation result at intervals as recommended by the API 283 | /// service. 284 | pub async fn get_operation( 285 | &mut self, 286 | request: impl tonic::IntoRequest, 287 | ) -> std::result::Result, tonic::Status> { 288 | self.inner 289 | .ready() 290 | .await 291 | .map_err(|e| { 292 | tonic::Status::new( 293 | tonic::Code::Unknown, 294 | format!("Service was not ready: {}", e.into()), 295 | ) 296 | })?; 297 | let codec = tonic::codec::ProstCodec::default(); 298 | let path = http::uri::PathAndQuery::from_static( 299 | "/google.longrunning.Operations/GetOperation", 300 | ); 301 | let mut req = request.into_request(); 302 | req.extensions_mut() 303 | .insert( 304 | GrpcMethod::new("google.longrunning.Operations", "GetOperation"), 305 | ); 306 | self.inner.unary(req, path, codec).await 307 | } 308 | /// Deletes a long-running operation. This method indicates that the client is 309 | /// no longer interested in the operation result. It does not cancel the 310 | /// operation. If the server doesn't support this method, it returns 311 | /// `google.rpc.Code.UNIMPLEMENTED`. 312 | pub async fn delete_operation( 313 | &mut self, 314 | request: impl tonic::IntoRequest, 315 | ) -> std::result::Result, tonic::Status> { 316 | self.inner 317 | .ready() 318 | .await 319 | .map_err(|e| { 320 | tonic::Status::new( 321 | tonic::Code::Unknown, 322 | format!("Service was not ready: {}", e.into()), 323 | ) 324 | })?; 325 | let codec = tonic::codec::ProstCodec::default(); 326 | let path = http::uri::PathAndQuery::from_static( 327 | "/google.longrunning.Operations/DeleteOperation", 328 | ); 329 | let mut req = request.into_request(); 330 | req.extensions_mut() 331 | .insert( 332 | GrpcMethod::new("google.longrunning.Operations", "DeleteOperation"), 333 | ); 334 | self.inner.unary(req, path, codec).await 335 | } 336 | /// Starts asynchronous cancellation on a long-running operation. The server 337 | /// makes a best effort to cancel the operation, but success is not 338 | /// guaranteed. If the server doesn't support this method, it returns 339 | /// `google.rpc.Code.UNIMPLEMENTED`. Clients can use 340 | /// [Operations.GetOperation][google.longrunning.Operations.GetOperation] or 341 | /// other methods to check whether the cancellation succeeded or whether the 342 | /// operation completed despite cancellation. On successful cancellation, 343 | /// the operation is not deleted; instead, it becomes an operation with 344 | /// an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, 345 | /// corresponding to `Code.CANCELLED`. 346 | pub async fn cancel_operation( 347 | &mut self, 348 | request: impl tonic::IntoRequest, 349 | ) -> std::result::Result, tonic::Status> { 350 | self.inner 351 | .ready() 352 | .await 353 | .map_err(|e| { 354 | tonic::Status::new( 355 | tonic::Code::Unknown, 356 | format!("Service was not ready: {}", e.into()), 357 | ) 358 | })?; 359 | let codec = tonic::codec::ProstCodec::default(); 360 | let path = http::uri::PathAndQuery::from_static( 361 | "/google.longrunning.Operations/CancelOperation", 362 | ); 363 | let mut req = request.into_request(); 364 | req.extensions_mut() 365 | .insert( 366 | GrpcMethod::new("google.longrunning.Operations", "CancelOperation"), 367 | ); 368 | self.inner.unary(req, path, codec).await 369 | } 370 | /// Waits until the specified long-running operation is done or reaches at most 371 | /// a specified timeout, returning the latest state. If the operation is 372 | /// already done, the latest state is immediately returned. If the timeout 373 | /// specified is greater than the default HTTP/RPC timeout, the HTTP/RPC 374 | /// timeout is used. If the server does not support this method, it returns 375 | /// `google.rpc.Code.UNIMPLEMENTED`. 376 | /// Note that this method is on a best-effort basis. It may return the latest 377 | /// state before the specified timeout (including immediately), meaning even an 378 | /// immediate response is no guarantee that the operation is done. 379 | pub async fn wait_operation( 380 | &mut self, 381 | request: impl tonic::IntoRequest, 382 | ) -> std::result::Result, tonic::Status> { 383 | self.inner 384 | .ready() 385 | .await 386 | .map_err(|e| { 387 | tonic::Status::new( 388 | tonic::Code::Unknown, 389 | format!("Service was not ready: {}", e.into()), 390 | ) 391 | })?; 392 | let codec = tonic::codec::ProstCodec::default(); 393 | let path = http::uri::PathAndQuery::from_static( 394 | "/google.longrunning.Operations/WaitOperation", 395 | ); 396 | let mut req = request.into_request(); 397 | req.extensions_mut() 398 | .insert( 399 | GrpcMethod::new("google.longrunning.Operations", "WaitOperation"), 400 | ); 401 | self.inner.unary(req, path, codec).await 402 | } 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /crates/proxy/src/generated/google.rpc.rs: -------------------------------------------------------------------------------- 1 | /// The `Status` type defines a logical error model that is suitable for 2 | /// different programming environments, including REST APIs and RPC APIs. It is 3 | /// used by [gRPC](). Each `Status` message contains 4 | /// three pieces of data: error code, error message, and error details. 5 | /// 6 | /// You can find out more about this error model and how to work with it in the 7 | /// [API Design Guide](). 8 | #[allow(clippy::derive_partial_eq_without_eq)] 9 | #[derive(Clone, PartialEq, ::prost::Message)] 10 | pub struct Status { 11 | /// The status code, which should be an enum value of 12 | /// [google.rpc.Code][google.rpc.Code]. 13 | #[prost(int32, tag = "1")] 14 | pub code: i32, 15 | /// A developer-facing error message, which should be in English. Any 16 | /// user-facing error message should be localized and sent in the 17 | /// [google.rpc.Status.details][google.rpc.Status.details] field, or localized 18 | /// by the client. 19 | #[prost(string, tag = "2")] 20 | pub message: ::prost::alloc::string::String, 21 | /// A list of messages that carry the error details. There is a common set of 22 | /// message types for APIs to use. 23 | #[prost(message, repeated, tag = "3")] 24 | pub details: ::prost::alloc::vec::Vec<::prost_types::Any>, 25 | } 26 | -------------------------------------------------------------------------------- /crates/proxy/src/generated/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod google { 2 | pub mod api { 3 | include!("google.api.rs"); 4 | } 5 | pub mod bytestream { 6 | include!("google.bytestream.rs"); 7 | } 8 | pub mod longrunning { 9 | include!("google.longrunning.rs"); 10 | } 11 | pub mod rpc { 12 | include!("google.rpc.rs"); 13 | } 14 | } 15 | pub mod build { 16 | pub mod bazel { 17 | pub mod semver { 18 | include!("build.bazel.semver.rs"); 19 | } 20 | pub mod remote { 21 | pub mod execution { 22 | pub mod v2 { 23 | include!("build.bazel.remote.execution.v2.rs"); 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /crates/proxy/src/lib.rs: -------------------------------------------------------------------------------- 1 | use futures::StreamExt; 2 | use prost::Message; 3 | use ring::digest::{Context, SHA256}; 4 | use tonic::transport::Channel; 5 | use uuid::Uuid; 6 | 7 | pub mod generated; 8 | 9 | use generated::{ 10 | build::bazel::remote::execution::v2::{Digest, NodeProperties}, 11 | google::bytestream::{byte_stream_client::ByteStreamClient, ReadRequest, WriteRequest}, 12 | }; 13 | 14 | #[derive(Debug, Clone)] 15 | pub struct TypedDigest(pub Digest, std::marker::PhantomData); 16 | 17 | impl TypedDigest { 18 | pub fn new(digest: Digest) -> Self { 19 | TypedDigest(digest, std::marker::PhantomData) 20 | } 21 | 22 | pub fn from_message(msg: &T) -> Self { 23 | Self::new(digest(&msg.encode_to_vec())) 24 | } 25 | } 26 | 27 | pub struct Blob { 28 | pub data: Vec, 29 | pub digest: Digest, 30 | } 31 | 32 | pub fn digest(data: &[u8]) -> Digest { 33 | let mut ctx = Context::new(&SHA256); 34 | ctx.update(data); 35 | let digest = ctx.finish(); 36 | let hash_parts: Vec<_> = digest.as_ref().iter().map(|c| format!("{c:02x}")).collect(); 37 | let hash: String = hash_parts.iter().flat_map(|c| c.chars()).collect(); 38 | Digest { 39 | hash, 40 | size_bytes: data.len() as i64, 41 | } 42 | } 43 | 44 | pub fn default_properties(executable: bool) -> NodeProperties { 45 | NodeProperties { 46 | properties: vec![], 47 | mtime: Some(prost_types::Timestamp { 48 | seconds: 0, 49 | nanos: 0, 50 | }), 51 | unix_mode: Some(if executable { 0o444 } else { 0o555 }), 52 | } 53 | } 54 | 55 | pub fn blob_cloned(data: impl AsRef<[u8]>) -> (Blob, Digest) { 56 | blob(data.as_ref().to_owned()) 57 | } 58 | 59 | pub fn blob(data: Vec) -> (Blob, Digest) { 60 | let digest = digest(&data); 61 | ( 62 | Blob { 63 | digest: digest.clone(), 64 | data, 65 | }, 66 | digest, 67 | ) 68 | } 69 | 70 | pub fn protoblob(data: &T) -> (Blob, TypedDigest) { 71 | let data = data.encode_to_vec(); 72 | let digest = digest(&data); 73 | ( 74 | Blob { 75 | digest: digest.clone(), 76 | data, 77 | }, 78 | TypedDigest(digest, std::marker::PhantomData), 79 | ) 80 | } 81 | 82 | const CHUNK_SIZE: usize = 64 * 1024; 83 | 84 | // TODO: check if the blob is there already 85 | pub async fn upload_blob(client: &mut ByteStreamClient, blob: Blob) -> anyhow::Result<()> { 86 | // TODO: respect size limits by making actual streams 87 | let uuid = Uuid::new_v4(); 88 | // let req = WriteRequest { 89 | // resource_name: format!( 90 | // "my-instance/uploads/{uuid}/blobs/{}/{}", 91 | // blob.digest.hash, blob.digest.size_bytes 92 | // ), 93 | // write_offset: 0, 94 | // finish_write: true, 95 | // data: blob.data, 96 | // }; 97 | let mut chunks: Vec<_> = blob.data.chunks(CHUNK_SIZE).map(|c| c.to_owned()).collect(); 98 | let resource_name = format!( 99 | "my-instance/uploads/{uuid}/blobs/{}/{}", 100 | blob.digest.hash, blob.digest.size_bytes 101 | ); 102 | let last_chunk = chunks.pop().unwrap_or(vec![]); 103 | let requests = chunks 104 | .into_iter() 105 | .enumerate() 106 | .map({ 107 | let resource_name = resource_name.clone(); 108 | move |(i, data)| WriteRequest { 109 | resource_name: resource_name.clone(), 110 | write_offset: (i * CHUNK_SIZE) as i64, 111 | finish_write: false, 112 | data, 113 | } 114 | }) 115 | .chain(std::iter::once(WriteRequest { 116 | resource_name: resource_name.clone(), 117 | write_offset: blob.digest.size_bytes - last_chunk.len() as i64, 118 | finish_write: true, 119 | data: last_chunk, 120 | })); 121 | // dbg!(resource_name); 122 | client.write(futures::stream::iter(requests)).await?; 123 | Ok(()) 124 | } 125 | 126 | pub async fn upload_proto( 127 | client: &mut ByteStreamClient, 128 | data: &T, 129 | ) -> anyhow::Result> { 130 | let data = data.encode_to_vec(); 131 | let (blob, digest) = blob(data); 132 | upload_blob(client, blob).await?; 133 | Ok(TypedDigest(digest, std::marker::PhantomData)) 134 | } 135 | 136 | pub async fn upload_proto_untyped( 137 | client: &mut ByteStreamClient, 138 | data: Vec, 139 | ) -> anyhow::Result { 140 | let (blob, digest) = blob(data); 141 | upload_blob(client, blob).await?; 142 | Ok(digest) 143 | } 144 | 145 | // pub async fn upload_proto( 146 | // client: &mut ByteStreamClient, 147 | // data: &T, 148 | // ) -> anyhow::Result { 149 | // let data = data.encode_to_vec(); 150 | // let (blob, digest) = blob(data); 151 | // dbg!(&digest); 152 | // upload_blob(client, blob).await?; 153 | // Ok(digest) 154 | // } 155 | 156 | pub fn blob_request(digest: &Digest) -> ReadRequest { 157 | let resource_name = format!("my-instance/blobs/{}/{}", digest.hash, digest.size_bytes); 158 | ReadRequest { 159 | resource_name, 160 | read_offset: 0, 161 | read_limit: 0, 162 | } 163 | } 164 | 165 | pub async fn download_blob( 166 | client: &mut ByteStreamClient, 167 | digest: &Digest, 168 | ) -> anyhow::Result> { 169 | let req = blob_request(digest); 170 | let mut resp = client.read(req).await?.into_inner(); 171 | let mut buf = Vec::new(); 172 | while let Some(next) = resp.next().await { 173 | let next = next?; 174 | buf.extend_from_slice(&next.data); 175 | } 176 | 177 | Ok(buf) 178 | } 179 | 180 | pub async fn download_proto( 181 | client: &mut ByteStreamClient, 182 | digest: &TypedDigest, 183 | ) -> anyhow::Result { 184 | let bytes = download_blob(client, &digest.0).await?; 185 | Ok(T::decode(bytes.as_ref())?) 186 | } 187 | 188 | // pub async fn download_proto( 189 | // client: &mut ByteStreamClient, 190 | // digest: &Digest, 191 | // ) -> anyhow::Result { 192 | // let bytes = download_blob(client, digest).await?; 193 | // Ok(T::decode(bytes.as_ref())?) 194 | // } 195 | -------------------------------------------------------------------------------- /crates/proxy/src/main.rs: -------------------------------------------------------------------------------- 1 | // TODO: 2 | // - write a EntrySink impl for nix.write somehow, this will facilitate some streaming 3 | // - basic sending of the nar tree works, but we aren't streaming from or to nix 4 | // - (bonus: pack small files into batch requests) 5 | // - figure out how authentication is going to work. It doesn't seem to be defined as 6 | // part of the REv2 protocol, so services like buildbuddy seem to roll their own. 7 | // For now, we're using a locally-running buildbarn instance. 8 | // - stream the worker's stderr and its stdout 9 | 10 | // TODO(eventually): make nar generic over the file contents to make the hydrating nicer 11 | 12 | // Known issues: 13 | // - the fuse runner fails in unpackPhase because cp can't preserve permissions. Maybe set things up in /build instead? For now, hardlinking works 14 | 15 | // There was a choice to be made: do we store the files/trees in CAS, or do we store nars. Current strategy is storing files, and packing/unpacking nars in the proxy. 16 | // When returning the build result, we need to 17 | // - return a nar 18 | // - know all the references. 19 | // Our approach: build the nar on the fly and stream it. Have the builder precompute references and store them somewhere in the CAS. 20 | 21 | // Notes 2024-7-23: 22 | // - the output path isn't included in the QueryValidPaths op: if the client's nix store doesn't have the built derivation, 23 | // it just asks the remote builder to build it. (It doesn't first check if the remote builder already has it.) This means 24 | // that if we want a cache hit for the already-build derivations we need to handle that ourselves in BuildDerivation. 25 | // - If we want to do substitutions ourself, we should do it upon receiving QueryValidPaths. Then we should respond 26 | // that we already have the substituted paths. 27 | 28 | use std::collections::{HashMap, HashSet}; 29 | use std::io::{Cursor, Write}; 30 | use std::pin::Pin; 31 | 32 | use anyhow::anyhow; 33 | use futures::{Future, StreamExt}; 34 | use nix_remote::framed_data::FramedData; 35 | use nix_remote::nar::{DirectorySink, EntrySink, FileSink, NarDirectoryEntry, NarFile}; 36 | use nix_remote::worker_op::{ 37 | BuildResult, Derivation, DrvOutputs, QueryPathInfoResponse, ValidPathInfo, WorkerOp, 38 | }; 39 | use nix_remote::{nar::Nar, NixProxy, NixReadExt, NixWriteExt}; 40 | use nix_remote::{stderr, NarHash, NixString, StorePath, StorePathSet, ValidPathInfoWithPath}; 41 | use nix_rev2::generated::build::bazel::remote::execution::v2::command::OutputDirectoryFormat; 42 | use nix_rev2::{ 43 | blob, blob_cloned, blob_request, default_properties, digest, download_blob, download_proto, 44 | protoblob, upload_blob, upload_proto, upload_proto_untyped, Blob, TypedDigest, 45 | }; 46 | use prost::Message; 47 | 48 | use serde::{Deserialize, Serialize}; 49 | use tonic::transport::{Channel, Endpoint}; 50 | 51 | use nix_rev2::generated::{ 52 | self, 53 | build::bazel::remote::execution::v2::{ 54 | action_cache_client::ActionCacheClient, 55 | content_addressable_storage_client::ContentAddressableStorageClient, 56 | execution_client::ExecutionClient, Action, ActionResult, Command, Digest, Directory, 57 | DirectoryNode, ExecuteRequest, ExecuteResponse, ExecutedActionMetadata, FileNode, 58 | FindMissingBlobsRequest, GetActionResultRequest, OutputDirectory, OutputFile, SymlinkNode, 59 | Tree, UpdateActionResultRequest, 60 | }, 61 | google::bytestream::byte_stream_client::ByteStreamClient, 62 | }; 63 | 64 | //const KEY = env!("BUILDBUDDY_API_KEY"); 65 | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] 66 | pub enum PathType { 67 | File { executable: bool }, 68 | Directory, 69 | } 70 | 71 | #[derive(Debug, Clone)] 72 | pub enum PathInfo { 73 | File { 74 | digest: Digest, 75 | executable: bool, 76 | }, 77 | Directory { 78 | root_digest: TypedDigest, 79 | tree_digest: TypedDigest, 80 | }, 81 | } 82 | 83 | impl PathInfo { 84 | pub fn is_file(&self) -> bool { 85 | match self { 86 | PathInfo::File { .. } => true, 87 | PathInfo::Directory { .. } => false, 88 | } 89 | } 90 | } 91 | 92 | pub async fn path_info_from_tree( 93 | bs_client: &mut ByteStreamClient, 94 | tree_digest: TypedDigest, 95 | ) -> anyhow::Result { 96 | let tree: Tree = download_proto(bs_client, &tree_digest).await?; 97 | let root_digest = TypedDigest::from_message(&tree.root.unwrap()); 98 | 99 | Ok(PathInfo::Directory { 100 | root_digest, 101 | tree_digest, 102 | }) 103 | } 104 | 105 | pub fn convert(nar: &Nar) -> (Vec, PathInfo) { 106 | let mut blobs = Vec::new(); 107 | 108 | fn convert_file_rec(file: &NarFile, acc: &mut Vec) -> Digest { 109 | let (blob, digest) = blob_cloned(&file.contents); 110 | acc.push(blob); 111 | digest 112 | } 113 | 114 | fn convert_dir_rec( 115 | entries: &[NarDirectoryEntry], 116 | acc: &mut Vec, 117 | dir_acc: &mut Vec, 118 | ) -> (Directory, TypedDigest) { 119 | let mut files = Vec::new(); 120 | let mut symlinks = Vec::new(); 121 | let mut directories = Vec::new(); 122 | for entry in entries { 123 | // FIXME: proper error for non-utf8 names. The protocol apparently doesn't support non-utf8 names. 124 | let name = entry.name.to_string().unwrap(); 125 | match &entry.node { 126 | Nar::Contents(file) => { 127 | let digest = convert_file_rec(file, acc); 128 | let properties = default_properties(file.executable); 129 | let node = FileNode { 130 | name, 131 | digest: Some(digest), 132 | is_executable: file.executable, 133 | node_properties: Some(properties), 134 | }; 135 | files.push(node); 136 | } 137 | Nar::Target(sym) => { 138 | let target = sym.to_string().unwrap(); 139 | let properties = default_properties(true); 140 | let node = SymlinkNode { 141 | name, 142 | target, 143 | node_properties: Some(properties), 144 | }; 145 | symlinks.push(node); 146 | } 147 | Nar::Directory(entries) => { 148 | let (dir, digest) = convert_dir_rec(entries, acc, dir_acc); 149 | dir_acc.push(dir); 150 | let node = DirectoryNode { 151 | name, 152 | digest: Some(digest.0), 153 | }; 154 | directories.push(node); 155 | } 156 | } 157 | } 158 | 159 | let dir = Directory { 160 | files, 161 | directories, 162 | symlinks, 163 | node_properties: Some(default_properties(true)), 164 | }; 165 | let (blob, digest) = protoblob(&dir); 166 | acc.push(blob); 167 | (dir, digest) 168 | } 169 | 170 | let info = match nar { 171 | Nar::Contents(file) => PathInfo::File { 172 | executable: file.executable, 173 | digest: convert_file_rec(file, &mut blobs), 174 | }, 175 | Nar::Target(_) => panic!("symlink at top level!"), 176 | Nar::Directory(entries) => { 177 | let mut dir_acc = Vec::new(); 178 | let (dir, root_digest) = convert_dir_rec(entries, &mut blobs, &mut dir_acc); 179 | let tree = Tree { 180 | root: Some(dir), 181 | children: dir_acc, 182 | }; 183 | let (tree_blob, tree_digest) = protoblob(&tree); 184 | blobs.push(tree_blob); 185 | PathInfo::Directory { 186 | root_digest, 187 | tree_digest, 188 | } 189 | } 190 | }; 191 | 192 | (blobs, info) 193 | } 194 | 195 | #[derive(serde::Deserialize, Debug)] 196 | struct AddMultipleToStoreData { 197 | data: Vec<(ValidPathInfoWithPath, Nar)>, 198 | } 199 | 200 | const METADATA_PATH: &str = "outputmetadata"; 201 | const INSTANCE: &str = "my-instance"; 202 | 203 | #[derive(Debug, Serialize, Deserialize)] 204 | struct OutputMetadata { 205 | references: Vec, 206 | nar_hash: NixString, 207 | nar_size: usize, 208 | } 209 | 210 | #[derive(Debug, Serialize, Deserialize)] 211 | struct BuildMetadata { 212 | // The key is the output name, like "bin" 213 | metadata: HashMap, 214 | } 215 | 216 | fn build_input_root( 217 | store_path_map: &HashMap, 218 | derivation: &Derivation, 219 | ) -> (Vec, Digest) { 220 | let (files, dirs): (Vec<_>, Vec<_>) = derivation 221 | .input_sources 222 | .paths 223 | .iter() 224 | .partition(|t| store_path_map.get(t).unwrap().is_file()); 225 | let store_dir = Directory { 226 | files: files 227 | .into_iter() 228 | .map(|f| { 229 | let info = store_path_map.get(f).unwrap(); 230 | let (executable, digest) = match info { 231 | PathInfo::File { executable, digest } => (executable, digest), 232 | _ => unreachable!(), 233 | }; 234 | FileNode { 235 | name: String::from_utf8(f.as_ref().to_owned()) 236 | .unwrap() 237 | .strip_prefix("/nix/store/") // FIXME: look up the actual store path, and also adjust the directory tree building 238 | .unwrap() 239 | .to_owned(), 240 | digest: Some(digest.clone()), 241 | is_executable: *executable, 242 | node_properties: Some(default_properties(*executable)), 243 | } 244 | }) 245 | .collect(), 246 | directories: dirs 247 | .into_iter() 248 | .map(|d| { 249 | let root_digest = match store_path_map.get(d).unwrap() { 250 | PathInfo::File { .. } => panic!("cannot be file"), 251 | PathInfo::Directory { root_digest, .. } => root_digest, 252 | }; 253 | 254 | DirectoryNode { 255 | name: String::from_utf8(d.as_ref().to_owned()) 256 | .unwrap() 257 | .strip_prefix("/nix/store/") // FIXME: look up the actual store path, and also adjust the directory tree building 258 | .unwrap() 259 | .to_owned(), 260 | digest: Some(root_digest.0.clone()), 261 | } 262 | }) 263 | .collect(), 264 | symlinks: vec![], 265 | node_properties: Some(default_properties(true)), 266 | }; 267 | let (store_dir_blob, store_dir_digest) = blob(store_dir.encode_to_vec()); 268 | 269 | let nix_dir = Directory { 270 | files: vec![], 271 | directories: vec![DirectoryNode { 272 | name: "store".to_owned(), 273 | digest: Some(store_dir_digest), 274 | }], 275 | symlinks: vec![], 276 | node_properties: Some(default_properties(true)), 277 | }; 278 | let (nix_dir_blob, nix_dir_digest) = blob(nix_dir.encode_to_vec()); 279 | 280 | // Serialize the derivation to json and include it in the root directory. 281 | let contents = bincode::serialize(derivation).unwrap(); 282 | let (deriv_blob, deriv_digest) = blob(contents); 283 | 284 | let drv_builder = include_bytes!("../../../target/x86_64-unknown-linux-musl/debug/drv-adapter"); 285 | let (drv_builder_blob, drv_builder_digest) = blob(drv_builder.to_vec()); 286 | 287 | let root_dir = Directory { 288 | files: vec![ 289 | FileNode { 290 | name: "root.drv".to_owned(), 291 | digest: Some(deriv_digest), 292 | is_executable: false, 293 | node_properties: Some(default_properties(false)), 294 | }, 295 | FileNode { 296 | name: "drv-adapter".to_owned(), 297 | digest: Some(drv_builder_digest), 298 | is_executable: true, 299 | node_properties: Some(default_properties(true)), 300 | }, 301 | ], 302 | directories: vec![DirectoryNode { 303 | name: "nix".to_owned(), 304 | digest: Some(nix_dir_digest), 305 | }], 306 | symlinks: vec![], 307 | node_properties: Some(default_properties(true)), 308 | }; 309 | let (root_dir_blob, root_dir_digest) = blob(root_dir.encode_to_vec()); 310 | 311 | ( 312 | vec![ 313 | store_dir_blob, 314 | nix_dir_blob, 315 | root_dir_blob, 316 | deriv_blob, 317 | drv_builder_blob, 318 | ], 319 | root_dir_digest, 320 | ) 321 | } 322 | 323 | async fn valid_path_info_from_digest( 324 | bs_client: &mut ByteStreamClient, 325 | digest: &Digest, 326 | ) -> anyhow::Result { 327 | let blob = download_blob(bs_client, digest).await?; 328 | Ok(blob.as_slice().read_nix()?) 329 | } 330 | 331 | // Given a collection of store paths, looks them up in the CAS (using the store-path-to-CA 332 | // mapping we're storing in the action cache) and returns a mapping of all found paths. 333 | async fn lookup_store_paths( 334 | bs_client: &mut ByteStreamClient, 335 | cas_client: &mut ContentAddressableStorageClient, 336 | ac_client: &mut ActionCacheClient, 337 | paths: &[StorePath], 338 | ) -> anyhow::Result> { 339 | let mut digest_map: HashMap<_, _> = paths 340 | .iter() 341 | .map(|path| (path, store_path_action_digest(path.0.to_string().unwrap()))) 342 | .collect(); 343 | 344 | let req = FindMissingBlobsRequest { 345 | instance_name: INSTANCE.to_owned(), 346 | blob_digests: digest_map.values().cloned().collect(), 347 | digest_function: 0, 348 | }; 349 | let missing: HashSet<_> = cas_client 350 | .find_missing_blobs(req) 351 | .await? 352 | .into_inner() 353 | .missing_blob_digests 354 | .into_iter() 355 | .map(|d| d.hash) 356 | .collect(); 357 | 358 | digest_map.retain(|_path, digest| !missing.contains(&digest.hash)); 359 | 360 | let mut ret = HashMap::new(); 361 | for (path, path_digest) in digest_map { 362 | let req = GetActionResultRequest { 363 | instance_name: INSTANCE.to_owned(), 364 | action_digest: Some(path_digest), 365 | inline_stdout: false, 366 | inline_stderr: false, 367 | inline_output_files: vec![], 368 | digest_function: 0, 369 | }; 370 | // TODO: better would be to treat NOT_FOUND specially 371 | let action_result = match ac_client.get_action_result(req).await { 372 | Ok(x) => x.into_inner(), 373 | Err(e) => { 374 | eprintln!("failed to get actionresult: {e}"); 375 | continue; 376 | } 377 | }; 378 | let valid_path_info_file = action_result 379 | .output_files 380 | .iter() 381 | .find(|f| f.path == "valid-path-info") 382 | .expect("huh?"); 383 | let valid_path_info = 384 | valid_path_info_from_digest(bs_client, valid_path_info_file.digest.as_ref().unwrap()) 385 | .await?; 386 | let path_info = if let Some(dir) = action_result.output_directories.first() { 387 | path_info_from_tree( 388 | bs_client, 389 | TypedDigest::new(dir.tree_digest.clone().unwrap()), 390 | ) 391 | .await? 392 | } else if let Some(file) = action_result 393 | .output_files 394 | .iter() 395 | .find(|f| f.path == "store-path") 396 | { 397 | PathInfo::File { 398 | digest: file.digest.clone().unwrap(), 399 | executable: file.is_executable, 400 | } 401 | } else { 402 | panic!("what?"); 403 | }; 404 | ret.insert(path.clone(), (path_info, valid_path_info)); 405 | } 406 | Ok(ret) 407 | } 408 | 409 | fn store_path_action_digest(store_path: String) -> Digest { 410 | let cmd = Command { 411 | arguments: vec![store_path], 412 | output_paths: vec!["store-path".into()], 413 | ..Default::default() 414 | }; 415 | let cmd_digest = digest(&cmd.encode_to_vec()); 416 | 417 | let action = Action { 418 | command_digest: Some(cmd_digest), 419 | ..Default::default() 420 | }; 421 | digest(&action.encode_to_vec()) 422 | } 423 | 424 | // Use this when the store path has already been uploaded to the CAS. root_digest is the digest of the store path's root directory 425 | // (well, not actually the store path's root directory: it points at a directory called "nix", which contains "store" etc) 426 | async fn add_store_path( 427 | ac_client: &mut ActionCacheClient, 428 | bs_client: &mut ByteStreamClient, 429 | store_path: String, 430 | path_info: ValidPathInfo, 431 | info: PathInfo, 432 | ) -> anyhow::Result<()> { 433 | let cmd = Command { 434 | arguments: vec![store_path], 435 | output_paths: vec!["store-path".into()], 436 | ..Default::default() 437 | }; 438 | let cmd_digest = upload_proto(bs_client, &cmd).await?; 439 | 440 | let action = Action { 441 | command_digest: Some(cmd_digest.0), 442 | ..Default::default() 443 | }; 444 | let action_digest = upload_proto(bs_client, &action).await?; 445 | 446 | let mut path_info_data = Vec::new(); 447 | path_info_data.write_nix(&path_info)?; 448 | let valid_path_info_digest = upload_proto_untyped(bs_client, path_info_data).await?; 449 | let valid_path_info_file = OutputFile { 450 | path: "valid-path-info".into(), 451 | digest: Some(valid_path_info_digest), 452 | is_executable: false, 453 | contents: vec![], 454 | node_properties: None, 455 | }; 456 | 457 | let (output_files, output_directories) = match info { 458 | PathInfo::File { executable, digest } => ( 459 | vec![ 460 | OutputFile { 461 | path: "store-path".into(), 462 | digest: Some(digest.clone()), 463 | is_executable: executable, 464 | contents: vec![], 465 | node_properties: None, 466 | }, 467 | valid_path_info_file, 468 | ], 469 | vec![], 470 | ), 471 | PathInfo::Directory { 472 | tree_digest, 473 | root_digest, 474 | } => ( 475 | vec![valid_path_info_file], 476 | vec![OutputDirectory { 477 | path: "store-path".into(), 478 | tree_digest: Some(tree_digest.0.clone()), 479 | is_topologically_sorted: false, 480 | root_directory_digest: Some(root_digest.0.clone()), 481 | }], 482 | ), 483 | }; 484 | 485 | let action_result = ActionResult { 486 | output_files, 487 | output_directories, 488 | execution_metadata: Some(ExecutedActionMetadata { 489 | worker: "Nix store upload".to_owned(), 490 | ..Default::default() 491 | }), 492 | ..Default::default() 493 | }; 494 | 495 | let req = UpdateActionResultRequest { 496 | instance_name: "my-instance".to_owned(), 497 | action_digest: Some(action_digest.0.clone()), 498 | action_result: Some(action_result), 499 | results_cache_policy: None, 500 | digest_function: 0, 501 | }; 502 | 503 | ac_client.update_action_result(req).await?; 504 | 505 | Ok(()) 506 | } 507 | 508 | #[derive(Debug)] 509 | struct BuiltPath { 510 | deriver: StorePath, 511 | registration_time: u64, 512 | build_metadata: Digest, 513 | info: PathInfo, 514 | } 515 | 516 | #[tokio::main] 517 | async fn main() -> anyhow::Result<()> { 518 | let channel = Endpoint::from_static("http://localhost:8980") 519 | .connect() 520 | .await 521 | .unwrap(); 522 | let mut exec_client = ExecutionClient::new(channel.clone()); 523 | let mut ac_client = ActionCacheClient::new(channel.clone()); 524 | let mut bs_client = ByteStreamClient::new(channel.clone()); 525 | let mut cas_client = ContentAddressableStorageClient::new(channel); 526 | eprintln!("Connected to CAS"); 527 | 528 | let mut nix = NixProxy::new(std::io::stdin(), std::io::stdout()); 529 | eprintln!("Preparing for handshake"); 530 | let v = nix.handshake()?; 531 | eprintln!("got version {v}"); 532 | nix.write.inner.write_nix(&stderr::Msg::Last(()))?; 533 | nix.write.inner.flush()?; 534 | 535 | while let Some(op) = nix.next_op()? { 536 | eprintln!("read op {op:?}"); 537 | match op { 538 | WorkerOp::QueryValidPaths(op, resp) => { 539 | dbg!(&op); 540 | let found_paths = lookup_store_paths( 541 | &mut bs_client, 542 | &mut cas_client, 543 | &mut ac_client, 544 | &op.paths.paths, 545 | ) 546 | .await?; 547 | dbg!(&found_paths); 548 | 549 | let reply = resp.ty(StorePathSet { 550 | paths: found_paths.into_keys().collect(), 551 | }); 552 | nix.write.inner.write_nix(&stderr::Msg::Last(()))?; 553 | nix.write.inner.write_nix(&reply)?; 554 | nix.write.inner.flush()?; 555 | } 556 | WorkerOp::QueryPathInfo(path, resp) => { 557 | let found_paths = lookup_store_paths( 558 | &mut bs_client, 559 | &mut cas_client, 560 | &mut ac_client, 561 | &[path.0.clone()], 562 | ) 563 | .await?; 564 | dbg!(&path, &found_paths); 565 | 566 | let Some((_, valid_path_info)) = found_paths.get(&path) else { 567 | panic!("didn't know about path {}", path.0 .0.to_string().unwrap()); 568 | }; 569 | 570 | let reply = resp.ty(QueryPathInfoResponse { 571 | path: Some(valid_path_info.clone()), 572 | }); 573 | nix.write.inner.write_nix(&stderr::Msg::Last(()))?; 574 | nix.write.inner.write_nix(&reply)?; 575 | nix.write.inner.flush()?; 576 | } 577 | WorkerOp::AddMultipleToStore(_op, _) => { 578 | let framed = FramedData::read(&mut nix.read.inner)?; 579 | let buf = framed.data.into_iter().fold(Vec::new(), |mut acc, data| { 580 | acc.extend_from_slice(&data); 581 | acc 582 | }); 583 | let data: AddMultipleToStoreData = Cursor::new(buf).read_nix()?; 584 | for (path, nar) in data.data { 585 | let (blobs, root_info) = convert(&nar); 586 | for blob in blobs { 587 | upload_blob(&mut bs_client, blob).await?; 588 | } 589 | add_store_path( 590 | &mut ac_client, 591 | &mut bs_client, 592 | path.path.0.to_string().unwrap(), 593 | path.info, 594 | root_info, 595 | ) 596 | .await?; 597 | } 598 | nix.write.inner.write_nix(&stderr::Msg::Last(()))?; 599 | nix.write.inner.write_nix(&())?; 600 | nix.write.inner.flush()?; 601 | } 602 | WorkerOp::BuildDerivation(op, _resp) => { 603 | dbg!(&op); 604 | let store_path_map = lookup_store_paths( 605 | &mut bs_client, 606 | &mut cas_client, 607 | &mut ac_client, 608 | &op.0.derivation.input_sources.paths, 609 | ) 610 | .await?; 611 | let store_path_map = store_path_map.into_iter().map(|(k, v)| (k, v.0)).collect(); 612 | let (blobs, input_digest) = build_input_root(&store_path_map, &op.0.derivation); 613 | for blob in blobs { 614 | upload_blob(&mut bs_client, blob).await?; 615 | } 616 | 617 | let cmd = Command { 618 | arguments: vec!["./drv-adapter".to_owned()], 619 | environment_variables: vec![], 620 | output_files: vec![], 621 | output_directories: vec![], 622 | output_paths: op 623 | .0 624 | .derivation 625 | .outputs 626 | .iter() 627 | .map(|out| out.1.store_path.0.to_string().unwrap()[1..].to_owned()) 628 | .chain(std::iter::once(METADATA_PATH.to_owned())) 629 | .collect(), 630 | platform: None, 631 | working_directory: "".to_owned(), 632 | output_node_properties: vec![], 633 | output_directory_format: OutputDirectoryFormat::TreeAndDirectory.into(), 634 | }; 635 | let (cmd_blob, cmd_digest) = blob(cmd.encode_to_vec()); 636 | upload_blob(&mut bs_client, cmd_blob).await?; 637 | 638 | let action = Action { 639 | command_digest: Some(cmd_digest), 640 | input_root_digest: Some(input_digest), 641 | timeout: None, 642 | do_not_cache: false, 643 | salt: "salt".as_bytes().to_owned(), 644 | platform: None, 645 | }; 646 | 647 | let (action_blob, action_digest) = blob(action.encode_to_vec()); 648 | dbg!(&action_digest); 649 | upload_blob(&mut bs_client, action_blob).await?; 650 | 651 | let req = ExecuteRequest { 652 | instance_name: "hardlinking".to_string(), 653 | skip_cache_lookup: true, 654 | action_digest: Some(action_digest), 655 | execution_policy: None, 656 | results_cache_policy: None, 657 | digest_function: 0, 658 | inline_stdout: false, 659 | inline_stderr: false, 660 | inline_output_files: vec![], 661 | }; 662 | 663 | let mut results = exec_client.execute(req).await?.into_inner(); 664 | let mut last_op = None; 665 | while let Some(op) = results.next().await.transpose()? { 666 | if op.done { 667 | last_op = op.result; 668 | break; 669 | } 670 | } 671 | match last_op.unwrap() { 672 | generated::google::longrunning::operation::Result::Error(e) => { 673 | panic!("{:?}", e) 674 | } 675 | generated::google::longrunning::operation::Result::Response(resp) => { 676 | assert_eq!( 677 | resp.type_url, 678 | "type.googleapis.com/build.bazel.remote.execution.v2.ExecuteResponse" 679 | ); 680 | let resp = ExecuteResponse::decode(resp.value.as_ref())?; 681 | let action_result = resp.result.unwrap(); 682 | dbg!(&action_result); 683 | 684 | if action_result.exit_code != 0 { 685 | panic!(); 686 | } 687 | 688 | let (start_time, stop_time) = action_result 689 | .execution_metadata 690 | .and_then(|m| { 691 | m.worker_start_timestamp.zip(m.worker_completed_timestamp) 692 | }) 693 | .unwrap_or_default(); 694 | 695 | let metadata_digest = action_result 696 | .output_files 697 | .iter() 698 | .find(|file| file.path == METADATA_PATH) 699 | .unwrap() 700 | .digest 701 | .as_ref() 702 | .unwrap(); 703 | 704 | for output in op.0.derivation.outputs { 705 | let output_store_path = output.1.store_path.0.to_string().unwrap(); 706 | let output_store_path_without_slash: &[u8] = 707 | &output.1.store_path.as_ref()[1..]; 708 | let info = if let Some(dir) = action_result 709 | .output_directories 710 | .iter() 711 | .find(|d| d.path.as_bytes() == output_store_path_without_slash) 712 | { 713 | path_info_from_tree( 714 | &mut bs_client, 715 | TypedDigest::new(dir.tree_digest.clone().unwrap()), 716 | ) 717 | .await? 718 | } else { 719 | let file = action_result 720 | .output_files 721 | .iter() 722 | .find(|f| f.path.as_bytes() == output_store_path_without_slash) 723 | .unwrap(); 724 | PathInfo::File { 725 | digest: file.digest.clone().unwrap(), 726 | executable: file.is_executable, 727 | } 728 | }; 729 | let metadata_blob = download_blob(&mut bs_client, metadata_digest) 730 | .await 731 | .unwrap(); 732 | let metadata: BuildMetadata = 733 | bincode::deserialize(&metadata_blob).unwrap(); 734 | dbg!(&metadata); 735 | 736 | let OutputMetadata { 737 | references, 738 | nar_hash, 739 | nar_size, 740 | } = metadata.metadata.get(&output.1.store_path.0).unwrap(); 741 | 742 | let valid_path_info = ValidPathInfo { 743 | deriver: op.0.store_path.clone(), 744 | hash: NarHash::from_bytes(nar_hash.as_ref()), 745 | references: StorePathSet { 746 | paths: references.clone(), 747 | }, 748 | registration_time: stop_time.seconds as u64, 749 | nar_size: *nar_size as u64, 750 | ultimate: true, 751 | sigs: nix_remote::StringSet { paths: vec![] }, 752 | content_address: NixString::default(), 753 | }; 754 | 755 | add_store_path( 756 | &mut ac_client, 757 | &mut bs_client, 758 | output_store_path.clone(), 759 | valid_path_info, 760 | info.clone(), 761 | ) 762 | .await?; 763 | } 764 | 765 | let resp = BuildResult { 766 | status: nix_remote::worker_op::BuildStatus::Built, 767 | error_msg: NixString::default(), 768 | times_built: 1, 769 | is_non_deterministic: false, 770 | start_time: start_time.seconds as u64, // FIXME 771 | stop_time: stop_time.seconds as u64, 772 | built_outputs: DrvOutputs(vec![]), 773 | }; 774 | 775 | if let Some(stderr_digest) = action_result.stderr_digest { 776 | // TODO: stream this instead of sending all at once 777 | let stderr = download_blob(&mut bs_client, &stderr_digest).await?; 778 | nix.write 779 | .inner 780 | .write_nix(&stderr::Msg::Next(stderr.into()))?; 781 | } 782 | nix.write.inner.write_nix(&stderr::Msg::Last(()))?; 783 | nix.write.inner.write_nix(&resp)?; 784 | nix.write.inner.flush()?; 785 | } 786 | } 787 | } 788 | WorkerOp::NarFromPath(op, _resp) => { 789 | let found_paths = lookup_store_paths( 790 | &mut bs_client, 791 | &mut cas_client, 792 | &mut ac_client, 793 | &[op.clone().0], 794 | ) 795 | .await?; 796 | 797 | let info = &found_paths.get(&op).unwrap().0; 798 | 799 | let nar = match info { 800 | PathInfo::File { executable, digest } => { 801 | let file_contents = download_blob(&mut bs_client, digest).await?; 802 | Nar::Contents(NarFile { 803 | contents: file_contents.into(), 804 | executable: *executable, 805 | }) 806 | } 807 | PathInfo::Directory { tree_digest, .. } => { 808 | let tree: Tree = download_proto(&mut bs_client, tree_digest).await.unwrap(); 809 | 810 | let flattened = flatten_tree(&tree); 811 | 812 | let mut nar = Nar::default(); 813 | hydrate_nar(&mut bs_client, flattened, &mut nar) 814 | .await 815 | .unwrap(); 816 | 817 | nar 818 | } 819 | }; 820 | nix.write.inner.write_nix(&stderr::Msg::Last(()))?; 821 | 822 | nix.write.inner.write_nix(&nar)?; 823 | 824 | nix.write.inner.flush()?; 825 | } 826 | _ => { 827 | panic!("ignoring op"); 828 | } 829 | } 830 | eprintln!("done with op"); 831 | } 832 | 833 | Ok(()) 834 | } 835 | 836 | // String is the hash of a digest 837 | fn digest_directory_map(tree: &Tree) -> HashMap { 838 | tree.children 839 | .iter() 840 | .chain(tree.root.as_ref()) 841 | .map(|dir| { 842 | let msg = dir.encode_to_vec(); 843 | let digest = digest(&msg); 844 | (digest.hash, dir.clone()) 845 | }) 846 | .collect() 847 | } 848 | 849 | // HACK: the returned thing isn't the real nar, but the file "contents" are replaced by some serialized digest. 850 | fn flatten_tree(tree: &Tree) -> Nar { 851 | let dirs = digest_directory_map(tree); 852 | let mut nar = Nar::default(); 853 | let root = (&mut nar).become_directory(); 854 | 855 | fn flatten_tree_rec<'a>( 856 | dir: &Directory, 857 | dirs: &HashMap, 858 | mut sink: impl DirectorySink<'a>, 859 | ) { 860 | for entry in &dir.files { 861 | let mut file = sink.create_entry(entry.name.clone().into()).become_file(); 862 | let digest = entry.digest.as_ref().unwrap(); 863 | file.set_executable(entry.is_executable); 864 | file.add_contents(format!("{}-{}", digest.hash, digest.size_bytes).as_bytes()); 865 | } 866 | 867 | for entry in &dir.symlinks { 868 | sink.create_entry(entry.name.clone().into()) 869 | .become_symlink(entry.target.clone().into()); 870 | } 871 | 872 | for entry in &dir.directories { 873 | let dir_sink = sink 874 | .create_entry(entry.name.clone().into()) 875 | .become_directory(); 876 | let dir = dirs 877 | .get(&entry.digest.as_ref().unwrap().hash) 878 | .expect("some hash wasn't in our list"); 879 | flatten_tree_rec(dir, dirs, dir_sink); 880 | } 881 | } 882 | 883 | flatten_tree_rec(tree.root.as_ref().unwrap(), &dirs, root); 884 | 885 | nar.sort(); 886 | nar 887 | } 888 | 889 | fn hydrate_nar<'a, 'b: 'a>( 890 | bs_client: &'b mut ByteStreamClient, 891 | fake_nar: Nar, 892 | sink: impl EntrySink<'a>, 893 | ) -> Pin> + 'a>> { 894 | Box::pin(async { 895 | match fake_nar { 896 | Nar::Contents(NarFile { 897 | contents, 898 | executable, 899 | }) => { 900 | let mut sink = sink.become_file(); 901 | sink.set_executable(executable); 902 | 903 | let contents = contents.to_string()?; 904 | let (hash, size_str) = contents 905 | .rsplit_once('-') 906 | .ok_or(anyhow!("invalid digest format"))?; 907 | let digest = Digest { 908 | hash: hash.to_string(), 909 | size_bytes: size_str.parse()?, 910 | }; 911 | let req = blob_request(&digest); 912 | let mut resp = bs_client.read(req).await?.into_inner(); 913 | while let Some(next) = resp.next().await { 914 | let next = next?; 915 | sink.add_contents(&next.data); 916 | } 917 | } 918 | Nar::Target(target) => sink.become_symlink(target), 919 | Nar::Directory(entries) => { 920 | let mut sink = sink.become_directory(); 921 | for NarDirectoryEntry { name, node } in entries { 922 | hydrate_nar(bs_client, node, sink.create_entry(name)).await?; 923 | } 924 | } 925 | } 926 | Ok(()) 927 | }) 928 | } 929 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "fenix": { 4 | "inputs": { 5 | "nixpkgs": "nixpkgs", 6 | "rust-analyzer-src": "rust-analyzer-src" 7 | }, 8 | "locked": { 9 | "lastModified": 1702362203, 10 | "narHash": "sha256-etsSWZfvmVA9RWqixmoKTf+JLEMtjlOaLxh/tK80ZCg=", 11 | "owner": "nix-community", 12 | "repo": "fenix", 13 | "rev": "7622e4a2d4378861d9e83fc02c1eeb0e084bf3f2", 14 | "type": "github" 15 | }, 16 | "original": { 17 | "owner": "nix-community", 18 | "repo": "fenix", 19 | "type": "github" 20 | } 21 | }, 22 | "flake-utils": { 23 | "inputs": { 24 | "systems": "systems" 25 | }, 26 | "locked": { 27 | "lastModified": 1701680307, 28 | "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", 29 | "owner": "numtide", 30 | "repo": "flake-utils", 31 | "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", 32 | "type": "github" 33 | }, 34 | "original": { 35 | "owner": "numtide", 36 | "repo": "flake-utils", 37 | "type": "github" 38 | } 39 | }, 40 | "nixpkgs": { 41 | "locked": { 42 | "lastModified": 1702151865, 43 | "narHash": "sha256-9VAt19t6yQa7pHZLDbil/QctAgVsA66DLnzdRGqDisg=", 44 | "owner": "nixos", 45 | "repo": "nixpkgs", 46 | "rev": "666fc80e7b2afb570462423cb0e1cf1a3a34fedd", 47 | "type": "github" 48 | }, 49 | "original": { 50 | "owner": "nixos", 51 | "ref": "nixos-unstable", 52 | "repo": "nixpkgs", 53 | "type": "github" 54 | } 55 | }, 56 | "nixpkgs_2": { 57 | "locked": { 58 | "lastModified": 1702151865, 59 | "narHash": "sha256-9VAt19t6yQa7pHZLDbil/QctAgVsA66DLnzdRGqDisg=", 60 | "owner": "NixOS", 61 | "repo": "nixpkgs", 62 | "rev": "666fc80e7b2afb570462423cb0e1cf1a3a34fedd", 63 | "type": "github" 64 | }, 65 | "original": { 66 | "owner": "NixOS", 67 | "ref": "nixos-unstable", 68 | "repo": "nixpkgs", 69 | "type": "github" 70 | } 71 | }, 72 | "root": { 73 | "inputs": { 74 | "fenix": "fenix", 75 | "flake-utils": "flake-utils", 76 | "nixpkgs": "nixpkgs_2", 77 | "unstable": "unstable" 78 | } 79 | }, 80 | "rust-analyzer-src": { 81 | "flake": false, 82 | "locked": { 83 | "lastModified": 1702322912, 84 | "narHash": "sha256-CtQtHdJp6naa5xtMmrkNwZx0aVq4215RtWw5/f7l0zw=", 85 | "owner": "rust-lang", 86 | "repo": "rust-analyzer", 87 | "rev": "8c3e28e3e2d4f190b633fbd43d689b45b28b5598", 88 | "type": "github" 89 | }, 90 | "original": { 91 | "owner": "rust-lang", 92 | "ref": "nightly", 93 | "repo": "rust-analyzer", 94 | "type": "github" 95 | } 96 | }, 97 | "systems": { 98 | "locked": { 99 | "lastModified": 1681028828, 100 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 101 | "owner": "nix-systems", 102 | "repo": "default", 103 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 104 | "type": "github" 105 | }, 106 | "original": { 107 | "owner": "nix-systems", 108 | "repo": "default", 109 | "type": "github" 110 | } 111 | }, 112 | "unstable": { 113 | "locked": { 114 | "lastModified": 1702151865, 115 | "narHash": "sha256-9VAt19t6yQa7pHZLDbil/QctAgVsA66DLnzdRGqDisg=", 116 | "owner": "NixOS", 117 | "repo": "nixpkgs", 118 | "rev": "666fc80e7b2afb570462423cb0e1cf1a3a34fedd", 119 | "type": "github" 120 | }, 121 | "original": { 122 | "id": "nixpkgs", 123 | "ref": "nixos-unstable", 124 | "type": "indirect" 125 | } 126 | } 127 | }, 128 | "root": "root", 129 | "version": 7 130 | } 131 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A basic rust devshell"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | fenix.url = "github:nix-community/fenix"; 7 | flake-utils.url = "github:numtide/flake-utils"; 8 | unstable.url = "nixpkgs/nixos-unstable"; 9 | }; 10 | 11 | outputs = { self, nixpkgs, fenix, flake-utils, unstable, ... }: 12 | flake-utils.lib.eachDefaultSystem (system: 13 | let 14 | overlays = [ fenix.overlays.default ]; 15 | pkgs = import nixpkgs { 16 | inherit system overlays; 17 | }; 18 | rust-toolchain = pkgs.fenix.combine [ 19 | pkgs.fenix.stable.defaultToolchain 20 | pkgs.fenix.stable.rust-src 21 | pkgs.fenix.stable.rust-analyzer 22 | pkgs.fenix.targets.x86_64-unknown-linux-musl.stable.rust-std 23 | ]; 24 | in 25 | with pkgs; 26 | rec { 27 | devShells.default = mkShell { 28 | buildInputs = [ 29 | rust-toolchain 30 | cargo-expand 31 | protobuf 32 | grpcurl 33 | ]; 34 | 35 | shellHook = '' 36 | alias ls=exa 37 | alias find=fd 38 | ''; 39 | }; 40 | 41 | packages.test = pkgs.stdenv.mkDerivation { 42 | pname = "test"; 43 | version = "0.0.1"; 44 | #src = ./.; 45 | dontUnpack = true; 46 | 47 | 48 | installPhase = '' 49 | mkdir -p $out 50 | echo ${builtins.toString builtins.currentTime} >> $out/out.txt 51 | echo "${pkgs.bash}" >> $out/hi.txt 52 | mkdir -p $out/subdir/again 53 | echo "hi" >> $out/subdir/again/file.txt 54 | ''; 55 | }; 56 | 57 | packages.test-file = pkgs.stdenv.mkDerivation { 58 | pname = "test-file"; 59 | version = "0.0.1"; 60 | src = ./.; 61 | 62 | installPhase = '' 63 | cat ${self.packages.x86_64-linux.test}/hi.txt 64 | echo "Hello" >&2 65 | echo ${builtins.toString builtins.currentTime} >> $out 66 | echo "World" >&2 67 | chmod +x $out 68 | echo "on stdout" 69 | ''; 70 | }; 71 | 72 | packages.test-slow = pkgs.stdenv.mkDerivation { 73 | pname = "test-slow"; 74 | version = "0.0.1"; 75 | #src = ./.; 76 | dontUnpack = true; 77 | 78 | installPhase = '' 79 | echo "Hello" >&2 80 | echo "World" >&2 81 | echo not the current time > $out 82 | chmod +x $out 83 | echo "on stdout and sleeping" 84 | sleep 5 85 | echo "Done sleeping" 86 | ''; 87 | }; 88 | 89 | packages.test-deps = pkgs.stdenv.mkDerivation { 90 | pname = "test-deps"; 91 | version = "0.0.1"; 92 | dontUnpack = true; 93 | 94 | installPhase = '' 95 | mkdir -p "$out" 96 | echo 'hello' > $out/hello.txt 97 | ''; 98 | 99 | }; 100 | 101 | 102 | packages.test-depends = pkgs.stdenv.mkDerivation { 103 | pname = "test-depends"; 104 | version = "0.0.1"; 105 | dontUnpack = true; 106 | 107 | installPhase = '' 108 | mkdir -p "$out" 109 | cat "${packages.test-deps}/hello.txt" > $out/hello.txt 110 | echo ' deps' >> $out/hello.txt 111 | ''; 112 | }; 113 | } 114 | ); 115 | } 116 | -------------------------------------------------------------------------------- /generator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generator" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = { version = "4.4.11", features = ["derive"] } 10 | prost-build = "0.12.3" 11 | tonic-build = "0.10.2" 12 | -------------------------------------------------------------------------------- /generator/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut config = prost_build::Config::new(); 3 | config.out_dir("out"); 4 | std::fs::create_dir_all("out").unwrap(); 5 | 6 | tonic_build::configure() 7 | .build_client(true) 8 | .build_server(false) 9 | .out_dir("out") 10 | .compile_with_config( 11 | config, 12 | &[ 13 | "build/bazel/remote/execution/v2/remote_execution.proto", 14 | "google/bytestream/bytestream.proto", 15 | ], 16 | &["proto/remote-apis", "proto/googleapis-master"], 17 | ) 18 | .unwrap(); 19 | } 20 | -------------------------------------------------------------------------------- /remote-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # A hacky script to test the BuildDerivation worker op, which only activates on distributed builds. 4 | # You'll have to change the hardcoded paths to your own home directory. 5 | 6 | cd crates/drv-adapter && cargo build && cd ../.. 7 | cargo build 8 | 9 | TEST_ROOT=/home/jneeman/tweag/nix-rev2/test-remote-store 10 | 11 | #builder="ssh-ng://localhost?remote-store=$TEST_ROOT/remote?remote-program=/home/jneeman/tweag/nix-remote-rust/nix-remote-rust.sh - - 1 1 foo" 12 | builder="ssh-ng://localhost?remote-program=/home/jneeman/tweag/nix-rev2/nix-remote-rust.sh - - 1 1 foo" 13 | 14 | #chmod -R +w $TEST_ROOT/remote || true 15 | rm -rf $TEST_ROOT/remote/* || true 16 | chmod -R +w $TEST_ROOT/local || true 17 | rm -rf $TEST_ROOT/local/* || true 18 | 19 | nix build -L -v -o result --max-jobs 0 \ 20 | --builders-use-substitutes \ 21 | .#test-deps \ 22 | --store $TEST_ROOT/local \ 23 | --builders "$builder" --impure 24 | 25 | nix build -L -v -o result --max-jobs 0 \ 26 | --builders-use-substitutes \ 27 | .#test-depends \ 28 | --store $TEST_ROOT/local \ 29 | --builders "$builder" --impure 30 | #.#test \ 31 | #--expr '(builtins.getFlake "nixpkgs").legacyPackages.${builtins.currentSystem}.writeText "current-time" "${builtins.toString builtins.currentTime}"' \ 32 | 33 | --------------------------------------------------------------------------------