diff --git a/src/main.rs b/src/main.rs index 6968579..d365905 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,6 +78,11 @@ enum Commands { #[arg(long, short, action)] force: bool, }, + /// Forbid a mod from the modpack + Forbid { + /// Name of the mod to remove and forbid from the modpack + name: String, + }, /// Download the mods in the pack to a specified folder Download { /// Mods directory @@ -184,7 +189,7 @@ async fn main() -> Result<(), Box> { for provider in providers.into_iter() { mod_meta = mod_meta.provider(provider); } - modpack_meta = modpack_meta.add_mod(&mod_meta); + modpack_meta = modpack_meta.add_mod(&mod_meta)?; modpack_meta.save_current_dir_project()?; let revert_modpack_meta = |e| -> ! { @@ -250,6 +255,38 @@ async fn main() -> Result<(), Box> { } }; } + Commands::Forbid { name } => { + let mut modpack_meta = ModpackMeta::load_from_current_directory()?; + let old_modpack_meta = modpack_meta.clone(); + + modpack_meta.forbid_mod(&name); + modpack_meta = modpack_meta.remove_mod(&name); + modpack_meta.save_current_dir_project()?; + + let revert_modpack_meta = |e| -> ! { + let revert_result = old_modpack_meta.save_current_dir_project(); + if let Err(result) = revert_result { + panic!("Failed to revert modpack meta: {}", result); + } + panic!("Reverted modpack meta:\n{}", e); + }; + + match resolver::PinnedPackMeta::load_from_current_directory(true).await { + Ok(mut modpack_lock) => { + let remove_result = modpack_lock.remove_mod(&name, &modpack_meta, true); + if let Err(e) = remove_result { + revert_modpack_meta(e); + } + + if let Err(e) = modpack_lock.save_current_dir_lock() { + revert_modpack_meta(e); + } + } + Err(e) => { + revert_modpack_meta(e); + } + }; + } Commands::Download { mods_dir, side } => { let pack_lock = resolver::PinnedPackMeta::load_from_current_directory(true).await?; pack_lock.download_mods(&mods_dir, side).await?; diff --git a/src/modpack.rs b/src/modpack.rs index 92d9fa6..223ae8f 100644 --- a/src/modpack.rs +++ b/src/modpack.rs @@ -1,6 +1,10 @@ -use std::{collections::HashMap, error::Error, path::PathBuf}; -use serde::{Deserialize, Serialize}; use crate::mod_meta::{ModMeta, ModProvider}; +use serde::{Deserialize, Serialize}; +use std::{ + collections::{HashMap, HashSet}, + error::Error, + path::PathBuf, +}; const MODPACK_FILENAME: &str = "modpack.toml"; @@ -39,6 +43,7 @@ pub struct ModpackMeta { pub modloader: ModLoader, pub mods: HashMap, pub default_providers: Vec, + pub forbidden_mods: HashSet, } impl ModpackMeta { @@ -51,7 +56,7 @@ impl ModpackMeta { } } - pub fn iter_mods(&self) -> std::collections::hash_map::Values { + pub fn iter_mods(&self) -> std::collections::hash_map::Values { self.mods.values().into_iter() } @@ -79,18 +84,19 @@ impl ModpackMeta { self } - pub fn add_mod(mut self, mod_meta: &ModMeta) -> Self { - // if let Some(old_mod_meta) = self.mods.get(&mod_meta.name) { - // println!("Updating {} version constraints: {} -> {}", mod_meta.name, old_mod_meta.version, mod_meta.version); - // } - // else { - // println!( - // "Adding {}@{} to modpack '{}'...", - // mod_meta.name, mod_meta.version, self.pack_name - // ); - // } - self.mods.insert(mod_meta.name.to_string(), mod_meta.clone()); - self + pub fn add_mod(mut self, mod_meta: &ModMeta) -> Result> { + if self.forbidden_mods.contains(&mod_meta.name) { + return Err(format!("Cannot add forbidden mod {} to modpack", mod_meta.name).into()); + } else { + self.mods + .insert(mod_meta.name.to_string(), mod_meta.clone()); + } + Ok(self) + } + + pub fn forbid_mod(&mut self, mod_name: &str) { + self.forbidden_mods.insert(mod_name.into()); + println!("Mod {} has been forbidden from the modpack", mod_name); } pub fn remove_mod(mut self, mod_name: &str) -> Self { @@ -137,6 +143,7 @@ impl std::default::Default for ModpackMeta { modloader: ModLoader::Forge, mods: Default::default(), default_providers: vec![ModProvider::Modrinth], + forbidden_mods: Default::default(), } } } diff --git a/src/resolver.rs b/src/resolver.rs index 1d720ae..573f998 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -191,6 +191,11 @@ impl PinnedPackMeta { mod_metadata: &ModMeta, pack_metadata: &ModpackMeta, ) -> Result, Box> { + if pack_metadata.forbidden_mods.contains(&mod_metadata.name) { + println!("Skipping adding forbidden mod {}...", mod_metadata.name); + return Ok(vec![]); + } + let mod_providers = if let Some(mod_providers) = &mod_metadata.providers { mod_providers } else { @@ -262,7 +267,10 @@ impl PinnedPackMeta { force: bool, ) -> Result<(), Box> { if !self.mods.contains_key(mod_name) { - eprintln!("Skipping removing non-existent mod {} from modpack", mod_name); + eprintln!( + "Skipping removing non-existent mod {} from modpack", + mod_name + ); return Ok(()); } let dependent_mods = self.get_dependent_mods(mod_name);