├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src ├── error.rs ├── lib.rs ├── platform.rs ├── releases.rs ├── vvm │ ├── main.rs │ └── print.rs └── vyper │ ├── cache.rs │ ├── error.rs │ └── main.rs └── test-data ├── Token.vy └── vvm-vyper-files-cache.json /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Formatting 22 | run: cargo fmt --all -- --check 23 | - name: Linting 24 | run: cargo clippy -- -D warnings 25 | - name: Run tests 26 | run: cargo test --all-features 27 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | tags: 9 | - v[0-9]+.* 10 | 11 | jobs: 12 | create-release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: taiki-e/create-gh-release-action@v1 17 | env: 18 | # (required) GitHub token for creating GitHub Releases. 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | 21 | upload-assets: 22 | strategy: 23 | matrix: 24 | os: 25 | - ubuntu-latest 26 | - macos-latest 27 | - windows-latest 28 | runs-on: ${{ matrix.os }} 29 | steps: 30 | - uses: actions/checkout@v3 31 | - uses: taiki-e/upload-rust-binary-action@v1 32 | with: 33 | # (required) Comma-separated list of binary names (non-extension portion of filename) to build and upload. 34 | # Note that glob pattern is not supported yet. 35 | bin: vvm,vyper 36 | # (optional) On which platform to distribute the `.tar.gz` file. 37 | # [default value: unix] 38 | # [possible values: all, unix, windows, none] 39 | tar: unix 40 | # (optional) On which platform to distribute the `.zip` file. 41 | # [default value: windows] 42 | # [possible values: all, unix, windows, none] 43 | zip: windows 44 | archive: $tag-$target 45 | env: 46 | # (required) GitHub token for uploading assets to GitHub Releases. 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | cache 3 | -------------------------------------------------------------------------------- /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 = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "aes" 13 | version = "0.7.5" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" 16 | dependencies = [ 17 | "cfg-if", 18 | "cipher", 19 | "cpufeatures", 20 | "opaque-debug", 21 | ] 22 | 23 | [[package]] 24 | name = "anyhow" 25 | version = "1.0.51" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" 28 | 29 | [[package]] 30 | name = "atty" 31 | version = "0.2.14" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 34 | dependencies = [ 35 | "hermit-abi", 36 | "libc", 37 | "winapi", 38 | ] 39 | 40 | [[package]] 41 | name = "autocfg" 42 | version = "1.0.1" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 45 | 46 | [[package]] 47 | name = "base64" 48 | version = "0.13.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 51 | 52 | [[package]] 53 | name = "base64ct" 54 | version = "1.0.1" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" 57 | 58 | [[package]] 59 | name = "bitflags" 60 | version = "1.3.2" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 63 | 64 | [[package]] 65 | name = "block-buffer" 66 | version = "0.9.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 69 | dependencies = [ 70 | "generic-array", 71 | ] 72 | 73 | [[package]] 74 | name = "block-buffer" 75 | version = "0.10.2" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 78 | dependencies = [ 79 | "generic-array", 80 | ] 81 | 82 | [[package]] 83 | name = "bumpalo" 84 | version = "3.8.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" 87 | 88 | [[package]] 89 | name = "byteorder" 90 | version = "1.4.3" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 93 | 94 | [[package]] 95 | name = "bytes" 96 | version = "1.1.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 99 | 100 | [[package]] 101 | name = "bzip2" 102 | version = "0.4.3" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" 105 | dependencies = [ 106 | "bzip2-sys", 107 | "libc", 108 | ] 109 | 110 | [[package]] 111 | name = "bzip2-sys" 112 | version = "0.1.11+1.0.8" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 115 | dependencies = [ 116 | "cc", 117 | "libc", 118 | "pkg-config", 119 | ] 120 | 121 | [[package]] 122 | name = "cc" 123 | version = "1.0.72" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 126 | dependencies = [ 127 | "jobserver", 128 | ] 129 | 130 | [[package]] 131 | name = "cfg-if" 132 | version = "1.0.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 135 | 136 | [[package]] 137 | name = "cipher" 138 | version = "0.3.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 141 | dependencies = [ 142 | "generic-array", 143 | ] 144 | 145 | [[package]] 146 | name = "clap" 147 | version = "3.0.6" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0" 150 | dependencies = [ 151 | "atty", 152 | "bitflags", 153 | "clap_derive", 154 | "indexmap", 155 | "lazy_static", 156 | "os_str_bytes", 157 | "strsim", 158 | "termcolor", 159 | "textwrap", 160 | ] 161 | 162 | [[package]] 163 | name = "clap_derive" 164 | version = "3.0.6" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153" 167 | dependencies = [ 168 | "heck", 169 | "proc-macro-error", 170 | "proc-macro2", 171 | "quote", 172 | "syn", 173 | ] 174 | 175 | [[package]] 176 | name = "console" 177 | version = "0.14.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" 180 | dependencies = [ 181 | "encode_unicode", 182 | "lazy_static", 183 | "libc", 184 | "regex", 185 | "terminal_size", 186 | "unicode-width", 187 | "winapi", 188 | ] 189 | 190 | [[package]] 191 | name = "console" 192 | version = "0.15.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" 195 | dependencies = [ 196 | "encode_unicode", 197 | "libc", 198 | "once_cell", 199 | "terminal_size", 200 | "winapi", 201 | ] 202 | 203 | [[package]] 204 | name = "constant_time_eq" 205 | version = "0.1.5" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 208 | 209 | [[package]] 210 | name = "core-foundation" 211 | version = "0.9.2" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" 214 | dependencies = [ 215 | "core-foundation-sys", 216 | "libc", 217 | ] 218 | 219 | [[package]] 220 | name = "core-foundation-sys" 221 | version = "0.8.3" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 224 | 225 | [[package]] 226 | name = "cpufeatures" 227 | version = "0.2.1" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 230 | dependencies = [ 231 | "libc", 232 | ] 233 | 234 | [[package]] 235 | name = "crc32fast" 236 | version = "1.3.2" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 239 | dependencies = [ 240 | "cfg-if", 241 | ] 242 | 243 | [[package]] 244 | name = "crossbeam-utils" 245 | version = "0.8.9" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "8ff1f980957787286a554052d03c7aee98d99cc32e09f6d45f0a814133c87978" 248 | dependencies = [ 249 | "cfg-if", 250 | "once_cell", 251 | ] 252 | 253 | [[package]] 254 | name = "crypto-common" 255 | version = "0.1.3" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" 258 | dependencies = [ 259 | "generic-array", 260 | "typenum", 261 | ] 262 | 263 | [[package]] 264 | name = "dialoguer" 265 | version = "0.8.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "c9dd058f8b65922819fabb4a41e7d1964e56344042c26efbccd465202c23fa0c" 268 | dependencies = [ 269 | "console 0.14.1", 270 | "lazy_static", 271 | "tempfile", 272 | "zeroize", 273 | ] 274 | 275 | [[package]] 276 | name = "digest" 277 | version = "0.9.0" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 280 | dependencies = [ 281 | "generic-array", 282 | ] 283 | 284 | [[package]] 285 | name = "digest" 286 | version = "0.10.3" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 289 | dependencies = [ 290 | "block-buffer 0.10.2", 291 | "crypto-common", 292 | "subtle", 293 | ] 294 | 295 | [[package]] 296 | name = "either" 297 | version = "1.6.1" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 300 | 301 | [[package]] 302 | name = "encode_unicode" 303 | version = "0.3.6" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 306 | 307 | [[package]] 308 | name = "encoding_rs" 309 | version = "0.8.30" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" 312 | dependencies = [ 313 | "cfg-if", 314 | ] 315 | 316 | [[package]] 317 | name = "flate2" 318 | version = "1.0.24" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" 321 | dependencies = [ 322 | "crc32fast", 323 | "miniz_oxide", 324 | ] 325 | 326 | [[package]] 327 | name = "fnv" 328 | version = "1.0.7" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 331 | 332 | [[package]] 333 | name = "foreign-types" 334 | version = "0.3.2" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 337 | dependencies = [ 338 | "foreign-types-shared", 339 | ] 340 | 341 | [[package]] 342 | name = "foreign-types-shared" 343 | version = "0.1.1" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 346 | 347 | [[package]] 348 | name = "form_urlencoded" 349 | version = "1.0.1" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 352 | dependencies = [ 353 | "matches", 354 | "percent-encoding", 355 | ] 356 | 357 | [[package]] 358 | name = "fs2" 359 | version = "0.4.3" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" 362 | dependencies = [ 363 | "libc", 364 | "winapi", 365 | ] 366 | 367 | [[package]] 368 | name = "futures-channel" 369 | version = "0.3.17" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" 372 | dependencies = [ 373 | "futures-core", 374 | ] 375 | 376 | [[package]] 377 | name = "futures-core" 378 | version = "0.3.17" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" 381 | 382 | [[package]] 383 | name = "futures-io" 384 | version = "0.3.21" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" 387 | 388 | [[package]] 389 | name = "futures-sink" 390 | version = "0.3.17" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" 393 | 394 | [[package]] 395 | name = "futures-task" 396 | version = "0.3.17" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" 399 | 400 | [[package]] 401 | name = "futures-util" 402 | version = "0.3.17" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" 405 | dependencies = [ 406 | "autocfg", 407 | "futures-core", 408 | "futures-io", 409 | "futures-task", 410 | "memchr", 411 | "pin-project-lite", 412 | "pin-utils", 413 | "slab", 414 | ] 415 | 416 | [[package]] 417 | name = "generic-array" 418 | version = "0.14.4" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 421 | dependencies = [ 422 | "typenum", 423 | "version_check", 424 | ] 425 | 426 | [[package]] 427 | name = "getrandom" 428 | version = "0.2.3" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" 431 | dependencies = [ 432 | "cfg-if", 433 | "libc", 434 | "wasi", 435 | ] 436 | 437 | [[package]] 438 | name = "h2" 439 | version = "0.3.9" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" 442 | dependencies = [ 443 | "bytes", 444 | "fnv", 445 | "futures-core", 446 | "futures-sink", 447 | "futures-util", 448 | "http", 449 | "indexmap", 450 | "slab", 451 | "tokio", 452 | "tokio-util", 453 | "tracing", 454 | ] 455 | 456 | [[package]] 457 | name = "hashbrown" 458 | version = "0.11.2" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 461 | 462 | [[package]] 463 | name = "heck" 464 | version = "0.4.0" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 467 | 468 | [[package]] 469 | name = "hermit-abi" 470 | version = "0.1.19" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 473 | dependencies = [ 474 | "libc", 475 | ] 476 | 477 | [[package]] 478 | name = "hex" 479 | version = "0.4.3" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 482 | 483 | [[package]] 484 | name = "hmac" 485 | version = "0.12.1" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 488 | dependencies = [ 489 | "digest 0.10.3", 490 | ] 491 | 492 | [[package]] 493 | name = "home" 494 | version = "0.5.3" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" 497 | dependencies = [ 498 | "winapi", 499 | ] 500 | 501 | [[package]] 502 | name = "http" 503 | version = "0.2.5" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" 506 | dependencies = [ 507 | "bytes", 508 | "fnv", 509 | "itoa 0.4.8", 510 | ] 511 | 512 | [[package]] 513 | name = "http-body" 514 | version = "0.4.4" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" 517 | dependencies = [ 518 | "bytes", 519 | "http", 520 | "pin-project-lite", 521 | ] 522 | 523 | [[package]] 524 | name = "httparse" 525 | version = "1.5.1" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" 528 | 529 | [[package]] 530 | name = "httpdate" 531 | version = "1.0.2" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 534 | 535 | [[package]] 536 | name = "hyper" 537 | version = "0.14.16" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" 540 | dependencies = [ 541 | "bytes", 542 | "futures-channel", 543 | "futures-core", 544 | "futures-util", 545 | "h2", 546 | "http", 547 | "http-body", 548 | "httparse", 549 | "httpdate", 550 | "itoa 0.4.8", 551 | "pin-project-lite", 552 | "socket2", 553 | "tokio", 554 | "tower-service", 555 | "tracing", 556 | "want", 557 | ] 558 | 559 | [[package]] 560 | name = "hyper-rustls" 561 | version = "0.23.0" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" 564 | dependencies = [ 565 | "http", 566 | "hyper", 567 | "rustls", 568 | "tokio", 569 | "tokio-rustls", 570 | ] 571 | 572 | [[package]] 573 | name = "hyper-tls" 574 | version = "0.5.0" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 577 | dependencies = [ 578 | "bytes", 579 | "hyper", 580 | "native-tls", 581 | "tokio", 582 | "tokio-native-tls", 583 | ] 584 | 585 | [[package]] 586 | name = "idna" 587 | version = "0.2.3" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 590 | dependencies = [ 591 | "matches", 592 | "unicode-bidi", 593 | "unicode-normalization", 594 | ] 595 | 596 | [[package]] 597 | name = "indexmap" 598 | version = "1.7.0" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 601 | dependencies = [ 602 | "autocfg", 603 | "hashbrown", 604 | ] 605 | 606 | [[package]] 607 | name = "indicatif" 608 | version = "0.16.2" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" 611 | dependencies = [ 612 | "console 0.15.0", 613 | "lazy_static", 614 | "number_prefix", 615 | "regex", 616 | ] 617 | 618 | [[package]] 619 | name = "instant" 620 | version = "0.1.12" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 623 | dependencies = [ 624 | "cfg-if", 625 | ] 626 | 627 | [[package]] 628 | name = "ipnet" 629 | version = "2.3.1" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" 632 | 633 | [[package]] 634 | name = "itertools" 635 | version = "0.10.3" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 638 | dependencies = [ 639 | "either", 640 | ] 641 | 642 | [[package]] 643 | name = "itoa" 644 | version = "0.4.8" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 647 | 648 | [[package]] 649 | name = "itoa" 650 | version = "1.0.1" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 653 | 654 | [[package]] 655 | name = "jobserver" 656 | version = "0.1.24" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" 659 | dependencies = [ 660 | "libc", 661 | ] 662 | 663 | [[package]] 664 | name = "js-sys" 665 | version = "0.3.55" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 668 | dependencies = [ 669 | "wasm-bindgen", 670 | ] 671 | 672 | [[package]] 673 | name = "lazy_static" 674 | version = "1.4.0" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 677 | 678 | [[package]] 679 | name = "libc" 680 | version = "0.2.112" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 683 | 684 | [[package]] 685 | name = "lock_api" 686 | version = "0.4.5" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 689 | dependencies = [ 690 | "scopeguard", 691 | ] 692 | 693 | [[package]] 694 | name = "log" 695 | version = "0.4.14" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 698 | dependencies = [ 699 | "cfg-if", 700 | ] 701 | 702 | [[package]] 703 | name = "matches" 704 | version = "0.1.9" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 707 | 708 | [[package]] 709 | name = "md-5" 710 | version = "0.10.1" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" 713 | dependencies = [ 714 | "digest 0.10.3", 715 | ] 716 | 717 | [[package]] 718 | name = "memchr" 719 | version = "2.4.1" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 722 | 723 | [[package]] 724 | name = "mime" 725 | version = "0.3.16" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 728 | 729 | [[package]] 730 | name = "miniz_oxide" 731 | version = "0.5.3" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" 734 | dependencies = [ 735 | "adler", 736 | ] 737 | 738 | [[package]] 739 | name = "mio" 740 | version = "0.7.14" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 743 | dependencies = [ 744 | "libc", 745 | "log", 746 | "miow", 747 | "ntapi", 748 | "winapi", 749 | ] 750 | 751 | [[package]] 752 | name = "miow" 753 | version = "0.3.7" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 756 | dependencies = [ 757 | "winapi", 758 | ] 759 | 760 | [[package]] 761 | name = "native-tls" 762 | version = "0.2.8" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" 765 | dependencies = [ 766 | "lazy_static", 767 | "libc", 768 | "log", 769 | "openssl", 770 | "openssl-probe", 771 | "openssl-sys", 772 | "schannel", 773 | "security-framework", 774 | "security-framework-sys", 775 | "tempfile", 776 | ] 777 | 778 | [[package]] 779 | name = "ntapi" 780 | version = "0.3.6" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 783 | dependencies = [ 784 | "winapi", 785 | ] 786 | 787 | [[package]] 788 | name = "num_cpus" 789 | version = "1.13.0" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 792 | dependencies = [ 793 | "hermit-abi", 794 | "libc", 795 | ] 796 | 797 | [[package]] 798 | name = "num_threads" 799 | version = "0.1.6" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" 802 | dependencies = [ 803 | "libc", 804 | ] 805 | 806 | [[package]] 807 | name = "number_prefix" 808 | version = "0.4.0" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" 811 | 812 | [[package]] 813 | name = "once_cell" 814 | version = "1.9.0" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" 817 | 818 | [[package]] 819 | name = "opaque-debug" 820 | version = "0.3.0" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 823 | 824 | [[package]] 825 | name = "openssl" 826 | version = "0.10.38" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" 829 | dependencies = [ 830 | "bitflags", 831 | "cfg-if", 832 | "foreign-types", 833 | "libc", 834 | "once_cell", 835 | "openssl-sys", 836 | ] 837 | 838 | [[package]] 839 | name = "openssl-probe" 840 | version = "0.1.4" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" 843 | 844 | [[package]] 845 | name = "openssl-sys" 846 | version = "0.9.72" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" 849 | dependencies = [ 850 | "autocfg", 851 | "cc", 852 | "libc", 853 | "pkg-config", 854 | "vcpkg", 855 | ] 856 | 857 | [[package]] 858 | name = "os_str_bytes" 859 | version = "6.0.0" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" 862 | dependencies = [ 863 | "memchr", 864 | ] 865 | 866 | [[package]] 867 | name = "parking_lot" 868 | version = "0.11.2" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 871 | dependencies = [ 872 | "instant", 873 | "lock_api", 874 | "parking_lot_core", 875 | ] 876 | 877 | [[package]] 878 | name = "parking_lot_core" 879 | version = "0.8.5" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 882 | dependencies = [ 883 | "cfg-if", 884 | "instant", 885 | "libc", 886 | "redox_syscall", 887 | "smallvec", 888 | "winapi", 889 | ] 890 | 891 | [[package]] 892 | name = "password-hash" 893 | version = "0.3.2" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" 896 | dependencies = [ 897 | "base64ct", 898 | "rand_core", 899 | "subtle", 900 | ] 901 | 902 | [[package]] 903 | name = "pbkdf2" 904 | version = "0.10.1" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" 907 | dependencies = [ 908 | "digest 0.10.3", 909 | "hmac", 910 | "password-hash", 911 | "sha2 0.10.2", 912 | ] 913 | 914 | [[package]] 915 | name = "percent-encoding" 916 | version = "2.1.0" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 919 | 920 | [[package]] 921 | name = "pin-project-lite" 922 | version = "0.2.7" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 925 | 926 | [[package]] 927 | name = "pin-utils" 928 | version = "0.1.0" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 931 | 932 | [[package]] 933 | name = "pkg-config" 934 | version = "0.3.24" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" 937 | 938 | [[package]] 939 | name = "ppv-lite86" 940 | version = "0.2.15" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" 943 | 944 | [[package]] 945 | name = "proc-macro-error" 946 | version = "1.0.4" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 949 | dependencies = [ 950 | "proc-macro-error-attr", 951 | "proc-macro2", 952 | "quote", 953 | "syn", 954 | "version_check", 955 | ] 956 | 957 | [[package]] 958 | name = "proc-macro-error-attr" 959 | version = "1.0.4" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 962 | dependencies = [ 963 | "proc-macro2", 964 | "quote", 965 | "version_check", 966 | ] 967 | 968 | [[package]] 969 | name = "proc-macro2" 970 | version = "1.0.34" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" 973 | dependencies = [ 974 | "unicode-xid", 975 | ] 976 | 977 | [[package]] 978 | name = "quote" 979 | version = "1.0.10" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 982 | dependencies = [ 983 | "proc-macro2", 984 | ] 985 | 986 | [[package]] 987 | name = "rand" 988 | version = "0.8.5" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 991 | dependencies = [ 992 | "libc", 993 | "rand_chacha", 994 | "rand_core", 995 | ] 996 | 997 | [[package]] 998 | name = "rand_chacha" 999 | version = "0.3.1" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1002 | dependencies = [ 1003 | "ppv-lite86", 1004 | "rand_core", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "rand_core" 1009 | version = "0.6.3" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1012 | dependencies = [ 1013 | "getrandom", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "redox_syscall" 1018 | version = "0.2.10" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1021 | dependencies = [ 1022 | "bitflags", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "regex" 1027 | version = "1.6.0" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" 1030 | dependencies = [ 1031 | "regex-syntax", 1032 | ] 1033 | 1034 | [[package]] 1035 | name = "regex-syntax" 1036 | version = "0.6.27" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" 1039 | 1040 | [[package]] 1041 | name = "remove_dir_all" 1042 | version = "0.5.3" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1045 | dependencies = [ 1046 | "winapi", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "reqwest" 1051 | version = "0.11.7" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" 1054 | dependencies = [ 1055 | "base64", 1056 | "bytes", 1057 | "encoding_rs", 1058 | "futures-core", 1059 | "futures-util", 1060 | "http", 1061 | "http-body", 1062 | "hyper", 1063 | "hyper-rustls", 1064 | "hyper-tls", 1065 | "ipnet", 1066 | "js-sys", 1067 | "lazy_static", 1068 | "log", 1069 | "mime", 1070 | "native-tls", 1071 | "percent-encoding", 1072 | "pin-project-lite", 1073 | "rustls", 1074 | "rustls-pemfile", 1075 | "serde", 1076 | "serde_json", 1077 | "serde_urlencoded", 1078 | "tokio", 1079 | "tokio-native-tls", 1080 | "tokio-rustls", 1081 | "url", 1082 | "wasm-bindgen", 1083 | "wasm-bindgen-futures", 1084 | "web-sys", 1085 | "webpki-roots", 1086 | "winreg", 1087 | ] 1088 | 1089 | [[package]] 1090 | name = "ring" 1091 | version = "0.16.20" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1094 | dependencies = [ 1095 | "cc", 1096 | "libc", 1097 | "once_cell", 1098 | "spin", 1099 | "untrusted", 1100 | "web-sys", 1101 | "winapi", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "rustls" 1106 | version = "0.20.2" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" 1109 | dependencies = [ 1110 | "log", 1111 | "ring", 1112 | "sct", 1113 | "webpki 0.22.0", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "rustls-pemfile" 1118 | version = "0.2.1" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" 1121 | dependencies = [ 1122 | "base64", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "ryu" 1127 | version = "1.0.9" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 1130 | 1131 | [[package]] 1132 | name = "schannel" 1133 | version = "0.1.19" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1136 | dependencies = [ 1137 | "lazy_static", 1138 | "winapi", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "scopeguard" 1143 | version = "1.1.0" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1146 | 1147 | [[package]] 1148 | name = "sct" 1149 | version = "0.7.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 1152 | dependencies = [ 1153 | "ring", 1154 | "untrusted", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "security-framework" 1159 | version = "2.4.2" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" 1162 | dependencies = [ 1163 | "bitflags", 1164 | "core-foundation", 1165 | "core-foundation-sys", 1166 | "libc", 1167 | "security-framework-sys", 1168 | ] 1169 | 1170 | [[package]] 1171 | name = "security-framework-sys" 1172 | version = "2.4.2" 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" 1174 | checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" 1175 | dependencies = [ 1176 | "core-foundation-sys", 1177 | "libc", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "semver" 1182 | version = "1.0.4" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" 1185 | dependencies = [ 1186 | "serde", 1187 | ] 1188 | 1189 | [[package]] 1190 | name = "serde" 1191 | version = "1.0.132" 1192 | source = "registry+https://github.com/rust-lang/crates.io-index" 1193 | checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" 1194 | dependencies = [ 1195 | "serde_derive", 1196 | ] 1197 | 1198 | [[package]] 1199 | name = "serde_derive" 1200 | version = "1.0.132" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" 1203 | dependencies = [ 1204 | "proc-macro2", 1205 | "quote", 1206 | "syn", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "serde_json" 1211 | version = "1.0.79" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" 1214 | dependencies = [ 1215 | "itoa 1.0.1", 1216 | "ryu", 1217 | "serde", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "serde_urlencoded" 1222 | version = "0.7.0" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" 1225 | dependencies = [ 1226 | "form_urlencoded", 1227 | "itoa 0.4.8", 1228 | "ryu", 1229 | "serde", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "sha1" 1234 | version = "0.10.1" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" 1237 | dependencies = [ 1238 | "cfg-if", 1239 | "cpufeatures", 1240 | "digest 0.10.3", 1241 | ] 1242 | 1243 | [[package]] 1244 | name = "sha2" 1245 | version = "0.9.9" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1248 | dependencies = [ 1249 | "block-buffer 0.9.0", 1250 | "cfg-if", 1251 | "cpufeatures", 1252 | "digest 0.9.0", 1253 | "opaque-debug", 1254 | "sha2-asm", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "sha2" 1259 | version = "0.10.2" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" 1262 | dependencies = [ 1263 | "cfg-if", 1264 | "cpufeatures", 1265 | "digest 0.10.3", 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "sha2-asm" 1270 | version = "0.6.2" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea" 1273 | dependencies = [ 1274 | "cc", 1275 | ] 1276 | 1277 | [[package]] 1278 | name = "signal-hook-registry" 1279 | version = "1.4.0" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1282 | dependencies = [ 1283 | "libc", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "slab" 1288 | version = "0.4.5" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 1291 | 1292 | [[package]] 1293 | name = "smallvec" 1294 | version = "1.7.0" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" 1297 | 1298 | [[package]] 1299 | name = "socket2" 1300 | version = "0.4.2" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 1303 | dependencies = [ 1304 | "libc", 1305 | "winapi", 1306 | ] 1307 | 1308 | [[package]] 1309 | name = "spin" 1310 | version = "0.5.2" 1311 | source = "registry+https://github.com/rust-lang/crates.io-index" 1312 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1313 | 1314 | [[package]] 1315 | name = "strsim" 1316 | version = "0.10.0" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1319 | 1320 | [[package]] 1321 | name = "subtle" 1322 | version = "2.4.1" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1325 | 1326 | [[package]] 1327 | name = "syn" 1328 | version = "1.0.82" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" 1331 | dependencies = [ 1332 | "proc-macro2", 1333 | "quote", 1334 | "unicode-xid", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "tempfile" 1339 | version = "3.2.0" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 1342 | dependencies = [ 1343 | "cfg-if", 1344 | "libc", 1345 | "rand", 1346 | "redox_syscall", 1347 | "remove_dir_all", 1348 | "winapi", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "termcolor" 1353 | version = "1.1.2" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1356 | dependencies = [ 1357 | "winapi-util", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "terminal_size" 1362 | version = "0.1.17" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 1365 | dependencies = [ 1366 | "libc", 1367 | "winapi", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "textwrap" 1372 | version = "0.14.2" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" 1375 | 1376 | [[package]] 1377 | name = "thiserror" 1378 | version = "1.0.30" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1381 | dependencies = [ 1382 | "thiserror-impl", 1383 | ] 1384 | 1385 | [[package]] 1386 | name = "thiserror-impl" 1387 | version = "1.0.30" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1390 | dependencies = [ 1391 | "proc-macro2", 1392 | "quote", 1393 | "syn", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "time" 1398 | version = "0.3.11" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" 1401 | dependencies = [ 1402 | "itoa 1.0.1", 1403 | "libc", 1404 | "num_threads", 1405 | "time-macros", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "time-macros" 1410 | version = "0.2.4" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" 1413 | 1414 | [[package]] 1415 | name = "tinyvec" 1416 | version = "1.5.1" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" 1419 | dependencies = [ 1420 | "tinyvec_macros", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "tinyvec_macros" 1425 | version = "0.1.0" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1428 | 1429 | [[package]] 1430 | name = "tokio" 1431 | version = "1.15.0" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" 1434 | dependencies = [ 1435 | "bytes", 1436 | "libc", 1437 | "memchr", 1438 | "mio", 1439 | "num_cpus", 1440 | "once_cell", 1441 | "parking_lot", 1442 | "pin-project-lite", 1443 | "signal-hook-registry", 1444 | "tokio-macros", 1445 | "winapi", 1446 | ] 1447 | 1448 | [[package]] 1449 | name = "tokio-macros" 1450 | version = "1.7.0" 1451 | source = "registry+https://github.com/rust-lang/crates.io-index" 1452 | checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" 1453 | dependencies = [ 1454 | "proc-macro2", 1455 | "quote", 1456 | "syn", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "tokio-native-tls" 1461 | version = "0.3.0" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 1464 | dependencies = [ 1465 | "native-tls", 1466 | "tokio", 1467 | ] 1468 | 1469 | [[package]] 1470 | name = "tokio-rustls" 1471 | version = "0.23.2" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" 1474 | dependencies = [ 1475 | "rustls", 1476 | "tokio", 1477 | "webpki 0.22.0", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "tokio-util" 1482 | version = "0.6.9" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" 1485 | dependencies = [ 1486 | "bytes", 1487 | "futures-core", 1488 | "futures-sink", 1489 | "log", 1490 | "pin-project-lite", 1491 | "tokio", 1492 | ] 1493 | 1494 | [[package]] 1495 | name = "tower-service" 1496 | version = "0.3.1" 1497 | source = "registry+https://github.com/rust-lang/crates.io-index" 1498 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1499 | 1500 | [[package]] 1501 | name = "tracing" 1502 | version = "0.1.30" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" 1505 | dependencies = [ 1506 | "cfg-if", 1507 | "pin-project-lite", 1508 | "tracing-attributes", 1509 | "tracing-core", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "tracing-attributes" 1514 | version = "0.1.19" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" 1517 | dependencies = [ 1518 | "proc-macro2", 1519 | "quote", 1520 | "syn", 1521 | ] 1522 | 1523 | [[package]] 1524 | name = "tracing-core" 1525 | version = "0.1.22" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" 1528 | dependencies = [ 1529 | "lazy_static", 1530 | ] 1531 | 1532 | [[package]] 1533 | name = "try-lock" 1534 | version = "0.2.3" 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" 1536 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1537 | 1538 | [[package]] 1539 | name = "typenum" 1540 | version = "1.14.0" 1541 | source = "registry+https://github.com/rust-lang/crates.io-index" 1542 | checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" 1543 | 1544 | [[package]] 1545 | name = "unicode-bidi" 1546 | version = "0.3.7" 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" 1548 | checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" 1549 | 1550 | [[package]] 1551 | name = "unicode-normalization" 1552 | version = "0.1.19" 1553 | source = "registry+https://github.com/rust-lang/crates.io-index" 1554 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 1555 | dependencies = [ 1556 | "tinyvec", 1557 | ] 1558 | 1559 | [[package]] 1560 | name = "unicode-width" 1561 | version = "0.1.9" 1562 | source = "registry+https://github.com/rust-lang/crates.io-index" 1563 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1564 | 1565 | [[package]] 1566 | name = "unicode-xid" 1567 | version = "0.2.2" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1570 | 1571 | [[package]] 1572 | name = "untrusted" 1573 | version = "0.7.1" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1576 | 1577 | [[package]] 1578 | name = "url" 1579 | version = "2.2.2" 1580 | source = "registry+https://github.com/rust-lang/crates.io-index" 1581 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1582 | dependencies = [ 1583 | "form_urlencoded", 1584 | "idna", 1585 | "matches", 1586 | "percent-encoding", 1587 | ] 1588 | 1589 | [[package]] 1590 | name = "vcpkg" 1591 | version = "0.2.15" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1594 | 1595 | [[package]] 1596 | name = "version_check" 1597 | version = "0.9.3" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1600 | 1601 | [[package]] 1602 | name = "vvm-rs" 1603 | version = "0.0.2" 1604 | dependencies = [ 1605 | "anyhow", 1606 | "cfg-if", 1607 | "clap", 1608 | "console 0.14.1", 1609 | "dialoguer", 1610 | "fs2", 1611 | "hex", 1612 | "home", 1613 | "indicatif", 1614 | "itertools", 1615 | "md-5", 1616 | "once_cell", 1617 | "rand", 1618 | "reqwest", 1619 | "semver", 1620 | "serde", 1621 | "serde_json", 1622 | "sha2 0.9.9", 1623 | "tempfile", 1624 | "thiserror", 1625 | "tokio", 1626 | "tracing", 1627 | "url", 1628 | "zip", 1629 | ] 1630 | 1631 | [[package]] 1632 | name = "want" 1633 | version = "0.3.0" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1636 | dependencies = [ 1637 | "log", 1638 | "try-lock", 1639 | ] 1640 | 1641 | [[package]] 1642 | name = "wasi" 1643 | version = "0.10.2+wasi-snapshot-preview1" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1646 | 1647 | [[package]] 1648 | name = "wasm-bindgen" 1649 | version = "0.2.78" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 1652 | dependencies = [ 1653 | "cfg-if", 1654 | "wasm-bindgen-macro", 1655 | ] 1656 | 1657 | [[package]] 1658 | name = "wasm-bindgen-backend" 1659 | version = "0.2.78" 1660 | source = "registry+https://github.com/rust-lang/crates.io-index" 1661 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 1662 | dependencies = [ 1663 | "bumpalo", 1664 | "lazy_static", 1665 | "log", 1666 | "proc-macro2", 1667 | "quote", 1668 | "syn", 1669 | "wasm-bindgen-shared", 1670 | ] 1671 | 1672 | [[package]] 1673 | name = "wasm-bindgen-futures" 1674 | version = "0.4.28" 1675 | source = "registry+https://github.com/rust-lang/crates.io-index" 1676 | checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" 1677 | dependencies = [ 1678 | "cfg-if", 1679 | "js-sys", 1680 | "wasm-bindgen", 1681 | "web-sys", 1682 | ] 1683 | 1684 | [[package]] 1685 | name = "wasm-bindgen-macro" 1686 | version = "0.2.78" 1687 | source = "registry+https://github.com/rust-lang/crates.io-index" 1688 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 1689 | dependencies = [ 1690 | "quote", 1691 | "wasm-bindgen-macro-support", 1692 | ] 1693 | 1694 | [[package]] 1695 | name = "wasm-bindgen-macro-support" 1696 | version = "0.2.78" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 1699 | dependencies = [ 1700 | "proc-macro2", 1701 | "quote", 1702 | "syn", 1703 | "wasm-bindgen-backend", 1704 | "wasm-bindgen-shared", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "wasm-bindgen-shared" 1709 | version = "0.2.78" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 1712 | 1713 | [[package]] 1714 | name = "web-sys" 1715 | version = "0.3.55" 1716 | source = "registry+https://github.com/rust-lang/crates.io-index" 1717 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 1718 | dependencies = [ 1719 | "js-sys", 1720 | "wasm-bindgen", 1721 | ] 1722 | 1723 | [[package]] 1724 | name = "webpki" 1725 | version = "0.21.4" 1726 | source = "registry+https://github.com/rust-lang/crates.io-index" 1727 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 1728 | dependencies = [ 1729 | "ring", 1730 | "untrusted", 1731 | ] 1732 | 1733 | [[package]] 1734 | name = "webpki" 1735 | version = "0.22.0" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" 1738 | dependencies = [ 1739 | "ring", 1740 | "untrusted", 1741 | ] 1742 | 1743 | [[package]] 1744 | name = "webpki-roots" 1745 | version = "0.21.1" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" 1748 | dependencies = [ 1749 | "webpki 0.21.4", 1750 | ] 1751 | 1752 | [[package]] 1753 | name = "winapi" 1754 | version = "0.3.9" 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" 1756 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1757 | dependencies = [ 1758 | "winapi-i686-pc-windows-gnu", 1759 | "winapi-x86_64-pc-windows-gnu", 1760 | ] 1761 | 1762 | [[package]] 1763 | name = "winapi-i686-pc-windows-gnu" 1764 | version = "0.4.0" 1765 | source = "registry+https://github.com/rust-lang/crates.io-index" 1766 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1767 | 1768 | [[package]] 1769 | name = "winapi-util" 1770 | version = "0.1.5" 1771 | source = "registry+https://github.com/rust-lang/crates.io-index" 1772 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1773 | dependencies = [ 1774 | "winapi", 1775 | ] 1776 | 1777 | [[package]] 1778 | name = "winapi-x86_64-pc-windows-gnu" 1779 | version = "0.4.0" 1780 | source = "registry+https://github.com/rust-lang/crates.io-index" 1781 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1782 | 1783 | [[package]] 1784 | name = "winreg" 1785 | version = "0.7.0" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" 1788 | dependencies = [ 1789 | "winapi", 1790 | ] 1791 | 1792 | [[package]] 1793 | name = "zeroize" 1794 | version = "1.4.3" 1795 | source = "registry+https://github.com/rust-lang/crates.io-index" 1796 | checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" 1797 | 1798 | [[package]] 1799 | name = "zip" 1800 | version = "0.6.2" 1801 | source = "registry+https://github.com/rust-lang/crates.io-index" 1802 | checksum = "bf225bcf73bb52cbb496e70475c7bd7a3f769df699c0020f6c7bd9a96dcf0b8d" 1803 | dependencies = [ 1804 | "aes", 1805 | "byteorder", 1806 | "bzip2", 1807 | "constant_time_eq", 1808 | "crc32fast", 1809 | "crossbeam-utils", 1810 | "flate2", 1811 | "hmac", 1812 | "pbkdf2", 1813 | "sha1", 1814 | "time", 1815 | "zstd", 1816 | ] 1817 | 1818 | [[package]] 1819 | name = "zstd" 1820 | version = "0.10.2+zstd.1.5.2" 1821 | source = "registry+https://github.com/rust-lang/crates.io-index" 1822 | checksum = "5f4a6bd64f22b5e3e94b4e238669ff9f10815c27a5180108b849d24174a83847" 1823 | dependencies = [ 1824 | "zstd-safe", 1825 | ] 1826 | 1827 | [[package]] 1828 | name = "zstd-safe" 1829 | version = "4.1.6+zstd.1.5.2" 1830 | source = "registry+https://github.com/rust-lang/crates.io-index" 1831 | checksum = "94b61c51bb270702d6167b8ce67340d2754b088d0c091b06e593aa772c3ee9bb" 1832 | dependencies = [ 1833 | "libc", 1834 | "zstd-sys", 1835 | ] 1836 | 1837 | [[package]] 1838 | name = "zstd-sys" 1839 | version = "1.6.3+zstd.1.5.2" 1840 | source = "registry+https://github.com/rust-lang/crates.io-index" 1841 | checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" 1842 | dependencies = [ 1843 | "cc", 1844 | "libc", 1845 | ] 1846 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vvm-rs" 3 | version = "0.0.2" 4 | edition = "2018" 5 | license = "MIT OR Apache-2.0" 6 | description = """ 7 | Vyper-Compiler (vyper) Version Manager. 8 | """ 9 | readme = "README.md" 10 | repository = "https://github.com/storming0x/vvm-rs" 11 | homepage = "https://github.com/storming0x/vvm-rs" 12 | 13 | [lib] 14 | name = "vvm_lib" 15 | path = "src/lib.rs" 16 | 17 | [[bin]] 18 | name = "vyper" 19 | path = "src/vyper/main.rs" 20 | 21 | [[bin]] 22 | name = "vvm" 23 | path = "src/vvm/main.rs" 24 | 25 | [dependencies] 26 | anyhow = { version = "1.0.43", default-features = false, features = ["std"] } 27 | cfg-if = { version = "1.0.0", default-features = false } 28 | clap = { version = "3.0.6", features = ["derive"] } 29 | console = { version = "0.14.1", default-features = false } 30 | dialoguer = { version = "0.8.0", default-features = false } 31 | fs2 = "0.4.3" 32 | hex = { version = "0.4.3", default-features = false, features = ["std"] } 33 | home = { version = "0.5.3", default-features = false } 34 | indicatif = { version = "0.16.2", default-features = false } 35 | itertools = { version = "0.10.1", default-features = false, features = [ 36 | "use_std", 37 | ] } 38 | md-5 = "0.10.1" 39 | once_cell = { version = "1.8.0", default-features = false } 40 | rand = { version = "0.8.5", default-features = false } 41 | reqwest = { version = "^0.11.7", default-features = false, features = ["json", "blocking"] } 42 | semver = { version = "1.0.4", default-features = false, features = ["std", "serde"] } 43 | serde = { version = "1.0.130", default-features = false, features = ["derive"] } 44 | serde_json = { version = "1.0.59", default-features = false } 45 | sha2 = { version = "0.9.9", default-features = false } 46 | tempfile = { version = "3.2.0", default-features = false } 47 | thiserror = { version = "1.0.29", default-features = false } 48 | tokio = { version = "1.11.0", features = ["full"] } 49 | tracing = "0.1.30" 50 | url = { version = "2.2.2", default-features = false } 51 | 52 | [target.'cfg(all(target_os = "windows", target_arch = "x86_64"))'.dependencies] 53 | zip = "0.6.2" 54 | 55 | [build-dependencies] 56 | home = { version = "0.5.3", default-features = false } 57 | 58 | [features] 59 | default = ["rustls"] 60 | openssl = ["reqwest/native-tls"] 61 | rustls = ["reqwest/rustls-tls"] 62 | sha2-asm = ["sha2/asm"] 63 | blocking = ["reqwest/blocking"] 64 | 65 | -------------------------------------------------------------------------------- /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 | MIT License 2 | 3 | Copyright (c) 2021 Rohit Narurkar 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 | # Vyper Compiler Version Manager in Rust 2 | 3 | ### Install 4 | ``` 5 | $ cargo install --git https://github.com/storming0x/vvm-rs --locked vvm-rs 6 | ``` 7 | 8 | ### Install from source `vvm` and `vyper` (runner) 9 | ``` 10 | $ git clone https://github.com/storming0x/vvm-rs 11 | cd vvm-rs 12 | cargo install --path ./ --bins --locked --force 13 | ``` 14 | 15 | ### Manual Download 16 | 17 | You can manually download release for your platform [here](https://github.com/storming0x/vvm-rs/releases) 18 | 19 | ### Usage 20 | * List available versions 21 | ``` 22 | $ vvm list 23 | ``` 24 | * Install a version 25 | ``` 26 | $ vvm install 27 | ``` 28 | * Use an installed version 29 | ``` 30 | $ vvm use 31 | ``` 32 | * Remove an installed version 33 | ``` 34 | $ vvm remove 35 | ``` 36 | 37 | ### Note and Issues 38 | VVM tries to use an environment variable called `GITHUB_TOKEN` to fetch and install vyper releases. In case its not found the installation may failed because of github rate limits 39 | 40 | ### Vyper Runner Usage 41 | 42 | Vyper runner included in this repository proxies all commands to vyper compiler with an added layer of caching for all your vyper projects. 43 | 44 | ``` 45 | $ vyper 46 | ``` 47 | 48 | Note: in case of issues with caching just delete the folder under `$HOME/.vvm/cache/` 49 | 50 | Caching only supports one file as input on commands. 51 | 52 | 53 | ### Credit and Acknowledgments 54 | 55 | * [SVM-RS](https://github.com/roynalnaruto/svm-rs) 56 | * [VVM](https://github.com/vyperlang/vvm) 57 | 58 | ## Contributing 59 | 60 | Help is always appreciated! Feel free to open an issue if you find a problem, or a pull request if you've solved an issue. 61 | 62 | TODO: Contribution guide 63 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use reqwest::StatusCode; 2 | use thiserror::Error; 3 | use url::Url; 4 | 5 | /// Error types from the vvm_lib crate. 6 | #[derive(Debug, Error)] 7 | pub enum VyperVmError { 8 | #[error("VVM global version not set")] 9 | GlobalVersionNotSet, 10 | #[error("Unknown version provided")] 11 | UnknownVersion, 12 | #[error("Unsupported version {0} for platform {1}")] 13 | UnsupportedVersion(String, String), 14 | #[error("Version {0} not installed")] 15 | VersionNotInstalled(String), 16 | #[error("Checksum mismatch for version {0}")] 17 | ChecksumMismatch(String), 18 | #[error("Install step for solc version {0} timed out after {1} seconds")] 19 | Timeout(String, u64), 20 | #[error("Unable to patch solc binary for nixos. stdout: {0}. stderr: {1}")] 21 | CouldNotPatchForNixOs(String, String), 22 | #[error(transparent)] 23 | IoError(#[from] std::io::Error), 24 | #[error(transparent)] 25 | ReqwestError(#[from] reqwest::Error), 26 | #[error(transparent)] 27 | SemverError(#[from] semver::Error), 28 | #[error(transparent)] 29 | UrlError(#[from] url::ParseError), 30 | #[error("Received unsuccessful response with code {1} for {0}")] 31 | UnsuccessfulResponse(Url, StatusCode), 32 | #[cfg(all(target_os = "windows", target_arch = "x86_64"))] 33 | #[error(transparent)] 34 | ZipError(#[from] zip::result::ZipError), 35 | } 36 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use semver::Version; 3 | // use sha2::Digest; 4 | 5 | use std::{ 6 | ffi::OsString, 7 | fs, 8 | io::{Cursor, Write}, 9 | path::PathBuf, 10 | }; 11 | 12 | use std::time::Duration; 13 | /// Use permissions extensions on unix 14 | #[cfg(target_family = "unix")] 15 | use std::{fs::Permissions, os::unix::fs::PermissionsExt}; 16 | 17 | mod error; 18 | pub use error::VyperVmError; 19 | 20 | mod platform; 21 | pub use platform::{platform, Platform}; 22 | 23 | mod releases; 24 | pub use releases::{all_releases, Releases}; 25 | 26 | #[cfg(feature = "blocking")] 27 | pub use releases::blocking_all_releases; 28 | 29 | /// Declare path to Vyper Version Manager's home directory, "~/.vvm" on Unix-based machines. 30 | pub static VVM_HOME: Lazy = Lazy::new(|| { 31 | cfg_if::cfg_if! { 32 | if #[cfg(test)] { 33 | let dir = tempfile::tempdir().expect("could not create temp directory"); 34 | dir.path().join(".vvm") 35 | } else { 36 | let mut user_home = home::home_dir().expect("could not detect user home directory"); 37 | user_home.push(".vvm"); 38 | user_home 39 | } 40 | } 41 | }); 42 | 43 | /// The timeout to use for requests to the source 44 | const REQUEST_TIMEOUT: Duration = Duration::from_secs(120); 45 | 46 | // Installer type that copies binary data to the appropriate Vyper binary file: 47 | // 1. create target file to copy binary data 48 | // 2. copy data 49 | struct Installer { 50 | // version of vyper 51 | version: Version, 52 | // binary data of the Vyper executable 53 | binbytes: Vec, 54 | } 55 | 56 | impl Installer { 57 | /// Installs the vyper version at the version specific destination and returns the path to the installed Vyper file. 58 | fn install(&self) -> Result { 59 | let version_path = version_path(self.version.to_string().as_str()); 60 | let vyper_path = version_path.join(&format!("vyper-{}", self.version)); 61 | // create vyper file. 62 | let mut f = fs::File::create(&vyper_path)?; 63 | 64 | #[cfg(target_family = "unix")] 65 | f.set_permissions(Permissions::from_mode(0o777))?; 66 | 67 | // copy contents over 68 | let mut content = Cursor::new(&self.binbytes); 69 | std::io::copy(&mut content, &mut f)?; 70 | 71 | Ok(vyper_path) 72 | } 73 | } 74 | 75 | /// Derive path to a specific Vyper version's binary. 76 | pub fn version_path(version: &str) -> PathBuf { 77 | let mut version_path = VVM_HOME.to_path_buf(); 78 | version_path.push(&version); 79 | version_path 80 | } 81 | 82 | /// Derive path to VVM's global version file. 83 | pub fn global_version_path() -> PathBuf { 84 | let mut global_version_path = VVM_HOME.to_path_buf(); 85 | global_version_path.push(".global-version"); 86 | global_version_path 87 | } 88 | 89 | /// Reads the currently set global version for Vyper. Returns None if none has yet been set. 90 | pub fn current_version() -> Result, VyperVmError> { 91 | let v = fs::read_to_string(global_version_path().as_path())?; 92 | Ok(Version::parse(v.trim_end_matches('\n').to_string().as_str()).ok()) 93 | } 94 | 95 | /// Sets the provided version as the global version for Vyper. 96 | pub fn use_version(version: &Version) -> Result<(), VyperVmError> { 97 | let mut v = fs::File::create(global_version_path().as_path())?; 98 | v.write_all(version.to_string().as_bytes())?; 99 | Ok(()) 100 | } 101 | 102 | /// Unset the global version. This should be done if all versions are removed. 103 | pub fn unset_global_version() -> Result<(), VyperVmError> { 104 | let mut v = fs::File::create(global_version_path().as_path())?; 105 | v.write_all("".as_bytes())?; 106 | Ok(()) 107 | } 108 | 109 | /// Reads the list of Vyper versions that have been installed in the machine. The version list is 110 | /// sorted in ascending order. 111 | pub fn installed_versions() -> Result, VyperVmError> { 112 | let home_dir = VVM_HOME.to_path_buf(); 113 | println!("home_dir {:?}", &home_dir); 114 | let mut versions = vec![]; 115 | for v in fs::read_dir(&home_dir)? { 116 | let v = v?; 117 | if v.file_name() != OsString::from(".global-version".to_string()) { 118 | versions.push(Version::parse( 119 | &v.path() 120 | .file_name() 121 | .ok_or(VyperVmError::UnknownVersion)? 122 | .to_str() 123 | .ok_or(VyperVmError::UnknownVersion)? 124 | .to_string() 125 | .as_str() 126 | .replace("vyper-", ""), 127 | )?); 128 | } 129 | } 130 | versions.sort(); 131 | 132 | Ok(versions) 133 | } 134 | 135 | /// Blocking version of [`all_versions`] 136 | #[cfg(feature = "blocking")] 137 | pub fn blocking_all_versions() -> Result, VyperVmError> { 138 | Ok(releases::blocking_all_releases(platform::platform())?.into_versions()) 139 | } 140 | 141 | /// Fetches the list of all the available versions of Vyper. The list is platform dependent, so 142 | /// different versions can be found for macosx vs linux. 143 | pub async fn all_versions() -> Result, VyperVmError> { 144 | Ok(releases::all_releases(platform::platform()) 145 | .await? 146 | .into_versions()) 147 | } 148 | 149 | /// Blocking version of [`install`] 150 | #[cfg(feature = "blocking")] 151 | pub fn blocking_install(version: &Version) -> Result { 152 | setup_home()?; 153 | 154 | let artifacts = releases::blocking_all_releases(platform::platform())?; 155 | let artifact = artifacts 156 | .get_artifact(version) 157 | .ok_or(VyperVmError::UnknownVersion)?; 158 | let download_url = 159 | releases::artifact_url(platform::platform(), version, artifact.to_string().as_str())?; 160 | 161 | // TODO: implement checksum for vyper binaries 162 | // let checksum = artifacts 163 | // .get_checksum(version) 164 | // .unwrap_or_else(|| panic!("checksum not available: {:?}", version.to_string())); 165 | 166 | let res = reqwest::blocking::Client::builder() 167 | .timeout(REQUEST_TIMEOUT) 168 | .build() 169 | .expect("reqwest::Client::new()") 170 | .get(download_url.clone()) 171 | .send()?; 172 | 173 | if !res.status().is_success() { 174 | return Err(VyperVmError::UnsuccessfulResponse( 175 | download_url, 176 | res.status(), 177 | )); 178 | } 179 | 180 | let binbytes = res.bytes()?; 181 | // TODO: implement checksum for vyper binaries 182 | // ensure_checksum(&binbytes, version, checksum)?; 183 | 184 | // lock file to indicate that installation of this Vyper version will be in progress. 185 | let lock_path = lock_file_path(version); 186 | // wait until lock file is released, possibly by another parallel thread trying to install the 187 | // same version of Vyper. 188 | let _lock = try_lock_file(lock_path)?; 189 | 190 | do_install( 191 | version.clone(), 192 | binbytes.to_vec(), 193 | artifact.to_string().as_str(), 194 | ) 195 | } 196 | 197 | /// Installs the provided version of Vyper in the machine. 198 | /// 199 | /// Returns the path to the Vyper file. 200 | pub async fn install(version: &Version) -> Result { 201 | setup_home()?; 202 | 203 | let artifacts = releases::all_releases(platform::platform()).await?; 204 | let artifact = artifacts 205 | .releases 206 | .get(version) 207 | .ok_or(VyperVmError::UnknownVersion)?; 208 | let download_url = 209 | releases::artifact_url(platform::platform(), version, artifact.to_string().as_str())?; 210 | 211 | // TODO: implement checksum for vyper binaries 212 | // let checksum = artifacts 213 | // .get_checksum(version) 214 | // .unwrap_or_else(|| panic!("checksum not available: {:?}", version.to_string())); 215 | 216 | let res = reqwest::Client::builder() 217 | .timeout(REQUEST_TIMEOUT) 218 | .build() 219 | .expect("reqwest::Client::new()") 220 | .get(download_url.clone()) 221 | .send() 222 | .await?; 223 | 224 | if !res.status().is_success() { 225 | return Err(VyperVmError::UnsuccessfulResponse( 226 | download_url, 227 | res.status(), 228 | )); 229 | } 230 | 231 | let binbytes = res.bytes().await?; 232 | // TODO: implement checksum for vyper binaries 233 | // ensure_checksum(&binbytes, version, checksum)?; 234 | 235 | // lock file to indicate that installation of this Vyper version will be in progress. 236 | let lock_path = lock_file_path(version); 237 | // wait until lock file is released, possibly by another parallel thread trying to install the 238 | // same version of Vyper. 239 | let _lock = try_lock_file(lock_path)?; 240 | 241 | do_install( 242 | version.clone(), 243 | binbytes.to_vec(), 244 | artifact.to_string().as_str(), 245 | ) 246 | } 247 | 248 | fn do_install( 249 | version: Version, 250 | binbytes: Vec, 251 | _artifact: &str, 252 | ) -> Result { 253 | let installer = { 254 | setup_version(version.to_string().as_str())?; 255 | 256 | Installer { version, binbytes } 257 | }; 258 | 259 | installer.install() 260 | } 261 | 262 | /// Removes the provided version of Vyper from the machine. 263 | pub fn remove_version(version: &Version) -> Result<(), VyperVmError> { 264 | fs::remove_dir_all(version_path(version.to_string().as_str()))?; 265 | Ok(()) 266 | } 267 | 268 | /// Setup VVM home directory. 269 | pub fn setup_home() -> Result { 270 | // create ~/.vvm 271 | let home_dir = VVM_HOME.to_path_buf(); 272 | if !home_dir.as_path().exists() { 273 | fs::create_dir_all(home_dir.clone())?; 274 | } 275 | // create ~/.vvm/.global-version 276 | let mut global_version = VVM_HOME.to_path_buf(); 277 | global_version.push(".global-version"); 278 | if !global_version.as_path().exists() { 279 | fs::File::create(global_version.as_path())?; 280 | } 281 | Ok(home_dir) 282 | } 283 | 284 | fn setup_version(version: &str) -> Result<(), VyperVmError> { 285 | let v = version_path(version); 286 | if !v.exists() { 287 | fs::create_dir_all(v.as_path())? 288 | } 289 | Ok(()) 290 | } 291 | 292 | // TODO: implement checksum for vyper binaries 293 | // fn ensure_checksum( 294 | // binbytes: impl AsRef<[u8]>, 295 | // version: &Version, 296 | // expected_checksum: Vec, 297 | // ) -> Result<(), VyperVmError> { 298 | // let mut hasher = sha2::Sha256::new(); 299 | // hasher.update(binbytes); 300 | // let cs = &hasher.finalize()[..]; 301 | // // checksum does not match 302 | // if cs != expected_checksum { 303 | // return Err(VyperVmError::ChecksumMismatch(version.to_string())); 304 | // } 305 | // Ok(()) 306 | // } 307 | 308 | /// Creates the file and locks it exclusively, this will block if the file is currently locked 309 | fn try_lock_file(lock_path: PathBuf) -> Result { 310 | use fs2::FileExt; 311 | let _lock_file = fs::OpenOptions::new() 312 | .create(true) 313 | .read(true) 314 | .write(true) 315 | .open(&lock_path)?; 316 | _lock_file.lock_exclusive()?; 317 | Ok(LockFile { 318 | lock_path, 319 | _lock_file, 320 | }) 321 | } 322 | 323 | /// Represents a lockfile that's removed once dropped 324 | struct LockFile { 325 | _lock_file: fs::File, 326 | lock_path: PathBuf, 327 | } 328 | 329 | impl Drop for LockFile { 330 | fn drop(&mut self) { 331 | let _ = fs::remove_file(&self.lock_path); 332 | } 333 | } 334 | 335 | /// Returns the lockfile to use for a specific file 336 | fn lock_file_path(version: &Version) -> PathBuf { 337 | VVM_HOME.join(&format!(".lock-vyper-{}", version)) 338 | } 339 | 340 | #[cfg(test)] 341 | mod tests { 342 | use crate::{ 343 | platform::Platform, 344 | releases::{all_releases, artifact_url}, 345 | }; 346 | use rand::seq::SliceRandom; 347 | use reqwest::Url; 348 | 349 | use std::process::{Command, Stdio}; 350 | 351 | use super::*; 352 | 353 | #[tokio::test] 354 | async fn test_artifact_url() { 355 | let version = Version::new(0, 3, 3); 356 | let version_str = version.to_string(); 357 | let artifact = &format!("vyper.{}%2Bcommit.48e326f0.darwin", version_str); 358 | assert_eq!( 359 | artifact_url(Platform::Linux, &version, artifact).unwrap(), 360 | Url::parse(&format!( 361 | "https://github.com/vyperlang/vyper/releases/download/v{}/{}", 362 | version_str, artifact 363 | )) 364 | .unwrap(), 365 | ) 366 | } 367 | 368 | #[tokio::test] 369 | async fn test_install() { 370 | let versions = all_releases(platform()) 371 | .await 372 | .unwrap() 373 | .releases 374 | .into_keys() 375 | .collect::>(); 376 | let rand_version = versions.choose(&mut rand::thread_rng()).unwrap(); 377 | assert!(install(rand_version).await.is_ok()); 378 | } 379 | 380 | #[ignore] 381 | #[tokio::test] 382 | async fn test_installed_versions() { 383 | let versions = all_releases(platform()) 384 | .await 385 | .unwrap() 386 | .releases 387 | .into_keys() 388 | .collect::>(); 389 | let rand_version = versions.choose(&mut rand::thread_rng()).unwrap(); 390 | assert!(install(rand_version).await.is_ok()); 391 | let installed_versions = installed_versions().unwrap_or_default(); 392 | assert!(installed_versions.len() > 0); 393 | assert!(&installed_versions.contains(rand_version)); 394 | } 395 | 396 | #[cfg(feature = "blocking")] 397 | #[test] 398 | fn blocking_test_install() { 399 | let versions = crate::releases::blocking_all_releases(platform::platform()) 400 | .unwrap() 401 | .into_versions(); 402 | let rand_version = versions.choose(&mut rand::thread_rng()).unwrap(); 403 | assert!(blocking_install(rand_version).is_ok()); 404 | } 405 | 406 | #[tokio::test] 407 | async fn test_version() { 408 | let version = "0.3.3".parse().unwrap(); 409 | install(&version).await.unwrap(); 410 | let vyper_path = 411 | version_path(version.to_string().as_str()).join(&format!("vyper-{}", version)); 412 | let output = Command::new(&vyper_path) 413 | .arg("--version") 414 | .stdin(Stdio::piped()) 415 | .stderr(Stdio::piped()) 416 | .stdout(Stdio::piped()) 417 | .output() 418 | .unwrap(); 419 | 420 | assert!(String::from_utf8_lossy(&output.stdout) 421 | .as_ref() 422 | .contains("0.3.3")); 423 | } 424 | 425 | #[cfg(feature = "blocking")] 426 | #[test] 427 | fn blocking_test_version() { 428 | let version = "0.3.3".parse().unwrap(); 429 | blocking_install(&version).unwrap(); 430 | let vyper_path = 431 | version_path(version.to_string().as_str()).join(&format!("vyper-{}", version)); 432 | let output = Command::new(&vyper_path) 433 | .arg("--version") 434 | .stdin(Stdio::piped()) 435 | .stderr(Stdio::piped()) 436 | .stdout(Stdio::piped()) 437 | .output() 438 | .unwrap(); 439 | 440 | assert!(String::from_utf8_lossy(&output.stdout) 441 | .as_ref() 442 | .contains("0.3.3")); 443 | } 444 | 445 | #[ignore] 446 | #[cfg(feature = "blocking")] 447 | #[test] 448 | fn can_install_parallel() { 449 | let version: Version = "0.3.3".parse().unwrap(); 450 | let cloned_version = version.clone(); 451 | let t = std::thread::spawn(move || blocking_install(&cloned_version)); 452 | blocking_install(&version).unwrap(); 453 | t.join().unwrap().unwrap(); 454 | } 455 | 456 | #[ignore] 457 | #[tokio::test(flavor = "multi_thread")] 458 | async fn can_install_parallel_async() { 459 | let version: Version = "0.3.3".parse().unwrap(); 460 | let cloned_version = version.clone(); 461 | let t = tokio::task::spawn(async move { install(&cloned_version).await }); 462 | install(&version).await.unwrap(); 463 | t.await.unwrap().unwrap(); 464 | } 465 | 466 | // ensures we can download the latest native Vyper for apple silicon 467 | #[tokio::test(flavor = "multi_thread")] 468 | async fn can_download_latest_macos() { 469 | let latest: Version = "0.3.3".parse().unwrap(); 470 | 471 | let artifacts = all_releases(Platform::MacOs).await.unwrap(); 472 | 473 | let artifact = artifacts.releases.get(&latest).unwrap(); 474 | let download_url = 475 | artifact_url(Platform::MacOs, &latest, artifact.to_string().as_str()).unwrap(); 476 | // TODO: implement checksum for vyper binaries 477 | // let checksum = artifacts.get_checksum(&latest).unwrap(); 478 | 479 | let resp = reqwest::get(download_url).await.unwrap(); 480 | assert!(resp.status().is_success()); 481 | let _binbytes = resp.bytes().await.unwrap(); 482 | // TODO: implement checksum for vyper binaries 483 | // ensure_checksum(&binbytes, &latest, checksum).unwrap(); 484 | } 485 | } 486 | -------------------------------------------------------------------------------- /src/platform.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Formatter; 2 | use std::str::FromStr; 3 | use std::{env, fmt}; 4 | 5 | /// Types of supported platforms. 6 | #[derive(Clone, Debug, Copy, PartialEq, Eq)] 7 | pub enum Platform { 8 | Linux, 9 | MacOs, 10 | Windows, 11 | Unsupported, 12 | } 13 | 14 | impl fmt::Display for Platform { 15 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 16 | let s = match self { 17 | Platform::Linux => "linux", 18 | Platform::MacOs => "darwin", 19 | Platform::Windows => "windows", 20 | Platform::Unsupported => "Unsupported-platform", 21 | }; 22 | f.write_str(s) 23 | } 24 | } 25 | 26 | impl FromStr for Platform { 27 | type Err = String; 28 | 29 | fn from_str(s: &str) -> Result { 30 | match s { 31 | "linux" => Ok(Platform::Linux), 32 | "macosx" => Ok(Platform::MacOs), 33 | "darwin" => Ok(Platform::MacOs), 34 | "windows" => Ok(Platform::Windows), 35 | s => Err(format!("unsupported platform {}", s)), 36 | } 37 | } 38 | } 39 | 40 | /// Read the current machine's platform. 41 | pub fn platform() -> Platform { 42 | match (env::consts::OS, env::consts::ARCH) { 43 | ("linux", "x86_64") => Platform::Linux, 44 | ("linux", "aarch64") => Platform::Linux, 45 | ("macos", "x86_64") => Platform::MacOs, 46 | ("macos", "aarch64") => Platform::MacOs, 47 | ("windows", "x86_64") => Platform::Windows, 48 | _ => Platform::Unsupported, 49 | } 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | 56 | #[test] 57 | #[cfg(all(target_os = "linux", target_arch = "x86_64"))] 58 | fn get_platform() { 59 | assert_eq!(platform(), Platform::Linux); 60 | } 61 | 62 | #[test] 63 | #[cfg(all(target_os = "linux", target_arch = "aarch64"))] 64 | fn get_platform() { 65 | assert_eq!(platform(), Platform::Linux); 66 | } 67 | 68 | #[test] 69 | #[cfg(all(target_os = "macos", target_arch = "x86_64"))] 70 | fn get_platform() { 71 | assert_eq!(platform(), Platform::MacOs); 72 | } 73 | 74 | #[test] 75 | #[cfg(all(target_os = "macos", target_arch = "aarch64"))] 76 | fn get_platform() { 77 | assert_eq!(platform(), Platform::MacOs); 78 | } 79 | 80 | #[test] 81 | #[cfg(all(target_os = "windows", target_arch = "x86_64"))] 82 | fn get_platform() { 83 | assert_eq!(platform(), Platform::Windows); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/releases.rs: -------------------------------------------------------------------------------- 1 | use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT}; 2 | use semver::Version; 3 | use serde::{ 4 | de::{self, Deserializer}, 5 | Deserialize, Serialize, 6 | }; 7 | use std::collections::BTreeMap; 8 | use url::Url; 9 | 10 | use std::env; 11 | 12 | use crate::{error::VyperVmError, platform::Platform}; 13 | 14 | const GITHUB_RELEASES: &str = "https://api.github.com/repos/vyperlang/vyper/releases?per_page=100"; 15 | 16 | /// Defines the struct that the JSON-formatted release list can be deserialized into. 17 | /// 18 | /// { 19 | /// "tag_name": "v0.3.3", 20 | /// ... 21 | /// "assets": [ 22 | /// { 23 | /// "name": "vyper.0.3.3+commit.48e326f0.darwin", 24 | /// ... 25 | /// "browser_download_url": "https://github.com/vyperlang/vyper/releases/download/v0.3.3/vyper.0.3.3%2Bcommit.48e326f0.darwin" 26 | /// } 27 | /// ] 28 | /// } 29 | /// 30 | /// 31 | /// 32 | /// 33 | #[derive(Debug, Serialize, Deserialize)] 34 | struct VyperAsset { 35 | name: String, 36 | browser_download_url: String, 37 | } 38 | /// Both the key and value are deserialized into semver::Version. 39 | #[derive(Debug, Serialize, Deserialize)] 40 | struct VyperReleases { 41 | tag_name: String, 42 | assets: Vec, 43 | } 44 | 45 | /// Both the key and value are deserialized into semver::Version. 46 | #[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)] 47 | pub struct Releases { 48 | pub builds: Vec, 49 | pub releases: BTreeMap, 50 | } 51 | 52 | impl Releases { 53 | /// NOTE: vyper binaries dont support checksums 54 | pub fn get_checksum(&self, v: &Version) -> Option> { 55 | for build in self.builds.iter() { 56 | if build.version.eq(v) { 57 | return Some(build.sha256.clone()); 58 | } 59 | } 60 | None 61 | } 62 | 63 | /// Returns the artifact of the version if any 64 | pub fn get_artifact(&self, version: &Version) -> Option<&String> { 65 | self.releases.get(version) 66 | } 67 | 68 | /// Returns a sorted list of all versions 69 | pub fn into_versions(self) -> Vec { 70 | let mut versions = self.releases.into_keys().collect::>(); 71 | versions.sort_unstable(); 72 | versions 73 | } 74 | } 75 | 76 | /// Build info contains the SHA256 checksum of a solc binary. 77 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 78 | pub struct BuildInfo { 79 | pub version: Version, 80 | #[serde(with = "hex_string")] 81 | pub sha256: Vec, 82 | } 83 | 84 | /// Helper serde module to serialize and deserialize bytes as hex. 85 | mod hex_string { 86 | use super::*; 87 | use serde::Serializer; 88 | pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> 89 | where 90 | D: Deserializer<'de>, 91 | { 92 | let str_hex = String::deserialize(deserializer)?; 93 | let str_hex = str_hex.trim_start_matches("0x"); 94 | hex::decode(str_hex).map_err(|err| de::Error::custom(err.to_string())) 95 | } 96 | 97 | pub fn serialize(value: &T, serializer: S) -> Result 98 | where 99 | S: Serializer, 100 | T: AsRef<[u8]>, 101 | { 102 | let value = hex::encode(value); 103 | serializer.serialize_str(&value) 104 | } 105 | } 106 | 107 | /// Blocking version for [`all_releases`] 108 | #[cfg(feature = "blocking")] 109 | pub fn blocking_all_releases(platform: Platform) -> Result { 110 | let vyper_releases = blocking_get_releases()?; 111 | 112 | let mut builds: Vec = Vec::new(); 113 | let mut releases: BTreeMap = BTreeMap::new(); 114 | let platform_str = &platform.to_string(); 115 | for vyper_release in vyper_releases { 116 | for asset in vyper_release.assets { 117 | if asset.name.contains(platform_str) { 118 | let version = 119 | Version::parse(&vyper_release.tag_name.trim_start_matches("v")).unwrap(); 120 | builds.push(BuildInfo { 121 | version: version.clone(), 122 | sha256: Vec::new(), 123 | }); 124 | releases.insert(version, asset.name); 125 | } 126 | } 127 | } 128 | 129 | Ok(Releases { builds, releases }) 130 | } 131 | 132 | /// Fetch all releases available for the provided platform. 133 | pub async fn all_releases(platform: Platform) -> Result { 134 | let vyper_releases = get_releases().await?; 135 | 136 | let mut builds: Vec = Vec::new(); 137 | let mut releases: BTreeMap = BTreeMap::new(); 138 | let platform_str = &platform.to_string(); 139 | for vyper_release in vyper_releases { 140 | for asset in vyper_release.assets { 141 | if asset.name.contains(platform_str) { 142 | let version = 143 | Version::parse(vyper_release.tag_name.trim_start_matches('v')).unwrap(); 144 | builds.push(BuildInfo { 145 | version: version.clone(), 146 | sha256: Vec::new(), 147 | }); 148 | releases.insert(version, asset.name); 149 | } 150 | } 151 | } 152 | 153 | Ok(Releases { builds, releases }) 154 | } 155 | 156 | async fn get_releases() -> Result, VyperVmError> { 157 | let mut headers = HeaderMap::new(); 158 | // add the user-agent header required by github 159 | headers.insert(USER_AGENT, HeaderValue::from_static("reqwest")); 160 | 161 | add_gh_token(&mut headers); 162 | 163 | let vyper_releases = reqwest::Client::new() 164 | .get(GITHUB_RELEASES) 165 | .headers(headers) 166 | .send() 167 | .await? 168 | .json::>() 169 | .await?; 170 | 171 | Ok(vyper_releases) 172 | } 173 | 174 | fn add_gh_token(headers: &mut HeaderMap) { 175 | if let Ok(gh_token) = env::var("GITHUB_TOKEN") { 176 | let auth_string = format!("Basic {}", &gh_token); 177 | if let Ok(auth_header) = HeaderValue::from_str(auth_string.as_str()) { 178 | // println!("GITHUB_TOKEN found! using it to fetch releases"); 179 | headers.insert("Authorization", auth_header); 180 | } 181 | } 182 | } 183 | 184 | #[allow(dead_code)] 185 | fn blocking_get_releases() -> Result, VyperVmError> { 186 | let mut headers = HeaderMap::new(); 187 | // add the user-agent header required by github 188 | headers.insert(USER_AGENT, HeaderValue::from_static("reqwest")); 189 | 190 | add_gh_token(&mut headers); 191 | 192 | let vyper_releases = reqwest::blocking::Client::new() 193 | .get(GITHUB_RELEASES) 194 | .headers(headers) 195 | .send()? 196 | .json::>()?; 197 | 198 | Ok(vyper_releases) 199 | } 200 | 201 | /// Construct the URL to the Vyper binary for the specified release version and target platform. 202 | pub fn artifact_url( 203 | _platform: Platform, 204 | version: &Version, 205 | artifact: &str, 206 | ) -> Result { 207 | Ok(Url::parse(&format!( 208 | "https://github.com/vyperlang/vyper/releases/download/v{}/{}", 209 | &version.to_string(), 210 | artifact 211 | ))?) 212 | } 213 | 214 | #[cfg(test)] 215 | mod tests { 216 | use super::*; 217 | 218 | // #[tokio::test] 219 | // async fn test_macos_aarch64() { 220 | // let releases = all_releases(Platform::MacOs) 221 | // .await 222 | // .expect("could not fetch releases for macos-aarch64"); 223 | // let rosetta = Version::new(0, 8, 4); 224 | // let native = MACOS_AARCH64_NATIVE.clone(); 225 | // let url1 = artifact_url( 226 | // Platform::MacOsAarch64, 227 | // &rosetta, 228 | // releases.get_artifact(&rosetta).unwrap(), 229 | // ) 230 | // .expect("could not fetch artifact URL"); 231 | // let url2 = artifact_url( 232 | // Platform::MacOsAarch64, 233 | // &native, 234 | // releases.get_artifact(&native).unwrap(), 235 | // ) 236 | // .expect("could not fetch artifact URL"); 237 | // assert!(url1.to_string().contains(SOLC_RELEASES_URL)); 238 | // assert!(url2.to_string().contains(MACOS_AARCH64_URL_PREFIX)); 239 | // } 240 | 241 | #[tokio::test] 242 | async fn test_all_releases_macos() { 243 | assert!(all_releases(Platform::MacOs).await.is_ok()); 244 | } 245 | 246 | #[tokio::test] 247 | async fn test_all_releases_linux() { 248 | assert!(all_releases(Platform::Linux).await.is_ok()); 249 | } 250 | 251 | #[tokio::test] 252 | async fn releases_roundtrip() { 253 | let releases = all_releases(Platform::Linux).await.unwrap(); 254 | let s = serde_json::to_string(&releases).unwrap(); 255 | let de_releases: Releases = serde_json::from_str(&s).unwrap(); 256 | assert_eq!(releases, de_releases); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/vvm/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use dialoguer::Input; 3 | use semver::Version; 4 | 5 | use std::collections::HashSet; 6 | 7 | mod print; 8 | 9 | #[derive(Debug, Parser)] 10 | #[clap(name = "vvm", about = "Vyper Version Manager", version)] 11 | enum VyperVm { 12 | #[clap(about = "List all versions of Vyper")] 13 | List, 14 | #[clap(about = "Install Vyper versions")] 15 | Install { versions: Vec }, 16 | #[clap(about = "Use a Vyper version")] 17 | Use { version: String }, 18 | #[clap(about = "Remove a Vyper version")] 19 | Remove { version: String }, 20 | } 21 | 22 | #[tokio::main] 23 | async fn main() -> anyhow::Result<()> { 24 | let opt = VyperVm::parse(); 25 | 26 | vvm_lib::setup_home()?; 27 | 28 | match opt { 29 | VyperVm::List => { 30 | handle_list().await?; 31 | } 32 | VyperVm::Install { versions } => { 33 | for v in versions { 34 | handle_install(Version::parse(&v)?).await?; 35 | } 36 | } 37 | VyperVm::Use { version } => { 38 | handle_use(Version::parse(&version)?).await?; 39 | } 40 | VyperVm::Remove { version } => match version.as_str() { 41 | "ALL" | "all" => { 42 | for v in vvm_lib::installed_versions().unwrap_or_default() { 43 | vvm_lib::remove_version(&v)?; 44 | } 45 | vvm_lib::unset_global_version()?; 46 | } 47 | _ => handle_remove(Version::parse(&version)?)?, 48 | }, 49 | } 50 | 51 | Ok(()) 52 | } 53 | 54 | async fn handle_list() -> anyhow::Result<()> { 55 | let all_versions = vvm_lib::all_versions().await?; 56 | let installed_versions = vvm_lib::installed_versions().unwrap_or_default(); 57 | let current_version = vvm_lib::current_version()?; 58 | 59 | let a: HashSet = all_versions.iter().cloned().collect(); 60 | let b: HashSet = installed_versions.iter().cloned().collect(); 61 | let c = &a - &b; 62 | 63 | let mut available_versions = c.iter().cloned().collect::>(); 64 | available_versions.sort(); 65 | 66 | print::current_version(current_version); 67 | print::installed_versions(installed_versions); 68 | print::available_versions(available_versions); 69 | 70 | Ok(()) 71 | } 72 | 73 | async fn handle_install(version: Version) -> anyhow::Result<()> { 74 | let all_versions = vvm_lib::all_versions().await?; 75 | let installed_versions = vvm_lib::installed_versions().unwrap_or_default(); 76 | let current_version = vvm_lib::current_version()?; 77 | 78 | if installed_versions.contains(&version) { 79 | println!("Vyper {} is already installed", version); 80 | let input: String = Input::new() 81 | .with_prompt("Would you like to set it as the global version?") 82 | .with_initial_text("Y") 83 | .default("N".into()) 84 | .interact_text()?; 85 | if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") { 86 | vvm_lib::use_version(&version)?; 87 | print::set_global_version(&version); 88 | } 89 | } else if all_versions.contains(&version) { 90 | let spinner = print::installing_version(&version); 91 | vvm_lib::install(&version).await?; 92 | spinner.finish_with_message(format!("Downloaded Vyper: {}", version)); 93 | if current_version.is_none() { 94 | vvm_lib::use_version(&version)?; 95 | print::set_global_version(&version); 96 | } 97 | } else { 98 | print::unsupported_version(&version); 99 | } 100 | 101 | Ok(()) 102 | } 103 | 104 | async fn handle_use(version: Version) -> anyhow::Result<()> { 105 | let all_versions = vvm_lib::all_versions().await?; 106 | let installed_versions = vvm_lib::installed_versions().unwrap_or_default(); 107 | 108 | if installed_versions.contains(&version) { 109 | vvm_lib::use_version(&version)?; 110 | print::set_global_version(&version); 111 | } else if all_versions.contains(&version) { 112 | println!("Vyper {} is not installed", version); 113 | let input: String = Input::new() 114 | .with_prompt("Would you like to install it?") 115 | .with_initial_text("Y") 116 | .default("N".into()) 117 | .interact_text()?; 118 | if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") { 119 | handle_install(version).await?; 120 | } 121 | } else { 122 | print::unsupported_version(&version); 123 | } 124 | 125 | Ok(()) 126 | } 127 | 128 | fn handle_remove(version: Version) -> anyhow::Result<()> { 129 | let mut installed_versions = vvm_lib::installed_versions().unwrap_or_default(); 130 | let current_version = vvm_lib::current_version()?; 131 | 132 | if installed_versions.contains(&version) { 133 | let input: String = Input::new() 134 | .with_prompt("Are you sure?") 135 | .with_initial_text("Y") 136 | .default("N".into()) 137 | .interact_text()?; 138 | if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") { 139 | vvm_lib::remove_version(&version)?; 140 | if let Some(v) = current_version { 141 | if version == v { 142 | if let Some(i) = installed_versions.iter().position(|x| *x == v) { 143 | installed_versions.remove(i); 144 | if let Some(new_version) = installed_versions.pop() { 145 | vvm_lib::use_version(&new_version)?; 146 | print::set_global_version(&new_version); 147 | } else { 148 | vvm_lib::unset_global_version()?; 149 | } 150 | } 151 | } 152 | } 153 | } 154 | } else { 155 | print::version_not_found(&version); 156 | } 157 | 158 | Ok(()) 159 | } 160 | -------------------------------------------------------------------------------- /src/vvm/print.rs: -------------------------------------------------------------------------------- 1 | use console::style; 2 | use indicatif::{ProgressBar, ProgressStyle}; 3 | use itertools::Itertools; 4 | use semver::Version; 5 | 6 | pub fn current_version(version: Option) { 7 | match version { 8 | Some(v) => { 9 | println!("{} (current)", style(v.to_string().as_str()).green()); 10 | } 11 | None => { 12 | println!("Global version not set"); 13 | } 14 | } 15 | } 16 | 17 | pub fn installed_versions(versions: Vec) { 18 | println!("\n{}", style("Installed Versions").bold()); 19 | versions.iter().for_each(|v| { 20 | println!("{}", style(v.to_string().as_str()).yellow()); 21 | }); 22 | } 23 | 24 | pub fn available_versions(versions: Vec) { 25 | println!("\n{}", style("Available to Install").bold()); 26 | let groups = versions 27 | .iter() 28 | .group_by(|v| v.minor) 29 | .into_iter() 30 | .map(|(_, g)| g.cloned().collect()) 31 | .collect::>>(); 32 | for group in groups { 33 | println!( 34 | "{:?}", 35 | group.iter().map(|v| v.to_string()).collect::>() 36 | ); 37 | } 38 | } 39 | 40 | pub fn installing_version(version: &Version) -> ProgressBar { 41 | let spinner = ProgressBar::new_spinner(); 42 | spinner.enable_steady_tick(120); 43 | spinner.set_message(format!("Downloading Vyper {}", version)); 44 | spinner.set_style( 45 | ProgressStyle::default_spinner() 46 | .tick_strings(&[ 47 | "☀️ ", "☀️ ", "☀️ ", "🌤 ", "⛅️ ", "🌥 ", "☁️ ", "🌧 ", "🌨 ", "🌧 ", "🌨 ", "🌧 ", "🌨 ", 48 | "⛈ ", "🌨 ", "🌧 ", "🌨 ", "☁️ ", "🌥 ", "⛅️ ", "🌤 ", "☀️ ", "☀️ ", 49 | ]) 50 | .template("{spinner:.green} {msg}"), 51 | ); 52 | spinner 53 | } 54 | 55 | pub fn unsupported_version(version: &Version) { 56 | println!( 57 | "{}", 58 | style(format!("Version: {} unsupported", version)).red() 59 | ); 60 | } 61 | 62 | pub fn set_global_version(version: &Version) { 63 | ProgressBar::new_spinner().finish_with_message(format!("Global version set: {}", version)); 64 | } 65 | 66 | pub fn version_not_found(version: &Version) { 67 | println!("{}", style(format!("Version: {} not found", version)).red()); 68 | } 69 | -------------------------------------------------------------------------------- /src/vyper/cache.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{Result, VyperError}; 2 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; 3 | use std::{ 4 | collections::btree_map::BTreeMap, 5 | fs::{self}, 6 | io, 7 | path::{Path, PathBuf}, 8 | }; 9 | use vvm_lib::VVM_HOME; 10 | 11 | use md5::Digest; 12 | 13 | // simplified cache based on ether-rs solc logic with adjustments for vyper 14 | // https://github.com/gakonst/ethers-rs/blob/c75608eda1e1fdc7366a7501c1a6b3f0216a25ea/ethers-solc/src/cache.rs 15 | 16 | // close to ether-rs solidity cache format 17 | const FORMAT_VERSION: &str = "vvm-rs-vyper-cache-1"; 18 | 19 | /// The file name of the default cache file 20 | pub const VYPER_FILES_CACHE_FILENAME: &str = "vvm-vyper-files-cache.json"; 21 | 22 | /// A cache file 23 | #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] 24 | pub struct VyperFilesCache { 25 | #[serde(rename = "_format")] 26 | pub format: String, 27 | pub files: BTreeMap, 28 | } 29 | 30 | impl VyperFilesCache { 31 | /// Create a new cache instance with empty entries 32 | fn new() -> Self { 33 | Self { 34 | format: FORMAT_VERSION.to_string(), 35 | files: BTreeMap::new(), 36 | } 37 | } 38 | 39 | // loads existing cache or create a new one 40 | pub fn get() -> Self { 41 | if let Ok(cache) = VyperFilesCache::read(get_cache_path()) { 42 | cache 43 | } else { 44 | VyperFilesCache::new() 45 | } 46 | } 47 | 48 | // pub fn is_empty(&self) -> bool { 49 | // self.files.is_empty() 50 | // } 51 | 52 | /// How many entries the cache contains where each entry represents a source file 53 | pub fn len(&self) -> usize { 54 | self.files.len() 55 | } 56 | 57 | /// Returns the corresponding `CacheEntry` for the file if it exists 58 | pub fn entry(&self, file: impl AsRef) -> Option<&CacheEntry> { 59 | self.files.get(file.as_ref()) 60 | } 61 | 62 | /// Returns the corresponding `CacheEntry` for the file if it exists 63 | pub fn entry_mut(&mut self, file: impl AsRef) -> Option<&mut CacheEntry> { 64 | self.files.get_mut(file.as_ref()) 65 | } 66 | 67 | /// adds or updates an entry in cache 68 | pub fn add_entry(&mut self, file: impl AsRef, bytecode: &str) -> Result<()> { 69 | if let Some(mut entry) = self.entry_mut(file.as_ref()) { 70 | // update 71 | entry.content_hash = get_file_hash(file.as_ref())?; 72 | entry.deployed_bytecode = bytecode.to_string(); 73 | } 74 | 75 | // add new entry 76 | let new_entry = CacheEntry { 77 | content_hash: get_file_hash(file.as_ref())?, 78 | source_name: file.as_ref().to_path_buf(), 79 | deployed_bytecode: bytecode.to_string(), 80 | }; 81 | 82 | self.files.insert(file.as_ref().to_path_buf(), new_entry); 83 | 84 | Ok(()) 85 | } 86 | 87 | /// Reads the cache json file from the given path 88 | #[tracing::instrument(skip_all, name = "vyper-files-cache::read")] 89 | pub fn read(path: impl AsRef) -> Result { 90 | let path = path.as_ref(); 91 | tracing::trace!("reading vyper files cache at {}", path.display()); 92 | let cache: VyperFilesCache = read_json_file(path)?; 93 | tracing::trace!( 94 | "read cache \"{}\" with {} entries", 95 | cache.format, 96 | cache.files.len() 97 | ); 98 | Ok(cache) 99 | } 100 | 101 | /// Write the cache as json file to the given path 102 | pub fn write(&self, path: impl AsRef) -> Result<()> { 103 | let path = path.as_ref(); 104 | create_parent_dir_all(path)?; 105 | let file = fs::File::create(path).map_err(|err| VyperError::io(err, path))?; 106 | tracing::trace!( 107 | "writing cache with {} entries to json file: \"{}\"", 108 | self.len(), 109 | path.display() 110 | ); 111 | serde_json::to_writer_pretty(file, self)?; 112 | tracing::trace!("cache file located: \"{}\"", path.display()); 113 | Ok(()) 114 | } 115 | } 116 | 117 | /// A `CacheEntry` in the cache file represents a vyper file 118 | /// 119 | /// TODO: add better cache invalidation of entries 120 | /// Simplified version of cache entry for basic caching 121 | #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] 122 | #[serde(rename_all = "camelCase")] 123 | pub struct CacheEntry { 124 | /// hash to identify whether the content of the file changed 125 | pub content_hash: String, 126 | /// identifier name 127 | pub source_name: PathBuf, 128 | // TODO: implement version 129 | // pub version_requirement: Option, 130 | // TODO: implement version 131 | // pub last_modified: : u6, 132 | pub deployed_bytecode: String, 133 | } 134 | 135 | impl CacheEntry { 136 | /// returns true file: 137 | /// - is new 138 | /// - has changed 139 | /// returns false if file si found and hash is the same 140 | pub fn is_dirty(&self) -> bool { 141 | if let Ok(hash) = get_file_hash(&self.source_name) { 142 | if hash == self.content_hash { 143 | return false; 144 | } 145 | } 146 | 147 | true 148 | } 149 | } 150 | 151 | ///// Helper Functions ///// 152 | 153 | fn get_file_hash(path: impl AsRef) -> Result { 154 | let path = path.as_ref(); 155 | let file = std::fs::File::open(path).map_err(|err| VyperError::io(err, path))?; 156 | let mut file = std::io::BufReader::new(file); 157 | 158 | let mut hasher = md5::Md5::new(); 159 | let _ = io::copy(&mut file, &mut hasher).map_err(|err| VyperError::io(err, path))?; 160 | let result = hasher.finalize(); 161 | 162 | Ok(hex::encode(result)) 163 | } 164 | 165 | /// Reads the json file and deserialize it into the provided type 166 | fn read_json_file(path: impl AsRef) -> Result { 167 | let path = path.as_ref(); 168 | let file = std::fs::File::open(path).map_err(|err| VyperError::io(err, path))?; 169 | let file = std::io::BufReader::new(file); 170 | let val: T = serde_json::from_reader(file)?; 171 | Ok(val) 172 | } 173 | 174 | /// Creates the parent directory of the `file` and all its ancestors if it does not exist 175 | /// See [`std::fs::create_dir_all()`] 176 | fn create_parent_dir_all(file: impl AsRef) -> Result<()> { 177 | let file = file.as_ref(); 178 | if let Some(parent) = file.parent() { 179 | std::fs::create_dir_all(parent).map_err(|err| { 180 | VyperError::msg(format!( 181 | "Failed to create artifact parent folder \"{}\": {}", 182 | parent.display(), 183 | err 184 | )) 185 | })?; 186 | } 187 | Ok(()) 188 | } 189 | 190 | /// Get cache dir path 191 | pub fn get_cache_path() -> PathBuf { 192 | let mut cache_path = VVM_HOME.to_path_buf(); 193 | cache_path.push("cache"); 194 | cache_path.push(VYPER_FILES_CACHE_FILENAME); 195 | cache_path 196 | } 197 | 198 | #[test] 199 | fn test_read_cache_file() -> Result<()> { 200 | let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 201 | d.push(format!("test-data/{}", VYPER_FILES_CACHE_FILENAME)); 202 | 203 | let file_name = "test-data/Token.vy"; 204 | 205 | println!("path read cache {}", d.display()); 206 | 207 | let cache_result = VyperFilesCache::read(d); 208 | 209 | assert!(cache_result.is_ok()); 210 | 211 | let cache = cache_result.unwrap(); 212 | 213 | assert_eq!(cache.len(), 1); 214 | 215 | let cache_entry = cache 216 | .entry(file_name) 217 | .expect("expected cache entry to exist"); 218 | 219 | let CacheEntry { 220 | source_name, 221 | content_hash, 222 | deployed_bytecode, 223 | } = cache_entry; 224 | 225 | assert_eq!(source_name.as_os_str(), file_name); 226 | assert_eq!(content_hash, "089f6055c2d023b76eed71e820e7b580"); 227 | assert_eq!( 228 | deployed_bytecode, 229 | r#"0x61048561001161000039610485610000f36003361161000c5761046d565b60003560e01c34610473576306fdde03811861009f576004361861047357602080608052600a6040527f5465737420546f6b656e0000000000000000000000000000000000000000000060605260408160800181518082526020830160208301815181525050508051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506080f35b6395d89b41811861012757600436186104735760208060805260046040527f544553540000000000000000000000000000000000000000000000000000000060605260408160800181518082526020830160208301815181525050508051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506080f35b63313ce5678118610145576004361861047357601260405260206040f35b63a9059cbb81186101eb5760443618610473576004358060a01c610473576040526001336020526000526040600020805460243580820382811161047357905090508155506001604051602052600052604060002080546024358082018281106104735790509050815550604051337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60243560605260206060a3600160605260206060f35b63095ea7b3811861026a5760443618610473576004358060a01c610473576040526024356002336020526000526040600020806040516020526000526040600020905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f35b6323b872dd81186103575760643618610473576004358060a01c610473576040526024358060a01c610473576060526002604051602052600052604060002080336020526000526040600020905080546044358082038281116104735790509050815550600160405160205260005260406000208054604435808203828111610473579050905081555060016060516020526000526040600020805460443580820182811061047357905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60443560805260206080a3600160805260206080f35b6341a9680381186103b75760443618610473576004358060a01c6104735760405260016040516020526000526040600020805460243580820182811061047357905090508155506000546024358082018281106104735790509050600055005b6318160ddd81186103d657600436186104735760005460405260206040f35b6370a0823181186104115760243618610473576004358060a01c61047357604052600160405160205260005260406000205460605260206060f35b63dd62ed3e811861046b5760443618610473576004358060a01c610473576040526024358060a01c610473576060526002604051602052600052604060002080606051602052600052604060002090505460805260206080f35b505b60006000fd5b600080fda165767970657283000306000b"# 230 | ); 231 | 232 | Ok(()) 233 | } 234 | 235 | #[test] 236 | fn test_get_file_hash() -> Result<()> { 237 | let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 238 | path.push("test-data/Token.vy"); 239 | 240 | let expected_hash = "089f6055c2d023b76eed71e820e7b580"; 241 | let hash = get_file_hash(path)?; 242 | assert_eq!(hash, expected_hash); 243 | 244 | Ok(()) 245 | } 246 | 247 | #[test] 248 | fn test_cache_entry_is_dirty() -> Result<()> { 249 | let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 250 | path.push("test-data/Token.vy"); 251 | 252 | const BAD_HASH: &str = "b95e2a6f5312b7df45db0caa631f2d21"; 253 | 254 | let clean_entry = CacheEntry { 255 | content_hash: "089f6055c2d023b76eed71e820e7b580".to_string(), 256 | source_name: path.clone(), 257 | deployed_bytecode: "mockbytecode".to_string(), 258 | }; 259 | 260 | let dirty_entry = CacheEntry { 261 | content_hash: BAD_HASH.to_string(), 262 | source_name: path.clone(), 263 | deployed_bytecode: "mockbytecode".to_string(), 264 | }; 265 | 266 | assert!(clean_entry.is_dirty() != true); 267 | assert!(dirty_entry.is_dirty()); 268 | 269 | Ok(()) 270 | } 271 | 272 | #[test] 273 | fn test_add_cache_entry() -> Result<()> { 274 | let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 275 | path.push("test-data/Token.vy"); 276 | 277 | const UPDATED_BYTECODE: &str = "mocknewbytecode"; 278 | const MOCK_BYTECODE: &str = "mockbytecode"; 279 | const CONTENT_HASH: &str = "089f6055c2d023b76eed71e820e7b580"; 280 | 281 | let new_entry = CacheEntry { 282 | content_hash: "089f6055c2d023b76eed71e820e7b580".to_string(), 283 | source_name: path.clone(), 284 | deployed_bytecode: MOCK_BYTECODE.to_string(), 285 | }; 286 | 287 | let mut cache = VyperFilesCache::new(); 288 | 289 | cache.add_entry(&path, &MOCK_BYTECODE)?; 290 | 291 | assert!(cache.len() > 0); 292 | let first_entry_op = cache.entry(new_entry.source_name); 293 | assert!(first_entry_op.is_some()); 294 | let first_entry = first_entry_op.unwrap(); 295 | assert_eq!(first_entry.deployed_bytecode, MOCK_BYTECODE); 296 | assert_eq!(first_entry.content_hash, CONTENT_HASH); 297 | 298 | // update 299 | cache.add_entry(&path, &UPDATED_BYTECODE)?; 300 | assert!(cache.len() == 1); 301 | let updated_entry = cache.entry(path.clone()); 302 | assert!(updated_entry.is_some()); 303 | assert_eq!(updated_entry.unwrap().deployed_bytecode, UPDATED_BYTECODE); 304 | 305 | Ok(()) 306 | } 307 | -------------------------------------------------------------------------------- /src/vyper/error.rs: -------------------------------------------------------------------------------- 1 | use std::{io, path::PathBuf}; 2 | use thiserror::Error; 3 | 4 | pub type Result = std::result::Result; 5 | 6 | /// Error types 7 | #[derive(Debug, Error)] 8 | pub enum VyperError { 9 | /// Internal error 10 | // #[error("Vyper Error: {0}")] 11 | // VyperError(String), 12 | #[error(transparent)] 13 | SerdeJson(#[from] serde_json::Error), 14 | #[error(transparent)] 15 | Io(#[from] VyperIoError), 16 | #[error(transparent)] 17 | VvmError(#[from] vvm_lib::VyperVmError), 18 | 19 | /// General purpose message 20 | #[error("{0}")] 21 | Message(String), 22 | } 23 | 24 | impl VyperError { 25 | pub(crate) fn io(err: io::Error, path: impl Into) -> Self { 26 | VyperIoError::new(err, path).into() 27 | } 28 | pub fn msg(msg: impl Into) -> Self { 29 | VyperError::Message(msg.into()) 30 | } 31 | } 32 | 33 | #[derive(Debug, Error)] 34 | #[error("\"{}\": {io}", self.path.display())] 35 | pub struct VyperIoError { 36 | io: io::Error, 37 | path: PathBuf, 38 | } 39 | 40 | impl VyperIoError { 41 | pub fn new(io: io::Error, path: impl Into) -> Self { 42 | Self { 43 | io, 44 | path: path.into(), 45 | } 46 | } 47 | } 48 | 49 | impl From for io::Error { 50 | fn from(err: VyperIoError) -> Self { 51 | err.io 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/vyper/main.rs: -------------------------------------------------------------------------------- 1 | mod cache; 2 | mod error; 3 | 4 | use cache::VyperFilesCache; 5 | use std::{ 6 | env, fs, 7 | path::PathBuf, 8 | process::{Command, Stdio}, 9 | }; 10 | 11 | use crate::error::VyperError; 12 | 13 | #[tokio::main] 14 | async fn main() -> error::Result<()> { 15 | let args = env::args().skip(1).collect::>(); 16 | 17 | // setup .vvm/ dir in home directory 18 | vvm_lib::setup_home()?; 19 | 20 | let mut cache = VyperFilesCache::get(); 21 | let mut file_name: Option = None; 22 | 23 | if args.len() == 1 && !args[0].starts_with('-') { 24 | let file_name_canon = 25 | fs::canonicalize(&args[0]).map_err(|err| VyperError::io(err, &args[0]))?; 26 | file_name = Some(file_name_canon); 27 | // support cache only for single file inputs 28 | if let Some(entry) = cache.entry(file_name.clone().unwrap()) { 29 | if !entry.is_dirty() { 30 | // print out cached version 31 | println!("{}", entry.deployed_bytecode); 32 | return Ok(()); 33 | } 34 | } 35 | } 36 | 37 | // if we are here it means cache entry was not found or was dirty 38 | // compile as normal and update/create cache file 39 | let version = vvm_lib::current_version()?.ok_or(vvm_lib::VyperVmError::GlobalVersionNotSet)?; 40 | let mut version_path = vvm_lib::version_path(version.to_string().as_str()); 41 | version_path.push(format!("vyper-{}", version.to_string().as_str())); 42 | 43 | let child = Command::new(version_path) 44 | .args(args.clone()) 45 | .stdout(Stdio::piped()) 46 | .spawn() 47 | .expect("Vyper wrapper: failed to execute vyper command"); 48 | 49 | let output = child 50 | .wait_with_output() 51 | .expect("Vyper wrapper: failed to wait for child output"); 52 | 53 | if output.status.success() { 54 | println!("{}", std::str::from_utf8(&output.stdout).unwrap()); 55 | // cache house keeping 56 | if args.len() == 1 && !args[0].starts_with('-') { 57 | if let Some(bytecode) = get_bytecode(&output.stdout) { 58 | if cache.add_entry(file_name.unwrap(), &bytecode).is_ok() { 59 | let _ = cache.write(cache::get_cache_path()); 60 | // ignore errors 61 | // TODO: add debug statements 62 | } 63 | } 64 | } 65 | } else { 66 | println!("{}", std::str::from_utf8(&output.stderr).unwrap()); 67 | } 68 | 69 | Ok(()) 70 | } 71 | 72 | fn get_bytecode(bytecode: &[u8]) -> Option { 73 | return match std::str::from_utf8(bytecode) { 74 | Ok(b) if b.starts_with("0x") => Some(b.to_string()), 75 | Ok(_) => None, 76 | _ => None, 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /test-data/Token.vy: -------------------------------------------------------------------------------- 1 | # @version 0.3.6 2 | from vyper.interfaces import ERC20 3 | 4 | implements: ERC20 5 | 6 | totalSupply: public(uint256) 7 | balanceOf: public(HashMap[address, uint256]) 8 | allowance: public(HashMap[address, HashMap[address, uint256]]) 9 | 10 | NAME: constant(String[10]) = "Test Token" 11 | SYMBOL: constant(String[4]) = "TEST" 12 | DECIMALS: constant(uint8) = 18 13 | 14 | event Transfer: 15 | sender: indexed(address) 16 | receiver: indexed(address) 17 | amount: uint256 18 | 19 | event Approval: 20 | owner: indexed(address) 21 | spender: indexed(address) 22 | allowance: uint256 23 | 24 | @view 25 | @external 26 | def name() -> String[10]: 27 | return NAME 28 | 29 | 30 | @view 31 | @external 32 | def symbol() -> String[4]: 33 | return SYMBOL 34 | 35 | 36 | @view 37 | @external 38 | def decimals() -> uint8: 39 | return DECIMALS 40 | 41 | 42 | @external 43 | def transfer(receiver: address, amount: uint256) -> bool: 44 | self.balanceOf[msg.sender] -= amount 45 | self.balanceOf[receiver] += amount 46 | log Transfer(msg.sender, receiver, amount) 47 | return True 48 | 49 | 50 | @external 51 | def approve(spender: address, amount: uint256) -> bool: 52 | self.allowance[msg.sender][spender] = amount 53 | log Approval(msg.sender, spender, amount) 54 | return True 55 | 56 | 57 | @external 58 | def transferFrom(sender: address, receiver: address, amount: uint256) -> bool: 59 | self.allowance[sender][msg.sender] -= amount 60 | self.balanceOf[sender] -= amount 61 | self.balanceOf[receiver] += amount 62 | log Transfer(sender, receiver, amount) 63 | return True 64 | 65 | 66 | @external 67 | def DEBUG_mint(receiver: address, amount: uint256): 68 | self.balanceOf[receiver] += amount 69 | self.totalSupply += amount -------------------------------------------------------------------------------- /test-data/vvm-vyper-files-cache.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "vvm-rs-vyper-cache-1", 3 | "files": { 4 | "test-data/Token.vy": { 5 | "contentHash": "089f6055c2d023b76eed71e820e7b580", 6 | "sourceName": "test-data/Token.vy", 7 | "deployedBytecode": "0x61048561001161000039610485610000f36003361161000c5761046d565b60003560e01c34610473576306fdde03811861009f576004361861047357602080608052600a6040527f5465737420546f6b656e0000000000000000000000000000000000000000000060605260408160800181518082526020830160208301815181525050508051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506080f35b6395d89b41811861012757600436186104735760208060805260046040527f544553540000000000000000000000000000000000000000000000000000000060605260408160800181518082526020830160208301815181525050508051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506080f35b63313ce5678118610145576004361861047357601260405260206040f35b63a9059cbb81186101eb5760443618610473576004358060a01c610473576040526001336020526000526040600020805460243580820382811161047357905090508155506001604051602052600052604060002080546024358082018281106104735790509050815550604051337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60243560605260206060a3600160605260206060f35b63095ea7b3811861026a5760443618610473576004358060a01c610473576040526024356002336020526000526040600020806040516020526000526040600020905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f35b6323b872dd81186103575760643618610473576004358060a01c610473576040526024358060a01c610473576060526002604051602052600052604060002080336020526000526040600020905080546044358082038281116104735790509050815550600160405160205260005260406000208054604435808203828111610473579050905081555060016060516020526000526040600020805460443580820182811061047357905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60443560805260206080a3600160805260206080f35b6341a9680381186103b75760443618610473576004358060a01c6104735760405260016040516020526000526040600020805460243580820182811061047357905090508155506000546024358082018281106104735790509050600055005b6318160ddd81186103d657600436186104735760005460405260206040f35b6370a0823181186104115760243618610473576004358060a01c61047357604052600160405160205260005260406000205460605260206060f35b63dd62ed3e811861046b5760443618610473576004358060a01c610473576040526024358060a01c610473576060526002604051602052600052604060002080606051602052600052604060002090505460805260206080f35b505b60006000fd5b600080fda165767970657283000306000b" 8 | } 9 | } 10 | } --------------------------------------------------------------------------------