From d13ee4e3c5e110a01d211235725ddd95a6e5e737 Mon Sep 17 00:00:00 2001 From: tippfehlr Date: Thu, 16 Mar 2023 22:52:37 +0100 Subject: [PATCH 1/5] remove 20 lines align threshold in Rustfmt.toml --- rustfmt.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 520073d0..ce11fe5b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,6 +1,6 @@ format_code_in_doc_comments = true -enum_discrim_align_threshold = 20 -struct_field_align_threshold = 20 +# enum_discrim_align_threshold = 20 +# struct_field_align_threshold = 20 condense_wildcard_suffixes = true match_block_trailing_comma = true normalize_doc_attributes = true From e08002994af272b62e72b26a159eb002066bfba7 Mon Sep 17 00:00:00 2001 From: tippfehlr Date: Thu, 16 Mar 2023 22:56:52 +0100 Subject: [PATCH 2/5] add multiple mods at the same time --- src/cli.rs | 3 +- src/main.rs | 79 +++++++++++++------------------ src/subcommands/add.rs | 103 +++++++++++++++++++++++++++++++---------- 3 files changed, 112 insertions(+), 73 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 67376d1e..dbed1a55 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -38,7 +38,8 @@ pub enum SubCommands { /// The Modrinth project ID is specified at the bottom of the left sidebar under 'Technical information'. You can also use the project slug in the URL. /// The CurseForge mod 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`. - identifier: String, + identifiers: Vec, + #[clap(long)] /// The game version will not be checked for this mod dont_check_game_version: bool, diff --git a/src/main.rs b/src/main.rs index 25a5561f..1589cb7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,49 +113,36 @@ async fn actual_main(cli_app: Ferium) -> Result<()> { match cli_app.subcommand { SubCommands::Complete { .. } => unreachable!(), SubCommands::Add { - identifier, + identifiers, dont_check_game_version, dont_check_mod_loader, dependencies, } => { let profile = get_active_profile(&mut config)?; check_internet().await?; - if let Ok(project_id) = identifier.parse::() { - subcommands::add::curseforge( + let mut error = false; + for identifier in identifiers { + match subcommands::add::add_mod( + identifier, &curseforge, - project_id, - profile, - Some(!dont_check_game_version), - Some(!dont_check_mod_loader), - dependencies, - ) - .await?; - } else if identifier.split('/').count() == 2 { - let split = identifier.split('/').collect::>(); - subcommands::add::github( - github.repos(split[0], split[1]), + &github, + &modrinth, profile, - Some(!dont_check_game_version), - Some(!dont_check_mod_loader), + dont_check_game_version, + dont_check_mod_loader, + &dependencies, ) - .await?; - } else if let Err(err) = subcommands::add::modrinth( - &modrinth, - &identifier, - profile, - Some(!dont_check_game_version), - Some(!dont_check_mod_loader), - dependencies, - ) - .await - { - return Err( - if err.to_string() == ferinth::Error::NotBase62.to_string() { - anyhow!("Invalid indentifier") - } else { - err + .await + { + Ok(_) => {}, + Err(e) => { + eprintln!("{}", e.to_string().red().bold()); + error = true; }, - ); + } + } + if error { + return Err(anyhow!("")); } }, SubCommands::List { verbose, markdown } => { @@ -216,21 +203,17 @@ async fn actual_main(cli_app: Ferium) -> Result<()> { } } else { for mod_ in &profile.mods { - println!( - "{:45} {}", - mod_.name.bold(), - match &mod_.identifier { - ModIdentifier::CurseForgeProject(id) => - format!("{:10} {}", "CurseForge".red(), id.to_string().dimmed()), - ModIdentifier::ModrinthProject(id) => - format!("{:10} {}", "Modrinth".green(), id.dimmed()), - ModIdentifier::GitHubRepository(name) => format!( - "{:10} {}", - "GitHub".purple(), - format!("{}/{}", name.0, name.1).dimmed() - ), - }, - ); + println!("{:45} {}", mod_.name.bold(), match &mod_.identifier { + ModIdentifier::CurseForgeProject(id) => + format!("{:10} {}", "CurseForge".red(), id.to_string().dimmed()), + ModIdentifier::ModrinthProject(id) => + format!("{:10} {}", "Modrinth".green(), id.dimmed()), + ModIdentifier::GitHubRepository(name) => format!( + "{:10} {}", + "GitHub".purple(), + format!("{}/{}", name.0, name.1).dimmed() + ), + },); } } }, diff --git a/src/subcommands/add.rs b/src/subcommands/add.rs index 803bedff..757cf86d 100644 --- a/src/subcommands/add.rs +++ b/src/subcommands/add.rs @@ -1,16 +1,66 @@ use crate::{cli::DependencyLevel, CROSS, THEME, TICK}; -use anyhow::{bail, Result}; +use anyhow::{anyhow, bail, Result}; use colored::Colorize; use dialoguer::Confirm; -use ferinth::structures::version::DependencyType; -use ferinth::Ferinth; +use ferinth::{structures::version::DependencyType, Ferinth}; use furse::{structures::file_structs::FileRelationType, Furse}; use itertools::Itertools; use libium::{ add, config::structs::{Mod, ModIdentifier, ModLoader, Profile}, }; -use octocrab::repos::RepoHandler; +use octocrab::{repos::RepoHandler, Octocrab}; + +pub async fn add_mod( + identifier: String, + furse: &Furse, + octocrab: &Octocrab, + ferinth: &Ferinth, + profile: &mut Profile, + dont_check_game_version: bool, + dont_check_mod_loader: bool, + dependencies: &Option, +) -> Result<()> { + eprint!("Adding mod {} … ", identifier.bold()); + if let Ok(project_id) = identifier.parse::() { + return curseforge( + &furse, + project_id, + profile, + Some(!dont_check_game_version), + Some(!dont_check_mod_loader), + &dependencies, + ) + .await; + } else if identifier.split('/').count() == 2 { + let split = identifier.split('/').collect::>(); + return github( + octocrab.repos(split[0], split[1]), + profile, + Some(!dont_check_game_version), + Some(!dont_check_mod_loader), + ) + .await; + } else if let Err(err) = modrinth( + &ferinth, + &identifier, + profile, + Some(!dont_check_game_version), + Some(!dont_check_mod_loader), + dependencies, + ) + .await + { + return Err( + if err.to_string() == ferinth::Error::NotBase62.to_string() { + anyhow!("Invalid indentifier") + } else { + err + }, + ); + } + Ok(()) +} #[allow(clippy::expect_used)] pub async fn github( @@ -19,7 +69,6 @@ pub async fn github( should_check_game_version: Option, should_check_mod_loader: Option, ) -> Result<()> { - eprint!("Adding mod... "); let (repo, _) = add::github( &repo_handler, profile, @@ -54,18 +103,21 @@ pub async fn modrinth( profile: &mut Profile, should_check_game_version: Option, should_check_mod_loader: Option, - dependencies: Option, + dependencies: &Option, ) -> Result<()> { - eprint!("Adding mod... "); let project = modrinth.get_project(project_id).await?; - let latest_version = add::modrinth( + let latest_version = match add::modrinth( modrinth, &project, profile, should_check_game_version, should_check_mod_loader, ) - .await?; + .await + { + Ok(latest_version) => latest_version, + Err(e) => return Err(e.into()), + }; println!("{} {}", *TICK, project.title.bold()); profile.mods.push(Mod { name: project.title.trim().into(), @@ -81,7 +133,7 @@ pub async fn modrinth( should_check_mod_loader }, }); - if dependencies != Some(DependencyLevel::None) { + if dependencies != &Some(DependencyLevel::None) { for dependency in &latest_version.dependencies { let mut id = if let Some(project_id) = &dependency.project_id { project_id.clone() @@ -122,14 +174,14 @@ pub async fn modrinth( if matches!(err, add::Error::AlreadyAdded) { println!("{} Already added", *TICK); } else { - bail!(err); + return Err(err.into()); } }, }; } else if dependency.dependency_type == DependencyType::Optional - && (dependencies == Some(DependencyLevel::All) || dependencies.is_none()) + && (dependencies == &Some(DependencyLevel::All) || dependencies.is_none()) { - if dependencies == Some(DependencyLevel::All) { + if dependencies == &Some(DependencyLevel::All) { eprint!("Adding optional dependency {}... ", id.dimmed()); } else { eprint!("Checking optional dependency {}... ", id.dimmed()); @@ -141,8 +193,8 @@ pub async fn modrinth( println!("{}", *TICK); } // If it's optional, confirm with the user if they want to add it - if dependencies == Some(DependencyLevel::All) - || Confirm::with_theme(&*THEME) + if dependencies == &Some(DependencyLevel::All) + || match Confirm::with_theme(&*THEME) .with_prompt(format!( "Add optional dependency {} ({})?", project.title.bold(), @@ -150,7 +202,11 @@ pub async fn modrinth( .blue() .underline() )) - .interact()? + .interact() + { + Ok(dependencies) => dependencies, + Err(_) => false, + } { profile.mods.push(Mod { name: project.title.trim().into(), @@ -166,7 +222,7 @@ pub async fn modrinth( should_check_mod_loader }, }); - if dependencies == Some(DependencyLevel::All) { + if dependencies == &Some(DependencyLevel::All) { println!("{} {}", *TICK, project.title.bold()); } } @@ -207,9 +263,8 @@ pub async fn curseforge( profile: &mut Profile, should_check_game_version: Option, should_check_mod_loader: Option, - dependencies: Option, + dependencies: &Option, ) -> Result<()> { - eprint!("Adding mod... "); let project = curseforge.get_mod(project_id).await?; let latest_file = add::curseforge( curseforge, @@ -234,7 +289,7 @@ pub async fn curseforge( should_check_mod_loader }, }); - if dependencies != Some(DependencyLevel::None) { + if dependencies != &Some(DependencyLevel::None) { for dependency in &latest_file.dependencies { let id = dependency.mod_id; if dependency.relation_type == FileRelationType::RequiredDependency { @@ -268,9 +323,9 @@ pub async fn curseforge( }, }; } else if dependency.relation_type == FileRelationType::OptionalDependency - && (dependencies == Some(DependencyLevel::All) || dependencies.is_none()) + && (dependencies == &Some(DependencyLevel::All) || dependencies.is_none()) { - if dependencies == Some(DependencyLevel::All) { + if dependencies == &Some(DependencyLevel::All) { eprint!("Adding optional dependency {}... ", id.to_string().dimmed()); } else { eprint!( @@ -285,7 +340,7 @@ pub async fn curseforge( println!("{}", *TICK); } // If it's optional, confirm with the user if they want to add it - if dependencies == Some(DependencyLevel::All) + if dependencies == &Some(DependencyLevel::All) || Confirm::with_theme(&*THEME) .with_prompt(format!( "Add optional dependency {} ({})?", @@ -308,7 +363,7 @@ pub async fn curseforge( should_check_mod_loader }, }); - if dependencies == Some(DependencyLevel::All) { + if dependencies == &Some(DependencyLevel::All) { println!("{} {}", *TICK, project.name.bold()); } } From ed82aa43cb7fb8117bab558cef08120cf97da110 Mon Sep 17 00:00:00 2001 From: tippfehlr Date: Fri, 17 Mar 2023 08:21:38 +0100 Subject: [PATCH 3/5] add indentation to dependencies & make "already added" error green --- src/main.rs | 6 +++++- src/subcommands/add.rs | 24 +++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1589cb7c..b31ceddb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -136,7 +136,11 @@ async fn actual_main(cli_app: Ferium) -> Result<()> { { Ok(_) => {}, Err(e) => { - eprintln!("{}", e.to_string().red().bold()); + if e.to_string() == libium::add::Error::AlreadyAdded.to_string() { + println!("{} Already added", *TICK); + } else { + eprintln!("{}", e.to_string().red().bold()); + } error = true; }, } diff --git a/src/subcommands/add.rs b/src/subcommands/add.rs index 757cf86d..571e1378 100644 --- a/src/subcommands/add.rs +++ b/src/subcommands/add.rs @@ -149,7 +149,7 @@ pub async fn modrinth( } if dependency.dependency_type == DependencyType::Required { - eprint!("Adding required dependency {}... ", id.dimmed()); + eprint!(" ⮱ Adding required dependency {}... ", id.dimmed()); let project = modrinth.get_project(&id).await?; match add::modrinth(modrinth, &project, profile, None, None).await { Ok(_) => { @@ -182,9 +182,9 @@ pub async fn modrinth( && (dependencies == &Some(DependencyLevel::All) || dependencies.is_none()) { if dependencies == &Some(DependencyLevel::All) { - eprint!("Adding optional dependency {}... ", id.dimmed()); + eprint!(" ⮱ Adding optional dependency {}... ", id.dimmed()); } else { - eprint!("Checking optional dependency {}... ", id.dimmed()); + eprint!(" ⮱ Checking optional dependency {}... ", id.dimmed()); } let project = modrinth.get_project(&id).await?; match add::modrinth(modrinth, &project, profile, None, None).await { @@ -196,7 +196,7 @@ pub async fn modrinth( if dependencies == &Some(DependencyLevel::All) || match Confirm::with_theme(&*THEME) .with_prompt(format!( - "Add optional dependency {} ({})?", + " ⮱ Add optional dependency {} ({})?", project.title.bold(), format!("https://modrinth.com/mod/{}", project.slug) .blue() @@ -241,7 +241,7 @@ pub async fn modrinth( if !project.donation_urls.is_empty() { println!( - "Consider supporting the mod creator on {}", + " ⮱ Consider supporting the mod creator on {}", project .donation_urls .iter() @@ -293,7 +293,10 @@ pub async fn curseforge( for dependency in &latest_file.dependencies { let id = dependency.mod_id; if dependency.relation_type == FileRelationType::RequiredDependency { - eprint!("Adding required dependency {}... ", id.to_string().dimmed()); + eprint!( + " ⮱ Adding required dependency {}... ", + id.to_string().dimmed() + ); let project = curseforge.get_mod(id).await?; match add::curseforge(curseforge, &project, profile, None, None).await { Ok(_) => { @@ -326,10 +329,13 @@ pub async fn curseforge( && (dependencies == &Some(DependencyLevel::All) || dependencies.is_none()) { if dependencies == &Some(DependencyLevel::All) { - eprint!("Adding optional dependency {}... ", id.to_string().dimmed()); + eprint!( + " ⮱ Adding optional dependency {}... ", + id.to_string().dimmed() + ); } else { eprint!( - "Checking optional dependency {}... ", + " ⮱ Checking optional dependency {}... ", id.to_string().dimmed() ); } @@ -343,7 +349,7 @@ pub async fn curseforge( if dependencies == &Some(DependencyLevel::All) || Confirm::with_theme(&*THEME) .with_prompt(format!( - "Add optional dependency {} ({})?", + " ⮱ Add optional dependency {} ({})?", project.name.bold(), project.links.website_url.to_string().blue().underline() )) From 74b0e3a7a7cad06614535613a8526a851f04addf Mon Sep 17 00:00:00 2001 From: tippfehlr Date: Fri, 17 Mar 2023 08:23:25 +0100 Subject: [PATCH 4/5] add `-e/--export` option to ferium list to print ids without formatting --- src/cli.rs | 2 ++ src/main.rs | 38 ++++++++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index dbed1a55..82c7b695 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -67,6 +67,8 @@ pub enum SubCommands { /// Useful for creating modpack mod lists. /// Complements the verbose flag. markdown: bool, + #[clap(long, short)] + export: bool, }, #[clap(arg_required_else_help = true)] /// Add, configure, delete, switch, list, or upgrade modpacks diff --git a/src/main.rs b/src/main.rs index b31ceddb..6c906abb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -149,7 +149,11 @@ async fn actual_main(cli_app: Ferium) -> Result<()> { return Err(anyhow!("")); } }, - SubCommands::List { verbose, markdown } => { + SubCommands::List { + verbose, + markdown, + export, + } => { let profile = get_active_profile(&mut config)?; check_empty_profile(profile)?; if verbose { @@ -207,17 +211,27 @@ async fn actual_main(cli_app: Ferium) -> Result<()> { } } else { for mod_ in &profile.mods { - println!("{:45} {}", mod_.name.bold(), match &mod_.identifier { - ModIdentifier::CurseForgeProject(id) => - format!("{:10} {}", "CurseForge".red(), id.to_string().dimmed()), - ModIdentifier::ModrinthProject(id) => - format!("{:10} {}", "Modrinth".green(), id.dimmed()), - ModIdentifier::GitHubRepository(name) => format!( - "{:10} {}", - "GitHub".purple(), - format!("{}/{}", name.0, name.1).dimmed() - ), - },); + if export { + match &mod_.identifier { + ModIdentifier::CurseForgeProject(id) => println!("{}", id), + ModIdentifier::ModrinthProject(id) => println!("{}", id), + ModIdentifier::GitHubRepository(name) => { + println!("{}/{}", name.0, name.1) + }, + } + } else { + println!("{:45} {}", mod_.name.bold(), match &mod_.identifier { + ModIdentifier::CurseForgeProject(id) => + format!("{:10} {}", "CurseForge".red(), id.to_string().dimmed()), + ModIdentifier::ModrinthProject(id) => + format!("{:10} {}", "Modrinth".green(), id.dimmed()), + ModIdentifier::GitHubRepository(name) => format!( + "{:10} {}", + "GitHub".purple(), + format!("{}/{}", name.0, name.1).dimmed() + ), + },); + } } } }, From c945a4e55bd513dc57a2d6f57727a4fee1189a2b Mon Sep 17 00:00:00 2001 From: tippfehlr Date: Fri, 17 Mar 2023 22:58:26 +0100 Subject: [PATCH 5/5] add `-l/--less` option to `upgrade` to hide compatible mods --- src/cli.rs | 6 +++++- src/main.rs | 4 ++-- src/subcommands/upgrade.rs | 27 +++++++++++++++------------ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 82c7b695..e1e8b6ad 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -90,7 +90,11 @@ pub enum SubCommands { mod_names: Vec, }, /// Download and install the latest version of the mods specified - Upgrade, + Upgrade { + #[clap(long, short)] + /// Don’t print compatible mods + less: bool, + }, } #[derive(Subcommand)] diff --git a/src/main.rs b/src/main.rs index 6c906abb..1bd7ba04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -356,11 +356,11 @@ async fn actual_main(cli_app: Ferium) -> Result<()> { check_empty_profile(profile)?; subcommands::remove(profile, mod_names)?; }, - SubCommands::Upgrade => { + SubCommands::Upgrade { less } => { check_internet().await?; let profile = get_active_profile(&mut config)?; check_empty_profile(profile)?; - subcommands::upgrade(modrinth, curseforge, github, profile).await?; + subcommands::upgrade(modrinth, curseforge, github, profile, less).await?; }, }; diff --git a/src/subcommands/upgrade.rs b/src/subcommands/upgrade.rs index b20c6c2b..e0525fbc 100644 --- a/src/subcommands/upgrade.rs +++ b/src/subcommands/upgrade.rs @@ -28,6 +28,7 @@ pub async fn upgrade( curseforge: Furse, github: Octocrab, profile: &Profile, + less: bool, ) -> Result<()> { let profile = Arc::new(profile.clone()); let to_download = Arc::new(Mutex::new(Vec::new())); @@ -41,7 +42,7 @@ pub async fn upgrade( let modrinth = Arc::new(modrinth); let github = Arc::new(github); - println!("{}\n", "Determining the Latest Compatible Versions".bold()); + println!("{}", "Determining the Latest Compatible Versions".bold()); let semaphore = Arc::new(Semaphore::new(75)); progress_bar .force_lock() @@ -71,17 +72,19 @@ pub async fn upgrade( let progress_bar = progress_bar.force_lock(); match result { Ok((downloadable, backwards_compat)) => { - progress_bar.println(format!( - "{} {:43} {}", - if backwards_compat { - backwards_compat_msg.store(true, Ordering::Relaxed); - YELLOW_TICK.clone() - } else { - TICK.clone() - }, - mod_.name, - downloadable.filename().dimmed() - )); + if !less { + progress_bar.println(format!( + "{} {:43} {}", + if backwards_compat { + backwards_compat_msg.store(true, Ordering::Relaxed); + YELLOW_TICK.clone() + } else { + TICK.clone() + }, + mod_.name, + downloadable.filename().dimmed() + )); + } { let mut to_download = to_download.force_lock(); to_download.push(downloadable);