├── .github └── FUNDING.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── hurl ├── cardano-cli.hurl ├── cardano-node.hurl └── mithril.hurl ├── readme.md ├── rustfmt.toml └── src ├── commands ├── erase.rs ├── install.rs ├── list.rs ├── list_remote.rs ├── mod.rs ├── prefix.rs ├── uninstall.rs └── use_cmd.rs ├── dirs.rs ├── fs └── mod.rs ├── helpers ├── client │ └── mod.rs ├── mod.rs └── version │ └── mod.rs ├── main.rs ├── packages └── mod.rs ├── proxy └── mod.rs └── services ├── github.rs └── mod.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: falcucci 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aes" 22 | version = "0.8.4" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" 25 | dependencies = [ 26 | "cfg-if", 27 | "cipher", 28 | "cpufeatures", 29 | ] 30 | 31 | [[package]] 32 | name = "aho-corasick" 33 | version = "1.1.3" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 36 | dependencies = [ 37 | "memchr", 38 | ] 39 | 40 | [[package]] 41 | name = "android-tzdata" 42 | version = "0.1.1" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 45 | 46 | [[package]] 47 | name = "android_system_properties" 48 | version = "0.1.5" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 51 | dependencies = [ 52 | "libc", 53 | ] 54 | 55 | [[package]] 56 | name = "anstream" 57 | version = "0.6.14" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 60 | dependencies = [ 61 | "anstyle", 62 | "anstyle-parse", 63 | "anstyle-query", 64 | "anstyle-wincon", 65 | "colorchoice", 66 | "is_terminal_polyfill", 67 | "utf8parse", 68 | ] 69 | 70 | [[package]] 71 | name = "anstyle" 72 | version = "1.0.7" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 75 | 76 | [[package]] 77 | name = "anstyle-parse" 78 | version = "0.2.4" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 81 | dependencies = [ 82 | "utf8parse", 83 | ] 84 | 85 | [[package]] 86 | name = "anstyle-query" 87 | version = "1.0.3" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" 90 | dependencies = [ 91 | "windows-sys 0.52.0", 92 | ] 93 | 94 | [[package]] 95 | name = "anstyle-wincon" 96 | version = "3.0.3" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 99 | dependencies = [ 100 | "anstyle", 101 | "windows-sys 0.52.0", 102 | ] 103 | 104 | [[package]] 105 | name = "anyhow" 106 | version = "1.0.86" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 109 | 110 | [[package]] 111 | name = "arbitrary" 112 | version = "1.3.2" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" 115 | dependencies = [ 116 | "derive_arbitrary", 117 | ] 118 | 119 | [[package]] 120 | name = "arrayvec" 121 | version = "0.7.4" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" 124 | 125 | [[package]] 126 | name = "atomic-waker" 127 | version = "1.1.2" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 130 | 131 | [[package]] 132 | name = "autocfg" 133 | version = "1.3.0" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 136 | 137 | [[package]] 138 | name = "backtrace" 139 | version = "0.3.72" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" 142 | dependencies = [ 143 | "addr2line", 144 | "cc", 145 | "cfg-if", 146 | "libc", 147 | "miniz_oxide", 148 | "object", 149 | "rustc-demangle", 150 | ] 151 | 152 | [[package]] 153 | name = "backtrace-ext" 154 | version = "0.2.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" 157 | dependencies = [ 158 | "backtrace", 159 | ] 160 | 161 | [[package]] 162 | name = "base64" 163 | version = "0.22.1" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 166 | 167 | [[package]] 168 | name = "base64ct" 169 | version = "1.6.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 172 | 173 | [[package]] 174 | name = "bitflags" 175 | version = "1.3.2" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 178 | 179 | [[package]] 180 | name = "bitflags" 181 | version = "2.5.0" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 184 | 185 | [[package]] 186 | name = "block-buffer" 187 | version = "0.10.4" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 190 | dependencies = [ 191 | "generic-array", 192 | ] 193 | 194 | [[package]] 195 | name = "bumpalo" 196 | version = "3.16.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 199 | 200 | [[package]] 201 | name = "byteorder" 202 | version = "1.5.0" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 205 | 206 | [[package]] 207 | name = "bytes" 208 | version = "1.6.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" 211 | 212 | [[package]] 213 | name = "bzip2" 214 | version = "0.4.4" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" 217 | dependencies = [ 218 | "bzip2-sys", 219 | "libc", 220 | ] 221 | 222 | [[package]] 223 | name = "bzip2-sys" 224 | version = "0.1.11+1.0.8" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 227 | dependencies = [ 228 | "cc", 229 | "libc", 230 | "pkg-config", 231 | ] 232 | 233 | [[package]] 234 | name = "cc" 235 | version = "1.0.98" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" 238 | dependencies = [ 239 | "jobserver", 240 | "libc", 241 | "once_cell", 242 | ] 243 | 244 | [[package]] 245 | name = "cfg-if" 246 | version = "1.0.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 249 | 250 | [[package]] 251 | name = "cfg_aliases" 252 | version = "0.2.1" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 255 | 256 | [[package]] 257 | name = "chrono" 258 | version = "0.4.38" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 261 | dependencies = [ 262 | "android-tzdata", 263 | "iana-time-zone", 264 | "js-sys", 265 | "num-traits", 266 | "serde", 267 | "wasm-bindgen", 268 | "windows-targets 0.52.5", 269 | ] 270 | 271 | [[package]] 272 | name = "cipher" 273 | version = "0.4.4" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" 276 | dependencies = [ 277 | "crypto-common", 278 | "inout", 279 | ] 280 | 281 | [[package]] 282 | name = "clap" 283 | version = "4.5.4" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" 286 | dependencies = [ 287 | "clap_builder", 288 | "clap_derive", 289 | ] 290 | 291 | [[package]] 292 | name = "clap_builder" 293 | version = "4.5.2" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" 296 | dependencies = [ 297 | "anstream", 298 | "anstyle", 299 | "clap_lex", 300 | "strsim", 301 | ] 302 | 303 | [[package]] 304 | name = "clap_derive" 305 | version = "4.5.4" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" 308 | dependencies = [ 309 | "heck", 310 | "proc-macro2", 311 | "quote", 312 | "syn", 313 | ] 314 | 315 | [[package]] 316 | name = "clap_lex" 317 | version = "0.7.0" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" 320 | 321 | [[package]] 322 | name = "colorchoice" 323 | version = "1.0.1" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 326 | 327 | [[package]] 328 | name = "comfy-table" 329 | version = "7.1.1" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" 332 | dependencies = [ 333 | "crossterm", 334 | "strum", 335 | "strum_macros", 336 | "unicode-width", 337 | ] 338 | 339 | [[package]] 340 | name = "console" 341 | version = "0.15.8" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 344 | dependencies = [ 345 | "encode_unicode", 346 | "lazy_static", 347 | "libc", 348 | "unicode-width", 349 | "windows-sys 0.52.0", 350 | ] 351 | 352 | [[package]] 353 | name = "constant_time_eq" 354 | version = "0.1.5" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 357 | 358 | [[package]] 359 | name = "constant_time_eq" 360 | version = "0.3.0" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" 363 | 364 | [[package]] 365 | name = "core-foundation" 366 | version = "0.9.4" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 369 | dependencies = [ 370 | "core-foundation-sys", 371 | "libc", 372 | ] 373 | 374 | [[package]] 375 | name = "core-foundation-sys" 376 | version = "0.8.6" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 379 | 380 | [[package]] 381 | name = "cpufeatures" 382 | version = "0.2.12" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 385 | dependencies = [ 386 | "libc", 387 | ] 388 | 389 | [[package]] 390 | name = "crc" 391 | version = "3.2.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" 394 | dependencies = [ 395 | "crc-catalog", 396 | ] 397 | 398 | [[package]] 399 | name = "crc-catalog" 400 | version = "2.4.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 403 | 404 | [[package]] 405 | name = "crc32fast" 406 | version = "1.4.2" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 409 | dependencies = [ 410 | "cfg-if", 411 | ] 412 | 413 | [[package]] 414 | name = "crossbeam-utils" 415 | version = "0.8.20" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 418 | 419 | [[package]] 420 | name = "crossterm" 421 | version = "0.27.0" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" 424 | dependencies = [ 425 | "bitflags 2.5.0", 426 | "crossterm_winapi", 427 | "libc", 428 | "parking_lot", 429 | "winapi", 430 | ] 431 | 432 | [[package]] 433 | name = "crossterm_winapi" 434 | version = "0.9.1" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 437 | dependencies = [ 438 | "winapi", 439 | ] 440 | 441 | [[package]] 442 | name = "crypto-common" 443 | version = "0.1.6" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 446 | dependencies = [ 447 | "generic-array", 448 | "typenum", 449 | ] 450 | 451 | [[package]] 452 | name = "deflate64" 453 | version = "0.1.9" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" 456 | 457 | [[package]] 458 | name = "deranged" 459 | version = "0.3.11" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 462 | dependencies = [ 463 | "powerfmt", 464 | ] 465 | 466 | [[package]] 467 | name = "derive_arbitrary" 468 | version = "1.3.2" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" 471 | dependencies = [ 472 | "proc-macro2", 473 | "quote", 474 | "syn", 475 | ] 476 | 477 | [[package]] 478 | name = "digest" 479 | version = "0.10.7" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 482 | dependencies = [ 483 | "block-buffer", 484 | "crypto-common", 485 | "subtle", 486 | ] 487 | 488 | [[package]] 489 | name = "directories" 490 | version = "5.0.1" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" 493 | dependencies = [ 494 | "dirs-sys", 495 | ] 496 | 497 | [[package]] 498 | name = "dirs-sys" 499 | version = "0.4.1" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 502 | dependencies = [ 503 | "libc", 504 | "option-ext", 505 | "redox_users", 506 | "windows-sys 0.48.0", 507 | ] 508 | 509 | [[package]] 510 | name = "displaydoc" 511 | version = "0.2.5" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 514 | dependencies = [ 515 | "proc-macro2", 516 | "quote", 517 | "syn", 518 | ] 519 | 520 | [[package]] 521 | name = "encode_unicode" 522 | version = "0.3.6" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 525 | 526 | [[package]] 527 | name = "encoding_rs" 528 | version = "0.8.34" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 531 | dependencies = [ 532 | "cfg-if", 533 | ] 534 | 535 | [[package]] 536 | name = "equivalent" 537 | version = "1.0.1" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 540 | 541 | [[package]] 542 | name = "errno" 543 | version = "0.3.9" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 546 | dependencies = [ 547 | "libc", 548 | "windows-sys 0.52.0", 549 | ] 550 | 551 | [[package]] 552 | name = "fastrand" 553 | version = "2.1.0" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 556 | 557 | [[package]] 558 | name = "filetime" 559 | version = "0.2.23" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" 562 | dependencies = [ 563 | "cfg-if", 564 | "libc", 565 | "redox_syscall 0.4.1", 566 | "windows-sys 0.52.0", 567 | ] 568 | 569 | [[package]] 570 | name = "flate2" 571 | version = "1.0.30" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" 574 | dependencies = [ 575 | "crc32fast", 576 | "miniz_oxide", 577 | ] 578 | 579 | [[package]] 580 | name = "fnv" 581 | version = "1.0.7" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 584 | 585 | [[package]] 586 | name = "foreign-types" 587 | version = "0.3.2" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 590 | dependencies = [ 591 | "foreign-types-shared", 592 | ] 593 | 594 | [[package]] 595 | name = "foreign-types-shared" 596 | version = "0.1.1" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 599 | 600 | [[package]] 601 | name = "form_urlencoded" 602 | version = "1.2.1" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 605 | dependencies = [ 606 | "percent-encoding", 607 | ] 608 | 609 | [[package]] 610 | name = "futures-channel" 611 | version = "0.3.30" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 614 | dependencies = [ 615 | "futures-core", 616 | ] 617 | 618 | [[package]] 619 | name = "futures-core" 620 | version = "0.3.30" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 623 | 624 | [[package]] 625 | name = "futures-io" 626 | version = "0.3.30" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 629 | 630 | [[package]] 631 | name = "futures-macro" 632 | version = "0.3.30" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 635 | dependencies = [ 636 | "proc-macro2", 637 | "quote", 638 | "syn", 639 | ] 640 | 641 | [[package]] 642 | name = "futures-sink" 643 | version = "0.3.30" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 646 | 647 | [[package]] 648 | name = "futures-task" 649 | version = "0.3.30" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 652 | 653 | [[package]] 654 | name = "futures-util" 655 | version = "0.3.30" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 658 | dependencies = [ 659 | "futures-core", 660 | "futures-io", 661 | "futures-macro", 662 | "futures-sink", 663 | "futures-task", 664 | "memchr", 665 | "pin-project-lite", 666 | "pin-utils", 667 | "slab", 668 | ] 669 | 670 | [[package]] 671 | name = "generic-array" 672 | version = "0.14.7" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 675 | dependencies = [ 676 | "typenum", 677 | "version_check", 678 | ] 679 | 680 | [[package]] 681 | name = "getrandom" 682 | version = "0.2.15" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 685 | dependencies = [ 686 | "cfg-if", 687 | "libc", 688 | "wasi", 689 | ] 690 | 691 | [[package]] 692 | name = "gimli" 693 | version = "0.29.0" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 696 | 697 | [[package]] 698 | name = "h2" 699 | version = "0.4.5" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" 702 | dependencies = [ 703 | "atomic-waker", 704 | "bytes", 705 | "fnv", 706 | "futures-core", 707 | "futures-sink", 708 | "http", 709 | "indexmap", 710 | "slab", 711 | "tokio", 712 | "tokio-util", 713 | "tracing", 714 | ] 715 | 716 | [[package]] 717 | name = "hashbrown" 718 | version = "0.14.5" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 721 | 722 | [[package]] 723 | name = "heck" 724 | version = "0.5.0" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 727 | 728 | [[package]] 729 | name = "hermit-abi" 730 | version = "0.3.9" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 733 | 734 | [[package]] 735 | name = "hmac" 736 | version = "0.12.1" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 739 | dependencies = [ 740 | "digest", 741 | ] 742 | 743 | [[package]] 744 | name = "http" 745 | version = "1.1.0" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 748 | dependencies = [ 749 | "bytes", 750 | "fnv", 751 | "itoa", 752 | ] 753 | 754 | [[package]] 755 | name = "http-body" 756 | version = "1.0.1" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 759 | dependencies = [ 760 | "bytes", 761 | "http", 762 | ] 763 | 764 | [[package]] 765 | name = "http-body-util" 766 | version = "0.1.2" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 769 | dependencies = [ 770 | "bytes", 771 | "futures-util", 772 | "http", 773 | "http-body", 774 | "pin-project-lite", 775 | ] 776 | 777 | [[package]] 778 | name = "httparse" 779 | version = "1.9.4" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" 782 | 783 | [[package]] 784 | name = "hyper" 785 | version = "1.4.1" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 788 | dependencies = [ 789 | "bytes", 790 | "futures-channel", 791 | "futures-util", 792 | "h2", 793 | "http", 794 | "http-body", 795 | "httparse", 796 | "itoa", 797 | "pin-project-lite", 798 | "smallvec", 799 | "tokio", 800 | "want", 801 | ] 802 | 803 | [[package]] 804 | name = "hyper-jump" 805 | version = "0.9.2" 806 | dependencies = [ 807 | "anyhow", 808 | "chrono", 809 | "clap", 810 | "comfy-table", 811 | "directories", 812 | "flate2", 813 | "futures-util", 814 | "indicatif", 815 | "miette", 816 | "nix", 817 | "regex", 818 | "reqwest", 819 | "semver", 820 | "serde", 821 | "serde_json", 822 | "signal-hook", 823 | "tar", 824 | "tokio", 825 | "tracing", 826 | "tracing-indicatif", 827 | "tracing-subscriber", 828 | "xz2", 829 | "yansi", 830 | "zip 2.1.6", 831 | "zip-extract", 832 | ] 833 | 834 | [[package]] 835 | name = "hyper-rustls" 836 | version = "0.27.2" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" 839 | dependencies = [ 840 | "futures-util", 841 | "http", 842 | "hyper", 843 | "hyper-util", 844 | "rustls", 845 | "rustls-pki-types", 846 | "tokio", 847 | "tokio-rustls", 848 | "tower-service", 849 | "webpki-roots", 850 | ] 851 | 852 | [[package]] 853 | name = "hyper-tls" 854 | version = "0.6.0" 855 | source = "registry+https://github.com/rust-lang/crates.io-index" 856 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 857 | dependencies = [ 858 | "bytes", 859 | "http-body-util", 860 | "hyper", 861 | "hyper-util", 862 | "native-tls", 863 | "tokio", 864 | "tokio-native-tls", 865 | "tower-service", 866 | ] 867 | 868 | [[package]] 869 | name = "hyper-util" 870 | version = "0.1.6" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" 873 | dependencies = [ 874 | "bytes", 875 | "futures-channel", 876 | "futures-util", 877 | "http", 878 | "http-body", 879 | "hyper", 880 | "pin-project-lite", 881 | "socket2", 882 | "tokio", 883 | "tower", 884 | "tower-service", 885 | "tracing", 886 | ] 887 | 888 | [[package]] 889 | name = "iana-time-zone" 890 | version = "0.1.60" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 893 | dependencies = [ 894 | "android_system_properties", 895 | "core-foundation-sys", 896 | "iana-time-zone-haiku", 897 | "js-sys", 898 | "wasm-bindgen", 899 | "windows-core", 900 | ] 901 | 902 | [[package]] 903 | name = "iana-time-zone-haiku" 904 | version = "0.1.2" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 907 | dependencies = [ 908 | "cc", 909 | ] 910 | 911 | [[package]] 912 | name = "idna" 913 | version = "0.5.0" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 916 | dependencies = [ 917 | "unicode-bidi", 918 | "unicode-normalization", 919 | ] 920 | 921 | [[package]] 922 | name = "indexmap" 923 | version = "2.2.6" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 926 | dependencies = [ 927 | "equivalent", 928 | "hashbrown", 929 | ] 930 | 931 | [[package]] 932 | name = "indicatif" 933 | version = "0.17.8" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" 936 | dependencies = [ 937 | "console", 938 | "instant", 939 | "number_prefix", 940 | "portable-atomic", 941 | "unicode-width", 942 | "vt100", 943 | ] 944 | 945 | [[package]] 946 | name = "inout" 947 | version = "0.1.3" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" 950 | dependencies = [ 951 | "generic-array", 952 | ] 953 | 954 | [[package]] 955 | name = "instant" 956 | version = "0.1.13" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" 959 | dependencies = [ 960 | "cfg-if", 961 | ] 962 | 963 | [[package]] 964 | name = "ipnet" 965 | version = "2.9.0" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 968 | 969 | [[package]] 970 | name = "is-terminal" 971 | version = "0.4.12" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" 974 | dependencies = [ 975 | "hermit-abi", 976 | "libc", 977 | "windows-sys 0.52.0", 978 | ] 979 | 980 | [[package]] 981 | name = "is_ci" 982 | version = "1.2.0" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" 985 | 986 | [[package]] 987 | name = "is_terminal_polyfill" 988 | version = "1.70.0" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 991 | 992 | [[package]] 993 | name = "itoa" 994 | version = "1.0.11" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 997 | 998 | [[package]] 999 | name = "jobserver" 1000 | version = "0.1.32" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 1003 | dependencies = [ 1004 | "libc", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "js-sys" 1009 | version = "0.3.69" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 1012 | dependencies = [ 1013 | "wasm-bindgen", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "lazy_static" 1018 | version = "1.4.0" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1021 | 1022 | [[package]] 1023 | name = "libc" 1024 | version = "0.2.155" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 1027 | 1028 | [[package]] 1029 | name = "libredox" 1030 | version = "0.1.3" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 1033 | dependencies = [ 1034 | "bitflags 2.5.0", 1035 | "libc", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "linux-raw-sys" 1040 | version = "0.4.14" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 1043 | 1044 | [[package]] 1045 | name = "lock_api" 1046 | version = "0.4.12" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1049 | dependencies = [ 1050 | "autocfg", 1051 | "scopeguard", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "lockfree-object-pool" 1056 | version = "0.1.6" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" 1059 | 1060 | [[package]] 1061 | name = "log" 1062 | version = "0.4.21" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 1065 | 1066 | [[package]] 1067 | name = "lzma-rs" 1068 | version = "0.3.0" 1069 | source = "registry+https://github.com/rust-lang/crates.io-index" 1070 | checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" 1071 | dependencies = [ 1072 | "byteorder", 1073 | "crc", 1074 | ] 1075 | 1076 | [[package]] 1077 | name = "lzma-sys" 1078 | version = "0.1.20" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" 1081 | dependencies = [ 1082 | "cc", 1083 | "libc", 1084 | "pkg-config", 1085 | ] 1086 | 1087 | [[package]] 1088 | name = "memchr" 1089 | version = "2.7.2" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 1092 | 1093 | [[package]] 1094 | name = "miette" 1095 | version = "5.10.0" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" 1098 | dependencies = [ 1099 | "backtrace", 1100 | "backtrace-ext", 1101 | "is-terminal", 1102 | "miette-derive", 1103 | "once_cell", 1104 | "owo-colors", 1105 | "supports-color", 1106 | "supports-hyperlinks", 1107 | "supports-unicode", 1108 | "terminal_size", 1109 | "textwrap", 1110 | "thiserror", 1111 | "unicode-width", 1112 | ] 1113 | 1114 | [[package]] 1115 | name = "miette-derive" 1116 | version = "5.10.0" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" 1119 | dependencies = [ 1120 | "proc-macro2", 1121 | "quote", 1122 | "syn", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "mime" 1127 | version = "0.3.17" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1130 | 1131 | [[package]] 1132 | name = "miniz_oxide" 1133 | version = "0.7.3" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" 1136 | dependencies = [ 1137 | "adler", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "mio" 1142 | version = "0.8.11" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 1145 | dependencies = [ 1146 | "libc", 1147 | "wasi", 1148 | "windows-sys 0.48.0", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "native-tls" 1153 | version = "0.2.12" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 1156 | dependencies = [ 1157 | "libc", 1158 | "log", 1159 | "openssl", 1160 | "openssl-probe", 1161 | "openssl-sys", 1162 | "schannel", 1163 | "security-framework", 1164 | "security-framework-sys", 1165 | "tempfile", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "nix" 1170 | version = "0.29.0" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" 1173 | dependencies = [ 1174 | "bitflags 2.5.0", 1175 | "cfg-if", 1176 | "cfg_aliases", 1177 | "libc", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "nu-ansi-term" 1182 | version = "0.46.0" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1185 | dependencies = [ 1186 | "overload", 1187 | "winapi", 1188 | ] 1189 | 1190 | [[package]] 1191 | name = "num-conv" 1192 | version = "0.1.0" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1195 | 1196 | [[package]] 1197 | name = "num-traits" 1198 | version = "0.2.19" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1201 | dependencies = [ 1202 | "autocfg", 1203 | ] 1204 | 1205 | [[package]] 1206 | name = "num_cpus" 1207 | version = "1.16.0" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1210 | dependencies = [ 1211 | "hermit-abi", 1212 | "libc", 1213 | ] 1214 | 1215 | [[package]] 1216 | name = "number_prefix" 1217 | version = "0.4.0" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" 1220 | 1221 | [[package]] 1222 | name = "object" 1223 | version = "0.35.0" 1224 | source = "registry+https://github.com/rust-lang/crates.io-index" 1225 | checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" 1226 | dependencies = [ 1227 | "memchr", 1228 | ] 1229 | 1230 | [[package]] 1231 | name = "once_cell" 1232 | version = "1.19.0" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 1235 | 1236 | [[package]] 1237 | name = "openssl" 1238 | version = "0.10.64" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" 1241 | dependencies = [ 1242 | "bitflags 2.5.0", 1243 | "cfg-if", 1244 | "foreign-types", 1245 | "libc", 1246 | "once_cell", 1247 | "openssl-macros", 1248 | "openssl-sys", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "openssl-macros" 1253 | version = "0.1.1" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1256 | dependencies = [ 1257 | "proc-macro2", 1258 | "quote", 1259 | "syn", 1260 | ] 1261 | 1262 | [[package]] 1263 | name = "openssl-probe" 1264 | version = "0.1.5" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1267 | 1268 | [[package]] 1269 | name = "openssl-sys" 1270 | version = "0.9.102" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" 1273 | dependencies = [ 1274 | "cc", 1275 | "libc", 1276 | "pkg-config", 1277 | "vcpkg", 1278 | ] 1279 | 1280 | [[package]] 1281 | name = "option-ext" 1282 | version = "0.2.0" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 1285 | 1286 | [[package]] 1287 | name = "overload" 1288 | version = "0.1.1" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1291 | 1292 | [[package]] 1293 | name = "owo-colors" 1294 | version = "3.5.0" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 1297 | 1298 | [[package]] 1299 | name = "parking_lot" 1300 | version = "0.12.3" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1303 | dependencies = [ 1304 | "lock_api", 1305 | "parking_lot_core", 1306 | ] 1307 | 1308 | [[package]] 1309 | name = "parking_lot_core" 1310 | version = "0.9.10" 1311 | source = "registry+https://github.com/rust-lang/crates.io-index" 1312 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1313 | dependencies = [ 1314 | "cfg-if", 1315 | "libc", 1316 | "redox_syscall 0.5.1", 1317 | "smallvec", 1318 | "windows-targets 0.52.5", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "password-hash" 1323 | version = "0.4.2" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" 1326 | dependencies = [ 1327 | "base64ct", 1328 | "rand_core", 1329 | "subtle", 1330 | ] 1331 | 1332 | [[package]] 1333 | name = "pbkdf2" 1334 | version = "0.11.0" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" 1337 | dependencies = [ 1338 | "digest", 1339 | "hmac", 1340 | "password-hash", 1341 | "sha2", 1342 | ] 1343 | 1344 | [[package]] 1345 | name = "pbkdf2" 1346 | version = "0.12.2" 1347 | source = "registry+https://github.com/rust-lang/crates.io-index" 1348 | checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" 1349 | dependencies = [ 1350 | "digest", 1351 | "hmac", 1352 | ] 1353 | 1354 | [[package]] 1355 | name = "percent-encoding" 1356 | version = "2.3.1" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1359 | 1360 | [[package]] 1361 | name = "pin-project" 1362 | version = "1.1.5" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 1365 | dependencies = [ 1366 | "pin-project-internal", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "pin-project-internal" 1371 | version = "1.1.5" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 1374 | dependencies = [ 1375 | "proc-macro2", 1376 | "quote", 1377 | "syn", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "pin-project-lite" 1382 | version = "0.2.14" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1385 | 1386 | [[package]] 1387 | name = "pin-utils" 1388 | version = "0.1.0" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1391 | 1392 | [[package]] 1393 | name = "pkg-config" 1394 | version = "0.3.30" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 1397 | 1398 | [[package]] 1399 | name = "portable-atomic" 1400 | version = "1.6.0" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" 1403 | 1404 | [[package]] 1405 | name = "powerfmt" 1406 | version = "0.2.0" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1409 | 1410 | [[package]] 1411 | name = "ppv-lite86" 1412 | version = "0.2.17" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1415 | 1416 | [[package]] 1417 | name = "proc-macro2" 1418 | version = "1.0.84" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" 1421 | dependencies = [ 1422 | "unicode-ident", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "quinn" 1427 | version = "0.11.2" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" 1430 | dependencies = [ 1431 | "bytes", 1432 | "pin-project-lite", 1433 | "quinn-proto", 1434 | "quinn-udp", 1435 | "rustc-hash", 1436 | "rustls", 1437 | "thiserror", 1438 | "tokio", 1439 | "tracing", 1440 | ] 1441 | 1442 | [[package]] 1443 | name = "quinn-proto" 1444 | version = "0.11.3" 1445 | source = "registry+https://github.com/rust-lang/crates.io-index" 1446 | checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" 1447 | dependencies = [ 1448 | "bytes", 1449 | "rand", 1450 | "ring", 1451 | "rustc-hash", 1452 | "rustls", 1453 | "slab", 1454 | "thiserror", 1455 | "tinyvec", 1456 | "tracing", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "quinn-udp" 1461 | version = "0.5.2" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" 1464 | dependencies = [ 1465 | "libc", 1466 | "once_cell", 1467 | "socket2", 1468 | "tracing", 1469 | "windows-sys 0.52.0", 1470 | ] 1471 | 1472 | [[package]] 1473 | name = "quote" 1474 | version = "1.0.36" 1475 | source = "registry+https://github.com/rust-lang/crates.io-index" 1476 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1477 | dependencies = [ 1478 | "proc-macro2", 1479 | ] 1480 | 1481 | [[package]] 1482 | name = "rand" 1483 | version = "0.8.5" 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" 1485 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1486 | dependencies = [ 1487 | "libc", 1488 | "rand_chacha", 1489 | "rand_core", 1490 | ] 1491 | 1492 | [[package]] 1493 | name = "rand_chacha" 1494 | version = "0.3.1" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1497 | dependencies = [ 1498 | "ppv-lite86", 1499 | "rand_core", 1500 | ] 1501 | 1502 | [[package]] 1503 | name = "rand_core" 1504 | version = "0.6.4" 1505 | source = "registry+https://github.com/rust-lang/crates.io-index" 1506 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1507 | dependencies = [ 1508 | "getrandom", 1509 | ] 1510 | 1511 | [[package]] 1512 | name = "redox_syscall" 1513 | version = "0.4.1" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 1516 | dependencies = [ 1517 | "bitflags 1.3.2", 1518 | ] 1519 | 1520 | [[package]] 1521 | name = "redox_syscall" 1522 | version = "0.5.1" 1523 | source = "registry+https://github.com/rust-lang/crates.io-index" 1524 | checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" 1525 | dependencies = [ 1526 | "bitflags 2.5.0", 1527 | ] 1528 | 1529 | [[package]] 1530 | name = "redox_users" 1531 | version = "0.4.5" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" 1534 | dependencies = [ 1535 | "getrandom", 1536 | "libredox", 1537 | "thiserror", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "regex" 1542 | version = "1.10.5" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 1545 | dependencies = [ 1546 | "aho-corasick", 1547 | "memchr", 1548 | "regex-automata", 1549 | "regex-syntax", 1550 | ] 1551 | 1552 | [[package]] 1553 | name = "regex-automata" 1554 | version = "0.4.7" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 1557 | dependencies = [ 1558 | "aho-corasick", 1559 | "memchr", 1560 | "regex-syntax", 1561 | ] 1562 | 1563 | [[package]] 1564 | name = "regex-syntax" 1565 | version = "0.8.4" 1566 | source = "registry+https://github.com/rust-lang/crates.io-index" 1567 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 1568 | 1569 | [[package]] 1570 | name = "reqwest" 1571 | version = "0.12.5" 1572 | source = "registry+https://github.com/rust-lang/crates.io-index" 1573 | checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" 1574 | dependencies = [ 1575 | "base64", 1576 | "bytes", 1577 | "encoding_rs", 1578 | "futures-core", 1579 | "futures-util", 1580 | "h2", 1581 | "http", 1582 | "http-body", 1583 | "http-body-util", 1584 | "hyper", 1585 | "hyper-rustls", 1586 | "hyper-tls", 1587 | "hyper-util", 1588 | "ipnet", 1589 | "js-sys", 1590 | "log", 1591 | "mime", 1592 | "native-tls", 1593 | "once_cell", 1594 | "percent-encoding", 1595 | "pin-project-lite", 1596 | "quinn", 1597 | "rustls", 1598 | "rustls-pemfile", 1599 | "rustls-pki-types", 1600 | "serde", 1601 | "serde_json", 1602 | "serde_urlencoded", 1603 | "sync_wrapper", 1604 | "system-configuration", 1605 | "tokio", 1606 | "tokio-native-tls", 1607 | "tokio-rustls", 1608 | "tokio-util", 1609 | "tower-service", 1610 | "url", 1611 | "wasm-bindgen", 1612 | "wasm-bindgen-futures", 1613 | "wasm-streams", 1614 | "web-sys", 1615 | "webpki-roots", 1616 | "winreg", 1617 | ] 1618 | 1619 | [[package]] 1620 | name = "ring" 1621 | version = "0.17.8" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1624 | dependencies = [ 1625 | "cc", 1626 | "cfg-if", 1627 | "getrandom", 1628 | "libc", 1629 | "spin", 1630 | "untrusted", 1631 | "windows-sys 0.52.0", 1632 | ] 1633 | 1634 | [[package]] 1635 | name = "rustc-demangle" 1636 | version = "0.1.24" 1637 | source = "registry+https://github.com/rust-lang/crates.io-index" 1638 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1639 | 1640 | [[package]] 1641 | name = "rustc-hash" 1642 | version = "1.1.0" 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" 1644 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1645 | 1646 | [[package]] 1647 | name = "rustix" 1648 | version = "0.38.34" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1651 | dependencies = [ 1652 | "bitflags 2.5.0", 1653 | "errno", 1654 | "libc", 1655 | "linux-raw-sys", 1656 | "windows-sys 0.52.0", 1657 | ] 1658 | 1659 | [[package]] 1660 | name = "rustls" 1661 | version = "0.23.11" 1662 | source = "registry+https://github.com/rust-lang/crates.io-index" 1663 | checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" 1664 | dependencies = [ 1665 | "once_cell", 1666 | "ring", 1667 | "rustls-pki-types", 1668 | "rustls-webpki", 1669 | "subtle", 1670 | "zeroize", 1671 | ] 1672 | 1673 | [[package]] 1674 | name = "rustls-pemfile" 1675 | version = "2.1.2" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" 1678 | dependencies = [ 1679 | "base64", 1680 | "rustls-pki-types", 1681 | ] 1682 | 1683 | [[package]] 1684 | name = "rustls-pki-types" 1685 | version = "1.7.0" 1686 | source = "registry+https://github.com/rust-lang/crates.io-index" 1687 | checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" 1688 | 1689 | [[package]] 1690 | name = "rustls-webpki" 1691 | version = "0.102.5" 1692 | source = "registry+https://github.com/rust-lang/crates.io-index" 1693 | checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" 1694 | dependencies = [ 1695 | "ring", 1696 | "rustls-pki-types", 1697 | "untrusted", 1698 | ] 1699 | 1700 | [[package]] 1701 | name = "rustversion" 1702 | version = "1.0.17" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 1705 | 1706 | [[package]] 1707 | name = "ryu" 1708 | version = "1.0.18" 1709 | source = "registry+https://github.com/rust-lang/crates.io-index" 1710 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1711 | 1712 | [[package]] 1713 | name = "schannel" 1714 | version = "0.1.23" 1715 | source = "registry+https://github.com/rust-lang/crates.io-index" 1716 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 1717 | dependencies = [ 1718 | "windows-sys 0.52.0", 1719 | ] 1720 | 1721 | [[package]] 1722 | name = "scopeguard" 1723 | version = "1.2.0" 1724 | source = "registry+https://github.com/rust-lang/crates.io-index" 1725 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1726 | 1727 | [[package]] 1728 | name = "security-framework" 1729 | version = "2.11.0" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" 1732 | dependencies = [ 1733 | "bitflags 2.5.0", 1734 | "core-foundation", 1735 | "core-foundation-sys", 1736 | "libc", 1737 | "security-framework-sys", 1738 | ] 1739 | 1740 | [[package]] 1741 | name = "security-framework-sys" 1742 | version = "2.11.0" 1743 | source = "registry+https://github.com/rust-lang/crates.io-index" 1744 | checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" 1745 | dependencies = [ 1746 | "core-foundation-sys", 1747 | "libc", 1748 | ] 1749 | 1750 | [[package]] 1751 | name = "semver" 1752 | version = "1.0.23" 1753 | source = "registry+https://github.com/rust-lang/crates.io-index" 1754 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1755 | 1756 | [[package]] 1757 | name = "serde" 1758 | version = "1.0.204" 1759 | source = "registry+https://github.com/rust-lang/crates.io-index" 1760 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" 1761 | dependencies = [ 1762 | "serde_derive", 1763 | ] 1764 | 1765 | [[package]] 1766 | name = "serde_derive" 1767 | version = "1.0.204" 1768 | source = "registry+https://github.com/rust-lang/crates.io-index" 1769 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" 1770 | dependencies = [ 1771 | "proc-macro2", 1772 | "quote", 1773 | "syn", 1774 | ] 1775 | 1776 | [[package]] 1777 | name = "serde_json" 1778 | version = "1.0.120" 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" 1780 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" 1781 | dependencies = [ 1782 | "itoa", 1783 | "ryu", 1784 | "serde", 1785 | ] 1786 | 1787 | [[package]] 1788 | name = "serde_urlencoded" 1789 | version = "0.7.1" 1790 | source = "registry+https://github.com/rust-lang/crates.io-index" 1791 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1792 | dependencies = [ 1793 | "form_urlencoded", 1794 | "itoa", 1795 | "ryu", 1796 | "serde", 1797 | ] 1798 | 1799 | [[package]] 1800 | name = "sha1" 1801 | version = "0.10.6" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1804 | dependencies = [ 1805 | "cfg-if", 1806 | "cpufeatures", 1807 | "digest", 1808 | ] 1809 | 1810 | [[package]] 1811 | name = "sha2" 1812 | version = "0.10.8" 1813 | source = "registry+https://github.com/rust-lang/crates.io-index" 1814 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1815 | dependencies = [ 1816 | "cfg-if", 1817 | "cpufeatures", 1818 | "digest", 1819 | ] 1820 | 1821 | [[package]] 1822 | name = "sharded-slab" 1823 | version = "0.1.7" 1824 | source = "registry+https://github.com/rust-lang/crates.io-index" 1825 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1826 | dependencies = [ 1827 | "lazy_static", 1828 | ] 1829 | 1830 | [[package]] 1831 | name = "signal-hook" 1832 | version = "0.3.17" 1833 | source = "registry+https://github.com/rust-lang/crates.io-index" 1834 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 1835 | dependencies = [ 1836 | "libc", 1837 | "signal-hook-registry", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "signal-hook-registry" 1842 | version = "1.4.2" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1845 | dependencies = [ 1846 | "libc", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "simd-adler32" 1851 | version = "0.3.7" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1854 | 1855 | [[package]] 1856 | name = "slab" 1857 | version = "0.4.9" 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" 1859 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1860 | dependencies = [ 1861 | "autocfg", 1862 | ] 1863 | 1864 | [[package]] 1865 | name = "smallvec" 1866 | version = "1.13.2" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1869 | 1870 | [[package]] 1871 | name = "smawk" 1872 | version = "0.3.2" 1873 | source = "registry+https://github.com/rust-lang/crates.io-index" 1874 | checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" 1875 | 1876 | [[package]] 1877 | name = "socket2" 1878 | version = "0.5.7" 1879 | source = "registry+https://github.com/rust-lang/crates.io-index" 1880 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1881 | dependencies = [ 1882 | "libc", 1883 | "windows-sys 0.52.0", 1884 | ] 1885 | 1886 | [[package]] 1887 | name = "spin" 1888 | version = "0.9.8" 1889 | source = "registry+https://github.com/rust-lang/crates.io-index" 1890 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1891 | 1892 | [[package]] 1893 | name = "strsim" 1894 | version = "0.11.1" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1897 | 1898 | [[package]] 1899 | name = "strum" 1900 | version = "0.26.3" 1901 | source = "registry+https://github.com/rust-lang/crates.io-index" 1902 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 1903 | 1904 | [[package]] 1905 | name = "strum_macros" 1906 | version = "0.26.4" 1907 | source = "registry+https://github.com/rust-lang/crates.io-index" 1908 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 1909 | dependencies = [ 1910 | "heck", 1911 | "proc-macro2", 1912 | "quote", 1913 | "rustversion", 1914 | "syn", 1915 | ] 1916 | 1917 | [[package]] 1918 | name = "subtle" 1919 | version = "2.6.1" 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" 1921 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1922 | 1923 | [[package]] 1924 | name = "supports-color" 1925 | version = "2.1.0" 1926 | source = "registry+https://github.com/rust-lang/crates.io-index" 1927 | checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" 1928 | dependencies = [ 1929 | "is-terminal", 1930 | "is_ci", 1931 | ] 1932 | 1933 | [[package]] 1934 | name = "supports-hyperlinks" 1935 | version = "2.1.0" 1936 | source = "registry+https://github.com/rust-lang/crates.io-index" 1937 | checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" 1938 | dependencies = [ 1939 | "is-terminal", 1940 | ] 1941 | 1942 | [[package]] 1943 | name = "supports-unicode" 1944 | version = "2.1.0" 1945 | source = "registry+https://github.com/rust-lang/crates.io-index" 1946 | checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a" 1947 | dependencies = [ 1948 | "is-terminal", 1949 | ] 1950 | 1951 | [[package]] 1952 | name = "syn" 1953 | version = "2.0.66" 1954 | source = "registry+https://github.com/rust-lang/crates.io-index" 1955 | checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" 1956 | dependencies = [ 1957 | "proc-macro2", 1958 | "quote", 1959 | "unicode-ident", 1960 | ] 1961 | 1962 | [[package]] 1963 | name = "sync_wrapper" 1964 | version = "1.0.1" 1965 | source = "registry+https://github.com/rust-lang/crates.io-index" 1966 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 1967 | 1968 | [[package]] 1969 | name = "system-configuration" 1970 | version = "0.5.1" 1971 | source = "registry+https://github.com/rust-lang/crates.io-index" 1972 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 1973 | dependencies = [ 1974 | "bitflags 1.3.2", 1975 | "core-foundation", 1976 | "system-configuration-sys", 1977 | ] 1978 | 1979 | [[package]] 1980 | name = "system-configuration-sys" 1981 | version = "0.5.0" 1982 | source = "registry+https://github.com/rust-lang/crates.io-index" 1983 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 1984 | dependencies = [ 1985 | "core-foundation-sys", 1986 | "libc", 1987 | ] 1988 | 1989 | [[package]] 1990 | name = "tar" 1991 | version = "0.4.41" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" 1994 | dependencies = [ 1995 | "filetime", 1996 | "libc", 1997 | "xattr", 1998 | ] 1999 | 2000 | [[package]] 2001 | name = "tempfile" 2002 | version = "3.10.1" 2003 | source = "registry+https://github.com/rust-lang/crates.io-index" 2004 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 2005 | dependencies = [ 2006 | "cfg-if", 2007 | "fastrand", 2008 | "rustix", 2009 | "windows-sys 0.52.0", 2010 | ] 2011 | 2012 | [[package]] 2013 | name = "terminal_size" 2014 | version = "0.1.17" 2015 | source = "registry+https://github.com/rust-lang/crates.io-index" 2016 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 2017 | dependencies = [ 2018 | "libc", 2019 | "winapi", 2020 | ] 2021 | 2022 | [[package]] 2023 | name = "textwrap" 2024 | version = "0.15.2" 2025 | source = "registry+https://github.com/rust-lang/crates.io-index" 2026 | checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" 2027 | dependencies = [ 2028 | "smawk", 2029 | "unicode-linebreak", 2030 | "unicode-width", 2031 | ] 2032 | 2033 | [[package]] 2034 | name = "thiserror" 2035 | version = "1.0.63" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" 2038 | dependencies = [ 2039 | "thiserror-impl", 2040 | ] 2041 | 2042 | [[package]] 2043 | name = "thiserror-impl" 2044 | version = "1.0.63" 2045 | source = "registry+https://github.com/rust-lang/crates.io-index" 2046 | checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" 2047 | dependencies = [ 2048 | "proc-macro2", 2049 | "quote", 2050 | "syn", 2051 | ] 2052 | 2053 | [[package]] 2054 | name = "thread_local" 2055 | version = "1.1.8" 2056 | source = "registry+https://github.com/rust-lang/crates.io-index" 2057 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2058 | dependencies = [ 2059 | "cfg-if", 2060 | "once_cell", 2061 | ] 2062 | 2063 | [[package]] 2064 | name = "time" 2065 | version = "0.3.36" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 2068 | dependencies = [ 2069 | "deranged", 2070 | "num-conv", 2071 | "powerfmt", 2072 | "serde", 2073 | "time-core", 2074 | ] 2075 | 2076 | [[package]] 2077 | name = "time-core" 2078 | version = "0.1.2" 2079 | source = "registry+https://github.com/rust-lang/crates.io-index" 2080 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 2081 | 2082 | [[package]] 2083 | name = "tinyvec" 2084 | version = "1.8.0" 2085 | source = "registry+https://github.com/rust-lang/crates.io-index" 2086 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 2087 | dependencies = [ 2088 | "tinyvec_macros", 2089 | ] 2090 | 2091 | [[package]] 2092 | name = "tinyvec_macros" 2093 | version = "0.1.1" 2094 | source = "registry+https://github.com/rust-lang/crates.io-index" 2095 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2096 | 2097 | [[package]] 2098 | name = "tokio" 2099 | version = "1.37.0" 2100 | source = "registry+https://github.com/rust-lang/crates.io-index" 2101 | checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" 2102 | dependencies = [ 2103 | "backtrace", 2104 | "bytes", 2105 | "libc", 2106 | "mio", 2107 | "num_cpus", 2108 | "parking_lot", 2109 | "pin-project-lite", 2110 | "signal-hook-registry", 2111 | "socket2", 2112 | "tokio-macros", 2113 | "windows-sys 0.48.0", 2114 | ] 2115 | 2116 | [[package]] 2117 | name = "tokio-macros" 2118 | version = "2.2.0" 2119 | source = "registry+https://github.com/rust-lang/crates.io-index" 2120 | checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" 2121 | dependencies = [ 2122 | "proc-macro2", 2123 | "quote", 2124 | "syn", 2125 | ] 2126 | 2127 | [[package]] 2128 | name = "tokio-native-tls" 2129 | version = "0.3.1" 2130 | source = "registry+https://github.com/rust-lang/crates.io-index" 2131 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2132 | dependencies = [ 2133 | "native-tls", 2134 | "tokio", 2135 | ] 2136 | 2137 | [[package]] 2138 | name = "tokio-rustls" 2139 | version = "0.26.0" 2140 | source = "registry+https://github.com/rust-lang/crates.io-index" 2141 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 2142 | dependencies = [ 2143 | "rustls", 2144 | "rustls-pki-types", 2145 | "tokio", 2146 | ] 2147 | 2148 | [[package]] 2149 | name = "tokio-util" 2150 | version = "0.7.11" 2151 | source = "registry+https://github.com/rust-lang/crates.io-index" 2152 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 2153 | dependencies = [ 2154 | "bytes", 2155 | "futures-core", 2156 | "futures-sink", 2157 | "pin-project-lite", 2158 | "tokio", 2159 | ] 2160 | 2161 | [[package]] 2162 | name = "tower" 2163 | version = "0.4.13" 2164 | source = "registry+https://github.com/rust-lang/crates.io-index" 2165 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2166 | dependencies = [ 2167 | "futures-core", 2168 | "futures-util", 2169 | "pin-project", 2170 | "pin-project-lite", 2171 | "tokio", 2172 | "tower-layer", 2173 | "tower-service", 2174 | ] 2175 | 2176 | [[package]] 2177 | name = "tower-layer" 2178 | version = "0.3.2" 2179 | source = "registry+https://github.com/rust-lang/crates.io-index" 2180 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 2181 | 2182 | [[package]] 2183 | name = "tower-service" 2184 | version = "0.3.2" 2185 | source = "registry+https://github.com/rust-lang/crates.io-index" 2186 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 2187 | 2188 | [[package]] 2189 | name = "tracing" 2190 | version = "0.1.40" 2191 | source = "registry+https://github.com/rust-lang/crates.io-index" 2192 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 2193 | dependencies = [ 2194 | "pin-project-lite", 2195 | "tracing-attributes", 2196 | "tracing-core", 2197 | ] 2198 | 2199 | [[package]] 2200 | name = "tracing-attributes" 2201 | version = "0.1.27" 2202 | source = "registry+https://github.com/rust-lang/crates.io-index" 2203 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 2204 | dependencies = [ 2205 | "proc-macro2", 2206 | "quote", 2207 | "syn", 2208 | ] 2209 | 2210 | [[package]] 2211 | name = "tracing-core" 2212 | version = "0.1.32" 2213 | source = "registry+https://github.com/rust-lang/crates.io-index" 2214 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 2215 | dependencies = [ 2216 | "once_cell", 2217 | "valuable", 2218 | ] 2219 | 2220 | [[package]] 2221 | name = "tracing-indicatif" 2222 | version = "0.3.6" 2223 | source = "registry+https://github.com/rust-lang/crates.io-index" 2224 | checksum = "069580424efe11d97c3fef4197fa98c004fa26672cc71ad8770d224e23b1951d" 2225 | dependencies = [ 2226 | "indicatif", 2227 | "tracing", 2228 | "tracing-core", 2229 | "tracing-subscriber", 2230 | ] 2231 | 2232 | [[package]] 2233 | name = "tracing-log" 2234 | version = "0.2.0" 2235 | source = "registry+https://github.com/rust-lang/crates.io-index" 2236 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2237 | dependencies = [ 2238 | "log", 2239 | "once_cell", 2240 | "tracing-core", 2241 | ] 2242 | 2243 | [[package]] 2244 | name = "tracing-subscriber" 2245 | version = "0.3.18" 2246 | source = "registry+https://github.com/rust-lang/crates.io-index" 2247 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 2248 | dependencies = [ 2249 | "nu-ansi-term", 2250 | "sharded-slab", 2251 | "smallvec", 2252 | "thread_local", 2253 | "tracing-core", 2254 | "tracing-log", 2255 | ] 2256 | 2257 | [[package]] 2258 | name = "try-lock" 2259 | version = "0.2.5" 2260 | source = "registry+https://github.com/rust-lang/crates.io-index" 2261 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2262 | 2263 | [[package]] 2264 | name = "typenum" 2265 | version = "1.17.0" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2268 | 2269 | [[package]] 2270 | name = "unicode-bidi" 2271 | version = "0.3.15" 2272 | source = "registry+https://github.com/rust-lang/crates.io-index" 2273 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 2274 | 2275 | [[package]] 2276 | name = "unicode-ident" 2277 | version = "1.0.12" 2278 | source = "registry+https://github.com/rust-lang/crates.io-index" 2279 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 2280 | 2281 | [[package]] 2282 | name = "unicode-linebreak" 2283 | version = "0.1.5" 2284 | source = "registry+https://github.com/rust-lang/crates.io-index" 2285 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 2286 | 2287 | [[package]] 2288 | name = "unicode-normalization" 2289 | version = "0.1.23" 2290 | source = "registry+https://github.com/rust-lang/crates.io-index" 2291 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 2292 | dependencies = [ 2293 | "tinyvec", 2294 | ] 2295 | 2296 | [[package]] 2297 | name = "unicode-width" 2298 | version = "0.1.12" 2299 | source = "registry+https://github.com/rust-lang/crates.io-index" 2300 | checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" 2301 | 2302 | [[package]] 2303 | name = "untrusted" 2304 | version = "0.9.0" 2305 | source = "registry+https://github.com/rust-lang/crates.io-index" 2306 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2307 | 2308 | [[package]] 2309 | name = "url" 2310 | version = "2.5.2" 2311 | source = "registry+https://github.com/rust-lang/crates.io-index" 2312 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 2313 | dependencies = [ 2314 | "form_urlencoded", 2315 | "idna", 2316 | "percent-encoding", 2317 | ] 2318 | 2319 | [[package]] 2320 | name = "utf8parse" 2321 | version = "0.2.1" 2322 | source = "registry+https://github.com/rust-lang/crates.io-index" 2323 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 2324 | 2325 | [[package]] 2326 | name = "valuable" 2327 | version = "0.1.0" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 2330 | 2331 | [[package]] 2332 | name = "vcpkg" 2333 | version = "0.2.15" 2334 | source = "registry+https://github.com/rust-lang/crates.io-index" 2335 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2336 | 2337 | [[package]] 2338 | name = "version_check" 2339 | version = "0.9.5" 2340 | source = "registry+https://github.com/rust-lang/crates.io-index" 2341 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2342 | 2343 | [[package]] 2344 | name = "vt100" 2345 | version = "0.15.2" 2346 | source = "registry+https://github.com/rust-lang/crates.io-index" 2347 | checksum = "84cd863bf0db7e392ba3bd04994be3473491b31e66340672af5d11943c6274de" 2348 | dependencies = [ 2349 | "itoa", 2350 | "log", 2351 | "unicode-width", 2352 | "vte", 2353 | ] 2354 | 2355 | [[package]] 2356 | name = "vte" 2357 | version = "0.11.1" 2358 | source = "registry+https://github.com/rust-lang/crates.io-index" 2359 | checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" 2360 | dependencies = [ 2361 | "arrayvec", 2362 | "utf8parse", 2363 | "vte_generate_state_changes", 2364 | ] 2365 | 2366 | [[package]] 2367 | name = "vte_generate_state_changes" 2368 | version = "0.1.1" 2369 | source = "registry+https://github.com/rust-lang/crates.io-index" 2370 | checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" 2371 | dependencies = [ 2372 | "proc-macro2", 2373 | "quote", 2374 | ] 2375 | 2376 | [[package]] 2377 | name = "want" 2378 | version = "0.3.1" 2379 | source = "registry+https://github.com/rust-lang/crates.io-index" 2380 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2381 | dependencies = [ 2382 | "try-lock", 2383 | ] 2384 | 2385 | [[package]] 2386 | name = "wasi" 2387 | version = "0.11.0+wasi-snapshot-preview1" 2388 | source = "registry+https://github.com/rust-lang/crates.io-index" 2389 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2390 | 2391 | [[package]] 2392 | name = "wasm-bindgen" 2393 | version = "0.2.92" 2394 | source = "registry+https://github.com/rust-lang/crates.io-index" 2395 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 2396 | dependencies = [ 2397 | "cfg-if", 2398 | "wasm-bindgen-macro", 2399 | ] 2400 | 2401 | [[package]] 2402 | name = "wasm-bindgen-backend" 2403 | version = "0.2.92" 2404 | source = "registry+https://github.com/rust-lang/crates.io-index" 2405 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 2406 | dependencies = [ 2407 | "bumpalo", 2408 | "log", 2409 | "once_cell", 2410 | "proc-macro2", 2411 | "quote", 2412 | "syn", 2413 | "wasm-bindgen-shared", 2414 | ] 2415 | 2416 | [[package]] 2417 | name = "wasm-bindgen-futures" 2418 | version = "0.4.42" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 2421 | dependencies = [ 2422 | "cfg-if", 2423 | "js-sys", 2424 | "wasm-bindgen", 2425 | "web-sys", 2426 | ] 2427 | 2428 | [[package]] 2429 | name = "wasm-bindgen-macro" 2430 | version = "0.2.92" 2431 | source = "registry+https://github.com/rust-lang/crates.io-index" 2432 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 2433 | dependencies = [ 2434 | "quote", 2435 | "wasm-bindgen-macro-support", 2436 | ] 2437 | 2438 | [[package]] 2439 | name = "wasm-bindgen-macro-support" 2440 | version = "0.2.92" 2441 | source = "registry+https://github.com/rust-lang/crates.io-index" 2442 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 2443 | dependencies = [ 2444 | "proc-macro2", 2445 | "quote", 2446 | "syn", 2447 | "wasm-bindgen-backend", 2448 | "wasm-bindgen-shared", 2449 | ] 2450 | 2451 | [[package]] 2452 | name = "wasm-bindgen-shared" 2453 | version = "0.2.92" 2454 | source = "registry+https://github.com/rust-lang/crates.io-index" 2455 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 2456 | 2457 | [[package]] 2458 | name = "wasm-streams" 2459 | version = "0.4.0" 2460 | source = "registry+https://github.com/rust-lang/crates.io-index" 2461 | checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" 2462 | dependencies = [ 2463 | "futures-util", 2464 | "js-sys", 2465 | "wasm-bindgen", 2466 | "wasm-bindgen-futures", 2467 | "web-sys", 2468 | ] 2469 | 2470 | [[package]] 2471 | name = "web-sys" 2472 | version = "0.3.69" 2473 | source = "registry+https://github.com/rust-lang/crates.io-index" 2474 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 2475 | dependencies = [ 2476 | "js-sys", 2477 | "wasm-bindgen", 2478 | ] 2479 | 2480 | [[package]] 2481 | name = "webpki-roots" 2482 | version = "0.26.3" 2483 | source = "registry+https://github.com/rust-lang/crates.io-index" 2484 | checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" 2485 | dependencies = [ 2486 | "rustls-pki-types", 2487 | ] 2488 | 2489 | [[package]] 2490 | name = "winapi" 2491 | version = "0.3.9" 2492 | source = "registry+https://github.com/rust-lang/crates.io-index" 2493 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2494 | dependencies = [ 2495 | "winapi-i686-pc-windows-gnu", 2496 | "winapi-x86_64-pc-windows-gnu", 2497 | ] 2498 | 2499 | [[package]] 2500 | name = "winapi-i686-pc-windows-gnu" 2501 | version = "0.4.0" 2502 | source = "registry+https://github.com/rust-lang/crates.io-index" 2503 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2504 | 2505 | [[package]] 2506 | name = "winapi-x86_64-pc-windows-gnu" 2507 | version = "0.4.0" 2508 | source = "registry+https://github.com/rust-lang/crates.io-index" 2509 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2510 | 2511 | [[package]] 2512 | name = "windows-core" 2513 | version = "0.52.0" 2514 | source = "registry+https://github.com/rust-lang/crates.io-index" 2515 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 2516 | dependencies = [ 2517 | "windows-targets 0.52.5", 2518 | ] 2519 | 2520 | [[package]] 2521 | name = "windows-sys" 2522 | version = "0.48.0" 2523 | source = "registry+https://github.com/rust-lang/crates.io-index" 2524 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2525 | dependencies = [ 2526 | "windows-targets 0.48.5", 2527 | ] 2528 | 2529 | [[package]] 2530 | name = "windows-sys" 2531 | version = "0.52.0" 2532 | source = "registry+https://github.com/rust-lang/crates.io-index" 2533 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2534 | dependencies = [ 2535 | "windows-targets 0.52.5", 2536 | ] 2537 | 2538 | [[package]] 2539 | name = "windows-targets" 2540 | version = "0.48.5" 2541 | source = "registry+https://github.com/rust-lang/crates.io-index" 2542 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2543 | dependencies = [ 2544 | "windows_aarch64_gnullvm 0.48.5", 2545 | "windows_aarch64_msvc 0.48.5", 2546 | "windows_i686_gnu 0.48.5", 2547 | "windows_i686_msvc 0.48.5", 2548 | "windows_x86_64_gnu 0.48.5", 2549 | "windows_x86_64_gnullvm 0.48.5", 2550 | "windows_x86_64_msvc 0.48.5", 2551 | ] 2552 | 2553 | [[package]] 2554 | name = "windows-targets" 2555 | version = "0.52.5" 2556 | source = "registry+https://github.com/rust-lang/crates.io-index" 2557 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 2558 | dependencies = [ 2559 | "windows_aarch64_gnullvm 0.52.5", 2560 | "windows_aarch64_msvc 0.52.5", 2561 | "windows_i686_gnu 0.52.5", 2562 | "windows_i686_gnullvm", 2563 | "windows_i686_msvc 0.52.5", 2564 | "windows_x86_64_gnu 0.52.5", 2565 | "windows_x86_64_gnullvm 0.52.5", 2566 | "windows_x86_64_msvc 0.52.5", 2567 | ] 2568 | 2569 | [[package]] 2570 | name = "windows_aarch64_gnullvm" 2571 | version = "0.48.5" 2572 | source = "registry+https://github.com/rust-lang/crates.io-index" 2573 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2574 | 2575 | [[package]] 2576 | name = "windows_aarch64_gnullvm" 2577 | version = "0.52.5" 2578 | source = "registry+https://github.com/rust-lang/crates.io-index" 2579 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 2580 | 2581 | [[package]] 2582 | name = "windows_aarch64_msvc" 2583 | version = "0.48.5" 2584 | source = "registry+https://github.com/rust-lang/crates.io-index" 2585 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2586 | 2587 | [[package]] 2588 | name = "windows_aarch64_msvc" 2589 | version = "0.52.5" 2590 | source = "registry+https://github.com/rust-lang/crates.io-index" 2591 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 2592 | 2593 | [[package]] 2594 | name = "windows_i686_gnu" 2595 | version = "0.48.5" 2596 | source = "registry+https://github.com/rust-lang/crates.io-index" 2597 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2598 | 2599 | [[package]] 2600 | name = "windows_i686_gnu" 2601 | version = "0.52.5" 2602 | source = "registry+https://github.com/rust-lang/crates.io-index" 2603 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 2604 | 2605 | [[package]] 2606 | name = "windows_i686_gnullvm" 2607 | version = "0.52.5" 2608 | source = "registry+https://github.com/rust-lang/crates.io-index" 2609 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 2610 | 2611 | [[package]] 2612 | name = "windows_i686_msvc" 2613 | version = "0.48.5" 2614 | source = "registry+https://github.com/rust-lang/crates.io-index" 2615 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2616 | 2617 | [[package]] 2618 | name = "windows_i686_msvc" 2619 | version = "0.52.5" 2620 | source = "registry+https://github.com/rust-lang/crates.io-index" 2621 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 2622 | 2623 | [[package]] 2624 | name = "windows_x86_64_gnu" 2625 | version = "0.48.5" 2626 | source = "registry+https://github.com/rust-lang/crates.io-index" 2627 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2628 | 2629 | [[package]] 2630 | name = "windows_x86_64_gnu" 2631 | version = "0.52.5" 2632 | source = "registry+https://github.com/rust-lang/crates.io-index" 2633 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 2634 | 2635 | [[package]] 2636 | name = "windows_x86_64_gnullvm" 2637 | version = "0.48.5" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2640 | 2641 | [[package]] 2642 | name = "windows_x86_64_gnullvm" 2643 | version = "0.52.5" 2644 | source = "registry+https://github.com/rust-lang/crates.io-index" 2645 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 2646 | 2647 | [[package]] 2648 | name = "windows_x86_64_msvc" 2649 | version = "0.48.5" 2650 | source = "registry+https://github.com/rust-lang/crates.io-index" 2651 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2652 | 2653 | [[package]] 2654 | name = "windows_x86_64_msvc" 2655 | version = "0.52.5" 2656 | source = "registry+https://github.com/rust-lang/crates.io-index" 2657 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 2658 | 2659 | [[package]] 2660 | name = "winreg" 2661 | version = "0.52.0" 2662 | source = "registry+https://github.com/rust-lang/crates.io-index" 2663 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 2664 | dependencies = [ 2665 | "cfg-if", 2666 | "windows-sys 0.48.0", 2667 | ] 2668 | 2669 | [[package]] 2670 | name = "xattr" 2671 | version = "1.3.1" 2672 | source = "registry+https://github.com/rust-lang/crates.io-index" 2673 | checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" 2674 | dependencies = [ 2675 | "libc", 2676 | "linux-raw-sys", 2677 | "rustix", 2678 | ] 2679 | 2680 | [[package]] 2681 | name = "xz2" 2682 | version = "0.1.7" 2683 | source = "registry+https://github.com/rust-lang/crates.io-index" 2684 | checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" 2685 | dependencies = [ 2686 | "lzma-sys", 2687 | ] 2688 | 2689 | [[package]] 2690 | name = "yansi" 2691 | version = "1.0.1" 2692 | source = "registry+https://github.com/rust-lang/crates.io-index" 2693 | checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" 2694 | 2695 | [[package]] 2696 | name = "zeroize" 2697 | version = "1.8.1" 2698 | source = "registry+https://github.com/rust-lang/crates.io-index" 2699 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2700 | dependencies = [ 2701 | "zeroize_derive", 2702 | ] 2703 | 2704 | [[package]] 2705 | name = "zeroize_derive" 2706 | version = "1.4.2" 2707 | source = "registry+https://github.com/rust-lang/crates.io-index" 2708 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 2709 | dependencies = [ 2710 | "proc-macro2", 2711 | "quote", 2712 | "syn", 2713 | ] 2714 | 2715 | [[package]] 2716 | name = "zip" 2717 | version = "0.6.6" 2718 | source = "registry+https://github.com/rust-lang/crates.io-index" 2719 | checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" 2720 | dependencies = [ 2721 | "aes", 2722 | "byteorder", 2723 | "bzip2", 2724 | "constant_time_eq 0.1.5", 2725 | "crc32fast", 2726 | "crossbeam-utils", 2727 | "flate2", 2728 | "hmac", 2729 | "pbkdf2 0.11.0", 2730 | "sha1", 2731 | "zstd 0.11.2+zstd.1.5.2", 2732 | ] 2733 | 2734 | [[package]] 2735 | name = "zip" 2736 | version = "2.1.6" 2737 | source = "registry+https://github.com/rust-lang/crates.io-index" 2738 | checksum = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e" 2739 | dependencies = [ 2740 | "aes", 2741 | "arbitrary", 2742 | "bzip2", 2743 | "constant_time_eq 0.3.0", 2744 | "crc32fast", 2745 | "crossbeam-utils", 2746 | "deflate64", 2747 | "displaydoc", 2748 | "flate2", 2749 | "hmac", 2750 | "indexmap", 2751 | "lzma-rs", 2752 | "memchr", 2753 | "pbkdf2 0.12.2", 2754 | "rand", 2755 | "sha1", 2756 | "thiserror", 2757 | "time", 2758 | "zeroize", 2759 | "zopfli", 2760 | "zstd 0.13.2", 2761 | ] 2762 | 2763 | [[package]] 2764 | name = "zip-extract" 2765 | version = "0.1.3" 2766 | source = "registry+https://github.com/rust-lang/crates.io-index" 2767 | checksum = "e109e5a291403b4c1e514d39f8a22d3f98d257e691a52bb1f16051bb1ffed63e" 2768 | dependencies = [ 2769 | "log", 2770 | "thiserror", 2771 | "zip 0.6.6", 2772 | ] 2773 | 2774 | [[package]] 2775 | name = "zopfli" 2776 | version = "0.8.1" 2777 | source = "registry+https://github.com/rust-lang/crates.io-index" 2778 | checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" 2779 | dependencies = [ 2780 | "bumpalo", 2781 | "crc32fast", 2782 | "lockfree-object-pool", 2783 | "log", 2784 | "once_cell", 2785 | "simd-adler32", 2786 | ] 2787 | 2788 | [[package]] 2789 | name = "zstd" 2790 | version = "0.11.2+zstd.1.5.2" 2791 | source = "registry+https://github.com/rust-lang/crates.io-index" 2792 | checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" 2793 | dependencies = [ 2794 | "zstd-safe 5.0.2+zstd.1.5.2", 2795 | ] 2796 | 2797 | [[package]] 2798 | name = "zstd" 2799 | version = "0.13.2" 2800 | source = "registry+https://github.com/rust-lang/crates.io-index" 2801 | checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" 2802 | dependencies = [ 2803 | "zstd-safe 7.2.1", 2804 | ] 2805 | 2806 | [[package]] 2807 | name = "zstd-safe" 2808 | version = "5.0.2+zstd.1.5.2" 2809 | source = "registry+https://github.com/rust-lang/crates.io-index" 2810 | checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" 2811 | dependencies = [ 2812 | "libc", 2813 | "zstd-sys", 2814 | ] 2815 | 2816 | [[package]] 2817 | name = "zstd-safe" 2818 | version = "7.2.1" 2819 | source = "registry+https://github.com/rust-lang/crates.io-index" 2820 | checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" 2821 | dependencies = [ 2822 | "zstd-sys", 2823 | ] 2824 | 2825 | [[package]] 2826 | name = "zstd-sys" 2827 | version = "2.0.13+zstd.1.5.6" 2828 | source = "registry+https://github.com/rust-lang/crates.io-index" 2829 | checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" 2830 | dependencies = [ 2831 | "cc", 2832 | "pkg-config", 2833 | ] 2834 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hyper-jump" 3 | version = "0.9.2" 4 | edition = "2021" 5 | license = "Apache-2.0" 6 | readme = "README.md" 7 | authors = ["Alexsander Falcucci "] 8 | description = "A generalist all-in-one command-line version manager toolset for a more efficient development workflow." 9 | categories = ["command-line-utilities"] 10 | repository = "https://github.com/falcucci/hyper-jump" 11 | keywords = ["version-manager", "blockchain", "node-management", "cli-tool"] 12 | 13 | [dependencies] 14 | clap = { version = "4.5.4", features = ["derive", "env"] } 15 | tokio = { version = "1.37.0", features = ["full"] } 16 | miette = { version = "5.10.0", features = ["fancy"] } 17 | directories = "5.0.1" 18 | tracing = "0.1.40" 19 | tracing-indicatif = "0.3.5" 20 | tracing-subscriber = "0.3.17" 21 | regex = "1.10.5" 22 | semver = "1.0.23" 23 | anyhow = "1.0.86" 24 | reqwest = { version = "0.12.5", features = ["stream", "rustls-tls"] } 25 | indicatif = "0.17.8" 26 | futures-util = { version = "0.3.30", default-features = false } 27 | flate2 = "1.0.30" 28 | tar = "0.4.41" 29 | zip = "2.1.6" 30 | zip-extract = "0.1.3" 31 | xz2 = "0.1.7" 32 | signal-hook = "0.3.17" 33 | nix = { version = "0.29.0", features = ["signal"] } 34 | serde = { version = "1.0.204", features = ["derive"] } 35 | serde_json = "1.0.120" 36 | chrono = { version = "0.4.38", features = ["serde"] } 37 | yansi = "1.0.1" 38 | comfy-table = "7.1.1" 39 | 40 | [[bin]] 41 | path = "src/main.rs" 42 | name = "hyper-jump" 43 | proc-macro = false 44 | required-features = [] 45 | 46 | [profile.optimized] 47 | inherits = "release" 48 | opt-level = "z" 49 | strip = true 50 | lto = true 51 | codegen-units = 1 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /hurl/cardano-cli.hurl: -------------------------------------------------------------------------------- 1 | GET https://github.com//IntersectMBO/cardano-cli/releases/download/cardano-cli-9.0.0.1/cardano-cli-9.0.0.1-aarch64-darwin.tar.gz 2 | User-Agent: Hyper-Jump 3 | HTTP 200 4 | -------------------------------------------------------------------------------- /hurl/cardano-node.hurl: -------------------------------------------------------------------------------- 1 | GET http://github.com/intersectmbo/cardano-node/releases/download/9.0.0/cardano-node-9.0.0-macos.tar.gz 2 | User-Agent: Hyper-Jump 3 | HTTP 200 4 | -------------------------------------------------------------------------------- /hurl/mithril.hurl: -------------------------------------------------------------------------------- 1 | GET https://github.com//input-output-hk/mithril/releases/download/2423.0/mithril-2423.0-macos-arm64.tar.gz 2 | User-Agent: Hyper-Jump 3 | HTTP 200 4 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # hyper-jump 4 | 5 | _The console lights up, keys clack rapidly and then..._ 🛸 6 | 7 |
8 | 9 | hyper-jump is an agnostic all-in-one and cross-platform command-line version manager toolset which I have created and used personally based on internal tools I daily interact with for many different reasons, that being for educational purposes or as a professional project/task. 10 | 11 | ## Core Features 12 | 13 | - **Version Management**: Install and switch between different versions of package. 14 | - **Environment Isolation**: Create isolated environments for different projects, each with its own set of package versions. 15 | - **Remote Listing**: View available versions of packages from remote repositories. 16 | - **Package Installation**: Download and install specific versions of packages with ease. 17 | - **Package Uninstallation**: Remove installed versions of packages to declutter the environment. 18 | - **Version Switching**: Seamlessly switch between installed versions with a single command. 19 | - **Version Cleanup**: Erase all installed versions of packages to start fresh. 20 | - **Proxy Handling**: Hyper-Jump acts as a proxy, allowing users to run commands from the selected package version. 21 | 22 | ## Potential Features 23 | 24 | - **Updates notification**: Notify users when new versions of packages are available. 25 | - **Custom Package Sources**: Allow users to add custom package sources or repositories for more flexibility. 26 | - **Enhanced List Filtering**: Provide options to filter the list of installed and remote versions based on criteria such as release date or stability. 27 | 28 | ## Supported Packages 29 | 30 | | Package Name | Alias | Description | 31 | | ------------------------------------------------------------------------------ | --------------------- | ---------------------------------------------------- | 32 | | [Neovim](https://github.com/neovim/neovim) | `neovim` | Manage versions of the Neovim client software. | 33 | | [Zellij](https://github.com/zellij-org/zellij) | `zellij` | Manage versions of the Zellij client software. | 34 | | [Reth](https://github.com/paradigmxyz/reth) | `reth` | Manage versions of the Reth client software. | 35 | | [Cardano Node](https://github.com/IntersectMBO/cardano-node) | `cardano-node` | Manage versions of the Cardano Node software. | 36 | | [Cardano CLI](https://github.com/cardano-scaling/cardano-cli) | `cardano-cli` | Manage versions of the Cardano CLI tool. | 37 | | [Partner Chains CLI](https://github.com/input-output-hk/partner-chains) | `partner-chains-cli` | Manage versions of the Partner Chains CLI tool. | 38 | | [Partner Chains Node](https://github.com/input-output-hk/partner-chains) | `partner-chains-node` | Manage versions of the Partner Chains Node software. | 39 | | [Cardano Submit Api](https://github.com/IntersectMBO/cardano-node) | `cardano-submit-api` | Manage versions of the Cardano Submit Api software. | 40 | | [SideChain](https://github.com/input-output-hk/partner-chains-smart-contracts) | `sidechain-cli` | Manage versions of the SideChain CLI tool. | 41 | | [Mithril](https://github.com/input-output-hk/mithril) | `mithril-client` | Manage versions of the Mithril client software. | 42 | | [Scrolls](https://github.com/txpipe/scrolls) | `scrolls` | Manage versions of the Scrolls client software. | 43 | | [Oura](https://github.com/txpipe/oura/tree/main) | `oura` | Manage versions of the Oura client software. | 44 | | [Dolos](https://github.com/txpipe/dolos) | `dolos` | Manage versions of the Dolos client software. | 45 | | [Aiken](https://github.com/aiken-lang/aiken) | `aiken` | Manage versions of the Aiken client software. | 46 | 47 | ## Installation 48 | 49 | ```bash 50 | cargo install hyper-jump 51 | ``` 52 | 53 | ## Configuration 54 | 55 | #### On Linux and macOS: 56 | 57 | Add the following line to your shell configuration file (e.g., `~/.bashrc`, `~/.zshrc`, etc.): 58 | 59 | ```bash 60 | export PATH="$HOME/.local/share/hyper-jump/bin:$PATH" 61 | ``` 62 | 63 | Or add the hyper-jump binary path to your PATH by running: 64 | 65 | ```bash 66 | sudo launchctl config user path "$(hyper-jump prefix):${PATH}" 67 | ``` 68 | 69 | ## Usage 70 | 71 | To manage packages, use the following subcommands: 72 | 73 | ### Help 74 | 75 | Display help information: 76 | 77 | ```bash 78 | hyper-jump --help 79 | ``` 80 | 81 | ### Use 82 | 83 | Switch to a specific version of a package. 84 | 85 | ```sh 86 | hyper-jump use 87 | ``` 88 | 89 | ### Install 90 | 91 | Install a specific version of a package. 92 | 93 | ```sh 94 | hyper-jump install 95 | ``` 96 | 97 | ### List 98 | 99 | List installed versions of a package: 100 | 101 | ```sh 102 | hyper-jump list 103 | ``` 104 | 105 | ### List Remote 106 | 107 | List remote versions available for a package. 108 | 109 | ```sh 110 | hyper-jump list-remote 111 | ``` 112 | 113 | ### Uninstall 114 | 115 | Uninstall a specific version of a package. 116 | 117 | ```sh 118 | hyper-jump uninstall 119 | ``` 120 | 121 | ### Erase 122 | 123 | Remove all installed versions. 124 | 125 | ```sh 126 | hyper-jump erase 127 | ``` 128 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | format_code_in_doc_comments = true 2 | group_imports = "StdExternalCrate" 3 | imports_granularity = "Item" 4 | format_strings = true 5 | fn_single_line = true 6 | wrap_comments = true 7 | chain_width = 80 8 | -------------------------------------------------------------------------------- /src/commands/erase.rs: -------------------------------------------------------------------------------- 1 | use tokio::fs; 2 | use tracing::info; 3 | 4 | /// Asynchronously erases the hyper-jump installation and downloads folders. 5 | /// 6 | /// This function attempts to remove the hyper-jump installation directory and 7 | /// the downloads directory. It logs successful removals and returns an error if 8 | /// there is nothing to erase or if an error occurs during the removal process. 9 | /// 10 | /// # Errors 11 | /// 12 | /// Returns an error if both the installation and downloads directories do not 13 | /// exist or cannot be removed. 14 | /// 15 | /// # Examples 16 | /// 17 | /// ```no_run 18 | /// #[tokio::main] 19 | /// async fn main() -> miette::Result<()> { 20 | /// run().await?; 21 | /// Ok(()) 22 | /// } 23 | /// ``` 24 | pub async fn run() -> miette::Result<()> { 25 | let downloads = crate::fs::get_local_data_dir().unwrap(); 26 | 27 | if fs::remove_dir_all(&downloads).await.is_ok() { 28 | info!("Successfully removed hyper-jump installation folder"); 29 | } else { 30 | info!("No hyper-jump installation or downloads folder to remove"); 31 | } 32 | 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /src/commands/install.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::min; 2 | use std::env; 3 | use std::path::Path; 4 | 5 | use anyhow::anyhow; 6 | use anyhow::Error; 7 | use anyhow::Result; 8 | use clap::Parser; 9 | use futures_util::stream::StreamExt; 10 | use indicatif::ProgressBar; 11 | use reqwest::Client; 12 | use tokio::io::AsyncWriteExt; 13 | use tracing::info; 14 | 15 | use super::PostDownloadVersionType; 16 | use crate::fs::copy_package_proxy; 17 | use crate::fs::get_downloads_directory; 18 | use crate::fs::get_file_type; 19 | use crate::fs::unarchive; 20 | use crate::helpers::version::is_version_installed; 21 | use crate::helpers::version::LocalVersion; 22 | use crate::helpers::version::ParsedVersion; 23 | use crate::helpers::version::VersionType; 24 | use crate::packages::Package; 25 | use crate::packages::PackageType; 26 | 27 | #[derive(Parser)] 28 | pub struct Args { 29 | #[command(subcommand)] 30 | command: Commands, 31 | } 32 | 33 | #[derive(Parser)] 34 | pub enum Commands { 35 | Reth { version: String }, 36 | Oura { version: String }, 37 | Aiken { version: String }, 38 | Dolos { version: String }, 39 | Zellij { version: String }, 40 | NeoVim { version: String }, 41 | Mithril { version: String }, 42 | Scrolls { version: String }, 43 | CardanoCli { version: String }, 44 | CardanoNode { version: String }, 45 | SidechainCli { version: String }, 46 | PartnerChainCli { version: String }, 47 | PartnerChainNode { version: String }, 48 | CardanoSubmitApi { version: String }, 49 | } 50 | 51 | /// Macro to execute a command based on the provided variant and package type. 52 | /// 53 | /// This macro matches the provided command against a list of command variants 54 | /// and executes the corresponding code for each variant. It creates a new 55 | /// `Package` instance with the specified package type and client, and then 56 | /// installs the package. 57 | /// 58 | /// # Parameters 59 | /// 60 | /// - `$command`: The command to be matched and executed. The command must 61 | /// include a `version`. 62 | /// - `$client`: The client to be used for creating the `Package`. 63 | /// - `$(($variant:ident, $package_type:expr)),*`: A list of tuples containing 64 | /// the command variant and the corresponding package type. 65 | macro_rules! execute { 66 | ($command:expr, $client:expr, $(($variant:ident, $package_type:expr)),*) => { 67 | match $command { 68 | $( 69 | Commands::$variant { version } => { 70 | let package = Package::new($package_type, version, $client).await; 71 | install($client, package).await.expect("Failed to install"); 72 | } 73 | )* 74 | } 75 | } 76 | } 77 | 78 | pub async fn run( 79 | args: Args, 80 | _ctx: &crate::Context, 81 | client: Option<&reqwest::Client>, 82 | ) -> miette::Result<()> { 83 | execute!( 84 | args.command, 85 | client, 86 | (Reth, PackageType::Reth), 87 | (Oura, PackageType::Oura), 88 | (Aiken, PackageType::Aiken), 89 | (Dolos, PackageType::Dolos), 90 | (Zellij, PackageType::Zellij), 91 | (NeoVim, PackageType::Neovim), 92 | (Mithril, PackageType::Mithril), 93 | (Scrolls, PackageType::Scrolls), 94 | (CardanoCli, PackageType::CardanoCli), 95 | (CardanoNode, PackageType::CardanoNode), 96 | (SidechainCli, PackageType::SidechainCli), 97 | (PartnerChainCli, PackageType::PartnerChainCli), 98 | (PartnerChainNode, PackageType::PartnerChainNode), 99 | (CardanoSubmitApi, PackageType::CardanoSubmitApi) 100 | ); 101 | 102 | Ok(()) 103 | } 104 | 105 | /// Installs a specified version of a package asynchronously. 106 | /// 107 | /// This function handles the installation process of a package by first 108 | /// checking if the version is already installed, and if not, it proceeds to 109 | /// download and unarchive the specified version. 110 | /// 111 | /// # Arguments 112 | /// 113 | /// * `client` - A reference to a `reqwest::Client` for making HTTP requests. 114 | /// * `package` - The `Package` to be installed. 115 | /// * `version` - The `ParsedVersion` specifying the version to install. 116 | /// 117 | /// # Errors 118 | /// 119 | /// Returns an error if the installation process fails at any step, including 120 | /// checking for an already installed version, downloading, or unarchiving the 121 | /// package. 122 | /// 123 | /// # Examples 124 | /// 125 | /// ```rust 126 | /// let client = Client::new(); 127 | /// let package = Package::new_cardano_node("1.0.0".to_string()); 128 | /// let version = ParsedVersion::parse("1.0.0").unwrap(); 129 | /// install(&client, package, version).await?; 130 | /// ``` 131 | pub async fn install(client: Option<&Client>, package: Package) -> Result<(), Error> { 132 | let version = package.version().map_or_else(|| Err(anyhow!("No version specified")), Ok)?; 133 | let root = get_downloads_directory(package.clone()).await?; 134 | 135 | env::set_current_dir(&root)?; 136 | let root = root.as_path(); 137 | 138 | let is_version_installed = is_version_installed(&version.tag_name, package.clone()).await?; 139 | 140 | copy_package_proxy(package.clone()).await?; 141 | 142 | if is_version_installed { 143 | info!("{} is already installed.", version.tag_name); 144 | return Ok(()); 145 | } 146 | 147 | let downloaded_file = match version.version_type { 148 | VersionType::Normal | VersionType::Latest => { 149 | download_version(client, &version, root, package.clone()).await? 150 | } 151 | }; 152 | 153 | match downloaded_file { 154 | PostDownloadVersionType::Standard(local_version) => { 155 | unarchive(package, local_version).await?; 156 | } 157 | } 158 | 159 | info!("Successfully installed {}", version.tag_name); 160 | 161 | Ok(()) 162 | } 163 | 164 | /// This function sends a request to download the specified version based on the 165 | /// version type. If the version type is Normal, Nightly, or Latest, it sends a 166 | /// request to download the version. If the version type is Hash, it handles 167 | /// building from source. If the version type is NightlyRollback, it does 168 | /// nothing. 169 | /// 170 | /// # Arguments 171 | /// 172 | /// * `client` - A reference to the HTTP client. 173 | /// * `version` - A reference to the parsed version to be downloaded. 174 | /// * `root` - A reference to the path where the downloaded file will be saved. 175 | /// 176 | /// # Returns 177 | /// 178 | /// * `Result` - Returns a `Result` that contains a 179 | /// `PostDownloadVersionType` on success, or an error on failure. 180 | /// 181 | /// # Errors 182 | /// 183 | /// This function will return an error if: 184 | /// * There is a failure in sending the request to download the version. 185 | /// * The response status is not 200. 186 | /// * There is a failure in creating the file where the downloaded version will 187 | /// be saved. 188 | /// * There is a failure in writing the downloaded bytes to the file. 189 | /// 190 | /// # Example 191 | /// 192 | /// ```rust 193 | /// let client = Client::new(); 194 | /// let version = ParsedVersion::parse("0.5.0"); 195 | /// let root = Path::new("/path/to/save"); 196 | /// let result = download_version(&client, &version, &root).await; 197 | /// ``` 198 | async fn download_version( 199 | client: Option<&Client>, 200 | version: &ParsedVersion, 201 | root: &Path, 202 | package: Package, 203 | ) -> Result { 204 | let response = send_request(client, package.clone()).await?; 205 | if response.status() != reqwest::StatusCode::OK { 206 | return Err(anyhow!("Failed to send request to download version")); 207 | } 208 | 209 | let mut downloaded: u64 = 0; 210 | let content_length = get_content_length(&response).await?; 211 | let pb = ProgressBar::new(content_length); 212 | let mut response_bytes = response.bytes_stream(); 213 | let package_type = package.package_type(); 214 | let file_type = get_file_type(package_type); 215 | let file_path = create_file_path(version, root, file_type); 216 | let mut file = create_file(&file_path).await?; 217 | while let Some(item) = response_bytes.next().await { 218 | let chunk = item.map_err(|_| anyhow!("Failed to get chunk"))?; 219 | file.write_all(&chunk).await?; 220 | let new = min(downloaded + (chunk.len() as u64), content_length); 221 | downloaded = new; 222 | pb.set_position(new); 223 | } 224 | 225 | pb.finish_with_message(format!( 226 | "Downloaded version {} to {}", 227 | version.tag_name, file_path 228 | )); 229 | 230 | let local_version = LocalVersion { 231 | file_name: version.tag_name.to_owned(), 232 | file_format: file_type.to_string(), 233 | path: root.display().to_string(), 234 | semver: version.semver.clone(), 235 | }; 236 | 237 | Ok(PostDownloadVersionType::Standard(local_version)) 238 | } 239 | 240 | /// Retrieves the content length from an HTTP response. 241 | /// 242 | /// This function extracts the `Content-Length` header from the given HTTP 243 | /// response and returns it as a `u64`. If the header is not present, it returns 244 | /// an error. 245 | /// 246 | /// # Arguments 247 | /// 248 | /// * `response` - A reference to the `reqwest::Response` object. 249 | /// 250 | /// # Returns 251 | /// 252 | /// This function returns a `Result` indicating the success or failure of the 253 | /// operation. 254 | /// 255 | /// * `Ok(u64)` - The content length of the response. 256 | /// * `Err(anyhow::Error)` - An error occurred if the `Content-Length` header is 257 | /// missing. 258 | /// 259 | /// # Examples 260 | /// 261 | /// ```rust 262 | /// let response = reqwest::get("https://example.com").await?; 263 | /// let content_length = get_content_length(&response).await?; 264 | /// ``` 265 | async fn get_content_length(response: &reqwest::Response) -> Result { 266 | let content_length = response.content_length(); 267 | 268 | content_length.ok_or(anyhow!("Failed to get content length of the response")) 269 | } 270 | 271 | /// Creates a new file asynchronously at the specified path. 272 | /// 273 | /// This function creates a new file at the given file path using asynchronous 274 | /// file operations provided by `tokio::fs`. 275 | /// 276 | /// # Arguments 277 | /// 278 | /// * `file_path` - A string slice that holds the path where the file should be 279 | /// created. 280 | /// 281 | /// # Returns 282 | /// 283 | /// This function returns a `Result` indicating the success or failure of the 284 | /// file creation. 285 | /// 286 | /// * `Ok(tokio::fs::File)` - The created file handle. 287 | /// * `Err(anyhow::Error)` - An error occurred during file creation. 288 | /// 289 | /// # Examples 290 | /// 291 | /// ```rust 292 | /// let file_path = "/tmp/example.txt"; 293 | /// let file = create_file(file_path).await?; 294 | /// ``` 295 | async fn create_file(file_path: &str) -> Result { 296 | Ok(tokio::fs::File::create(&file_path).await?) 297 | } 298 | 299 | /// Constructs a file path string based on the version, root path, and file 300 | /// type. 301 | /// 302 | /// This function generates a file path string by combining the root path, 303 | /// version tag name, and file type. The resulting path is formatted as 304 | /// `root/tag_name.file_type`. 305 | /// 306 | /// # Arguments 307 | /// 308 | /// * `version` - A reference to a `ParsedVersion` object containing the version 309 | /// information. 310 | /// * `root` - A reference to a `Path` object representing the root directory. 311 | /// * `file_type` - A string slice representing the file extension or type. 312 | /// 313 | /// # Returns 314 | /// 315 | /// This function returns a `String` representing the constructed file path. 316 | /// 317 | /// # Examples 318 | /// 319 | /// ```rust 320 | /// let version = ParsedVersion { 321 | /// tag_name: "v1.0.0".to_string(), 322 | /// }; 323 | /// let root = Path::new("/tmp"); 324 | /// let file_type = "txt"; 325 | /// let file_path = create_file_path(&version, &root, file_type); 326 | /// ``` 327 | fn create_file_path(version: &ParsedVersion, root: &Path, file_type: &str) -> String { 328 | format!("{}/{}.{}", root.display(), version.tag_name, file_type) 329 | } 330 | 331 | /// Sends a GET request to the specified URL to download a specific version. 332 | /// 333 | /// # Arguments 334 | /// 335 | /// * `client: &Client` - A reference to the `Client` used for making requests. 336 | /// * `version: &ParsedVersion` - Contains the version information to be 337 | /// downloaded. 338 | /// 339 | /// It then sends a GET request to the constructed URL with the header 340 | /// "user-agent" set to "hyper-jump". 341 | /// 342 | /// # Returns 343 | /// 344 | /// * `Result` - Returns a `Result` 345 | /// containing the server's 346 | /// * response to the GET request. If the request fails, it returns an error. 347 | /// 348 | /// # Example 349 | /// 350 | /// ```rust 351 | /// let client = Client::new(); 352 | /// let response = send_request(&client, &version).await?; 353 | /// ``` 354 | /// 355 | /// # Note 356 | /// 357 | /// This function is asynchronous and must be awaited. 358 | /// 359 | /// # See Also 360 | /// 361 | /// * [`helpers::get_platform_name_download`](src/helpers/platform.rs) 362 | /// * [`helpers::get_file_type`](src/helpers/file.rs) 363 | async fn send_request( 364 | client: Option<&Client>, 365 | package: Package, 366 | ) -> Result { 367 | let package_url = package.download_url(); 368 | info!("Downloading: {}", package_url); 369 | 370 | client 371 | .expect("Client is not set") 372 | .get(package_url.to_string()) 373 | .header("user-agent", "hyper-jump") 374 | .send() 375 | .await 376 | } 377 | -------------------------------------------------------------------------------- /src/commands/list.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::PathBuf; 3 | 4 | use anyhow::Error; 5 | use anyhow::Result; 6 | use comfy_table::modifiers::UTF8_ROUND_CORNERS; 7 | use comfy_table::presets::UTF8_FULL; 8 | use comfy_table::Cell; 9 | use comfy_table::CellAlignment; 10 | use comfy_table::Color; 11 | use comfy_table::Table; 12 | use tracing::info; 13 | 14 | use crate::fs::get_downloads_directory; 15 | use crate::helpers::version::is_version_used; 16 | use crate::packages::Package; 17 | use crate::packages::PackageType; 18 | 19 | #[derive(clap::Parser)] 20 | pub struct Args { 21 | #[command(subcommand)] 22 | command: Commands, 23 | } 24 | 25 | #[derive(clap::Parser)] 26 | pub enum Commands { 27 | Reth, 28 | Oura, 29 | Aiken, 30 | Dolos, 31 | Zellij, 32 | Neovim, 33 | Mithril, 34 | Scrolls, 35 | CardanoCli, 36 | CardanoNode, 37 | SidechainCli, 38 | PartnerChainCli, 39 | PartnerChainNode, 40 | CardanoSubmitApi, 41 | } 42 | 43 | /// Macro to execute a command based on the provided variant and package type. 44 | /// 45 | /// This macro matches the provided command against a list of command variants 46 | /// and executes the corresponding code for each variant. It creates a new 47 | /// `Package` instance with the specified package type and client, and then 48 | /// lists the package versions. 49 | /// 50 | /// # Parameters 51 | /// 52 | /// - `$command`: The command to be matched and executed. 53 | /// - `$client`: The client to be used for creating the `Package`. 54 | /// - `$(($variant:ident, $package_type:expr)),*`: A list of tuples containing 55 | /// the command variant and the corresponding package type. 56 | macro_rules! execute { 57 | ($command:expr, $client:expr, $(($variant:ident, $package_type:expr)),*) => { 58 | match $command { 59 | $( 60 | Commands::$variant => { 61 | let package = Package::new($package_type, String::new(), $client).await; 62 | list(package).await.expect("Failed to list versions") 63 | } 64 | )* 65 | } 66 | } 67 | } 68 | 69 | pub async fn run( 70 | args: Args, 71 | _ctx: &crate::Context, 72 | client: Option<&reqwest::Client>, 73 | ) -> miette::Result<()> { 74 | execute!( 75 | args.command, 76 | client, 77 | (Reth, PackageType::Reth), 78 | (Oura, PackageType::Oura), 79 | (Aiken, PackageType::Aiken), 80 | (Dolos, PackageType::Dolos), 81 | (Zellij, PackageType::Zellij), 82 | (Neovim, PackageType::Neovim), 83 | (Mithril, PackageType::Mithril), 84 | (Scrolls, PackageType::Scrolls), 85 | (CardanoCli, PackageType::CardanoCli), 86 | (CardanoNode, PackageType::CardanoNode), 87 | (SidechainCli, PackageType::SidechainCli), 88 | (PartnerChainCli, PackageType::PartnerChainCli), 89 | (PartnerChainNode, PackageType::PartnerChainNode), 90 | (CardanoSubmitApi, PackageType::CardanoSubmitApi) 91 | ); 92 | 93 | Ok(()) 94 | } 95 | 96 | pub async fn list(package: Package) -> Result<(), Error> { 97 | let downloads_dir = get_downloads_directory(package.clone()).await?; 98 | 99 | let paths: Vec = fs::read_dir(downloads_dir)? 100 | .filter_map(Result::ok) 101 | .map(|entry| entry.path()) 102 | .collect(); 103 | 104 | if paths.is_empty() { 105 | info!("There are no versions installed"); 106 | return Ok(()); 107 | } 108 | 109 | let mut table = Table::new(); 110 | let header = vec!["Version", "Status"]; 111 | table.load_preset(UTF8_FULL).apply_modifier(UTF8_ROUND_CORNERS); 112 | table.set_header(header); 113 | 114 | for path in paths { 115 | if !path.is_dir() { 116 | continue; 117 | } 118 | 119 | let path_name = path.file_name().unwrap().to_str().unwrap(); 120 | 121 | let status = if is_version_used(path_name, package.clone()).await { 122 | Cell::new("Used").fg(Color::Green) 123 | } else { 124 | Cell::new("Installed") 125 | }; 126 | 127 | table.add_row(vec![ 128 | Cell::new(path_name).set_alignment(CellAlignment::Center), 129 | status, 130 | ]); 131 | } 132 | 133 | println!("{table}"); 134 | 135 | Ok(()) 136 | } 137 | -------------------------------------------------------------------------------- /src/commands/list_remote.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::PathBuf; 3 | 4 | use anyhow::Error; 5 | use anyhow::Result; 6 | use reqwest::Client; 7 | use yansi::Paint; 8 | 9 | use crate::helpers::version::is_version_used; 10 | use crate::helpers::version::RemoteVersion; 11 | use crate::helpers::version::VersionStatus; 12 | use crate::packages::Package; 13 | use crate::packages::PackageType; 14 | use crate::services::github::api; 15 | use crate::services::github::deserialize_response; 16 | 17 | #[derive(clap::Parser)] 18 | pub struct Args { 19 | #[command(subcommand)] 20 | command: Commands, 21 | } 22 | 23 | #[derive(clap::Parser)] 24 | pub enum Commands { 25 | Reth, 26 | Oura, 27 | Aiken, 28 | Dolos, 29 | Zellij, 30 | Neovim, 31 | Mithril, 32 | Scrolls, 33 | CardanoCli, 34 | CardanoNode, 35 | SidechainCli, 36 | PartnerChainCli, 37 | PartnerChainNode, 38 | CardanoSubmitApi, 39 | } 40 | 41 | /// Macro to execute a command based on the provided variant and package type. 42 | /// 43 | /// This macro matches the provided command against a list of command variants 44 | /// and executes the corresponding code for each variant. It creates a new 45 | /// `Package` instance with the specified package type and client, and then 46 | /// lists the remote package versions. 47 | /// 48 | /// # Parameters 49 | /// 50 | /// - `$command`: The command to be matched and executed. 51 | /// - `$client`: The client to be used for creating the `Package`. 52 | /// - `$(($variant:ident, $package_type:expr)),*`: A list of tuples containing 53 | /// the command variant and the corresponding package type. 54 | macro_rules! execute { 55 | ($command:expr, $client:expr, $(($variant:ident, $package_type:expr)),*) => { 56 | match $command { 57 | $( 58 | Commands::$variant => { 59 | let package = Package::new($package_type, String::new(), $client).await; 60 | list_remote($client, package).await.expect("Failed to list-remote versions") 61 | } 62 | )* 63 | } 64 | } 65 | } 66 | 67 | pub async fn run( 68 | args: Args, 69 | _ctx: &crate::Context, 70 | client: Option<&reqwest::Client>, 71 | ) -> miette::Result<()> { 72 | execute!( 73 | args.command, 74 | client, 75 | (Reth, PackageType::Reth), 76 | (Oura, PackageType::Oura), 77 | (Aiken, PackageType::Aiken), 78 | (Dolos, PackageType::Dolos), 79 | (Zellij, PackageType::Zellij), 80 | (Neovim, PackageType::Neovim), 81 | (Mithril, PackageType::Mithril), 82 | (Scrolls, PackageType::Scrolls), 83 | (CardanoCli, PackageType::CardanoCli), 84 | (CardanoNode, PackageType::CardanoNode), 85 | (SidechainCli, PackageType::SidechainCli), 86 | (PartnerChainCli, PackageType::PartnerChainCli), 87 | (PartnerChainNode, PackageType::PartnerChainNode), 88 | (CardanoSubmitApi, PackageType::CardanoSubmitApi) 89 | ); 90 | 91 | Ok(()) 92 | } 93 | 94 | /// Lists the remote versions of a specified package. 95 | /// 96 | /// This function fetches the list of releases from a remote repository, filters 97 | /// out pre-release versions, and then prints each version with a specific color 98 | /// coding: 99 | /// - Green if the version is currently used. 100 | /// - Yellow if the version is installed but not used. 101 | /// - Default color if the version is not installed. 102 | /// 103 | /// # Arguments 104 | /// 105 | /// * `client` - A reference to a `reqwest::Client` used to make HTTP requests. 106 | /// * `package` - The `Package` enum representing the package to list versions 107 | /// for. 108 | /// 109 | /// # Returns 110 | /// 111 | /// This function returns a `Result<(), Error>` indicating the operation's 112 | /// success or failure. 113 | /// 114 | /// # Errors 115 | /// 116 | /// This function will return an error if there is no releases URL for the 117 | /// package or if there is an issue with fetching or processing the list of 118 | /// versions. 119 | pub async fn list_remote(client: Option<&Client>, package: Package) -> Result<(), Error> { 120 | let url = package.releases_url(); 121 | let response = api(client, url).await?; 122 | 123 | let local_versions: Vec = filter_local_versions(package.clone()).await?; 124 | let versions: Vec = deserialize_response(response)?; 125 | let filtered_versions: Vec = filter_versions(versions)?; 126 | 127 | let padding = " ".repeat(12); 128 | for version in filtered_versions { 129 | let version_installed = check_version_installed(&local_versions, &version.tag_name); 130 | let tag = match package { 131 | Package::CardanoSubmitApi(_) => version.tag_name.clone(), 132 | Package::PartnerChainNode(_) => version.tag_name.clone(), 133 | Package::PartnerChainCli(_) => version.tag_name.clone(), 134 | Package::SidechainCli(_) => version.tag_name.clone(), 135 | Package::CardanoNode(_) => version.tag_name.clone(), 136 | Package::CardanoCli(_) => version.tag_name.clone(), 137 | Package::Mithril(_) => version.tag_name.clone(), 138 | Package::Scrolls(_) => version.tag_name.clone(), 139 | Package::Zellij(_) => version.tag_name.clone(), 140 | Package::Neovim(_) => version.tag_name.clone(), 141 | Package::Aiken(_) => version.tag_name.clone(), 142 | Package::Dolos(_) => version.tag_name.clone(), 143 | Package::Oura(_) => version.tag_name.clone(), 144 | Package::Reth(_) => version.tag_name.clone(), 145 | }; 146 | 147 | let version_status = 148 | match is_version_used(format!("v{}", tag).as_str(), package.clone()).await { 149 | true => VersionStatus::Used, 150 | false if version_installed => VersionStatus::Installed, 151 | false => VersionStatus::NotInstalled, 152 | }; 153 | 154 | let color = match version_status { 155 | VersionStatus::Used => Paint::green(&tag), 156 | VersionStatus::Installed => { 157 | retain_local_versions(local_versions.clone(), &version.tag_name); 158 | Paint::yellow(&tag) 159 | } 160 | VersionStatus::NotInstalled => Paint::italic(&tag), 161 | }; 162 | 163 | println!("{padding}{}", color); 164 | } 165 | 166 | Ok(()) 167 | } 168 | 169 | fn check_version_installed(local_versions: &[PathBuf], tag: &str) -> bool { 170 | local_versions.iter().any(|v| { 171 | v.file_name() 172 | .and_then(|str| str.to_str()) 173 | .map_or(false, |str| str.contains(tag)) 174 | }) 175 | } 176 | 177 | fn retain_local_versions(local_versions: Vec, tag: &str) { 178 | let mut local_versions = local_versions; 179 | local_versions.retain(|v| { 180 | v.file_name() 181 | .and_then(|str| str.to_str()) 182 | .map_or(true, |str| !str.contains(tag)) 183 | }); 184 | } 185 | 186 | /// Filters out pre-release versions from a list of `RemoteVersion`. 187 | /// 188 | /// # Arguments 189 | /// 190 | /// * `versions` - A vector of `RemoteVersion` instances to filter. 191 | /// 192 | /// # Returns 193 | /// 194 | /// This function returns a `Result, Error>` containing only 195 | /// the versions that are not marked as pre-releases. 196 | fn filter_versions(versions: Vec) -> Result, Error> { 197 | Ok(versions.into_iter().filter(|v| !v.prerelease).collect()) 198 | } 199 | 200 | /// Filters local versions of a package from the downloads directory. 201 | /// 202 | /// This function reads the downloads directory for the specified package and 203 | /// filters out entries that do not contain a 'v' character, which is assumed to 204 | /// indicate a version. 205 | /// 206 | /// # Arguments 207 | /// 208 | /// * `package` - The `Package` enum representing the package to filter local 209 | /// versions for. 210 | /// 211 | /// # Returns 212 | /// 213 | /// This function returns a `Result, Error>` containing paths to 214 | /// the local versions of the package. 215 | /// 216 | /// # Errors 217 | /// 218 | /// This function will return an error if there is an issue reading the 219 | /// downloads directory. 220 | async fn filter_local_versions(package: Package) -> Result, Error> { 221 | let downloads_dir = crate::fs::get_downloads_directory(package.clone()).await?; 222 | let local_versions: Vec = fs::read_dir(downloads_dir)? 223 | .filter_map(Result::ok) 224 | .filter(|entry| entry.path().file_name().unwrap().to_str().unwrap().contains('v')) 225 | .map(|entry| entry.path()) 226 | .collect(); 227 | 228 | Ok(local_versions) 229 | } 230 | -------------------------------------------------------------------------------- /src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::helpers::version::LocalVersion; 2 | 3 | pub mod erase; 4 | pub mod install; 5 | pub mod list; 6 | pub mod list_remote; 7 | pub mod prefix; 8 | pub mod uninstall; 9 | pub mod use_cmd; 10 | 11 | /// Represents the type of a version after it has been downloaded. 12 | /// 13 | /// This enum has three variants: 14 | /// 15 | /// * `None` - No specific version type is assigned. 16 | /// * `Standard(LocalVersion)` - The version is a standard version. The 17 | /// `LocalVersion` contains the details of the version. 18 | /// * `Hash` - The version is identified by a hash. 19 | #[derive(PartialEq)] 20 | pub enum PostDownloadVersionType { 21 | Standard(LocalVersion), 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/prefix.rs: -------------------------------------------------------------------------------- 1 | /// Part of the `prefix` command, which is useful for adding 2 | /// the installation directory to the PATH. The `prefix` command retrieves the 3 | /// installation directory and prints it to the standard output. 4 | pub async fn run() -> miette::Result<()> { 5 | let prefix = crate::fs::get_installation_directory() 6 | .await 7 | .expect("Failed to get installation directory"); 8 | 9 | println!("{}", prefix.display()); 10 | 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /src/commands/uninstall.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Error; 2 | use anyhow::Result; 3 | use clap::Parser; 4 | use tokio::fs; 5 | use tracing::info; 6 | 7 | use crate::fs::get_downloads_directory; 8 | use crate::helpers::version::get_current_version; 9 | use crate::packages::Package; 10 | use crate::packages::PackageType; 11 | 12 | #[derive(Parser)] 13 | pub struct Args { 14 | #[command(subcommand)] 15 | command: Commands, 16 | } 17 | 18 | #[derive(Parser)] 19 | pub enum Commands { 20 | Reth { version: String }, 21 | Oura { version: String }, 22 | Aiken { version: String }, 23 | Dolos { version: String }, 24 | Zellij { version: String }, 25 | Neovim { version: String }, 26 | Mithril { version: String }, 27 | Scrolls { version: String }, 28 | CardanoCli { version: String }, 29 | CardanoNode { version: String }, 30 | SidechainCli { version: String }, 31 | PartnerChainCli { version: String }, 32 | PartnerChainNode { version: String }, 33 | CardanoSubmitApi { version: String }, 34 | } 35 | 36 | /// A macro to execute an uninstall command based on the provided variant and 37 | /// package type. 38 | /// 39 | /// This macro matches the provided command against a list of command variants 40 | /// and executes the corresponding code for each variant. It creates a new 41 | /// `Package` instance with the specified package type, version, and client, and 42 | /// then uninstalls the package. 43 | /// 44 | /// # Parameters 45 | /// 46 | /// - `$command`: The command to be matched and executed. The command must 47 | /// include a `version`. 48 | /// - `$client`: The client to be used for creating the `Package`. 49 | /// - `$(($variant:ident, $package_type:expr)),*`: A list of tuples containing 50 | /// the command variant and the corresponding package type. 51 | macro_rules! execute { 52 | ($command:expr, $client:expr, $(($variant:ident, $package_type:expr)),*) => { 53 | match $command { 54 | $( 55 | Commands::$variant { version } => { 56 | let package = Package::new($package_type, version, $client).await; 57 | uninstall(package).await.expect("Failed to uninstall") 58 | } 59 | )* 60 | } 61 | } 62 | } 63 | 64 | pub async fn run( 65 | args: Args, 66 | _ctx: &crate::Context, 67 | client: Option<&reqwest::Client>, 68 | ) -> miette::Result<()> { 69 | execute!( 70 | args.command, 71 | client, 72 | (Reth, PackageType::Reth), 73 | (Oura, PackageType::Oura), 74 | (Aiken, PackageType::Aiken), 75 | (Dolos, PackageType::Dolos), 76 | (Zellij, PackageType::Zellij), 77 | (Neovim, PackageType::Neovim), 78 | (Mithril, PackageType::Mithril), 79 | (Scrolls, PackageType::Scrolls), 80 | (CardanoCli, PackageType::CardanoCli), 81 | (CardanoNode, PackageType::CardanoNode), 82 | (SidechainCli, PackageType::SidechainCli), 83 | (PartnerChainCli, PackageType::PartnerChainCli), 84 | (PartnerChainNode, PackageType::PartnerChainNode), 85 | (CardanoSubmitApi, PackageType::CardanoSubmitApi) 86 | ); 87 | 88 | Ok(()) 89 | } 90 | 91 | pub async fn uninstall(package: Package) -> Result<(), Error> { 92 | let parsed_version = package.version().expect("Failed to parse version"); 93 | let version = parsed_version.non_parsed_string.clone(); 94 | let used_version = get_current_version(package.clone()).await?; 95 | let same_version = used_version == version; 96 | 97 | let mut downloads = get_downloads_directory(package.clone()).await?; 98 | let location = downloads.join("used"); 99 | downloads.push(&version); 100 | 101 | if fs::remove_dir_all(&downloads).await.is_ok() { 102 | info!("Successfully uninstalled {} installation", &version); 103 | } else { 104 | info!("There's nothing to uninstall"); 105 | } 106 | 107 | if !same_version { 108 | return Ok(()); 109 | } 110 | 111 | if fs::remove_file(location).await.is_ok() { 112 | info!("Successfully removed {} from used versions", &version); 113 | } else { 114 | info!("There's nothing to uninstall"); 115 | } 116 | 117 | Ok(()) 118 | } 119 | -------------------------------------------------------------------------------- /src/commands/use_cmd.rs: -------------------------------------------------------------------------------- 1 | use tracing::info; 2 | 3 | use crate::commands::install::install; 4 | use crate::fs::copy_package_proxy; 5 | use crate::helpers::version::is_version_used; 6 | use crate::helpers::version::switch_version; 7 | use crate::packages::Package; 8 | use crate::packages::PackageType; 9 | 10 | #[derive(clap::Parser)] 11 | pub struct Args { 12 | #[command(subcommand)] 13 | command: Commands, 14 | } 15 | 16 | #[derive(clap::Parser)] 17 | pub enum Commands { 18 | Reth { version: String }, 19 | Oura { version: String }, 20 | Aiken { version: String }, 21 | Dolos { version: String }, 22 | Neovim { version: String }, 23 | Zellij { version: String }, 24 | Mithril { version: String }, 25 | Scrolls { version: String }, 26 | CardanoCli { version: String }, 27 | CardanoNode { version: String }, 28 | SidechainCli { version: String }, 29 | PartnerChainCli { version: String }, 30 | PartnerChainNode { version: String }, 31 | CardanoSubmitApi { version: String }, 32 | } 33 | 34 | macro_rules! execute { 35 | ($command:expr, $client:expr, $(($variant:ident, $package_type:expr)),*) => { 36 | match $command { 37 | $( 38 | Commands::$variant { version } => { 39 | let package = Package::new($package_type, version, $client).await; 40 | use_cmd($client, package).await.expect("Failed to use"); 41 | } 42 | )* 43 | } 44 | } 45 | } 46 | 47 | pub async fn run( 48 | args: Args, 49 | _ctx: &crate::Context, 50 | client: Option<&reqwest::Client>, 51 | ) -> miette::Result<()> { 52 | execute!( 53 | args.command, 54 | client, 55 | (Reth, PackageType::Reth), 56 | (Oura, PackageType::Oura), 57 | (Aiken, PackageType::Aiken), 58 | (Dolos, PackageType::Dolos), 59 | (Zellij, PackageType::Zellij), 60 | (Neovim, PackageType::Neovim), 61 | (Mithril, PackageType::Mithril), 62 | (Scrolls, PackageType::Scrolls), 63 | (CardanoCli, PackageType::CardanoCli), 64 | (CardanoNode, PackageType::CardanoNode), 65 | (SidechainCli, PackageType::SidechainCli), 66 | (PartnerChainCli, PackageType::PartnerChainCli), 67 | (PartnerChainNode, PackageType::PartnerChainNode), 68 | (CardanoSubmitApi, PackageType::CardanoSubmitApi) 69 | ); 70 | 71 | Ok(()) 72 | } 73 | 74 | pub async fn use_cmd( 75 | client: Option<&reqwest::Client>, 76 | package: Package, 77 | ) -> Result<(), Box> { 78 | let version = package.version().unwrap(); 79 | let is_version_used = is_version_used(&version.tag_name, package.clone()).await; 80 | 81 | copy_package_proxy(package.clone()).await?; 82 | 83 | if is_version_used { 84 | info!("{} is already in use.", version.tag_name); 85 | return Ok(()); 86 | } 87 | 88 | install(client, package.clone()).await?; 89 | 90 | switch_version(&version, package.clone()).await?; 91 | 92 | info!("You can now use {}!", version.tag_name); 93 | 94 | Ok(()) 95 | } 96 | -------------------------------------------------------------------------------- /src/dirs.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use std::path::PathBuf; 3 | 4 | use miette::bail; 5 | use miette::IntoDiagnostic; 6 | 7 | const DEFAULT_PATH_NAME: &str = "hyper-jump"; 8 | 9 | fn default_root_dir() -> miette::Result { 10 | if let Some(path) = directories::ProjectDirs::from("", "", DEFAULT_PATH_NAME) { 11 | return Ok(path.data_dir().into()); 12 | } 13 | 14 | bail!("Use root_dir parameter or env"); 15 | } 16 | 17 | pub fn ensure_root_dir(explicit: Option<&Path>) -> miette::Result { 18 | let defined = explicit.map(|p| p.join(DEFAULT_PATH_NAME)).unwrap_or(default_root_dir()?); 19 | 20 | std::fs::create_dir_all(&defined).into_diagnostic()?; 21 | 22 | Ok(defined) 23 | } 24 | 25 | pub struct Dirs { 26 | pub root_dir: PathBuf, 27 | } 28 | 29 | impl Dirs { 30 | pub fn try_new(root_dir: Option<&Path>) -> miette::Result { 31 | let root_dir = ensure_root_dir(root_dir)?; 32 | 33 | Ok(Self { root_dir }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/fs/mod.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs; 3 | use std::io; 4 | use std::path::Path; 5 | use std::path::PathBuf; 6 | use std::process::Command; 7 | 8 | use anyhow::anyhow; 9 | use anyhow::Result; 10 | use tracing::info; 11 | use xz2::read::XzDecoder; 12 | use zip_extract::extract; 13 | 14 | use crate::helpers::version::LocalVersion; 15 | use crate::packages::Package; 16 | use crate::packages::PackageType; 17 | 18 | /// Returns the home directory path for the current user. 19 | /// 20 | /// This function checks the target operating system using the `cfg!` macro and 21 | /// constructs the home directory path accordingly. For Windows, it uses the 22 | /// "USERPROFILE" environment variable. For macOS, it uses the "/Users/" 23 | /// directory and appends the "SUDO_USER" or "USER" environment variable if they 24 | /// exist and correspond to a valid directory. For other operating systems, it 25 | /// uses the "/home/" directory and appends the "SUDO_USER" or "USER" 26 | /// environment variable if they exist and correspond to a valid directory. 27 | /// If none of the above methods work, it uses the "HOME" environment variable. 28 | /// 29 | /// # Returns 30 | /// 31 | /// This function returns a `Result` that contains a `PathBuf` representing the 32 | /// home directory path if the operation was successful. If the operation 33 | /// failed, the function returns `Err` with a description of the error. 34 | /// 35 | /// # Example 36 | /// 37 | /// ```rust 38 | /// let home_dir = get_home_dir()?; 39 | /// ``` 40 | pub fn get_home_dir() -> Result { 41 | let mut home_str = PathBuf::new(); 42 | 43 | #[cfg(target_family = "windows")] 44 | { 45 | home_str.push(std::env::var("USERPROFILE")?); 46 | return Ok(home_str); 47 | } 48 | 49 | #[cfg(target_os = "macos")] 50 | { 51 | home_str.push("/Users/"); 52 | } 53 | 54 | #[cfg(target_os = "linux")] 55 | { 56 | home_str.push("/home/"); 57 | } 58 | 59 | if let Ok(value) = std::env::var("SUDO_USER") { 60 | home_str.push(&value); 61 | if fs::metadata(&home_str).is_ok() { 62 | return Ok(home_str); 63 | } 64 | } 65 | 66 | if let Ok(value) = std::env::var("USER") { 67 | home_str.push(&value); 68 | if fs::metadata(&home_str).is_ok() { 69 | return Ok(home_str); 70 | } 71 | } 72 | 73 | let home_value = std::env::var("HOME")?; 74 | home_str = PathBuf::from(home_value); 75 | 76 | Ok(home_str) 77 | } 78 | 79 | /// Returns the local data directory path for the current user. 80 | /// 81 | /// This function first gets the home directory path by calling the 82 | /// `get_home_dir` function. It then checks the target operating system using 83 | /// the `cfg!` macro and constructs the local data directory path accordingly. 84 | /// For Windows, it appends "AppData/Local" to the home directory path. 85 | /// For other operating systems, it appends ".local/share" to the home directory 86 | /// path. 87 | /// 88 | /// # Returns 89 | /// 90 | /// This function returns a `Result` that contains a `PathBuf` representing the 91 | /// local data directory path if the operation was successful. If the operation 92 | /// failed, the function returns `Err` with a description of the error. 93 | /// 94 | /// # Example 95 | /// 96 | /// ```rust 97 | /// let local_data_dir = get_local_data_dir()?; 98 | /// ``` 99 | pub fn get_local_data_dir() -> Result { 100 | let mut home_dir = get_home_dir()?; 101 | 102 | #[cfg(target_family = "windows")] 103 | home_dir.push("AppData/Local"); 104 | 105 | home_dir.push(".local/share"); 106 | home_dir.push("hyper-jump"); 107 | 108 | Ok(home_dir) 109 | } 110 | 111 | /// Asynchronously returns the downloads directory path based on the application 112 | /// configuration. 113 | /// 114 | /// # Returns 115 | /// 116 | /// This function returns a `Result` that contains a `PathBuf` representing the 117 | /// downloads directory path if the operation was successful. If the operation 118 | /// failed, the function returns `Err` with a description of the error. 119 | /// 120 | /// # Example 121 | /// 122 | /// ```rust 123 | /// let downloads_directory = get_downloads_directory().await?; 124 | /// ``` 125 | pub async fn get_downloads_directory(package: Package) -> Result { 126 | let mut data_dir = get_local_data_dir()?; 127 | let alias = package.alias(); 128 | data_dir.push(alias); 129 | 130 | let does_folder_exist = tokio::fs::metadata(&data_dir).await.is_ok(); 131 | let is_folder_created = tokio::fs::create_dir_all(&data_dir).await.is_ok(); 132 | 133 | if !does_folder_exist && !is_folder_created { 134 | return Err(anyhow!("Couldn't create downloads directory")); 135 | } 136 | 137 | Ok(data_dir) 138 | } 139 | 140 | /// Returns the file type binary download based on the target operating system. 141 | /// 142 | /// This function checks the target operating system using the `cfg!` macro and 143 | /// returns a string that corresponds to the appropriate file type binary 144 | /// download. For Windows, it returns "zip". 145 | /// For macOS, it returns "tar.gz". 146 | /// For other operating systems, it returns "appimage". 147 | /// 148 | /// # Returns 149 | /// 150 | /// This function returns a `&'static str` that corresponds to the file type 151 | /// binary download. 152 | /// 153 | /// # Example 154 | /// 155 | /// ```rust 156 | /// let file_type = get_file_type(); 157 | /// ``` 158 | pub fn get_file_type(package_type: PackageType) -> &'static str { 159 | #[cfg(target_family = "windows")] 160 | { 161 | "zip" 162 | } 163 | 164 | #[cfg(target_os = "macos")] 165 | { 166 | match package_type { 167 | PackageType::CardanoSubmitApi => "tar.gz", 168 | PackageType::PartnerChainNode => "zip", 169 | PackageType::PartnerChainCli => "zip", 170 | PackageType::SidechainCli => "zip", 171 | PackageType::CardanoNode => "tar.gz", 172 | PackageType::CardanoCli => "tar.gz", 173 | PackageType::Mithril => "tar.gz", 174 | PackageType::Scrolls => "tar.gz", 175 | PackageType::Aiken => "tar.gz", 176 | PackageType::Zellij => "tar.gz", 177 | PackageType::Neovim => "tar.gz", 178 | PackageType::Dolos => "tar.xz", 179 | PackageType::Oura => "tar.gz", 180 | PackageType::Reth => "tar.gz", 181 | } 182 | } 183 | 184 | #[cfg(target_os = "linux")] 185 | { 186 | match package_type { 187 | PackageType::CardanoSubmitApi => "tar.gz", 188 | PackageType::PartnerChainNode => "zip", 189 | PackageType::PartnerChainCli => "zip", 190 | PackageType::SidechainCli => "zip", 191 | PackageType::CardanoNode => "tar.gz", 192 | PackageType::CardanoCli => "tar.gz", 193 | PackageType::Mithril => "tar.gz", 194 | PackageType::Scrolls => "tar.gz", 195 | PackageType::Zellij => "tar.gz", 196 | PackageType::Neovim => "tar.gz", 197 | PackageType::Aiken => "tar.gz", 198 | PackageType::Dolos => "tar.xz", 199 | PackageType::Oura => "tar.gz", 200 | PackageType::Reth => "tar.gz", 201 | } 202 | } 203 | } 204 | 205 | /// Returns the platform-specific name. 206 | /// 207 | /// This function takes an `Option` as an argument, which represents 208 | /// the version to be downloaded. It checks the target operating system and 209 | /// architecture using the `cfg!` macro and returns a string that corresponds to 210 | /// the appropriate download for the platform. For Windows, it returns "win64". 211 | /// For macOS, it checks the version. If the version is less than or equal to 212 | /// 0.9.5, it returns "macos". If the target architecture is "aarch64", it 213 | /// returns "macos-arm64". Otherwise, it returns "macos-x86_64". 214 | /// 215 | /// # Arguments 216 | /// 217 | /// * `version` - An `Option` representing the version to be 218 | /// downloaded. 219 | /// 220 | /// # Returns 221 | /// 222 | /// This function returns a `&'static str` that corresponds to the 223 | /// platform-specific name for download. 224 | /// 225 | /// # Example 226 | /// 227 | /// ```rust 228 | /// let platform_name = get_platform_name_download(); 229 | /// ``` 230 | pub fn get_platform_name() -> &'static str { std::env::consts::OS } 231 | 232 | /// Retrieves the platform-specific name for downloads based on the target 233 | /// operating system. 234 | /// 235 | /// # Examples 236 | /// 237 | /// ``` 238 | /// let platform_name_download = get_platform_name_download(); 239 | /// println!("Platform name for downloads: {}", platform_name_download); 240 | /// ``` 241 | pub fn get_platform_name_download(package_type: PackageType) -> &'static str { 242 | #[cfg(target_family = "windows")] 243 | { 244 | "win64" 245 | } 246 | 247 | #[cfg(target_os = "macos")] 248 | { 249 | #[cfg(target_arch = "aarch64")] 250 | { 251 | match package_type { 252 | PackageType::CardanoSubmitApi => "", 253 | PackageType::PartnerChainNode => "arm64", 254 | PackageType::PartnerChainCli => "arm64", 255 | PackageType::SidechainCli => "arm64", 256 | PackageType::CardanoNode => "", 257 | PackageType::CardanoCli => "", 258 | PackageType::Mithril => "arm64", 259 | PackageType::Scrolls => "aarch64-apple-darwin", 260 | PackageType::Aiken => "aarch64-apple-darwin", 261 | PackageType::Dolos => "aarch64-apple-darwin", 262 | PackageType::Zellij => "aarch64-apple-darwin", 263 | PackageType::Neovim => "arm64", 264 | PackageType::Oura => "aarch64-apple-darwin", 265 | PackageType::Reth => "aarch64-apple-darwin", 266 | } 267 | } 268 | 269 | #[cfg(target_arch = "x86_64")] 270 | { 271 | match package_type { 272 | PackageType::CardanoSubmitApi => "", 273 | PackageType::PartnerChainNode => "x86_64", 274 | PackageType::PartnerChainCli => "x86_64", 275 | PackageType::SidechainCli => "x86_64", 276 | PackageType::CardanoNode => "", 277 | PackageType::CardanoCli => "", 278 | PackageType::Mithril => "x86_64", 279 | PackageType::Scrolls => "x86_64", 280 | PackageType::Aiken => "x86_64-apple-darwin", 281 | PackageType::Dolos => "x86_64-apple-darwin", 282 | PackageType::Zellij => "x86_64-apple-darwin", 283 | PackageType::Neovim => "x86_64", 284 | PackageType::Oura => "x86_64-apple-darwin", 285 | PackageType::Reth => "x86_64-apple-darwin", 286 | } 287 | } 288 | } 289 | 290 | #[cfg(target_os = "linux")] 291 | { 292 | match package_type { 293 | PackageType::CardanoSubmitApi => "", 294 | PackageType::PartnerChainNode => "", 295 | PackageType::PartnerChainCli => "", 296 | PackageType::SidechainCli => "", 297 | PackageType::CardanoNode => "", 298 | PackageType::CardanoCli => "", 299 | PackageType::Mithril => "x64", 300 | PackageType::Scrolls => "x64", 301 | PackageType::Aiken => "x86_64-unknown-linux-gnu", 302 | PackageType::Dolos => "x86_64-unknown-linux-gnu", 303 | PackageType::Zellij => "x86_64-unknown-linux-gnu", 304 | PackageType::Neovim => "x86_64", 305 | PackageType::Oura => "x86_64-unknown-linux-musl", 306 | PackageType::Reth => "x86_64-unknown-linux-gnu", 307 | } 308 | } 309 | } 310 | 311 | /// Copies the proxy to the installation directory. 312 | /// 313 | /// This function gets the current executable's path, determines the 314 | /// installation directory, creates it if it doesn't exist, adds it to the 315 | /// system's PATH, and copies the current executable to the installation 316 | /// directory as "cardano-node". 317 | /// 318 | /// # Returns 319 | /// 320 | /// * `Result<()>` - Returns a `Result` that indicates whether the operation was 321 | /// successful or not. 322 | /// 323 | /// # Errors 324 | /// 325 | /// This function will return an error if: 326 | /// 327 | /// * The current executable's path cannot be determined. 328 | /// * The installation directory cannot be created. 329 | /// * The installation directory cannot be added to the PATH. 330 | /// * The version of the existing file cannot be determined. 331 | /// * The existing file cannot be replaced. 332 | /// 333 | /// # Example 334 | /// 335 | /// ```rust 336 | /// let package = Package::CardanoNode(CardanoNode { 337 | /// alias: "cardano-node".to_string(), 338 | /// version: "1.0.0".to_string(), 339 | /// url: "https://example.com".to_string(), 340 | /// }); 341 | /// 342 | /// copy_package_proxy(package).await.unwrap(); 343 | /// ``` 344 | pub async fn copy_package_proxy(package: Package) -> Result<()> { 345 | let exe_path = env::current_exe().unwrap(); 346 | let mut installation_dir = get_installation_directory().await?; 347 | 348 | if fs::metadata(&installation_dir).is_err() { 349 | fs::create_dir_all(&installation_dir)?; 350 | } 351 | 352 | add_to_path(&installation_dir)?; 353 | 354 | let alias = package.alias(); 355 | installation_dir.push(&alias); 356 | if fs::metadata(&installation_dir).is_ok() { 357 | let output = Command::new(&alias).arg("--&hyper-jump").output()?.stdout; 358 | let version = String::from_utf8(output)?.trim().to_string(); 359 | 360 | if version == env!("CARGO_PKG_VERSION") { 361 | return Ok(()); 362 | } 363 | } 364 | 365 | fs::copy(&exe_path, &installation_dir).map_err(|_| anyhow!("Could not copy the proxy"))?; 366 | 367 | Ok(()) 368 | } 369 | 370 | /// Adds the installation directory to the system's PATH. 371 | /// 372 | /// This function checks if the installation directory is already in the PATH. 373 | /// If not, it adds the directory to the PATH. 374 | /// 375 | /// # Arguments 376 | /// 377 | /// * `installation_dir` - The directory to be added to the PATH. 378 | /// 379 | /// # Returns 380 | /// 381 | /// * `Result<()>` - Returns a `Result` that indicates whether the operation was 382 | /// successful or not. 383 | /// 384 | /// # Errors 385 | /// 386 | /// This function will return an error if: 387 | /// 388 | /// * The installation directory cannot be converted to a string. 389 | /// * The current user's environment variables cannot be accessed or modified 390 | /// (Windows only). 391 | /// * The PATH environment variable cannot be read (non-Windows only). 392 | /// 393 | /// # Example 394 | /// 395 | /// ```rust 396 | /// let installation_dir = Path::new("/usr/local/bin"); 397 | /// add_to_path(&installation_dir).unwrap(); 398 | /// ``` 399 | fn add_to_path(installation_dir: &Path) -> Result<()> { 400 | let installation_dir = installation_dir.to_str().unwrap(); 401 | 402 | if !std::env::var("PATH")?.contains("bin") { 403 | info!("Make sure to have {installation_dir} in PATH"); 404 | } 405 | 406 | Ok(()) 407 | } 408 | 409 | /// Asynchronously returns the installation directory path based on the 410 | /// application configuration. 411 | /// 412 | /// If the `installation_location` field in the `Config` is not set, it gets the 413 | /// downloads directory path by calling the `get_downloads_directory` function 414 | /// and appends "cardano-node-bin" to it. 415 | /// 416 | /// # Returns 417 | /// 418 | /// This function returns a `Result` that contains a `PathBuf` representing the 419 | /// installation directory path if the operation was successful. 420 | /// If the operation failed, the function returns `Err` with a description of 421 | /// the error. 422 | /// 423 | /// # Example 424 | /// 425 | /// ```rust 426 | /// let installation_directory = get_installation_directory().await?; 427 | /// ``` 428 | pub async fn get_installation_directory() -> Result { 429 | let mut installation_location = get_local_data_dir()?; 430 | 431 | installation_location.push("bin"); 432 | 433 | Ok(installation_location) 434 | } 435 | 436 | /// Starts the process of expanding a downloaded file. 437 | /// 438 | /// This function is asynchronous and uses `tokio::task::spawn_blocking` to run 439 | /// the `expand` function in a separate thread. It takes a `LocalVersion` struct 440 | /// which contains information about the downloaded file, such as its name, 441 | /// format, and path. The function first clones the `LocalVersion` struct and 442 | /// passes it to the `expand` function. If the `expand` function returns an 443 | /// error, the `start` function also returns an error. If the `expand` function 444 | /// is successful, the `start` function removes the original downloaded file. 445 | /// 446 | /// # Arguments 447 | /// 448 | /// * `file` - A `LocalVersion` struct representing the downloaded file. 449 | /// 450 | /// # Returns 451 | /// 452 | /// This function returns a `Result` that indicates whether the operation was 453 | /// successful. If the operation was successful, the function returns `Ok(())`. 454 | /// If the operation failed, the function returns `Err` with a description of 455 | /// the error. 456 | /// 457 | /// # Errors 458 | /// 459 | /// This function will return an error if: 460 | /// 461 | /// * The `expand` function returns an error. 462 | /// * The original downloaded file could not be removed. 463 | /// 464 | /// # Example 465 | /// 466 | /// ```rust 467 | /// let downloaded_file = LocalVersion { 468 | /// file_name: "cardano-node-darwin", 469 | /// file_format: "tar.gz", 470 | /// semver: semver::Version::parse("8.1.2").unwrap(), 471 | /// path: "/path/to/downloaded/file", 472 | /// }; 473 | /// unarchive(downloaded_file).await; 474 | /// ``` 475 | pub async fn unarchive(package: Package, file: LocalVersion) -> Result<()> { 476 | let path = format!("{}/{}.{}", file.path, file.file_name, file.file_format); 477 | tokio::task::spawn_blocking(move || expand(package, file)) 478 | .await? 479 | .map_err(|e| anyhow!(e))?; 480 | 481 | tokio::fs::remove_file(path).await?; 482 | 483 | Ok(()) 484 | } 485 | 486 | /// Expands a downloaded file on macOS. 487 | /// 488 | /// This function is specific to macOS due to the use of certain features like 489 | /// `os::unix::fs::PermissionsExt`. It takes a `LocalVersion` struct which 490 | /// contains information about the downloaded file, such as its name and format. 491 | /// The function then opens the file, decompresses it using `GzDecoder`, and 492 | /// extracts its contents using `tar::Archive`. During the extraction process, a 493 | /// progress bar is displayed to the user. After extraction, the function 494 | /// renames the `cardano-node-osx64` directory to `cardano-node-macos` if it 495 | /// exists. Finally, it sets the permissions of the `cardano-node` binary to 496 | /// `0o551`. 497 | /// 498 | /// # Arguments 499 | /// 500 | /// * `downloaded_file` - A `LocalVersion` struct representing the downloaded 501 | /// file. 502 | /// 503 | /// # Returns 504 | /// 505 | /// This function returns a `Result` that indicates whether the operation was 506 | /// successful. If the operation was successful, the function returns `Ok(())`. 507 | /// If the operation failed, the function returns `Err` with a description of 508 | /// the error. 509 | /// 510 | /// # Errors 511 | /// 512 | /// This function will return an error if: 513 | /// 514 | /// * The downloaded file could not be opened. 515 | /// * The file could not be decompressed or extracted. 516 | /// * The `cardano-node-osx64` directory could not be renamed. 517 | /// * The permissions of the `cardano-node` binary could not be set. 518 | /// 519 | /// # Example 520 | /// 521 | /// ```rust 522 | /// let downloaded_file = LocalVersion { 523 | /// file_name: "cardano-node-macos", 524 | /// file_format: "tar.gz", 525 | /// semver: semver::Version::parse("0.5.0").unwrap(), 526 | /// path: "/path/to/downloaded/file", 527 | /// }; 528 | /// expand(downloaded_file); 529 | /// ``` 530 | fn expand(package: Package, tmp: LocalVersion) -> Result<()> { 531 | use std::fs::File; 532 | use std::os::unix::fs::PermissionsExt; 533 | 534 | use anyhow::Context; 535 | use flate2::read::GzDecoder; 536 | use tar::Archive; 537 | 538 | if fs::metadata(&tmp.file_name).is_ok() { 539 | fs::remove_dir_all(&tmp.file_name)?; 540 | } 541 | 542 | let file_path = format!("{}/{}.{}", tmp.path, tmp.file_name, tmp.file_format); 543 | let file = File::open(&file_path).map_err(|error| { 544 | anyhow!( 545 | "Failed to open file {}.{}, file doesn't exist. additional info: {error}", 546 | tmp.file_name, 547 | tmp.file_format, 548 | ) 549 | })?; 550 | 551 | let output = format!("{}/{}", tmp.path, tmp.file_name); 552 | let decompress_stream: Box = match tmp.file_format.as_str() { 553 | "tar.gz" => Box::new(GzDecoder::new(&file)), 554 | "tar.xz" => Box::new(XzDecoder::new(&file)), 555 | "zip" => Box::new(io::empty()), 556 | _ => return Err(anyhow!("Unsupported file format")), 557 | }; 558 | 559 | let context_msg = format!( 560 | "Failed to decompress or extract file {}.{}", 561 | tmp.file_name, tmp.file_format 562 | ); 563 | 564 | match tmp.file_format.as_str() { 565 | "tar.gz" | "tar.xz" => { 566 | let mut archive = Archive::new(decompress_stream); 567 | archive.unpack(&output).with_context(|| context_msg)?; 568 | } 569 | "zip" => { 570 | extract(&file, Path::new(&output), true).with_context(|| context_msg)?; 571 | } 572 | _ => return Err(anyhow!("Unsupported file format")), 573 | } 574 | 575 | let binary = &format!( 576 | "{}/{}/{}", 577 | tmp.file_name, 578 | package.binary_path(), 579 | package.binary_name() 580 | ); 581 | let mut perms = fs::metadata(binary)?.permissions(); 582 | perms.set_mode(0o551); 583 | fs::set_permissions(binary, perms)?; 584 | 585 | Ok(()) 586 | } 587 | -------------------------------------------------------------------------------- /src/helpers/client/mod.rs: -------------------------------------------------------------------------------- 1 | use std::env::var; 2 | 3 | use anyhow::Error; 4 | use reqwest::header::HeaderMap; 5 | use reqwest::header::HeaderValue; 6 | use reqwest::header::AUTHORIZATION; 7 | use reqwest::Client; 8 | 9 | /// Creates a new `reqwest::Client` with default headers. 10 | /// 11 | /// This function fetches the `GITHUB_TOKEN` environment variable and uses it to 12 | /// set the `Authorization` header for the client. 13 | /// 14 | /// # Returns 15 | /// 16 | /// This function returns a `Result` that contains a `reqwest::Client` if the 17 | /// client was successfully created, or an `Error` if the client could not be 18 | /// created. 19 | /// 20 | /// # Example 21 | /// 22 | /// ```rust 23 | /// let client = create_reqwest_client(); 24 | /// ``` 25 | /// 26 | /// # Errors 27 | /// 28 | /// This function will return an error if the `reqwest::Client` could not be 29 | /// built. 30 | pub fn create_reqwest_client() -> Result { 31 | let mut headers = HeaderMap::new(); 32 | if let Ok(token) = var("GITHUB_TOKEN") { 33 | let token = HeaderValue::from_str(&format!("token {}", token))?; 34 | headers.insert(AUTHORIZATION, token); 35 | } 36 | 37 | Ok(Client::builder().default_headers(headers).build()?) 38 | } 39 | -------------------------------------------------------------------------------- /src/helpers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod client; 2 | pub mod version; 3 | -------------------------------------------------------------------------------- /src/helpers/version/mod.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | use anyhow::Result; 3 | use chrono::DateTime; 4 | use chrono::Utc; 5 | use regex::Regex; 6 | use semver::Version; 7 | use serde::Deserialize; 8 | use serde::Serialize; 9 | use tokio::fs; 10 | 11 | use crate::packages::Package; 12 | use crate::packages::PackageType; 13 | use crate::services::github::api; 14 | 15 | /// Represents a local version of the software. 16 | /// 17 | /// This struct contains information about a local version of the software, 18 | /// including the file name, file format, path, and semantic version. 19 | /// 20 | /// # Fields 21 | /// 22 | /// * `file_name: String` - The name of the file that contains the local 23 | /// version. 24 | /// * `file_format: String` - The format of the file that contains the local 25 | /// version. 26 | /// * `path: String` - The path to the file that contains the local version. 27 | /// * `semver: Option` - The semantic version of the local version, or 28 | /// `None` if the version is not a semantic version. 29 | /// 30 | /// # Example 31 | /// 32 | /// ```rust 33 | /// let local_version = LocalVersion { 34 | /// file_name: "version-1.0.0.tar.gz".to_string(), 35 | /// file_format: "tar.gz".to_string(), 36 | /// path: "/path/to/version-1.0.0.tar.gz".to_string(), 37 | /// semver: Some(Version::parse("1.0.0").unwrap()), 38 | /// }; 39 | /// println!("The local version is {:?}", local_version); 40 | /// ``` 41 | #[derive(Clone, PartialEq, Debug)] 42 | pub struct LocalVersion { 43 | pub file_name: String, 44 | pub file_format: String, 45 | pub path: String, 46 | pub semver: Option, 47 | } 48 | 49 | /// Represents a remote version. 50 | /// 51 | /// This struct is used to deserialize the response from the GitHub API request 52 | /// that gets the tags of the repository. Each tag represents a version 53 | /// of package, and the `name` field of the `RemoteVersion` struct represents 54 | /// the name of the version. 55 | /// 56 | /// # Fields 57 | /// 58 | /// * `name` - A `String` that represents the name of the version. 59 | /// 60 | /// # Example 61 | /// 62 | /// ```rust 63 | /// let remote_version = RemoteVersion { 64 | /// name: "v0.5.0".to_string(), 65 | /// }; 66 | /// ``` 67 | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] 68 | pub struct RemoteVersion { 69 | pub name: String, 70 | pub tag_name: String, 71 | pub prerelease: bool, 72 | } 73 | 74 | #[derive(Debug, Clone)] 75 | pub enum VersionStatus { 76 | Installed, 77 | Used, 78 | NotInstalled, 79 | } 80 | 81 | /// Represents the version of the upstream software in the GitHub API. 82 | /// 83 | /// This struct contains the tag name of the version, the target commitish of 84 | /// the version, and the date and time the version was published. 85 | /// 86 | /// # Fields 87 | /// 88 | /// * `tag_name: String` - The tag name of the version. 89 | /// * `target_commitish: Option` - The target commitish of the version. 90 | /// This is optional and may be `None`. 91 | /// * `published_at: DateTime` - The date and time the version was 92 | /// published, represented as a `DateTime` object. 93 | /// 94 | /// # Example 95 | /// 96 | /// ```rust 97 | /// let upstream_version = UpstreamVersion { 98 | /// tag_name: "v1.0.0".to_string(), 99 | /// target_commitish: Some("abc123".to_string()), 100 | /// published_at: Utc::now(), 101 | /// }; 102 | /// println!("The tag name is {}", upstream_version.tag_name); 103 | /// println!( 104 | /// "The target commitish is {}", 105 | /// upstream_version.target_commitish.unwrap_or_default() 106 | /// ); 107 | /// println!( 108 | /// "The published date and time is {}", 109 | /// upstream_version.published_at 110 | /// ); 111 | /// ``` 112 | #[derive(Serialize, Deserialize, Debug, Clone)] 113 | pub struct UpstreamVersion { 114 | pub tag_name: String, 115 | pub target_commitish: Option, 116 | pub published_at: DateTime, 117 | } 118 | 119 | /// Represents a parsed version of the software. 120 | /// 121 | /// This struct contains information about a parsed version of the software, 122 | /// including the tag name, version type, non-parsed string, and semantic 123 | /// version. 124 | /// 125 | /// # Fields 126 | /// 127 | /// * `tag_name: String` - The tag name of the parsed version. 128 | /// * `version_type: VersionType` - The type of the parsed version. 129 | /// * `non_parsed_string: String` - The non-parsed string of the parsed version. 130 | /// * `semver: Option` - The semantic version of the parsed version, or 131 | /// `None` if the version is not a semantic version. 132 | /// 133 | /// # Example 134 | /// 135 | /// ```rust 136 | /// let parsed_version = ParsedVersion { 137 | /// tag_name: "v1.0.0".to_string(), 138 | /// version_type: VersionType::Normal, 139 | /// non_parsed_string: "version-1.0.0".to_string(), 140 | /// semver: Some(Version::parse("1.0.0").unwrap()), 141 | /// }; 142 | /// println!("The parsed version is {:?}", parsed_version); 143 | /// ``` 144 | #[derive(Debug, Clone)] 145 | pub struct ParsedVersion { 146 | pub tag_name: String, 147 | pub version_type: VersionType, 148 | pub non_parsed_string: String, 149 | pub semver: Option, 150 | } 151 | 152 | /// Represents the type of a software version. 153 | /// 154 | /// This enum is used to distinguish between different types of software 155 | /// versions, such as normal versions, the latest version, nightly versions, 156 | /// versions identified by a hash, and nightly versions that have been rolled 157 | /// back. 158 | /// 159 | /// # Variants 160 | /// 161 | /// * `Normal` - Represents a normal version. 162 | /// * `Latest` - Represents the latest version. 163 | /// 164 | /// # Example 165 | /// 166 | /// ```rust 167 | /// let version_type = VersionType::Normal; 168 | /// match version_type { 169 | /// VersionType::Normal => println!("This is a normal version."), 170 | /// VersionType::Latest => println!("This is the latest version."), 171 | /// } 172 | /// ``` 173 | #[derive(PartialEq, Eq, Debug, Clone)] 174 | pub enum VersionType { 175 | Normal, 176 | Latest, 177 | } 178 | 179 | impl VersionType { 180 | pub fn from_string(version: &str) -> VersionType { 181 | match version { 182 | "latest" => VersionType::Latest, 183 | _ => VersionType::Normal, 184 | } 185 | } 186 | 187 | pub async fn parse( 188 | version: &str, 189 | client: Option<&reqwest::Client>, 190 | package_type: PackageType, 191 | ) -> Result { 192 | let version_type = VersionType::from_string(version); 193 | match version_type { 194 | VersionType::Normal => Ok(parse_normal_version(version, version_type).await?), 195 | VersionType::Latest => Ok(fetch_latest_version(client, package_type).await?), 196 | } 197 | } 198 | } 199 | 200 | pub async fn parse_normal_version( 201 | version: &str, 202 | version_type: VersionType, 203 | ) -> Result { 204 | let semver = semver(version)?; 205 | let returned_version = match (semver, version.starts_with('v')) { 206 | (true, false) => parse_semver(version)?, 207 | _ => ParsedVersion { 208 | tag_name: version.to_string(), 209 | version_type, 210 | non_parsed_string: version.to_string(), 211 | semver: None, 212 | }, 213 | }; 214 | 215 | Ok(returned_version) 216 | } 217 | 218 | pub async fn fetch_latest_version( 219 | client: Option<&reqwest::Client>, 220 | package_type: PackageType, 221 | ) -> Result { 222 | let url = package_type.get_latest_url(); 223 | let response = api(client, url).await.unwrap(); 224 | let latest_version: UpstreamVersion = serde_json::from_str(&response)?; 225 | let tag_name = latest_version.tag_name.clone(); 226 | 227 | parse_normal_version(&tag_name, VersionType::Latest).await 228 | } 229 | 230 | pub fn semver(version: &str) -> Result { 231 | Ok(Regex::new(r"^v?[0-9]+\.[0-9]+\.[0-9]+$")?.is_match(version)) 232 | } 233 | 234 | fn parse_semver(version: &str) -> Result { 235 | let version = version.to_string(); 236 | let semver = Version::parse(&version)?; 237 | Ok(ParsedVersion { 238 | tag_name: version.clone(), 239 | version_type: VersionType::Normal, 240 | non_parsed_string: version.clone(), 241 | semver: Some(semver), 242 | }) 243 | } 244 | 245 | /// This function reads the downloads directory and checks if there is a 246 | /// directory with the name matching the specified version. If such a directory 247 | /// is found, it means that the version is installed. 248 | /// 249 | /// # Arguments 250 | /// 251 | /// * `version` - The version to check. 252 | /// 253 | /// # Returns 254 | /// 255 | /// * `Result` - Returns a `Result` that contains `true` if the version is 256 | /// installed, `false` otherwise, or an error if the operation failed. 257 | /// 258 | /// # Errors 259 | /// 260 | /// This function will return an error if: 261 | /// 262 | /// * The downloads directory cannot be retrieved. 263 | /// * The downloads directory cannot be read. 264 | /// 265 | /// # Example 266 | /// 267 | /// ```rust 268 | /// let version = "1.0.0"; 269 | /// let is_installed = is_version_installed(version).await.unwrap(); 270 | /// println!("Is version {} installed? {}", version, is_installed); 271 | /// ``` 272 | pub async fn is_version_installed(version: &str, package: Package) -> Result { 273 | let downloads_dir = crate::fs::get_downloads_directory(package).await?; 274 | let mut dir = tokio::fs::read_dir(&downloads_dir).await?; 275 | 276 | while let Some(directory) = dir.next_entry().await? { 277 | let name = directory.file_name().to_str().unwrap().to_owned(); 278 | if !version.eq(&name) { 279 | continue; 280 | } else { 281 | return Ok(true); 282 | } 283 | } 284 | Ok(false) 285 | } 286 | 287 | /// Retrieves the current version being used. 288 | /// 289 | /// This function reads the "used" file from the downloads directory, which 290 | /// contains the current version being used. If the "used" file cannot be found, 291 | /// it means that is not installed through hyper-jump. 292 | /// 293 | /// # Returns 294 | /// 295 | /// * `Result` - Returns a `Result` that contains the current version 296 | /// being used, or an error if the operation failed. 297 | /// 298 | /// # Errors 299 | /// 300 | /// This function will return an error if: 301 | /// 302 | /// * The downloads directory cannot be retrieved. 303 | /// * The "used" file cannot be read. 304 | /// 305 | /// # Example 306 | /// 307 | /// ```rust 308 | /// let current_version = get_current_version().await.unwrap(); 309 | /// println!("The current version is {}", current_version); 310 | /// ``` 311 | pub async fn get_current_version(package: Package) -> Result { 312 | let mut downloads_dir = crate::fs::get_downloads_directory(package).await?; 313 | downloads_dir.push("used"); 314 | 315 | tokio::fs::read_to_string(&downloads_dir) 316 | .await 317 | .map_err(|_| anyhow!("Could not read the current version")) 318 | } 319 | 320 | pub async fn is_version_used(version: &str, package: Package) -> bool { 321 | let current_version = get_current_version(package).await; 322 | match current_version { 323 | Ok(current_version) => current_version.eq(version), 324 | Err(_) => false, 325 | } 326 | } 327 | 328 | /// Switches to a specified version. 329 | /// 330 | /// # Arguments 331 | /// 332 | /// * `version` - The version to switch to. 333 | /// * `package` - The package to switch versions for. 334 | /// 335 | /// # Returns 336 | /// 337 | /// * `Result<()>` - Returns a `Result` that indicates whether the operation was 338 | /// successful or not. 339 | /// 340 | /// # Errors 341 | /// 342 | /// This function will return an error if: 343 | /// 344 | /// * The downloads directory cannot be determined. 345 | /// * The current directory cannot be changed to the downloads directory. 346 | /// * The version cannot be written to the "used" file. 347 | pub async fn switch_version(version: &ParsedVersion, package: Package) -> Result<()> { 348 | std::env::set_current_dir(crate::fs::get_downloads_directory(package).await?)?; 349 | 350 | let file_version: String = version.tag_name.to_string(); 351 | 352 | fs::write("used", &file_version).await?; 353 | 354 | Ok(()) 355 | } 356 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod commands; 2 | mod dirs; 3 | mod fs; 4 | mod helpers; 5 | mod packages; 6 | mod proxy; 7 | mod services; 8 | 9 | use std::env; 10 | use std::path::Path; 11 | use std::path::PathBuf; 12 | 13 | use clap::Parser; 14 | use clap::Subcommand; 15 | use clap::ValueEnum; 16 | use commands::erase; 17 | use commands::install; 18 | use commands::list; 19 | use commands::list_remote; 20 | use commands::prefix; 21 | use commands::uninstall; 22 | use commands::use_cmd; 23 | use helpers::client; 24 | use proxy::handle_proxy; 25 | use tracing::Level; 26 | use tracing_indicatif::IndicatifLayer; 27 | use tracing_subscriber::layer::SubscriberExt; 28 | use tracing_subscriber::util::SubscriberInitExt; 29 | 30 | extern crate core; 31 | 32 | #[derive(Parser)] 33 | #[command(author, version, about, long_about = None)] 34 | struct Cli { 35 | #[command(subcommand)] 36 | command: Commands, 37 | 38 | #[arg( 39 | short, 40 | long, 41 | global = true, 42 | help = "root dir for config and data", 43 | env = "Hyper-jump_ROOT_DIR" 44 | )] 45 | root_dir: Option, 46 | 47 | #[arg( 48 | short, 49 | long, 50 | global = true, 51 | help = "output format for command response", 52 | env = "Hyper-jump_OUTPUT_FORMAT" 53 | )] 54 | output_format: Option, 55 | } 56 | 57 | #[derive(ValueEnum, Clone)] 58 | pub enum OutputFormat { 59 | Json, 60 | Table, 61 | } 62 | 63 | #[derive(Subcommand)] 64 | enum Commands { 65 | Use(use_cmd::Args), 66 | List(list::Args), 67 | Install(install::Args), 68 | Uninstall(uninstall::Args), 69 | ListRemote(list_remote::Args), 70 | Prefix, 71 | Erase, 72 | } 73 | 74 | pub struct Context { 75 | pub dirs: dirs::Dirs, 76 | pub output_format: OutputFormat, 77 | } 78 | 79 | impl Context { 80 | fn for_cli(cli: &Cli) -> miette::Result { 81 | let dirs = dirs::Dirs::try_new(cli.root_dir.as_deref())?; 82 | let output_format = cli.output_format.clone().unwrap_or(OutputFormat::Table); 83 | 84 | Ok(Context { 85 | dirs, 86 | output_format, 87 | }) 88 | } 89 | } 90 | 91 | pub fn with_tracing() { 92 | let indicatif_layer = IndicatifLayer::new(); 93 | tracing_subscriber::registry() 94 | .with(tracing_subscriber::filter::LevelFilter::INFO) 95 | .with(tracing_subscriber::filter::Targets::default().with_target("hyper-jump", Level::INFO)) 96 | .with(tracing_subscriber::fmt::layer().with_writer(indicatif_layer.get_stderr_writer())) 97 | .with(indicatif_layer) 98 | .init(); 99 | } 100 | 101 | fn parse_args(args: Vec) -> (String, Vec) { 102 | let exe_name_path = Path::new(&args[0]); 103 | let exe_name = exe_name_path.file_stem().unwrap().to_str().unwrap(); 104 | let rest_args = &args[1..]; 105 | (exe_name.to_string(), rest_args.to_vec()) 106 | } 107 | 108 | #[tokio::main] 109 | async fn main() -> miette::Result<()> { 110 | tracing_subscriber::fmt::init(); 111 | let args: Vec = env::args().collect(); 112 | let (exe_name, rest_args) = parse_args(args); 113 | 114 | if !exe_name.eq(env!("CARGO_PKG_NAME")) { 115 | return handle_proxy(&exe_name, &rest_args).await; 116 | } 117 | 118 | let cli = Cli::parse(); 119 | let ctx = Context::for_cli(&cli)?; 120 | let client = Some(client::create_reqwest_client().map_err(|e| miette::miette!(e))?); 121 | 122 | match cli.command { 123 | Commands::Use(args) => use_cmd::run(args, &ctx, client.as_ref()).await, 124 | Commands::List(args) => list::run(args, &ctx, client.as_ref()).await, 125 | Commands::Install(args) => install::run(args, &ctx, client.as_ref()).await, 126 | Commands::Uninstall(args) => uninstall::run(args, &ctx, client.as_ref()).await, 127 | Commands::ListRemote(args) => list_remote::run(args, &ctx, client.as_ref()).await, 128 | Commands::Prefix => prefix::run().await, 129 | Commands::Erase => erase::run().await, 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/packages/mod.rs: -------------------------------------------------------------------------------- 1 | use reqwest::Client; 2 | 3 | use crate::fs::get_file_type; 4 | use crate::fs::get_platform_name; 5 | use crate::fs::get_platform_name_download; 6 | use crate::helpers::version::ParsedVersion; 7 | use crate::helpers::version::VersionType; 8 | 9 | const GITHUB_BASE_URL: &str = "https://github.com"; 10 | const GITHUB_API_BASE_URL: &str = "https://api.github.com/repos"; 11 | const PARTNER_CHAIN_CLI_REPO: &str = "input-output-hk/partner-chains"; 12 | const CARDANO_NODE_REPO: &str = "IntersectMBO/cardano-node"; 13 | const CARDANO_CLI_REPO: &str = "IntersectMBO/cardano-node"; 14 | const MITHRIL_REPO: &str = "input-output-hk/mithril"; 15 | const ZELLIJ_REPO: &str = "zellij-org/zellij"; 16 | const NEOVIM_REPO: &str = "neovim/neovim"; 17 | const AIKEN_REPO: &str = "aiken-lang/aiken"; 18 | const OURA_REPO: &str = "txpipe/oura"; 19 | const DOLOS_REPO: &str = "txpipe/dolos"; 20 | const RETH_REPO: &str = "paradigmxyz/reth"; 21 | const SCROLLS_REPO: &str = "txpipe/scrolls"; 22 | 23 | /// Represents the specification of a package. 24 | /// 25 | /// * `alias` - Alias of the package. 26 | /// * `version` - Optional version of the package. 27 | /// * `binary_path` - Path to the binary of the package. 28 | /// * `package_type` - Type of the package. 29 | #[derive(Debug, Clone)] 30 | pub struct Spec { 31 | pub alias: String, 32 | pub version: Option, 33 | pub binary_path: String, 34 | pub package_type: PackageType, 35 | } 36 | 37 | /// Enum representing different types of packages. 38 | /// 39 | /// * `Aiken` - Represents an Aiken package. 40 | /// * `Mithril` - Represents a Mithril package. 41 | /// * `CardanoCli` - Represents a Cardano CLI package. 42 | /// * `CardanoNode` - Represents a Cardano Node package. 43 | #[derive(Debug, Clone)] 44 | pub enum Package { 45 | Reth(Spec), 46 | Oura(Spec), 47 | Aiken(Spec), 48 | Dolos(Spec), 49 | Zellij(Spec), 50 | Neovim(Spec), 51 | Mithril(Spec), 52 | Scrolls(Spec), 53 | CardanoCli(Spec), 54 | CardanoNode(Spec), 55 | SidechainCli(Spec), 56 | PartnerChainCli(Spec), 57 | PartnerChainNode(Spec), 58 | CardanoSubmitApi(Spec), 59 | } 60 | 61 | /// Enum representing different types of package types. 62 | /// 63 | /// * `CardanoNode` - Represents the Cardano Node package type. 64 | /// * `CardanoCli` - Represents the Cardano CLI package type. 65 | /// * `Mithril` - Represents the Mithril package type. 66 | /// * `Aiken` - Represents the Aiken package type. 67 | #[derive(Debug, Clone)] 68 | pub enum PackageType { 69 | Reth, 70 | Oura, 71 | Aiken, 72 | Dolos, 73 | Zellij, 74 | Neovim, 75 | Mithril, 76 | Scrolls, 77 | CardanoCli, 78 | CardanoNode, 79 | SidechainCli, 80 | PartnerChainCli, 81 | PartnerChainNode, 82 | CardanoSubmitApi, 83 | } 84 | 85 | /// Macro to create a `Package` variant with the appropriate `Spec` struct. 86 | /// 87 | /// This macro simplifies the creation of different `Package` variants by 88 | /// matching on the `PackageType` and constructing the corresponding `Spec` 89 | /// struct with the provided alias and binary path. 90 | /// 91 | /// # Parameters 92 | /// - `$package_type`: The type of the package (of type `PackageType`). 93 | /// - `$version`: The version of the package (of type `VersionType`). 94 | /// - `$(($variant:ident, $alias:expr, $binary_path:expr)),*`: A list of tuples 95 | /// where each tuple contains: 96 | /// - `$variant`: The variant of the `PackageType` enum. 97 | /// - `$alias`: The alias string for the package. 98 | /// - `$binary_path`: The binary path string for the package. 99 | macro_rules! create_package { 100 | ($package_type:expr, $version:expr, $(($variant:ident, $alias:expr, $binary_path:expr)),*) => { 101 | match $package_type { 102 | $( 103 | PackageType::$variant => Package::$variant(Spec { 104 | alias: $alias, 105 | version: $version, 106 | binary_path: $binary_path, 107 | package_type: $package_type, 108 | }), 109 | )* 110 | } 111 | }; 112 | } 113 | 114 | impl PackageType { 115 | /// Creates a `PackageType` from a string. 116 | /// 117 | /// # Arguments 118 | /// 119 | /// * `package` - A string slice representing the package. 120 | /// 121 | /// Returns a `PackageType`. 122 | /// 123 | /// # Panics 124 | /// 125 | /// Panics if the provided string does not match any known package type. 126 | /// 127 | /// # Examples 128 | /// 129 | /// ``` 130 | /// let package_type = PackageType::from_str("cardano-node"); 131 | /// ``` 132 | pub fn from_str(package: &str) -> Self { 133 | match package { 134 | "reth" => PackageType::Reth, 135 | "oura" => PackageType::Oura, 136 | "aiken" => PackageType::Aiken, 137 | "dolos" => PackageType::Dolos, 138 | "zellij" => PackageType::Zellij, 139 | "nvim" => PackageType::Neovim, 140 | "scrolls" => PackageType::Scrolls, 141 | "cardano-cli" => PackageType::CardanoCli, 142 | "cardano-node" => PackageType::CardanoNode, 143 | "mithril-client" => PackageType::Mithril, 144 | "sidechain-main-cli" => PackageType::SidechainCli, 145 | "partner-chains-cli" => PackageType::PartnerChainCli, 146 | "partner-chains-node" => PackageType::PartnerChainNode, 147 | "cardano-submit-api" => PackageType::CardanoSubmitApi, 148 | _ => panic!("Unknown package"), 149 | } 150 | } 151 | 152 | pub fn alias(&self) -> String { 153 | match self { 154 | PackageType::Reth => "reth".to_string(), 155 | PackageType::Oura => "oura".to_string(), 156 | PackageType::Aiken => "aiken".to_string(), 157 | PackageType::Dolos => "dolos".to_string(), 158 | PackageType::Zellij => "zellij".to_string(), 159 | PackageType::Neovim => "nvim".to_string(), 160 | PackageType::Scrolls => "scrolls".to_string(), 161 | PackageType::Mithril => "mithril-client".to_string(), 162 | PackageType::CardanoCli => "cardano-cli".to_string(), 163 | PackageType::CardanoNode => "cardano-node".to_string(), 164 | PackageType::SidechainCli => "sidechain-main-cli".to_string(), 165 | PackageType::PartnerChainCli => "partner-chains-cli".to_string(), 166 | PackageType::PartnerChainNode => "partner-chains-node".to_string(), 167 | PackageType::CardanoSubmitApi => "cardano-submit-api".to_string(), 168 | } 169 | } 170 | 171 | pub fn format_binary_path(&self) -> String { 172 | let platform = get_platform_name_download(self.clone()); 173 | let os = get_platform_name(); 174 | match self { 175 | PackageType::CardanoSubmitApi => "bin".to_string(), 176 | PackageType::PartnerChainNode => "".to_string(), 177 | PackageType::PartnerChainCli => "".to_string(), 178 | PackageType::SidechainCli => "".to_string(), 179 | PackageType::CardanoNode => "bin".to_string(), 180 | PackageType::CardanoCli => "bin".to_string(), 181 | PackageType::Mithril => "".to_string(), 182 | PackageType::Zellij => "".to_string(), 183 | PackageType::Neovim => { 184 | format!("nvim-{os}-{platform}/bin", os = os, platform = platform) 185 | } 186 | PackageType::Oura => "".to_string(), 187 | PackageType::Scrolls => "".to_string(), 188 | PackageType::Aiken => format!("aiken-{platform}", platform = platform), 189 | PackageType::Dolos => format!("dolos-{platform}", platform = platform), 190 | PackageType::Reth => "".to_string(), 191 | } 192 | } 193 | 194 | /// Returns the repository URL for the package type. 195 | /// 196 | /// # Returns 197 | /// 198 | /// A string slice representing the repository URL. 199 | /// 200 | /// # Examples 201 | /// 202 | /// ``` 203 | /// let repo_url = PackageType::CardanoNode.repo(); 204 | /// ``` 205 | pub fn repo(&self) -> &str { 206 | match self { 207 | PackageType::Reth => RETH_REPO, 208 | PackageType::Oura => OURA_REPO, 209 | PackageType::Aiken => AIKEN_REPO, 210 | PackageType::Dolos => DOLOS_REPO, 211 | PackageType::Zellij => ZELLIJ_REPO, 212 | PackageType::Neovim => NEOVIM_REPO, 213 | PackageType::Scrolls => SCROLLS_REPO, 214 | PackageType::Mithril => MITHRIL_REPO, 215 | PackageType::CardanoCli => CARDANO_CLI_REPO, 216 | PackageType::CardanoNode => CARDANO_NODE_REPO, 217 | PackageType::CardanoSubmitApi => CARDANO_NODE_REPO, 218 | PackageType::SidechainCli => PARTNER_CHAIN_CLI_REPO, 219 | PackageType::PartnerChainCli => PARTNER_CHAIN_CLI_REPO, 220 | PackageType::PartnerChainNode => PARTNER_CHAIN_CLI_REPO, 221 | } 222 | } 223 | 224 | /// Returns the base URL for GitHub. 225 | /// 226 | /// # Returns 227 | /// 228 | /// A string slice representing the base URL. 229 | /// 230 | /// # Examples 231 | /// 232 | /// ``` 233 | /// let base_url = PackageType::CardanoNode.base_url(); 234 | /// ``` 235 | pub fn base_url(&self) -> &str { GITHUB_BASE_URL } 236 | 237 | /// Returns the base URL for the GitHub API. 238 | /// 239 | /// # Returns 240 | /// 241 | /// A string slice representing the API base URL. 242 | /// 243 | /// # Examples 244 | /// 245 | /// ``` 246 | /// let api_base_url = PackageType::CardanoNode.api_base_url(); 247 | /// ``` 248 | pub fn api_base_url(&self) -> &str { GITHUB_API_BASE_URL } 249 | 250 | /// Constructs the URL to get the latest release for the package type. 251 | /// 252 | /// # Returns 253 | /// 254 | /// A string representing the URL to get the latest release. 255 | /// 256 | /// # Examples 257 | /// 258 | /// ``` 259 | /// let latest_url = PackageType::CardanoNode.get_latest_url(); 260 | /// ``` 261 | pub fn get_latest_url(&self) -> String { 262 | format!("{}/{}/releases/latest", self.api_base_url(), self.repo()) 263 | } 264 | } 265 | 266 | /// Constructs a new `Package` with the specified type and version. 267 | /// 268 | /// # Arguments 269 | /// 270 | /// * `package_type` - The type of the package to construct. 271 | /// 272 | /// * `version` - The version string of the package. 273 | /// * `client` - An optional reference to a `reqwest::Client` for making HTTP 274 | /// requests. 275 | /// 276 | /// # Returns 277 | /// 278 | /// Returns a new instance of `Package`. 279 | impl Package { 280 | /// Returns the alias of the package. 281 | /// 282 | /// # Returns 283 | /// 284 | /// A string representing the alias of the package. 285 | /// 286 | /// # Examples 287 | /// 288 | /// ``` 289 | /// let package = Package::CardanoNode(Spec { 290 | /// alias: "cardano-node".to_string(), 291 | /// ..Default::default() 292 | /// }); 293 | /// let alias = package.alias(); 294 | /// ``` 295 | pub fn alias(&self) -> String { 296 | match self { 297 | Package::Reth(Spec { alias, .. }) => alias.clone(), 298 | Package::Oura(Spec { alias, .. }) => alias.clone(), 299 | Package::Aiken(Spec { alias, .. }) => alias.clone(), 300 | Package::Dolos(Spec { alias, .. }) => alias.clone(), 301 | Package::Zellij(Spec { alias, .. }) => alias.clone(), 302 | Package::Neovim(Spec { alias, .. }) => alias.clone(), 303 | Package::Mithril(Spec { alias, .. }) => alias.clone(), 304 | Package::Scrolls(Spec { alias, .. }) => alias.clone(), 305 | Package::CardanoCli(Spec { alias, .. }) => alias.clone(), 306 | Package::CardanoNode(Spec { alias, .. }) => alias.clone(), 307 | Package::SidechainCli(Spec { alias, .. }) => alias.clone(), 308 | Package::PartnerChainCli(Spec { alias, .. }) => alias.clone(), 309 | Package::PartnerChainNode(Spec { alias, .. }) => alias.clone(), 310 | Package::CardanoSubmitApi(Spec { alias, .. }) => alias.clone(), 311 | } 312 | } 313 | 314 | /// Returns the version of the package. 315 | /// 316 | /// # Returns 317 | /// 318 | /// An optional `ParsedVersion` representing the version of the package. 319 | /// 320 | /// # Examples 321 | /// 322 | /// ``` 323 | /// let package = Package::CardanoNode(Spec { 324 | /// version: Some(ParsedVersion::new("1.0.0")), 325 | /// ..Default::default() 326 | /// }); 327 | /// let version = package.version(); 328 | /// ``` 329 | pub fn version(&self) -> Option { 330 | match self { 331 | Package::Reth(Spec { version, .. }) => version.clone(), 332 | Package::Oura(Spec { version, .. }) => version.clone(), 333 | Package::Aiken(Spec { version, .. }) => version.clone(), 334 | Package::Dolos(Spec { version, .. }) => version.clone(), 335 | Package::Zellij(Spec { version, .. }) => version.clone(), 336 | Package::Neovim(Spec { version, .. }) => version.clone(), 337 | Package::Scrolls(Spec { version, .. }) => version.clone(), 338 | Package::Mithril(Spec { version, .. }) => version.clone(), 339 | Package::CardanoCli(Spec { version, .. }) => version.clone(), 340 | Package::CardanoNode(Spec { version, .. }) => version.clone(), 341 | Package::SidechainCli(Spec { version, .. }) => version.clone(), 342 | Package::PartnerChainCli(Spec { version, .. }) => version.clone(), 343 | Package::PartnerChainNode(Spec { version, .. }) => version.clone(), 344 | Package::CardanoSubmitApi(Spec { version, .. }) => version.clone(), 345 | } 346 | } 347 | 348 | /// Returns the binary path of the package. 349 | /// 350 | /// # Returns 351 | /// 352 | /// A string representing the binary path of the package. 353 | /// 354 | /// # Examples 355 | /// 356 | /// ``` 357 | /// let package = Package::CardanoNode(Spec { 358 | /// binary_path: "bin".to_string(), 359 | /// ..Default::default() 360 | /// }); 361 | /// let binary_path = package.binary_path(); 362 | /// ``` 363 | pub fn binary_path(&self) -> String { 364 | match self { 365 | Package::Reth(Spec { binary_path, .. }) => binary_path.clone(), 366 | Package::Oura(Spec { binary_path, .. }) => binary_path.clone(), 367 | Package::Aiken(Spec { binary_path, .. }) => binary_path.clone(), 368 | Package::Dolos(Spec { binary_path, .. }) => binary_path.clone(), 369 | Package::Zellij(Spec { binary_path, .. }) => binary_path.clone(), 370 | Package::Neovim(Spec { binary_path, .. }) => binary_path.clone(), 371 | Package::Scrolls(Spec { binary_path, .. }) => binary_path.clone(), 372 | Package::Mithril(Spec { binary_path, .. }) => binary_path.clone(), 373 | Package::CardanoCli(Spec { binary_path, .. }) => binary_path.clone(), 374 | Package::CardanoNode(Spec { binary_path, .. }) => binary_path.clone(), 375 | Package::SidechainCli(Spec { binary_path, .. }) => binary_path.clone(), 376 | Package::PartnerChainCli(Spec { binary_path, .. }) => binary_path.clone(), 377 | Package::PartnerChainNode(Spec { binary_path, .. }) => binary_path.clone(), 378 | Package::CardanoSubmitApi(Spec { binary_path, .. }) => binary_path.clone(), 379 | } 380 | } 381 | // Returns the binary name of the package. 382 | /// 383 | /// # Returns 384 | /// 385 | /// A string representing the binary name of the package. 386 | /// 387 | /// # Examples 388 | /// 389 | /// ``` 390 | /// let package = Package::CardanoNode(Spec { 391 | /// alias: "cardano-node".to_string(), 392 | /// ..Default::default() 393 | /// }); 394 | /// let binary_name = package.binary_name(); 395 | /// ``` 396 | pub fn binary_name(&self) -> String { 397 | match self { 398 | Package::Reth(Spec { alias, .. }) => alias.clone(), 399 | Package::Oura(Spec { alias, .. }) => alias.clone(), 400 | Package::Aiken(Spec { alias, .. }) => alias.clone(), 401 | Package::Dolos(Spec { alias, .. }) => alias.clone(), 402 | Package::Zellij(Spec { alias, .. }) => alias.clone(), 403 | Package::Neovim(Spec { alias, .. }) => alias.clone(), 404 | Package::Scrolls(Spec { alias, .. }) => alias.clone(), 405 | Package::Mithril(Spec { alias, .. }) => alias.clone(), 406 | Package::CardanoCli(Spec { alias, .. }) => alias.clone(), 407 | Package::CardanoNode(Spec { alias, .. }) => alias.clone(), 408 | Package::SidechainCli(Spec { alias, .. }) => alias.clone(), 409 | Package::PartnerChainCli(Spec { alias, .. }) => alias.clone(), 410 | Package::PartnerChainNode(Spec { alias, .. }) => alias.clone(), 411 | Package::CardanoSubmitApi(Spec { alias, .. }) => alias.clone(), 412 | } 413 | } 414 | 415 | /// Returns the package type of the package. 416 | /// 417 | /// # Returns 418 | /// 419 | /// A `PackageType` representing the type of the package. 420 | /// 421 | /// # Examples 422 | /// 423 | /// ``` 424 | /// let package = Package::CardanoNode(Spec { 425 | /// package_type: PackageType::CardanoNode, 426 | /// ..Default::default() 427 | /// }); 428 | /// let package_type = package.package_type(); 429 | /// ``` 430 | pub fn package_type(&self) -> PackageType { 431 | match self { 432 | Package::Reth(Spec { package_type, .. }) => package_type.clone(), 433 | Package::Oura(Spec { package_type, .. }) => package_type.clone(), 434 | Package::Aiken(Spec { package_type, .. }) => package_type.clone(), 435 | Package::Dolos(Spec { package_type, .. }) => package_type.clone(), 436 | Package::Zellij(Spec { package_type, .. }) => package_type.clone(), 437 | Package::Neovim(Spec { package_type, .. }) => package_type.clone(), 438 | Package::Scrolls(Spec { package_type, .. }) => package_type.clone(), 439 | Package::Mithril(Spec { package_type, .. }) => package_type.clone(), 440 | Package::CardanoCli(Spec { package_type, .. }) => package_type.clone(), 441 | Package::CardanoNode(Spec { package_type, .. }) => package_type.clone(), 442 | Package::SidechainCli(Spec { package_type, .. }) => package_type.clone(), 443 | Package::PartnerChainCli(Spec { package_type, .. }) => package_type.clone(), 444 | Package::PartnerChainNode(Spec { package_type, .. }) => package_type.clone(), 445 | Package::CardanoSubmitApi(Spec { package_type, .. }) => package_type.clone(), 446 | } 447 | } 448 | 449 | /// Constructs the template URL for the package. 450 | /// 451 | /// # Returns 452 | /// 453 | /// A string representing the template URL for the package. 454 | /// 455 | /// # Examples 456 | /// 457 | /// ``` 458 | /// let package = Package::CardanoNode(Spec { 459 | /// package_type: PackageType::CardanoNode, 460 | /// ..Default::default() 461 | /// }); 462 | /// let template_url = package.get_template_url(); 463 | /// ``` 464 | pub fn get_template_url(&self) -> String { 465 | let p = self.package_type(); 466 | let base = p.base_url(); 467 | let repo = p.repo(); 468 | match p { 469 | PackageType::CardanoSubmitApi => format!( 470 | "{}/{}/releases/download/{{version}}/cardano-node-{{version}}-{{OS}}.{{file_type}}", 471 | base, repo, 472 | ), 473 | PackageType::PartnerChainNode => format!( 474 | "{}/{}/releases/download/{{version}}/{{OS}}_{{platform}}.{{file_type}}", 475 | base, repo, 476 | ), 477 | PackageType::PartnerChainCli => format!( 478 | "{}/{}/releases/download/{{version}}/{{OS}}_{{platform}}.{{file_type}}", 479 | base, repo, 480 | ), 481 | PackageType::SidechainCli => format!( 482 | "{}/{}/releases/download/{{version}}/{{OS}}_{{platform}}.{{file_type}}", 483 | base, repo, 484 | ), 485 | PackageType::CardanoNode => format!( 486 | "{}/{}/releases/download/{{version}}/cardano-node-{{version}}-{{OS}}.{{file_type}}", 487 | base, repo, 488 | ), 489 | PackageType::CardanoCli => format!( 490 | "{}/{}/releases/download/{{version}}/cardano-node-{{version}}-{{OS}}.{{file_type}}", 491 | base, repo, 492 | ), 493 | PackageType::Mithril => format!( 494 | "{}/{}/releases/download/{{version}}/mithril-{{version}}-{{OS}}-{{platform}}.\ 495 | {{file_type}}", 496 | base, repo, 497 | ), 498 | PackageType::Scrolls => format!( 499 | "{}/{}/releases/download/{{version}}/scrolls-{{platform}}.{{file_type}}", 500 | base, repo, 501 | ), 502 | PackageType::Aiken => format!( 503 | "{}/{}/releases/download/{{version}}/aiken-{{platform}}.{{file_type}}", 504 | base, repo, 505 | ), 506 | PackageType::Dolos => format!( 507 | "{}/{}/releases/download/{{version}}/dolos-{{platform}}.{{file_type}}", 508 | base, repo, 509 | ), 510 | PackageType::Zellij => format!( 511 | "{}/{}/releases/download/{{version}}/zellij-{{platform}}.{{file_type}}", 512 | base, repo, 513 | ), 514 | PackageType::Neovim => format!( 515 | "{}/{}/releases/download/{{version}}/nvim-{{OS}}-{{platform}}.{{file_type}}", 516 | base, repo, 517 | ), 518 | PackageType::Oura => format!( 519 | "{}/{}/releases/download/{{version}}/oura-{{platform}}.{{file_type}}", 520 | base, repo, 521 | ), 522 | PackageType::Reth => format!( 523 | "{}/{}/releases/download/{{version}}/reth-{{version}}-{{platform}}.{{file_type}}", 524 | base, repo, 525 | ), 526 | } 527 | } 528 | 529 | /// Constructs the download URL for the package. 530 | /// 531 | /// # Returns 532 | /// 533 | /// A string representing the download URL for the package. 534 | /// 535 | /// # Panics 536 | /// 537 | /// Panics if the version is not set. 538 | /// 539 | /// # Examples 540 | /// 541 | /// ``` 542 | /// let package = Package::CardanoNode(Spec { 543 | /// version: Some(ParsedVersion::new("1.0.0")), 544 | /// ..Default::default() 545 | /// }); 546 | /// let download_url = package.download_url(); 547 | /// ``` 548 | pub fn download_url(&self) -> String { 549 | let v = self.version().expect("Version not set"); 550 | let p = self.package_type(); 551 | 552 | self.get_template_url() 553 | .replace("{version}", v.non_parsed_string.as_str()) 554 | .replace("{OS}", get_platform_name()) 555 | .replace("{platform}", get_platform_name_download(p)) 556 | .replace("{file_type}", get_file_type(self.package_type())) 557 | } 558 | 559 | /// Constructs the releases URL for the package. 560 | /// 561 | /// # Returns 562 | /// 563 | /// A string representing the releases URL for the package. 564 | /// 565 | /// # Examples 566 | /// 567 | /// ``` 568 | /// let package = Package::CardanoNode(Spec { 569 | /// package_type: PackageType::CardanoNode, 570 | /// ..Default::default() 571 | /// }); 572 | /// let releases_url = package.releases_url(); 573 | /// ``` 574 | pub fn releases_url(&self) -> String { 575 | let p = self.package_type(); 576 | format!("{}/{}/releases", p.api_base_url(), p.repo()) 577 | } 578 | 579 | /// Creates a new instance of `Package`. 580 | /// 581 | /// # Arguments 582 | /// 583 | /// * `package_type` - The type of the package to construct. 584 | /// * `version` - The version string of the package. 585 | /// * `client` - An optional reference to a `reqwest::Client` for making 586 | /// HTTP requests. 587 | /// 588 | /// # Returns 589 | /// 590 | /// Returns a new instance of `Package`. 591 | /// 592 | /// # Examples 593 | /// 594 | /// ``` 595 | /// let client = Client::new(); 596 | /// let package = Package::new(PackageType::CardanoNode, "1.0.0".to_string(), Some(&client)).await; 597 | /// ``` 598 | pub async fn new(package_type: PackageType, version: String, client: Option<&Client>) -> Self { 599 | let version = VersionType::parse(&version, client, package_type.clone()).await.unwrap(); 600 | let binary_path = package_type.format_binary_path(); 601 | let alias = package_type.alias(); 602 | create_package!( 603 | package_type, 604 | Some(version), 605 | (Reth, alias, binary_path), 606 | (Oura, alias, binary_path), 607 | (Aiken, alias, binary_path), 608 | (Dolos, alias, binary_path), 609 | (Zellij, alias, binary_path), 610 | (Neovim, alias, binary_path), 611 | (Scrolls, alias, binary_path), 612 | (Mithril, alias, binary_path), 613 | (CardanoCli, alias, binary_path), 614 | (CardanoNode, alias, binary_path), 615 | (SidechainCli, alias, binary_path), 616 | (PartnerChainCli, alias, binary_path), 617 | (PartnerChainNode, alias, binary_path), 618 | (CardanoSubmitApi, alias, binary_path) 619 | ) 620 | } 621 | } 622 | -------------------------------------------------------------------------------- /src/proxy/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::AtomicBool; 2 | use std::sync::Arc; 3 | 4 | use anyhow::anyhow; 5 | use anyhow::Result; 6 | use tokio::time::sleep; 7 | use tokio::time::Duration; 8 | 9 | use crate::helpers::version::get_current_version; 10 | use crate::packages::Package; 11 | use crate::packages::PackageType; 12 | 13 | /// Handles the proxy command with optional arguments. 14 | /// 15 | /// This function processes the provided arguments and executes the appropriate 16 | /// action based on the input. If the first argument is `--hyper-jump`, it 17 | /// prints the version information of itself. Otherwise, it constructs a new 18 | /// `Package` to processes it. 19 | /// 20 | /// # Arguments 21 | /// 22 | /// * `rest_args` - A slice of strings containing the command-line arguments. 23 | /// 24 | /// # Returns 25 | /// 26 | /// This function returns a `Result` indicating the success or failure of the 27 | /// operation. 28 | /// 29 | /// * `Ok(())` - The operation was successful. 30 | /// * `Err(miette::Error)` - An error occurred during the operation. 31 | /// 32 | /// # Examples 33 | /// 34 | /// ```rust 35 | /// let args = vec!["some-other-arg".to_string()]; 36 | /// handle_proxy(&args).await?; 37 | /// ``` 38 | /// 39 | /// # Errors 40 | /// 41 | /// This function will return an error if the `handle_package_process` function 42 | /// fails. 43 | pub async fn handle_proxy(exec_name: &str, rest_args: &[String]) -> miette::Result<()> { 44 | if !rest_args.is_empty() && rest_args[0].eq("--hyper-jump") { 45 | print!("hyper-jump v{}", env!("CARGO_PKG_VERSION")); 46 | return Ok(()); 47 | } 48 | 49 | let package_type = PackageType::from_str(exec_name); 50 | let package = Package::new(package_type, String::new(), None).await; 51 | 52 | handle_package_process(rest_args, package).await.unwrap(); 53 | 54 | Ok(()) 55 | } 56 | 57 | /// Handles the execution process. 58 | /// 59 | /// It retrieves the downloads directory and the currently used version from the 60 | /// configuration. It then constructs the path to the binary and spawns a new 61 | /// process with the given arguments. The function then enters a loop where it 62 | /// continuously checks the status of the spawned process. If the process exits 63 | /// with a status code of `0`, the function returns `Ok(())`. If the process 64 | /// exits with a non-zero status code, the function returns an error with the 65 | /// status code as the error message. If the process is terminated by a signal, 66 | /// the function returns an error with the message "Process terminated by 67 | /// signal". If the function fails to wait on the child process, it returns an 68 | /// error with the message "Failed to wait on child process". 69 | /// 70 | /// # Arguments 71 | /// 72 | /// * `args` - A slice of `String` arguments to be passed to the process. 73 | /// 74 | /// # Returns 75 | /// 76 | /// This function returns a `Result` that indicates whether the operation was 77 | /// successful. If the operation was successful, the function returns `Ok(())`. 78 | /// If the operation failed, the function returns `Err` with a description of 79 | /// the error. 80 | /// 81 | /// # Errors 82 | /// 83 | /// This function will return an error if: 84 | /// 85 | /// * The process exits with a non-zero status code. 86 | /// * The process is terminated by a signal. 87 | /// * The function fails to wait on the child process. 88 | /// 89 | /// # Example 90 | /// 91 | /// ```rust 92 | /// let args = vec!["-v".to_string()]; 93 | /// handle_package_process(&args).await; 94 | /// ``` 95 | pub async fn handle_package_process(args: &[String], package: Package) -> Result<()> { 96 | let downloads_dir = crate::fs::get_downloads_directory(package.clone()).await?; 97 | let used_version = get_current_version(package.clone()).await?; 98 | 99 | let location = downloads_dir 100 | .join(used_version) 101 | .join(package.binary_path()) 102 | .join(package.binary_name()); 103 | 104 | let _term = Arc::new(AtomicBool::new(false)); 105 | 106 | #[cfg(unix)] 107 | { 108 | signal_hook::flag::register(signal_hook::consts::SIGUSR1, Arc::clone(&_term))?; 109 | } 110 | 111 | let mut child = tokio::process::Command::new(location); 112 | child.args(args); 113 | 114 | let mut spawned_child = child.spawn()?; 115 | 116 | watch_process(&mut spawned_child, &_term).await 117 | } 118 | 119 | /// Watches a spawned child process and handles termination signals. 120 | /// 121 | /// This function concurrently waits for the spawned child process to exit or 122 | /// for a Ctrl-C signal to be received. It handles each scenario appropriately. 123 | /// 124 | /// # Arguments 125 | /// 126 | /// * `spawned_child` - A mutable reference to the spawned child process. 127 | /// * `term_signal` - An `Arc` containing an `AtomicBool` used to signal 128 | /// termination. 129 | /// 130 | /// # Returns 131 | /// 132 | /// This function returns a `Result` indicating the success or failure of the 133 | /// operation. 134 | /// 135 | /// * `Ok(())` - The operation was successful. 136 | /// * `Err(anyhow::Error)` - An error occurred during the operation. 137 | /// 138 | /// # Errors 139 | /// 140 | /// This function will return an error if either `handle_process_exit` or 141 | /// `handle_ctrl_c` encounters an error. 142 | /// 143 | /// # Examples 144 | /// 145 | /// ```rust 146 | /// let term_signal = Arc::new(AtomicBool::new(false)); 147 | /// let mut child = tokio::process::Command::new("some_command").spawn()?; 148 | /// watch_process(&mut child, &term_signal).await?. 149 | /// ``` 150 | async fn watch_process( 151 | spawned_child: &mut tokio::process::Child, 152 | term_signal: &Arc, 153 | ) -> Result<()> { 154 | tokio::select! { 155 | status = spawned_child.wait() => handle_process_exit(status).await, 156 | _ = tokio::signal::ctrl_c() => handle_ctrl_c(spawned_child, term_signal).await, 157 | } 158 | } 159 | 160 | /// Handles the exit of a spawned child process. 161 | /// 162 | /// This function processes the exit status of the child process and returns an 163 | /// appropriate result based on the exit code. 164 | /// 165 | /// # Arguments 166 | /// 167 | /// * `status` - The exit status of the child process. 168 | /// 169 | /// # Returns 170 | /// 171 | /// This function returns a `Result` indicating the success or failure of the 172 | /// operation. 173 | /// 174 | /// * `Ok(())` - The process exited successfully. 175 | /// * `Err(anyhow::Error)` - The process exited with an error code or was 176 | /// terminated by a signal. 177 | /// 178 | /// # Errors 179 | /// 180 | /// This function will return an error if the process exited with a non-zero 181 | /// exit code or was terminated by a signal. 182 | /// 183 | /// # Examples 184 | /// 185 | /// ```rust 186 | /// let status = Ok(std::process::ExitStatus::from_raw(0)); 187 | /// handle_process_exit(status).await?; 188 | /// ``` 189 | async fn handle_process_exit( 190 | status: Result, 191 | ) -> Result<()> { 192 | match status?.code() { 193 | Some(0) => Ok(()), 194 | Some(2) => Ok(()), 195 | Some(code) => Err(anyhow!("Process exited with error code {}", code)), 196 | None => Err(anyhow!("Process terminated by signal")), 197 | } 198 | } 199 | 200 | /// Handles the Ctrl-C signal. 201 | /// 202 | /// This function sets the termination signal and handles Unix-specific signals 203 | /// if applicable. 204 | /// 205 | /// # Arguments 206 | /// 207 | /// * `spawned_child` - A mutable reference to the spawned child process. 208 | /// * `term_signal` - An `Arc` containing an `AtomicBool` used to signal 209 | /// termination. 210 | /// 211 | /// # Returns 212 | /// 213 | /// This function returns a `Result` indicating the success or failure of the 214 | /// operation. 215 | /// 216 | /// * `Ok(())` - The operation was successful. 217 | /// * `Err(anyhow::Error)` - An error occurred during the operation. 218 | /// 219 | /// # Errors 220 | /// 221 | /// This function will return an error if `handle_unix_signals` encounters an 222 | /// error. 223 | /// 224 | /// # Examples 225 | /// 226 | /// ```rust 227 | /// let term_signal = Arc::new(AtomicBool::new(false)); 228 | /// let mut child = tokio::process::Command::new("some_command").spawn()?; 229 | /// handle_ctrl_c(&mut child, &term_signal).await?; 230 | /// ``` 231 | async fn handle_ctrl_c( 232 | spawned_child: &mut tokio::process::Child, 233 | term_signal: &Arc, 234 | ) -> Result<()> { 235 | term_signal.store(true, std::sync::atomic::Ordering::Relaxed); 236 | 237 | #[cfg(unix)] 238 | handle_unix_signals(spawned_child, term_signal)?; 239 | 240 | sleep(Duration::from_millis(200)).await; 241 | Ok(()) 242 | } 243 | 244 | /// Handles Unix-specific termination signals. 245 | /// 246 | /// This function sends a Unix signal to the spawned child process if the 247 | /// termination signal is set. 248 | /// 249 | /// # Arguments 250 | /// 251 | /// * `spawned_child` - A mutable reference to the spawned child process. 252 | /// * `term_signal` - An `Arc` containing an `AtomicBool` used to signal 253 | /// termination. 254 | /// 255 | /// # Returns 256 | /// 257 | /// This function returns a `Result` indicating the success or failure of the 258 | /// operation. 259 | /// 260 | /// * `Ok(())` - The operation was successful. 261 | /// * `Err(anyhow::Error)` - An error occurred during the operation. 262 | /// 263 | /// # Errors 264 | /// 265 | /// This function will return an error if it fails to send the Unix signal. 266 | /// 267 | /// # Examples 268 | /// 269 | /// ```rust 270 | /// let term_signal = Arc::new(AtomicBool::new(true)); 271 | /// let mut child = tokio::process::Command::new("some_command").spawn()?; 272 | /// handle_unix_signals(&mut child, &term_signal)?; 273 | /// ``` 274 | #[cfg(unix)] 275 | fn handle_unix_signals( 276 | spawned_child: &mut tokio::process::Child, 277 | term_signal: &Arc, 278 | ) -> Result<()> { 279 | use std::sync::atomic::Ordering; 280 | 281 | use nix::sys::signal::Signal; 282 | use nix::sys::signal::{self}; 283 | use nix::unistd::Pid; 284 | 285 | if term_signal.load(Ordering::Relaxed) { 286 | let pid = spawned_child.id().expect("Failed to get child process ID") as i32; 287 | signal::kill(Pid::from_raw(pid), Signal::SIGUSR1)?; 288 | term_signal.store(false, Ordering::Relaxed); 289 | } 290 | 291 | Ok(()) 292 | } 293 | -------------------------------------------------------------------------------- /src/services/github.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | use anyhow::Result; 3 | use reqwest::Client; 4 | use serde::de::DeserializeOwned; 5 | use serde::Deserialize; 6 | use serde::Serialize; 7 | 8 | /// Represents an error response from the GitHub API. 9 | /// 10 | /// This struct contains information about an error response from the GitHub 11 | /// API, including the error message and the URL of the documentation related to 12 | /// the error. 13 | /// 14 | /// # Fields 15 | /// 16 | /// * `message: String` - The error message from the GitHub API. 17 | /// * `documentation_url: String` - The URL of the documentation related to the 18 | /// error. 19 | /// 20 | /// # Example 21 | /// 22 | /// ```rust 23 | /// let error_response = ErrorResponse { 24 | /// message: "Not Found".to_string(), 25 | /// documentation_url: "https://docs.github.com/rest".to_string(), 26 | /// }; 27 | /// println!("The error message is {}", error_response.message); 28 | /// println!( 29 | /// "The documentation URL is {}", 30 | /// error_response.documentation_url 31 | /// ); 32 | /// ``` 33 | #[derive(Debug, Deserialize, Serialize)] 34 | pub struct ErrorResponse { 35 | pub message: String, 36 | pub documentation_url: String, 37 | } 38 | 39 | pub async fn api(client: Option<&Client>, url: String) -> Result { 40 | let response = client 41 | .expect("Client not found") 42 | .get(url) 43 | .header(reqwest::header::USER_AGENT, "hyper-jump") 44 | .header(reqwest::header::ACCEPT, "application/vnd.github.v3+json") 45 | .send() 46 | .await? 47 | .error_for_status()? 48 | .text() 49 | .await?; 50 | 51 | Ok(response) 52 | } 53 | 54 | /// Deserializes a JSON response from the GitHub API. 55 | /// 56 | /// # Parameters 57 | /// 58 | /// * `response: String` - The JSON response from the GitHub API as a string. 59 | /// 60 | /// # Returns 61 | /// 62 | /// * `Result` - The deserialized response as the specified type `T`, or an 63 | /// error if the response could not be deserialized or contains an error 64 | /// message. 65 | /// 66 | /// # Errors 67 | /// 68 | /// This function will return an error if the response contains a "message" 69 | /// field (indicating an error from the GitHub API), or if the response could 70 | /// not be deserialized into the specified type `T`. 71 | /// 72 | /// # Example 73 | /// 74 | /// ```rust 75 | /// let response = "{\"data\": \"some data\"}"; 76 | /// let result: Result = deserialize_response(response); 77 | /// match result { 78 | /// Ok(data) => println!("Received data: {:?}", data), 79 | /// Err(e) => println!("An error occurred: {:?}", e), 80 | /// } 81 | /// ``` 82 | pub fn deserialize_response(response: String) -> Result { 83 | let value: serde_json::Value = serde_json::from_str(&response)?; 84 | if value.get("message").is_some() { 85 | let result: ErrorResponse = serde_json::from_value(value)?; 86 | if result.documentation_url.contains("rate-limiting") { 87 | return Err(anyhow!("Rate limited by GitHub API")); 88 | } 89 | 90 | return Err(anyhow!(result.message)); 91 | } 92 | 93 | Ok(serde_json::from_value(value)?) 94 | } 95 | -------------------------------------------------------------------------------- /src/services/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod github; 2 | --------------------------------------------------------------------------------