├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── default.nix ├── shell.nix └── src ├── lib.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | small/** 3 | .envrc 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ansi_term" 5 | version = "0.11.0" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 8 | dependencies = [ 9 | "winapi", 10 | ] 11 | 12 | [[package]] 13 | name = "atty" 14 | version = "0.2.14" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 17 | dependencies = [ 18 | "hermit-abi", 19 | "libc", 20 | "winapi", 21 | ] 22 | 23 | [[package]] 24 | name = "autocfg" 25 | version = "1.0.1" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 28 | 29 | [[package]] 30 | name = "base64" 31 | version = "0.13.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 34 | 35 | [[package]] 36 | name = "bitflags" 37 | version = "1.2.1" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 40 | 41 | [[package]] 42 | name = "block-buffer" 43 | version = "0.9.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 46 | dependencies = [ 47 | "generic-array", 48 | ] 49 | 50 | [[package]] 51 | name = "bumpalo" 52 | version = "3.4.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" 55 | 56 | [[package]] 57 | name = "bytes" 58 | version = "0.5.6" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" 61 | 62 | [[package]] 63 | name = "bytes" 64 | version = "1.0.1" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" 67 | 68 | [[package]] 69 | name = "cc" 70 | version = "1.0.61" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" 73 | 74 | [[package]] 75 | name = "cfg-if" 76 | version = "0.1.10" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 79 | 80 | [[package]] 81 | name = "cfg-if" 82 | version = "1.0.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 85 | 86 | [[package]] 87 | name = "clap" 88 | version = "2.33.3" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 91 | dependencies = [ 92 | "ansi_term", 93 | "atty", 94 | "bitflags", 95 | "strsim", 96 | "textwrap", 97 | "unicode-width", 98 | "vec_map", 99 | ] 100 | 101 | [[package]] 102 | name = "console" 103 | version = "0.13.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "a50aab2529019abfabfa93f1e6c41ef392f91fbf179b347a7e96abb524884a08" 106 | dependencies = [ 107 | "encode_unicode", 108 | "lazy_static", 109 | "libc", 110 | "regex", 111 | "terminal_size", 112 | "unicode-width", 113 | "winapi", 114 | "winapi-util", 115 | ] 116 | 117 | [[package]] 118 | name = "core-foundation" 119 | version = "0.7.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" 122 | dependencies = [ 123 | "core-foundation-sys", 124 | "libc", 125 | ] 126 | 127 | [[package]] 128 | name = "core-foundation-sys" 129 | version = "0.7.0" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" 132 | 133 | [[package]] 134 | name = "cpuid-bool" 135 | version = "0.1.2" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" 138 | 139 | [[package]] 140 | name = "digest" 141 | version = "0.9.0" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 144 | dependencies = [ 145 | "generic-array", 146 | ] 147 | 148 | [[package]] 149 | name = "encode_unicode" 150 | version = "0.3.6" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 153 | 154 | [[package]] 155 | name = "encoding_rs" 156 | version = "0.8.24" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "a51b8cf747471cb9499b6d59e59b0444f4c90eba8968c4e44874e92b5b64ace2" 159 | dependencies = [ 160 | "cfg-if 0.1.10", 161 | ] 162 | 163 | [[package]] 164 | name = "eyre" 165 | version = "0.6.5" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b" 168 | dependencies = [ 169 | "indenter", 170 | "once_cell", 171 | ] 172 | 173 | [[package]] 174 | name = "fnv" 175 | version = "1.0.7" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 178 | 179 | [[package]] 180 | name = "foreign-types" 181 | version = "0.3.2" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 184 | dependencies = [ 185 | "foreign-types-shared", 186 | ] 187 | 188 | [[package]] 189 | name = "foreign-types-shared" 190 | version = "0.1.1" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 193 | 194 | [[package]] 195 | name = "form_urlencoded" 196 | version = "1.0.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" 199 | dependencies = [ 200 | "matches", 201 | "percent-encoding", 202 | ] 203 | 204 | [[package]] 205 | name = "futures" 206 | version = "0.3.12" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" 209 | dependencies = [ 210 | "futures-channel", 211 | "futures-core", 212 | "futures-executor", 213 | "futures-io", 214 | "futures-sink", 215 | "futures-task", 216 | "futures-util", 217 | ] 218 | 219 | [[package]] 220 | name = "futures-channel" 221 | version = "0.3.12" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" 224 | dependencies = [ 225 | "futures-core", 226 | "futures-sink", 227 | ] 228 | 229 | [[package]] 230 | name = "futures-core" 231 | version = "0.3.12" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" 234 | 235 | [[package]] 236 | name = "futures-executor" 237 | version = "0.3.12" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" 240 | dependencies = [ 241 | "futures-core", 242 | "futures-task", 243 | "futures-util", 244 | ] 245 | 246 | [[package]] 247 | name = "futures-io" 248 | version = "0.3.12" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" 251 | 252 | [[package]] 253 | name = "futures-macro" 254 | version = "0.3.12" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" 257 | dependencies = [ 258 | "proc-macro-hack", 259 | "proc-macro2", 260 | "quote", 261 | "syn", 262 | ] 263 | 264 | [[package]] 265 | name = "futures-sink" 266 | version = "0.3.12" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" 269 | 270 | [[package]] 271 | name = "futures-task" 272 | version = "0.3.12" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" 275 | dependencies = [ 276 | "once_cell", 277 | ] 278 | 279 | [[package]] 280 | name = "futures-util" 281 | version = "0.3.12" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" 284 | dependencies = [ 285 | "futures-channel", 286 | "futures-core", 287 | "futures-io", 288 | "futures-macro", 289 | "futures-sink", 290 | "futures-task", 291 | "memchr", 292 | "pin-project-lite 0.2.4", 293 | "pin-utils", 294 | "proc-macro-hack", 295 | "proc-macro-nested", 296 | "slab", 297 | ] 298 | 299 | [[package]] 300 | name = "generic-array" 301 | version = "0.14.4" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 304 | dependencies = [ 305 | "typenum", 306 | "version_check", 307 | ] 308 | 309 | [[package]] 310 | name = "getrandom" 311 | version = "0.2.2" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 314 | dependencies = [ 315 | "cfg-if 1.0.0", 316 | "libc", 317 | "wasi", 318 | ] 319 | 320 | [[package]] 321 | name = "h2" 322 | version = "0.3.0" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" 325 | dependencies = [ 326 | "bytes 1.0.1", 327 | "fnv", 328 | "futures-core", 329 | "futures-sink", 330 | "futures-util", 331 | "http", 332 | "indexmap", 333 | "slab", 334 | "tokio", 335 | "tokio-util", 336 | "tracing", 337 | "tracing-futures", 338 | ] 339 | 340 | [[package]] 341 | name = "hashbrown" 342 | version = "0.9.1" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 345 | 346 | [[package]] 347 | name = "heck" 348 | version = "0.3.1" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 351 | dependencies = [ 352 | "unicode-segmentation", 353 | ] 354 | 355 | [[package]] 356 | name = "hermit-abi" 357 | version = "0.1.17" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" 360 | dependencies = [ 361 | "libc", 362 | ] 363 | 364 | [[package]] 365 | name = "http" 366 | version = "0.2.1" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" 369 | dependencies = [ 370 | "bytes 0.5.6", 371 | "fnv", 372 | "itoa", 373 | ] 374 | 375 | [[package]] 376 | name = "http-body" 377 | version = "0.4.0" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" 380 | dependencies = [ 381 | "bytes 1.0.1", 382 | "http", 383 | ] 384 | 385 | [[package]] 386 | name = "httparse" 387 | version = "1.3.4" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" 390 | 391 | [[package]] 392 | name = "httpdate" 393 | version = "0.3.2" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" 396 | 397 | [[package]] 398 | name = "hyper" 399 | version = "0.14.4" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7" 402 | dependencies = [ 403 | "bytes 1.0.1", 404 | "futures-channel", 405 | "futures-core", 406 | "futures-util", 407 | "h2", 408 | "http", 409 | "http-body", 410 | "httparse", 411 | "httpdate", 412 | "itoa", 413 | "pin-project 1.0.5", 414 | "socket2", 415 | "tokio", 416 | "tower-service", 417 | "tracing", 418 | "want", 419 | ] 420 | 421 | [[package]] 422 | name = "hyper-tls" 423 | version = "0.5.0" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 426 | dependencies = [ 427 | "bytes 1.0.1", 428 | "hyper", 429 | "native-tls", 430 | "tokio", 431 | "tokio-native-tls", 432 | ] 433 | 434 | [[package]] 435 | name = "idna" 436 | version = "0.2.0" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 439 | dependencies = [ 440 | "matches", 441 | "unicode-bidi", 442 | "unicode-normalization", 443 | ] 444 | 445 | [[package]] 446 | name = "indenter" 447 | version = "0.3.3" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 450 | 451 | [[package]] 452 | name = "indexmap" 453 | version = "1.6.0" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" 456 | dependencies = [ 457 | "autocfg", 458 | "hashbrown", 459 | ] 460 | 461 | [[package]] 462 | name = "indicatif" 463 | version = "0.15.0" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "7baab56125e25686df467fe470785512329883aab42696d661247aca2a2896e4" 466 | dependencies = [ 467 | "console", 468 | "lazy_static", 469 | "number_prefix", 470 | "regex", 471 | ] 472 | 473 | [[package]] 474 | name = "ipnet" 475 | version = "2.3.0" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" 478 | 479 | [[package]] 480 | name = "itoa" 481 | version = "0.4.6" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 484 | 485 | [[package]] 486 | name = "js-sys" 487 | version = "0.3.45" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" 490 | dependencies = [ 491 | "wasm-bindgen", 492 | ] 493 | 494 | [[package]] 495 | name = "lazy_static" 496 | version = "1.4.0" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 499 | 500 | [[package]] 501 | name = "libc" 502 | version = "0.2.80" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" 505 | 506 | [[package]] 507 | name = "log" 508 | version = "0.4.11" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" 511 | dependencies = [ 512 | "cfg-if 0.1.10", 513 | ] 514 | 515 | [[package]] 516 | name = "lzma-sys" 517 | version = "0.1.17" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "bdb4b7c3eddad11d3af9e86c487607d2d2442d185d848575365c4856ba96d619" 520 | dependencies = [ 521 | "cc", 522 | "libc", 523 | "pkg-config", 524 | ] 525 | 526 | [[package]] 527 | name = "matches" 528 | version = "0.1.8" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 531 | 532 | [[package]] 533 | name = "memchr" 534 | version = "2.3.4" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 537 | 538 | [[package]] 539 | name = "mime" 540 | version = "0.3.16" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 543 | 544 | [[package]] 545 | name = "mio" 546 | version = "0.7.7" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" 549 | dependencies = [ 550 | "libc", 551 | "log", 552 | "miow", 553 | "ntapi", 554 | "winapi", 555 | ] 556 | 557 | [[package]] 558 | name = "miow" 559 | version = "0.3.6" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" 562 | dependencies = [ 563 | "socket2", 564 | "winapi", 565 | ] 566 | 567 | [[package]] 568 | name = "native-tls" 569 | version = "0.2.4" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" 572 | dependencies = [ 573 | "lazy_static", 574 | "libc", 575 | "log", 576 | "openssl", 577 | "openssl-probe", 578 | "openssl-sys", 579 | "schannel", 580 | "security-framework", 581 | "security-framework-sys", 582 | "tempfile", 583 | ] 584 | 585 | [[package]] 586 | name = "nix-base32" 587 | version = "0.1.1" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "8548db8274cf1b2b4c093557783f99e9ad64ffdaaa29a6c1af0abc9895c15612" 590 | 591 | [[package]] 592 | name = "nix-mirror" 593 | version = "0.1.0" 594 | dependencies = [ 595 | "eyre", 596 | "futures", 597 | "indicatif", 598 | "nix-base32", 599 | "path-clean", 600 | "reqwest", 601 | "sha2", 602 | "structopt", 603 | "tempfile", 604 | "tokio", 605 | "xz2", 606 | ] 607 | 608 | [[package]] 609 | name = "ntapi" 610 | version = "0.3.6" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 613 | dependencies = [ 614 | "winapi", 615 | ] 616 | 617 | [[package]] 618 | name = "num_cpus" 619 | version = "1.13.0" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 622 | dependencies = [ 623 | "hermit-abi", 624 | "libc", 625 | ] 626 | 627 | [[package]] 628 | name = "number_prefix" 629 | version = "0.3.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a" 632 | 633 | [[package]] 634 | name = "once_cell" 635 | version = "1.4.1" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" 638 | 639 | [[package]] 640 | name = "opaque-debug" 641 | version = "0.3.0" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 644 | 645 | [[package]] 646 | name = "openssl" 647 | version = "0.10.30" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" 650 | dependencies = [ 651 | "bitflags", 652 | "cfg-if 0.1.10", 653 | "foreign-types", 654 | "lazy_static", 655 | "libc", 656 | "openssl-sys", 657 | ] 658 | 659 | [[package]] 660 | name = "openssl-probe" 661 | version = "0.1.2" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" 664 | 665 | [[package]] 666 | name = "openssl-sys" 667 | version = "0.9.58" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" 670 | dependencies = [ 671 | "autocfg", 672 | "cc", 673 | "libc", 674 | "pkg-config", 675 | "vcpkg", 676 | ] 677 | 678 | [[package]] 679 | name = "path-clean" 680 | version = "0.1.0" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd" 683 | 684 | [[package]] 685 | name = "percent-encoding" 686 | version = "2.1.0" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 689 | 690 | [[package]] 691 | name = "pin-project" 692 | version = "0.4.27" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" 695 | dependencies = [ 696 | "pin-project-internal 0.4.27", 697 | ] 698 | 699 | [[package]] 700 | name = "pin-project" 701 | version = "1.0.5" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" 704 | dependencies = [ 705 | "pin-project-internal 1.0.5", 706 | ] 707 | 708 | [[package]] 709 | name = "pin-project-internal" 710 | version = "0.4.27" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" 713 | dependencies = [ 714 | "proc-macro2", 715 | "quote", 716 | "syn", 717 | ] 718 | 719 | [[package]] 720 | name = "pin-project-internal" 721 | version = "1.0.5" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" 724 | dependencies = [ 725 | "proc-macro2", 726 | "quote", 727 | "syn", 728 | ] 729 | 730 | [[package]] 731 | name = "pin-project-lite" 732 | version = "0.1.11" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" 735 | 736 | [[package]] 737 | name = "pin-project-lite" 738 | version = "0.2.4" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" 741 | 742 | [[package]] 743 | name = "pin-utils" 744 | version = "0.1.0" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 747 | 748 | [[package]] 749 | name = "pkg-config" 750 | version = "0.3.19" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 753 | 754 | [[package]] 755 | name = "ppv-lite86" 756 | version = "0.2.9" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" 759 | 760 | [[package]] 761 | name = "proc-macro-error" 762 | version = "1.0.4" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 765 | dependencies = [ 766 | "proc-macro-error-attr", 767 | "proc-macro2", 768 | "quote", 769 | "syn", 770 | "version_check", 771 | ] 772 | 773 | [[package]] 774 | name = "proc-macro-error-attr" 775 | version = "1.0.4" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 778 | dependencies = [ 779 | "proc-macro2", 780 | "quote", 781 | "version_check", 782 | ] 783 | 784 | [[package]] 785 | name = "proc-macro-hack" 786 | version = "0.5.19" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 789 | 790 | [[package]] 791 | name = "proc-macro-nested" 792 | version = "0.1.6" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" 795 | 796 | [[package]] 797 | name = "proc-macro2" 798 | version = "1.0.24" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 801 | dependencies = [ 802 | "unicode-xid", 803 | ] 804 | 805 | [[package]] 806 | name = "quote" 807 | version = "1.0.7" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 810 | dependencies = [ 811 | "proc-macro2", 812 | ] 813 | 814 | [[package]] 815 | name = "rand" 816 | version = "0.8.3" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" 819 | dependencies = [ 820 | "libc", 821 | "rand_chacha", 822 | "rand_core", 823 | "rand_hc", 824 | ] 825 | 826 | [[package]] 827 | name = "rand_chacha" 828 | version = "0.3.0" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" 831 | dependencies = [ 832 | "ppv-lite86", 833 | "rand_core", 834 | ] 835 | 836 | [[package]] 837 | name = "rand_core" 838 | version = "0.6.1" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" 841 | dependencies = [ 842 | "getrandom", 843 | ] 844 | 845 | [[package]] 846 | name = "rand_hc" 847 | version = "0.3.0" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" 850 | dependencies = [ 851 | "rand_core", 852 | ] 853 | 854 | [[package]] 855 | name = "redox_syscall" 856 | version = "0.2.4" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" 859 | dependencies = [ 860 | "bitflags", 861 | ] 862 | 863 | [[package]] 864 | name = "regex" 865 | version = "1.4.1" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b" 868 | dependencies = [ 869 | "regex-syntax", 870 | ] 871 | 872 | [[package]] 873 | name = "regex-syntax" 874 | version = "0.6.20" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c" 877 | 878 | [[package]] 879 | name = "remove_dir_all" 880 | version = "0.5.3" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 883 | dependencies = [ 884 | "winapi", 885 | ] 886 | 887 | [[package]] 888 | name = "reqwest" 889 | version = "0.11.0" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "fd281b1030aa675fb90aa994d07187645bb3c8fc756ca766e7c3070b439de9de" 892 | dependencies = [ 893 | "base64", 894 | "bytes 1.0.1", 895 | "encoding_rs", 896 | "futures-core", 897 | "futures-util", 898 | "http", 899 | "http-body", 900 | "hyper", 901 | "hyper-tls", 902 | "ipnet", 903 | "js-sys", 904 | "lazy_static", 905 | "log", 906 | "mime", 907 | "native-tls", 908 | "percent-encoding", 909 | "pin-project-lite 0.2.4", 910 | "serde", 911 | "serde_urlencoded", 912 | "tokio", 913 | "tokio-native-tls", 914 | "url", 915 | "wasm-bindgen", 916 | "wasm-bindgen-futures", 917 | "web-sys", 918 | "winreg", 919 | ] 920 | 921 | [[package]] 922 | name = "ryu" 923 | version = "1.0.5" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 926 | 927 | [[package]] 928 | name = "schannel" 929 | version = "0.1.19" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 932 | dependencies = [ 933 | "lazy_static", 934 | "winapi", 935 | ] 936 | 937 | [[package]] 938 | name = "security-framework" 939 | version = "0.4.4" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" 942 | dependencies = [ 943 | "bitflags", 944 | "core-foundation", 945 | "core-foundation-sys", 946 | "libc", 947 | "security-framework-sys", 948 | ] 949 | 950 | [[package]] 951 | name = "security-framework-sys" 952 | version = "0.4.3" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" 955 | dependencies = [ 956 | "core-foundation-sys", 957 | "libc", 958 | ] 959 | 960 | [[package]] 961 | name = "serde" 962 | version = "1.0.117" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" 965 | 966 | [[package]] 967 | name = "serde_json" 968 | version = "1.0.59" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" 971 | dependencies = [ 972 | "itoa", 973 | "ryu", 974 | "serde", 975 | ] 976 | 977 | [[package]] 978 | name = "serde_urlencoded" 979 | version = "0.7.0" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" 982 | dependencies = [ 983 | "form_urlencoded", 984 | "itoa", 985 | "ryu", 986 | "serde", 987 | ] 988 | 989 | [[package]] 990 | name = "sha2" 991 | version = "0.9.3" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" 994 | dependencies = [ 995 | "block-buffer", 996 | "cfg-if 1.0.0", 997 | "cpuid-bool", 998 | "digest", 999 | "opaque-debug", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "slab" 1004 | version = "0.4.2" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1007 | 1008 | [[package]] 1009 | name = "socket2" 1010 | version = "0.3.19" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" 1013 | dependencies = [ 1014 | "cfg-if 1.0.0", 1015 | "libc", 1016 | "winapi", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "strsim" 1021 | version = "0.8.0" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1024 | 1025 | [[package]] 1026 | name = "structopt" 1027 | version = "0.3.21" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" 1030 | dependencies = [ 1031 | "clap", 1032 | "lazy_static", 1033 | "structopt-derive", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "structopt-derive" 1038 | version = "0.4.14" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" 1041 | dependencies = [ 1042 | "heck", 1043 | "proc-macro-error", 1044 | "proc-macro2", 1045 | "quote", 1046 | "syn", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "syn" 1051 | version = "1.0.60" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" 1054 | dependencies = [ 1055 | "proc-macro2", 1056 | "quote", 1057 | "unicode-xid", 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "tempfile" 1062 | version = "3.2.0" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 1065 | dependencies = [ 1066 | "cfg-if 1.0.0", 1067 | "libc", 1068 | "rand", 1069 | "redox_syscall", 1070 | "remove_dir_all", 1071 | "winapi", 1072 | ] 1073 | 1074 | [[package]] 1075 | name = "terminal_size" 1076 | version = "0.1.13" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13" 1079 | dependencies = [ 1080 | "libc", 1081 | "winapi", 1082 | ] 1083 | 1084 | [[package]] 1085 | name = "textwrap" 1086 | version = "0.11.0" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1089 | dependencies = [ 1090 | "unicode-width", 1091 | ] 1092 | 1093 | [[package]] 1094 | name = "tinyvec" 1095 | version = "0.3.4" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" 1098 | 1099 | [[package]] 1100 | name = "tokio" 1101 | version = "1.2.0" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a" 1104 | dependencies = [ 1105 | "autocfg", 1106 | "bytes 1.0.1", 1107 | "libc", 1108 | "memchr", 1109 | "mio", 1110 | "num_cpus", 1111 | "pin-project-lite 0.2.4", 1112 | "tokio-macros", 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "tokio-macros" 1117 | version = "1.1.0" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" 1120 | dependencies = [ 1121 | "proc-macro2", 1122 | "quote", 1123 | "syn", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "tokio-native-tls" 1128 | version = "0.3.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 1131 | dependencies = [ 1132 | "native-tls", 1133 | "tokio", 1134 | ] 1135 | 1136 | [[package]] 1137 | name = "tokio-util" 1138 | version = "0.6.3" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b" 1141 | dependencies = [ 1142 | "bytes 1.0.1", 1143 | "futures-core", 1144 | "futures-sink", 1145 | "log", 1146 | "pin-project-lite 0.2.4", 1147 | "tokio", 1148 | ] 1149 | 1150 | [[package]] 1151 | name = "tower-service" 1152 | version = "0.3.0" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" 1155 | 1156 | [[package]] 1157 | name = "tracing" 1158 | version = "0.1.21" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27" 1161 | dependencies = [ 1162 | "cfg-if 0.1.10", 1163 | "pin-project-lite 0.1.11", 1164 | "tracing-core", 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "tracing-core" 1169 | version = "0.1.17" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" 1172 | dependencies = [ 1173 | "lazy_static", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "tracing-futures" 1178 | version = "0.2.4" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" 1181 | dependencies = [ 1182 | "pin-project 0.4.27", 1183 | "tracing", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "try-lock" 1188 | version = "0.2.3" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1191 | 1192 | [[package]] 1193 | name = "typenum" 1194 | version = "1.12.0" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" 1197 | 1198 | [[package]] 1199 | name = "unicode-bidi" 1200 | version = "0.3.4" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1203 | dependencies = [ 1204 | "matches", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "unicode-normalization" 1209 | version = "0.1.13" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" 1212 | dependencies = [ 1213 | "tinyvec", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "unicode-segmentation" 1218 | version = "1.6.0" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 1221 | 1222 | [[package]] 1223 | name = "unicode-width" 1224 | version = "0.1.8" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 1227 | 1228 | [[package]] 1229 | name = "unicode-xid" 1230 | version = "0.2.1" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 1233 | 1234 | [[package]] 1235 | name = "url" 1236 | version = "2.2.0" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" 1239 | dependencies = [ 1240 | "form_urlencoded", 1241 | "idna", 1242 | "matches", 1243 | "percent-encoding", 1244 | ] 1245 | 1246 | [[package]] 1247 | name = "vcpkg" 1248 | version = "0.2.10" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" 1251 | 1252 | [[package]] 1253 | name = "vec_map" 1254 | version = "0.8.2" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1257 | 1258 | [[package]] 1259 | name = "version_check" 1260 | version = "0.9.2" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 1263 | 1264 | [[package]] 1265 | name = "want" 1266 | version = "0.3.0" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1269 | dependencies = [ 1270 | "log", 1271 | "try-lock", 1272 | ] 1273 | 1274 | [[package]] 1275 | name = "wasi" 1276 | version = "0.10.2+wasi-snapshot-preview1" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1279 | 1280 | [[package]] 1281 | name = "wasm-bindgen" 1282 | version = "0.2.68" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" 1285 | dependencies = [ 1286 | "cfg-if 0.1.10", 1287 | "serde", 1288 | "serde_json", 1289 | "wasm-bindgen-macro", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "wasm-bindgen-backend" 1294 | version = "0.2.68" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" 1297 | dependencies = [ 1298 | "bumpalo", 1299 | "lazy_static", 1300 | "log", 1301 | "proc-macro2", 1302 | "quote", 1303 | "syn", 1304 | "wasm-bindgen-shared", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "wasm-bindgen-futures" 1309 | version = "0.4.18" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" 1312 | dependencies = [ 1313 | "cfg-if 0.1.10", 1314 | "js-sys", 1315 | "wasm-bindgen", 1316 | "web-sys", 1317 | ] 1318 | 1319 | [[package]] 1320 | name = "wasm-bindgen-macro" 1321 | version = "0.2.68" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" 1324 | dependencies = [ 1325 | "quote", 1326 | "wasm-bindgen-macro-support", 1327 | ] 1328 | 1329 | [[package]] 1330 | name = "wasm-bindgen-macro-support" 1331 | version = "0.2.68" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" 1334 | dependencies = [ 1335 | "proc-macro2", 1336 | "quote", 1337 | "syn", 1338 | "wasm-bindgen-backend", 1339 | "wasm-bindgen-shared", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "wasm-bindgen-shared" 1344 | version = "0.2.68" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" 1347 | 1348 | [[package]] 1349 | name = "web-sys" 1350 | version = "0.3.45" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" 1353 | dependencies = [ 1354 | "js-sys", 1355 | "wasm-bindgen", 1356 | ] 1357 | 1358 | [[package]] 1359 | name = "winapi" 1360 | version = "0.3.9" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1363 | dependencies = [ 1364 | "winapi-i686-pc-windows-gnu", 1365 | "winapi-x86_64-pc-windows-gnu", 1366 | ] 1367 | 1368 | [[package]] 1369 | name = "winapi-i686-pc-windows-gnu" 1370 | version = "0.4.0" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1373 | 1374 | [[package]] 1375 | name = "winapi-util" 1376 | version = "0.1.5" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1379 | dependencies = [ 1380 | "winapi", 1381 | ] 1382 | 1383 | [[package]] 1384 | name = "winapi-x86_64-pc-windows-gnu" 1385 | version = "0.4.0" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1388 | 1389 | [[package]] 1390 | name = "winreg" 1391 | version = "0.7.0" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" 1394 | dependencies = [ 1395 | "winapi", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "xz2" 1400 | version = "0.1.6" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c" 1403 | dependencies = [ 1404 | "lzma-sys", 1405 | ] 1406 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nix-mirror" 3 | version = "0.1.0" 4 | authors = ["user "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | eyre = "0.6.5" 12 | futures = "0.3.12" 13 | indicatif = "0.15.0" 14 | structopt = "0.3.21" 15 | xz2 = "0.1.6" 16 | path-clean = "0.1.0" 17 | tempfile = "3.2.0" 18 | nix-base32 = "0.1.1" 19 | sha2 = "0.9.3" 20 | 21 | [dependencies.tokio] 22 | version = "1.2.0" 23 | features = [ "fs", "macros", "rt-multi-thread" ] 24 | 25 | [dependencies.reqwest] 26 | version = "0.11" 27 | features = [ "stream" ] 28 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 The sodiumoxide Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nix-mirror: a tool for mirroring nix binary caches 2 | 3 | ## Background 4 | 5 | It is possible to mirror a nix binary cache using the `nix` command line tool using a command sucn as: 6 | 7 | ``` 8 | xzcat store-paths.xz | nix copy --from https://cache.nixos.org --to file:///path/to/where/the/mirror/should/end/up 9 | ``` 10 | 11 | where store-paths.xz is a file containing the store-paths of all binaries in 12 | the cache, e.g. https://channels.nixos.org/nixos-unstable/store-paths.xz 13 | 14 | However that command will use a lot of system resources since it will unpack 15 | all of the downloaded files and repack them before writing them to disk (if I 16 | have understood the reasons for the high cpu usage correctly). 17 | 18 | ## Features 19 | 20 | - [x] Parallel downloads 21 | - [x] Atomic downloads 22 | - [x] Sha256 verification of downloaded archives. 23 | 24 | 25 | ## Building 26 | 27 | ### With cargo 28 | Make sure to have openssl and pkg-config installed and run `cargo build`. 29 | If using nix you can use the provided `shell.nix` which is only a symlink to 30 | `default.nix` to get the dependencies. 31 | 32 | ### With nix 33 | Run `nix-build` as usual. 34 | 35 | ## Usage 36 | - `nix-mirror --help` to show application help 37 | - `nix-mirror store-paths.xz ./mirror` to download all the archives in 38 | `store-paths.xz` and their transitive dependencies to the directory `./mirror`. 39 | 40 | ## License 41 | 42 | Licensed under either of 43 | - [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 44 | - [MIT license](http://opensource.org/licenses/MIT) 45 | 46 | at your option. 47 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {} 2 | , lib ? pkgs.lib 3 | , rustPlatform ? pkgs.rustPlatform 4 | , openssl ? pkgs.openssl 5 | , pkgconfig ? pkgs.pkgconfig 6 | }: 7 | rustPlatform.buildRustPackage rec { 8 | pname = "nix-mirror"; 9 | version = "0.1"; 10 | 11 | nativeBuildInputs = [ pkgconfig ]; 12 | buildInputs = [ openssl.dev ]; 13 | 14 | src = lib.cleanSource ./.; 15 | cargoSha256 = "0dm9nmz8qblj2s67jy6gcsx9hqqkh42nk64yd8zppmky06p2x939"; 16 | } 17 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | default.nix -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | use futures::stream::StreamExt; 4 | use tokio::fs; 5 | use tokio::io::{self, AsyncBufReadExt, AsyncSeekExt, AsyncWriteExt}; 6 | use tokio::task; 7 | 8 | use eyre::{bail, eyre, Result}; 9 | use nix_base32::to_nix_base32; 10 | use path_clean::PathClean; 11 | use sha2::{Digest, Sha256}; 12 | 13 | /// Extracts the narinfo hash part from a nix store filename. 14 | /// ``` 15 | /// use nix_mirror::filename_to_narinfo_hash; 16 | /// let hash = filename_to_narinfo_hash("0001w2k3pgl0pkrn827dxiibvc2sibnd-singleton-bool-0.1.5.tar.gz.drv").unwrap(); 17 | /// assert_eq!(hash, "0001w2k3pgl0pkrn827dxiibvc2sibnd"); 18 | /// ``` 19 | pub fn filename_to_narinfo_hash(filename: &str) -> Result<&str> { 20 | filename 21 | .split('-') 22 | .next() 23 | .ok_or_else(|| eyre!("failed to parse narinfo hash: {}", filename)) 24 | } 25 | 26 | /// Extracts the narinfo hash path from a nix store path 27 | /// ``` 28 | /// use nix_mirror::store_path_to_narinfo_hash; 29 | /// let hash = store_path_to_narinfo_hash("/nix/store/0001w2k3pgl0pkrn827dxiibvc2sibnd-singleton-bool-0.1.5.tar.gz.drv").unwrap(); 30 | /// assert_eq!(hash, "0001w2k3pgl0pkrn827dxiibvc2sibnd"); 31 | /// ``` 32 | pub fn store_path_to_narinfo_hash(store_path: &str) -> Result<&str> { 33 | store_path 34 | .split('/') 35 | .nth(3) 36 | .ok_or_else(|| eyre!("failed to parse store_path: {}", store_path)) 37 | .and_then(filename_to_narinfo_hash) 38 | } 39 | 40 | /// Download a single file to a temporary file, moving it to the destination file atomically 41 | /// if the download succeeded. 42 | /// 43 | /// `client` - a reqwest::Client, as given by `reqwest::Client::new()`. 44 | /// `url` - the url we want to download 45 | /// `destination` - where we want the resulting file to end up 46 | /// `hash` - optionally a sha256-digest (in nix-base32) of the file that will be checked 47 | pub async fn download_atomically( 48 | client: &reqwest::Client, 49 | url: String, 50 | destination: &Path, 51 | hash: Option<&str>, 52 | ) -> Result { 53 | let mut resp_stream = client 54 | .get(&url) 55 | .send() 56 | .await? 57 | .error_for_status()? 58 | .bytes_stream(); 59 | let mut ctx = hash.map(|_| Sha256::new()); 60 | 61 | let destination_dir = destination.parent().unwrap(); 62 | let result: Result<_> = task::block_in_place(|| { 63 | let tempfile = tempfile::NamedTempFile::new_in(&destination_dir)?; 64 | let f: fs::File = tempfile.reopen()?.into(); 65 | Ok((tempfile, f)) 66 | }); 67 | let (tempfile, mut async_file) = result?; 68 | 69 | while let Some(bytes) = resp_stream.next().await { 70 | let bytes = bytes?; 71 | if let Some(ctx) = ctx.as_mut() { 72 | ctx.update(&bytes); 73 | } 74 | async_file.write_all(&bytes).await?; 75 | } 76 | async_file.shutdown().await?; 77 | if let Some(ctx) = ctx { 78 | let hash = hash.unwrap(); 79 | let computed = to_nix_base32(&ctx.finalize().as_ref()); 80 | if computed != hash { 81 | bail!( 82 | "hash of file: {:?} failed, expected: {}, got: {}", 83 | destination, 84 | hash, 85 | computed 86 | ); 87 | } 88 | } 89 | 90 | let f = task::block_in_place(|| tempfile.persist(&destination))?; 91 | let mut f = fs::File::from(f); 92 | f.seek(std::io::SeekFrom::Start(0)).await?; 93 | 94 | Ok(f) 95 | } 96 | 97 | /// Download a narinfo file (or open it if it already exists), parse it and download 98 | /// the referenced nar-archive (if it doesn't already exist). 99 | /// 100 | /// Returns a `Vec` of narinfo hashes for all the packages references, so that they can 101 | /// be downloaded in turn. 102 | pub async fn handle_narinfo( 103 | client: &reqwest::Client, 104 | cache_url: &String, 105 | mirror_dir: &Path, 106 | narinfo_hash: String, 107 | ) -> Result> { 108 | let mut narinfo_filename = mirror_dir.join(&narinfo_hash); 109 | narinfo_filename.set_extension("narinfo"); 110 | let narinfo_filename = narinfo_filename.clean(); 111 | 112 | // check to see if the narinfo file exists and download it if it doesn't 113 | // (or if we fail to open it). 114 | let narinfo_file = if let Ok(f) = fs::File::open(&narinfo_filename).await { 115 | f 116 | } else { 117 | let url = format!("{}/{}.narinfo", cache_url, &narinfo_hash); 118 | download_atomically(client, url, &narinfo_filename, None).await? 119 | }; 120 | 121 | let narinfo_file = io::BufReader::new(narinfo_file); 122 | let mut lines = narinfo_file.lines(); 123 | 124 | // ugly parser, but it would be overkill to reach for a parsing library here 125 | let mut url = Err(eyre!("failed to find URL")); 126 | let mut references = Vec::new(); 127 | let mut filehash = Err(eyre!("failed to find filehash")); 128 | while let Some(line) = lines.next_line().await? { 129 | let mut split = line.splitn(2, ": "); 130 | let key = split.next().ok_or_else(|| eyre!("failed to find key"))?; 131 | let val = split.next().ok_or_else(|| eyre!("failed to find val"))?; 132 | match key { 133 | "URL" => url = Ok(String::from(val)), 134 | "References" => { 135 | references = val 136 | .split_whitespace() 137 | .flat_map(|x| x.split("-").next()) 138 | .map(String::from) 139 | .collect() 140 | } 141 | "FileHash" => { 142 | filehash = val 143 | .split(':') 144 | .nth(1) 145 | .map(String::from) 146 | .ok_or_else(|| eyre!("invalid filehash")) 147 | } 148 | _ => {} 149 | } 150 | } 151 | 152 | // we error out if we didn't find an url or a filehash 153 | let url = url?; 154 | let filehash = filehash?; 155 | 156 | // check to see if we need to download the nar archive, if so do it 157 | let filename = mirror_dir.join(&url).clean(); 158 | if fs::File::open(&filename).await.is_err() { 159 | let url = format!("{}/{}", cache_url, &url); 160 | download_atomically(client, url, &filename, Some(&filehash)).await?; 161 | } 162 | 163 | Ok(references.into_iter().map(String::from).collect()) 164 | } 165 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use nix_mirror::{handle_narinfo, store_path_to_narinfo_hash}; 2 | 3 | use std::collections::HashSet; 4 | use std::path::PathBuf; 5 | 6 | use futures::stream::{self, StreamExt}; 7 | use tokio::fs; 8 | 9 | use eyre::Result; 10 | use indicatif::ProgressBar; 11 | use structopt::StructOpt; 12 | 13 | /// An application to synchronize nix binary caches 14 | #[derive(StructOpt)] 15 | struct Opt { 16 | /// The path to a store-paths.xz file containing the store paths of the packages 17 | /// that should be synchronized, e.g a copy of http://channels.nixos.org/nixpkgs-unstable/store-paths.xz 18 | store_paths: PathBuf, 19 | 20 | /// The directory where the mirror should be stored 21 | mirror_dir: PathBuf, 22 | 23 | /// URL to the cache server that should be used 24 | #[structopt(short, long, default_value = "https://cache.nixos.org")] 25 | cache_url: String, 26 | 27 | /// Maximum number of concurrent downloads 28 | #[structopt(short, long, default_value = "8")] 29 | parallelism: usize, 30 | } 31 | 32 | #[tokio::main] 33 | async fn main() -> Result<()> { 34 | let opt = Opt::from_args(); 35 | let nar_dir = opt.mirror_dir.join("nar"); 36 | fs::create_dir_all(&nar_dir).await?; 37 | 38 | // read all store paths to memory, there aren't that many of 39 | // them, so we might as well read all of them into memory 40 | let store_paths = { 41 | use std::{fs::File, io::Read}; 42 | let mut s = String::new(); 43 | File::open(&opt.store_paths) 44 | .map(xz2::read::XzDecoder::new) 45 | .and_then(|mut rdr| rdr.read_to_string(&mut s))?; 46 | s 47 | }; 48 | 49 | // a bit hacky, since we don't know how many files we need to process until 50 | // we're done, but it might still be nice to see some progress. 51 | let progress = ProgressBar::new(0); 52 | 53 | let client = reqwest::Client::new(); 54 | 55 | // our initial set of narinfo hashes to process 56 | let mut current_narinfo_hashes = store_paths 57 | .lines() 58 | .map(|x| store_path_to_narinfo_hash(x).map(String::from)) 59 | .collect::>>()?; 60 | // all narinfo hashes that we have seen 61 | let mut processed_narinfo_hashes = HashSet::new(); 62 | 63 | while !current_narinfo_hashes.is_empty() { 64 | let mut futures = Vec::new(); 65 | for narinfo_hash in current_narinfo_hashes.drain() { 66 | futures.push(handle_narinfo( 67 | &client, 68 | &opt.cache_url, 69 | &opt.mirror_dir, 70 | narinfo_hash.clone(), 71 | )); 72 | processed_narinfo_hashes.insert(narinfo_hash); 73 | progress.inc_length(1); 74 | } 75 | 76 | // handle at most `opt.parallelism` concurrent futures at the same time 77 | let mut stream = stream::iter(futures).buffer_unordered(opt.parallelism); 78 | 79 | // for the result of each future, check to see if we've already seen that hash 80 | // and if not add it to the set of hashes to process 81 | while let Some(result) = stream.next().await { 82 | let new_hashes = result?; 83 | current_narinfo_hashes.extend( 84 | new_hashes 85 | .into_iter() 86 | .filter(|x| !processed_narinfo_hashes.contains(x)), 87 | ); 88 | progress.inc(1); 89 | } 90 | } 91 | 92 | Ok(()) 93 | } 94 | --------------------------------------------------------------------------------