From 3baa0c64bc558c77890fdccf075d88bd155cc16b Mon Sep 17 00:00:00 2001 From: Ilesh Thiada Date: Mon, 10 Jun 2024 22:59:37 +0530 Subject: [PATCH] Add multiple mods at once! And other bug fixes and code improvements --- CHANGELOG.md | 21 ++ Cargo.lock | 507 +++++++++++++++++++++--------- Cargo.toml | 6 +- README.md | 7 +- justfile | 1 + src/cli.rs | 7 +- src/main.rs | 151 ++++----- src/subcommands/modpack/delete.rs | 36 ++- src/subcommands/modpack/mod.rs | 12 +- src/subcommands/profile/create.rs | 25 +- src/subcommands/profile/delete.rs | 36 ++- src/subcommands/profile/mod.rs | 17 +- src/subcommands/remove.rs | 4 +- src/subcommands/upgrade.rs | 13 +- tests/integration_tests.rs | 6 +- 15 files changed, 553 insertions(+), 296 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb17335..6a31b44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog for Ferium +## `v4.6.0` +### 11.06.2024 + +#### You can now add multiple mods at once! ([#175](https://github.com/gorilla-devs/ferium/issues/175)) + +- Features + - Adding mods has been significantly improved + - No matter how many mods you add, there will only be a maximum of 3 network requests (for each platform) + - The `--ignore-game-version` and `--ignore-mod-loader` flags will only work when adding a single mod, since these are meant for fine-tuning + +- Bug Fixes + - Fix `No such file or directory (os error 2)` when downloading some specific modpacks ([#402](https://github.com/gorilla-devs/ferium/issues/402)) + - Fix issues with the active profile/modpack index changing when deleting profiles/modpacks + - Fix `--ignore-mod-loader` not working with curseforge mods ([#417](https://github.com/gorilla-devs/ferium/issues/417)) + +- Internal Changes + - Use `.eq_ignore_ascii_case()` where appropriate + - Use `anyhow::ensure!()` where appropriate + - Use `.ok_or_else()` where appropriate + - Replace `!__.is_relative()` with `.is_absolute()` + ## `v4.5.2` ### 23.02.2024 diff --git a/Cargo.lock b/Cargo.lock index 416bffd..287bd9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -73,9 +73,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] @@ -121,12 +121,12 @@ dependencies = [ [[package]] name = "async-broadcast" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" dependencies = [ - "event-listener 5.3.0", - "event-listener-strategy 0.5.2", + "event-listener", + "event-listener-strategy", "futures-core", "pin-project-lite", ] @@ -138,16 +138,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-compression" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" dependencies = [ "flate2", "futures-core", @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ "async-lock", "cfg-if", @@ -177,20 +177,20 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener", + "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-process" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d" +checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" dependencies = [ "async-channel", "async-io", @@ -199,7 +199,7 @@ dependencies = [ "async-task", "blocking", "cfg-if", - "event-listener 5.3.0", + "event-listener", "futures-lite", "rustix", "tracing", @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda" +checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" dependencies = [ "async-io", "async-lock", @@ -281,9 +281,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ "addr2line", "cc", @@ -335,12 +335,11 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel", - "async-lock", "async-task", "futures-io", "futures-lite", @@ -361,9 +360,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -394,9 +393,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -404,9 +403,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", @@ -416,20 +415,20 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.2" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" +checksum = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn", @@ -437,9 +436,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "colorchoice" @@ -567,6 +566,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.12.0" @@ -587,9 +597,9 @@ checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" [[package]] name = "enumflags2" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", "serde", @@ -597,9 +607,9 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", @@ -624,43 +634,22 @@ dependencies = [ [[package]] name = "event-listener" -version = "4.0.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] -[[package]] -name = "event-listener" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener", "pin-project-lite", ] @@ -688,7 +677,7 @@ dependencies = [ [[package]] name = "ferium" -version = "4.5.2" +version = "4.6.0" dependencies = [ "anyhow", "clap", @@ -884,9 +873,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "h2" @@ -913,12 +902,6 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -982,9 +965,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "8720bf4c5bfb5b6c350840c4cd14b787bf00ed51c148c857fbf7a6ddb7062764" [[package]] name = "hyper" @@ -1040,9 +1023,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", @@ -1081,14 +1064,134 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "idna" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", ] [[package]] @@ -1221,9 +1324,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libium" -version = "1.27.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01de108d454fb11ccd1982d48f561996740c417f76485aef26aa6ff65f99f00f" +checksum = "df9047c803f206f9e1149d4f85fa0bf67c51f842e445003e40245441c42fa5d2" dependencies = [ "async-recursion", "async_zip", @@ -1250,6 +1353,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "log" version = "0.4.21" @@ -1406,9 +1515,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -1530,9 +1639,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", "fastrand", @@ -1541,9 +1650,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" dependencies = [ "cfg-if", "concurrent-queue", @@ -1589,9 +1698,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -1643,9 +1752,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -1655,9 +1764,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1666,9 +1775,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" @@ -1873,18 +1982,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", @@ -1996,20 +2105,20 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snafu" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75976f4748ab44f6e5332102be424e7c2dc18daeaf7e725f2040c3ebb133512e" +checksum = "418b8136fec49956eba89be7da2847ec1909df92a9ae4178b5ff0ff092c8d95e" dependencies = [ "snafu-derive", ] [[package]] name = "snafu-derive" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b19911debfb8c2fb1107bc6cb2d61868aaf53a988449213959bb1b5b1ed95f" +checksum = "1a4812a669da00d17d8266a0439eddcacbc88b17f732f927e52eeb9d196f7fb5" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "syn", @@ -2031,6 +2140,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -2051,9 +2166,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.65" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -2066,6 +2181,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2151,25 +2277,20 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -2186,9 +2307,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -2341,32 +2462,17 @@ dependencies = [ "winapi", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "untrusted" @@ -2376,9 +2482,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", "idna", @@ -2392,11 +2498,23 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" @@ -2497,9 +2615,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" dependencies = [ "rustls-pki-types", ] @@ -2693,14 +2811,50 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "xdg-home" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" +checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", +] + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] @@ -2714,7 +2868,7 @@ dependencies = [ "async-recursion", "async-trait", "enumflags2", - "event-listener 5.3.0", + "event-listener", "futures-core", "futures-sink", "futures-util", @@ -2760,11 +2914,54 @@ dependencies = [ "zvariant", ] +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zvariant" diff --git a/Cargo.toml b/Cargo.toml index 4ca1a19..92f8b21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ferium" -version = "4.5.2" +version = "4.6.0" repository = "https://github.com/gorilla-devs/ferium" description = "Fast CLI program for managing Minecraft mods and modpacks from Modrinth, CurseForge, and Github Releases" authors = [ @@ -43,7 +43,7 @@ reqwest = { version = "0.12", default-features = false, features = [ "rustls-tls", "http2", ] } -tokio = { version = "1.37", default-features = false, features = [ +tokio = { version = "1.38", default-features = false, features = [ "rt-multi-thread", "macros", ] } @@ -58,7 +58,7 @@ octocrab = "0.38" fs_extra = "1.3" ferinth = "2.11" colored = "2.1" -libium = "1.27" +libium = "1.28" anyhow = "1.0" furse = "1.5" size = "0.4" diff --git a/README.md b/README.md index 9796ae7..c833a6b 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,9 @@ You can either have your own set of mods in what is called a 'profile', or insta ### Adding Mods +> [!TIP] +> You can specify multiple identifiers to add multiple mods at once + #### Modrinth ```bash ferium add project_id @@ -259,9 +262,9 @@ You can remove any of your mods using `ferium remove`; just select the ones you If some mod is supposed to be compatible with your game version and mod loader, but ferium does not download it, [create an issue](https://github.com/gorilla-devs/ferium/issues/new?labels=bug&template=bug-report.md) if you think it's a bug. -If you suspect the author has not specified compatible versions or mod loaders, you can disable the game version or mod loader checks by using the `--ignore-game-version` and/or `--ignore-mod-loader` flags when adding the mod, or manually setting `check_game_version` and/or `check_mod_loader` to false for the specific mod in the config file. +If you suspect the author has not specified compatible versions or mod loaders, you can disable the game version or mod loader checks by using the `--ignore-game-version` and/or `--ignore-mod-loader` flags when adding a single mod, or manually setting `check_game_version` and/or `check_mod_loader` to false for the specific mod in the config file. -For example, [Just Enough Items](https://www.curseforge.com/minecraft/mc-mods/jei) does not specify the mod loader for older Minecraft versions such as `1.12.2`. In this case, you would add JEI by running `ferium add 238222 --dont-check-mod-loader` so that the mod loader check is disabled. +For example, [Just Enough Items](https://www.curseforge.com/minecraft/mc-mods/jei) does not specify the mod loader for older Minecraft versions such as `1.12.2`. In this case, you would add JEI by running `ferium add 238222 --ignore-mod-loader` so that the mod loader check is disabled. You can also manually disable the mod loader (and/or game version) check(s) in the config like so: ```json { diff --git a/justfile b/justfile index 6056e7d..6049587 100644 --- a/justfile +++ b/justfile @@ -1,4 +1,5 @@ default: install-dev +set windows-powershell := true # Install ferium to cargo's binary folder install: diff --git a/src/cli.rs b/src/cli.rs index 875a5ca..f8f1038 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -41,14 +41,17 @@ pub enum SubCommands { /// You can also use the project slug in the URL. /// The Curseforge project ID is specified at the top of the right sidebar under 'About Project'. /// The GitHub identifier is the repository's full name, e.g. `gorilla-devs/ferium`. + #[clap(required = true)] identifiers: Vec, /// Temporarily ignore game version and mod loader checks and add the mod anyway #[clap(long, short, visible_alias = "override")] force: bool, - /// The game version will not be checked for this mod + /// The game version will not be checked for this mod. + /// Only works when adding a single mod. #[clap(long, short = 'V', alias = "dont-check-game-version")] ignore_game_version: bool, - /// The mod loader will not be checked for this mod + /// The mod loader will not be checked for this mod. + /// Only works when adding a single mod. #[clap(long, short = 'M', alias = "dont-check-mod-loader")] ignore_mod_loader: bool, }, diff --git a/src/main.rs b/src/main.rs index 0ceebba..54367b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,12 +11,10 @@ clippy::expect_used, // use anyhow::Context instead clippy::correctness )] -#![warn(clippy::dbg_macro, clippy::expect_used)] +#![warn(clippy::dbg_macro)] #![allow( clippy::case_sensitive_file_extension_comparisons, - clippy::cast_possible_truncation, clippy::multiple_crate_versions, - clippy::large_enum_variant, clippy::too_many_lines )] @@ -24,7 +22,7 @@ mod cli; mod download; mod subcommands; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, bail, ensure, Result}; use clap::{CommandFactory, Parser}; use cli::{Ferium, ModpackSubCommands, ProfileSubCommands, SubCommands}; use colored::{ColoredString, Colorize}; @@ -87,18 +85,24 @@ fn main() -> ExitCode { #[allow(clippy::expect_used)] // No error handling yet let runtime = builder.build().expect("Could not initialise Tokio runtime"); if let Err(err) = runtime.block_on(actual_main(cli)) { - eprintln!("{}", err.to_string().red().bold()); - if err - .to_string() - .to_lowercase() - .contains("error trying to connect") - { - eprintln!( - "{}", - "Verify that you are connnected to the internet" - .yellow() - .bold() - ); + if !err.to_string().is_empty() { + eprintln!("{}", err.to_string().red().bold()); + if err + .to_string() + .to_lowercase() + .contains("error trying to connect") + || err + .to_string() + .to_lowercase() + .contains("error sending request") + { + eprintln!( + "{}", + "Verify that you are connnected to the internet" + .yellow() + .bold() + ); + } } ExitCode::FAILURE } else { @@ -159,6 +163,7 @@ async fn actual_main(mut cli_app: Ferium) -> Result<()> { ) .await?; let mut config = config::deserialise(&read_wrapper(&mut config_file).await?)?; + let mut add_error = false; // Run function(s) based on the sub(sub)command to be executed match cli_app.subcommand { @@ -172,58 +177,57 @@ async fn actual_main(mut cli_app: Ferium) -> Result<()> { ignore_mod_loader, } => { let profile = get_active_profile(&mut config)?; - match identifiers.len() { - 0 => bail!("Must provide at least one identifier"), - 1 => { - eprint!("Adding mod... "); - let name = libium::add::add_single( - &modrinth, - &curseforge, - &github.build()?, - profile, - &identifiers[0], - !force, - !ignore_game_version, - !ignore_mod_loader, - ) - .await?; - println!("{} {}", *TICK, name.bold()); - } - _ => { - eprint!("Fetching mod information... "); - let (successes, failures) = libium::add::add_multiple( - &modrinth, - &curseforge, - &github.build()?, - profile, - identifiers, - ) - .await; - println!("{}", *TICK); - if !successes.is_empty() { - println!( - "Successfully added {}", - successes.iter().map(|s| s.bold()).format(", ") - ); - } - if !failures.is_empty() { - let mut grouped_errors = HashMap::new(); - for (id, error) in failures { - grouped_errors - .entry(error.to_string()) - .or_insert_with(Vec::new) - .push(id); - } - for (err, ids) in grouped_errors { - println!( - "{}: {}", - err.red().bold(), - ids.iter().map(|s| s.italic()).format(", ") - ); - } - } - } + if identifiers.len() > 1 && (ignore_game_version || ignore_mod_loader) { + bail!("Only use the ignore flags when adding a single mod!") + } + + let (successes, failures) = libium::add::add( + libium::APIs::new(&modrinth, &curseforge, &github.build()?), + profile, + identifiers, + !force, + !ignore_game_version, + !ignore_mod_loader, + ) + .await?; + + if !successes.is_empty() { + println!( + "{} {}", + "Successfully added".green(), + successes.iter().map(|s| s.bold()).format(", ") + ); + } + + let mut grouped_errors = HashMap::new(); + + for (id, error) in failures { + grouped_errors + .entry(error.to_string()) + .or_insert_with(Vec::new) + .push(id); + } + + let pad_len = grouped_errors + .keys() + .map(String::len) + .max() + .unwrap_or(0) + .clamp(0, 50); + + for (err, ids) in grouped_errors { + println!( + "{:pad_len$}: {}", + // Change already added into a warning + if err == libium::add::Error::AlreadyAdded.to_string() { + err.yellow() + } else { + add_error |= true; + err.red() + }, + ids.iter().map(|s| s.italic()).format(", ") + ); } } SubCommands::List { verbose, markdown } => { @@ -429,7 +433,11 @@ async fn actual_main(mut cli_app: Ferium) -> Result<()> { // Update config file with possibly edited config config::write_file(&mut config_file, &config).await?; - Ok(()) + if add_error { + Err(anyhow!("")) + } else { + Ok(()) + } } /// Get the active profile with error handling @@ -474,8 +482,9 @@ fn get_active_modpack(config: &mut Config) -> Result<&mut Modpack> { /// Check if `profile` is empty, and if so return an error fn check_empty_profile(profile: &Profile) -> Result<()> { - if profile.mods.is_empty() { - bail!("Your currently selected profile is empty! Run `ferium help` to see how to add mods"); - } + ensure!( + !profile.mods.is_empty(), + "Your currently selected profile is empty! Run `ferium help` to see how to add mods" + ); Ok(()) } diff --git a/src/subcommands/modpack/delete.rs b/src/subcommands/modpack/delete.rs index bc601c4..281a68a 100644 --- a/src/subcommands/modpack/delete.rs +++ b/src/subcommands/modpack/delete.rs @@ -1,6 +1,8 @@ +use std::cmp::Ordering; + use super::switch; use crate::THEME; -use anyhow::{bail, Result}; +use anyhow::{anyhow, Result}; use colored::Colorize; use dialoguer::Select; use libium::config::structs::{Config, ModpackIdentifier}; @@ -12,14 +14,11 @@ pub fn delete( ) -> Result<()> { // If the modpack name has been provided as an option let selection = if let Some(modpack_name) = modpack_name { - match config + config .modpacks .iter() .position(|modpack| modpack.name == modpack_name) - { - Some(selection) => selection, - None => bail!("The modpack name provided does not exist"), - } + .ok_or_else(|| anyhow!("The modpack name provided does not exist"))? } else { let modpack_names = config .modpacks @@ -51,15 +50,24 @@ pub fn delete( }; config.modpacks.remove(selection); - // If the currently selected modpack is being removed - if config.active_modpack == selection { - // And there is more than one modpack - if config.modpacks.len() > 1 { - // Let the user pick which modpack to switch to - switch(config, switch_to)?; - } else { - config.active_modpack = 0; + match config.active_modpack.cmp(&selection) { + // If the currently selected modpack is being removed + Ordering::Equal => { + // And there is more than one modpack + if config.modpacks.len() > 1 { + // Let the user pick which modpack to switch to + switch(config, switch_to)?; + } else { + config.active_modpack = 0; + } } + // If the active modpack comes after the removed modpack + Ordering::Greater => { + // Decrement the index by one + config.active_modpack -= 1; + } + Ordering::Less => (), } + Ok(()) } diff --git a/src/subcommands/modpack/mod.rs b/src/subcommands/modpack/mod.rs index fb3ddf3..7242cf1 100644 --- a/src/subcommands/modpack/mod.rs +++ b/src/subcommands/modpack/mod.rs @@ -11,7 +11,7 @@ pub use switch::switch; pub use upgrade::upgrade; use crate::THEME; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, ensure, Context, Result}; use dialoguer::Confirm; use fs_extra::dir::{copy, CopyOptions}; use libium::{file_picker::pick_folder, HOME}; @@ -19,9 +19,11 @@ use std::{fs::read_dir, path::Path}; #[allow(clippy::expect_used)] pub fn check_output_directory(output_dir: &Path) -> Result<()> { - if output_dir.is_relative() { - bail!("The provided output directory is not absolute, i.e. it is a relative path"); - } + ensure!( + output_dir.is_absolute(), + "The provided output directory is not absolute, i.e. it is a relative path" + ); + for check_dir in [output_dir.join("mods"), output_dir.join("resourcepacks")] { let mut backup = false; if check_dir.exists() { @@ -36,7 +38,7 @@ pub fn check_output_directory(output_dir: &Path) -> Result<()> { if backup { println!( "There are files in the {} folder in your output directory, these will be deleted when you upgrade.", - check_dir.file_name().expect("Unable to get folder name").to_string_lossy() + check_dir.file_name().context("Unable to get folder name")?.to_string_lossy() ); if Confirm::with_theme(&*THEME) .with_prompt("Would like to create a backup?") diff --git a/src/subcommands/profile/create.rs b/src/subcommands/profile/create.rs index 32675ef..3301eb1 100644 --- a/src/subcommands/profile/create.rs +++ b/src/subcommands/profile/create.rs @@ -1,6 +1,6 @@ use super::{check_output_directory, check_profile_name, pick_minecraft_version}; use crate::THEME; -use anyhow::{bail, Result}; +use anyhow::{anyhow, bail, ensure, Result}; use colored::Colorize; use dialoguer::{Confirm, Input, Select}; use libium::{ @@ -23,9 +23,11 @@ pub async fn create( (Some(game_version), Some(mod_loader), Some(name), output_dir) => { check_profile_name(config, &name)?; let output_dir = output_dir.unwrap_or_else(|| get_minecraft_dir().join("mods")); - if !output_dir.is_absolute() { - bail!("The provided output directory is not absolute, i.e. it is a relative path") - } + ensure!( + output_dir.is_absolute(), + "The provided output directory is not absolute, i.e. it is a relative path" + ); + Profile { name, output_dir, @@ -90,19 +92,18 @@ pub async fn create( }; if let Some(from) = import { - if config.profiles.is_empty() { - bail!("There are no profiles configured to import mods from") - } + ensure!( + !config.profiles.is_empty(), + "There are no profiles configured to import mods from" + ); + // If the profile name has been provided as an option let selection = if let Some(profile_name) = from { - match config + config .profiles .iter() .position(|profile| profile.name == profile_name) - { - Some(selection) => selection, - None => bail!("The profile name provided does not exist"), - } + .ok_or_else(|| anyhow!("The profile name provided does not exist"))? } else { let profile_names = config .profiles diff --git a/src/subcommands/profile/delete.rs b/src/subcommands/profile/delete.rs index a9848fa..b3904a9 100644 --- a/src/subcommands/profile/delete.rs +++ b/src/subcommands/profile/delete.rs @@ -1,6 +1,8 @@ +use std::cmp::Ordering; + use super::switch; use crate::THEME; -use anyhow::{bail, Result}; +use anyhow::{anyhow, Result}; use colored::Colorize; use dialoguer::Select; use libium::config::structs::Config; @@ -12,14 +14,11 @@ pub fn delete( ) -> Result<()> { // If the profile name has been provided as an option let selection = if let Some(profile_name) = profile_name { - match config + config .profiles .iter() .position(|profile| profile.name == profile_name) - { - Some(selection) => selection, - None => bail!("The profile name provided does not exist"), - } + .ok_or_else(|| anyhow!("The profile name provided does not exist"))? } else { let profile_names = config .profiles @@ -48,15 +47,24 @@ pub fn delete( }; config.profiles.remove(selection); - // If the currently selected profile is being removed - if config.active_profile == selection { - // And there is more than one profile - if config.profiles.len() > 1 { - // Let the user pick which profile to switch to - switch(config, switch_to)?; - } else { - config.active_profile = 0; + match config.active_profile.cmp(&selection) { + // If the currently selected profile is being removed + Ordering::Equal => { + // And there is more than one profile + if config.profiles.len() > 1 { + // Let the user pick which profile to switch to + switch(config, switch_to)?; + } else { + config.active_profile = 0; + } } + // If the active profile comes after the removed profile + Ordering::Greater => { + // Decrement the index by one + config.active_profile -= 1; + } + Ordering::Less => (), } + Ok(()) } diff --git a/src/subcommands/profile/mod.rs b/src/subcommands/profile/mod.rs index d475aac..cc00092 100644 --- a/src/subcommands/profile/mod.rs +++ b/src/subcommands/profile/mod.rs @@ -10,7 +10,7 @@ pub use info::info; pub use switch::switch; use crate::THEME; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, ensure, Result}; use colored::Colorize; use dialoguer::{Confirm, Select}; use ferinth::{structures::tag::GameVersionType, Ferinth}; @@ -81,20 +81,23 @@ pub async fn pick_minecraft_version() -> Result { /// Check that there isn't already a profile with the same name pub fn check_profile_name(config: &Config, name: &str) -> Result<()> { for profile in &config.profiles { - if profile.name == name { - bail!("A profile with name {name} already exists"); - } + ensure!( + profile.name != name, + "A profile with name {name} already exists" + ); } Ok(()) } pub async fn check_output_directory(output_dir: &PathBuf) -> Result<()> { - if output_dir.is_relative() { - bail!("The provided output directory is not absolute, i.e. it is a relative path"); - } + ensure!( + output_dir.is_absolute(), + "The provided output directory is not absolute, i.e. it is a relative path" + ); if output_dir.file_name() != Some(std::ffi::OsStr::new("mods")) { println!("{}", "Warning! The output directory is not called `mods`. Most mod loaders will load from a directory called `mods`.".bright_yellow()); } + let mut backup = false; if output_dir.exists() { for file in read_dir(output_dir)? { diff --git a/src/subcommands/remove.rs b/src/subcommands/remove.rs index 6775e51..ab18133 100644 --- a/src/subcommands/remove.rs +++ b/src/subcommands/remove.rs @@ -38,12 +38,12 @@ pub fn remove(profile: &mut Profile, to_remove: Vec) -> Result<()> { let mut items_to_remove = Vec::new(); for to_remove in to_remove { if let Some(index) = profile.mods.iter().position(|mod_| { - mod_.name.to_lowercase() == to_remove.to_lowercase() + mod_.name.eq_ignore_ascii_case(&to_remove) || match &mod_.identifier { ModIdentifier::CurseForgeProject(id) => id.to_string() == to_remove, ModIdentifier::ModrinthProject(id) => id == &to_remove, ModIdentifier::GitHubRepository((owner, name)) => { - format!("{owner}/{name}").to_lowercase() == to_remove.to_lowercase() + format!("{owner}/{name}").eq_ignore_ascii_case(&to_remove) } } }) { diff --git a/src/subcommands/upgrade.rs b/src/subcommands/upgrade.rs index 148c102..3fbad26 100644 --- a/src/subcommands/upgrade.rs +++ b/src/subcommands/upgrade.rs @@ -16,6 +16,7 @@ use libium::{ mod_downloadable::{self, get_latest_compatible_downloadable}, Downloadable, }, + APIs, }; use octocrab::Octocrab; use std::{ @@ -70,9 +71,7 @@ pub async fn get_platform_downloadables( tasks.spawn(async move { let _permit = permit; let result = get_latest_compatible_downloadable( - &modrinth, - &curseforge, - &github, + APIs::new(&modrinth, &curseforge, &github), &mod_, &profile.game_version, profile.mod_loader, @@ -177,8 +176,10 @@ pub async fn upgrade( } if error { - bail!("\nCould not get the latest compatible version of some mods") + Err(anyhow!( + "\nCould not get the latest compatible version of some mods" + )) + } else { + Ok(()) } - - Ok(()) } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 28114c2..ec6f2ad 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -183,13 +183,13 @@ fn modpack_add_curseforge() -> Result { #[test] fn already_added() { - assert!(run_command(vec!["add", "StArLiGhT"], Some("one_profile_full")).is_err()); - assert!(run_command(vec!["add", "591388"], Some("one_profile_full")).is_err()); + assert!(run_command(vec!["add", "StArLiGhT"], Some("one_profile_full")).is_ok()); + assert!(run_command(vec!["add", "591388"], Some("one_profile_full")).is_ok()); assert!(run_command( vec!["add", "caffeinemc/Sodium-Fabric"], Some("one_profile_full") ) - .is_err()); + .is_ok()); } #[test]