Added a remove command

This commit is contained in:
Warren Hood 2024-08-18 00:38:40 +02:00
parent 72407055ca
commit 6a18ac39bb
3 changed files with 105 additions and 3 deletions

View file

@ -60,6 +60,11 @@ enum Commands {
#[arg(long)]
url: Option<String>,
},
/// Remove a mod from the modpack
Remove {
/// Name of the mod to remove from the modpack
name: String,
},
}
#[tokio::main(flavor = "multi_thread")]
@ -152,7 +157,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
match resolver::PinnedPackMeta::load_from_current_directory().await {
Ok(mut modpack_lock) => {
let pin_result = modpack_lock.pin_mod_and_deps(&mod_meta, &modpack_meta).await;
let pin_result = modpack_lock
.pin_mod_and_deps(&mod_meta, &modpack_meta)
.await;
if let Err(e) = pin_result {
revert_modpack_meta(e);
}
@ -166,6 +173,37 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
};
}
Commands::Remove { name } => {
let mut modpack_meta = ModpackMeta::load_from_current_directory()?;
let old_modpack_meta = modpack_meta.clone();
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().await {
Ok(mut modpack_lock) => {
let remove_result = modpack_lock.remove_mod(&name, &modpack_meta);
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);
}
};
}
}
};

View file

@ -37,7 +37,7 @@ pub struct ModpackMeta {
pack_name: String,
pub mc_version: String,
pub modloader: ModLoader,
mods: HashMap<String, ModMeta>,
pub mods: HashMap<String, ModMeta>,
pub default_providers: Vec<ModProvider>,
}
@ -93,6 +93,11 @@ impl ModpackMeta {
self
}
pub fn remove_mod(mut self, mod_name: &str) -> Self {
self.mods.remove(mod_name);
self
}
pub fn init_project(&self, directory: &PathBuf) -> Result<(), Box<dyn Error>> {
let modpack_meta_file_path = directory.clone().join(PathBuf::from(MODPACK_FILENAME));
if modpack_meta_file_path.exists() {

View file

@ -124,6 +124,65 @@ impl PinnedPackMeta {
.into())
}
fn get_dependent_mods(&self, mod_name: &str) -> HashSet<String> {
let mut dependent_mods = HashSet::new();
for (pinned_mod_name, pinned_mod) in self.mods.iter() {
if let Some(deps) = &pinned_mod.deps {
for dep in deps.iter() {
if dep.name == mod_name {
dependent_mods.insert(pinned_mod_name.clone());
}
}
}
}
dependent_mods
}
pub fn remove_mod(
&mut self,
mod_name: &str,
pack_metadata: &ModpackMeta,
) -> Result<(), Box<dyn Error>> {
let dependent_mods = self.get_dependent_mods(mod_name);
if dependent_mods.len() > 0 {
return Err(format!(
"Cannot remove mod {}.The following mods depend on it:\n{:#?}",
mod_name, dependent_mods
)
.into());
}
let removed_mod = self.mods.remove(mod_name);
if let Some(removed_mod) = removed_mod {
println!("Removed mod {}@{}", mod_name, removed_mod.version);
}
self.prune_mods(pack_metadata)?;
Ok(())
}
/// Remove all mods from lockfile that aren't in the pack metadata or depended on by another mod
fn prune_mods(&mut self, pack_metadata: &ModpackMeta) -> Result<(), Box<dyn Error>> {
let mods_to_remove: HashSet<String> = self
.mods
.keys()
.filter(|mod_name| {
!pack_metadata.mods.contains_key(*mod_name)
&& self.get_dependent_mods(mod_name).len() == 0
})
.map(|mod_name| mod_name.into())
.collect();
for mod_name in mods_to_remove {
let removed_mod = self.mods.remove(&mod_name);
if let Some(removed_mod) = removed_mod {
println!("Pruned mod {}@{}", mod_name, removed_mod.version);
}
}
Ok(())
}
pub async fn init(&mut self, modpack_meta: &ModpackMeta) -> Result<(), Box<dyn Error>> {
for mod_meta in modpack_meta.iter_mods() {
self.pin_mod_and_deps(mod_meta, modpack_meta).await?;