diff --git a/src/instance.rs b/src/instance.rs index d70a465..6fbf9f5 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -5,7 +5,8 @@ use std::{ }; use globset::{Glob, GlobSet, GlobSetBuilder}; -use log::{error, warn}; +use log::warn; +use thiserror::Error; use crate::{ file_conflict_solver::ConflictSolver, @@ -20,7 +21,7 @@ pub fn insert_mod_to_instance( from_mod: &ModConfig, files: &[ModFile], priority: isize, -) -> bool { +) -> Result<(), InststanceError> { let mut solver = ConflictSolver::new(); let mut installed_files: Vec<(ModFile, &InstalledMod)> = Vec::new(); @@ -33,21 +34,18 @@ pub fn insert_mod_to_instance( for (file, from_mod) in &installed_files { if let Some(conflict) = solver.add_file(file, from_mod) { - warn!("Got file conflict on already added file: {:?}", conflict); + warn!("File conflict on already added file: {:?}", conflict); } } let new_mod = InstalledMod::new(from_mod.id(), priority); for file in files { if let Some(conflict) = solver.add_file(file, &new_mod) { - error!( - "File conflict detected at: {} between {} and {}", - conflict.rhs_file.dst().to_string_lossy(), - conflict.lhs_mod.mod_id(), - conflict.rhs_mod.mod_id() - ); - - return false; + return Err(InststanceError::FileConflict { + lhs_mod_id: conflict.lhs_mod.mod_id().to_owned(), + rhs_mod_id: conflict.rhs_mod.mod_id().to_owned(), + path: conflict.rhs_file.dst().to_owned(), + }); } } @@ -72,7 +70,7 @@ pub fn insert_mod_to_instance( instance.update_or_create_mod(&installed_mod); } - true + Ok(()) } pub fn files_to_install_mod( @@ -123,13 +121,18 @@ fn install_fomod( let module_config = fomod::Config::load_from_file(module_config_path)?; // TODO: add active plugins from instance config - let files = run_fomod_installer(module_config, &[], install_prompt::prompt)?; + let files = run_fomod_installer(module_config, &[], install_prompt::prompt) + .map_err(|_| InststanceError::FomodRunInstaller)?; let mod_files: Vec<_> = files .iter() - .flat_map(|f| ModFile::from_installer(f.clone(), &mod_root).unwrap()) + .map(|f| { + ModFile::from_installer(f.clone(), &mod_root).map_err(InststanceError::FomodFinalize) + }) + .collect::, _>>()? + .into_iter() + .flatten() .collect(); - Ok(mod_files) } @@ -202,3 +205,19 @@ fn should_be_included(path: impl AsRef) -> bool { ) ) } + +#[derive(Debug, Error)] +pub enum InststanceError { + #[error("Two mods write the same file")] + FileConflict { + lhs_mod_id: String, + rhs_mod_id: String, + path: PathBuf, + }, + + #[error("Failed to run fomod installer")] + FomodRunInstaller, + + #[error("Failed to handle results of fomod installer")] + FomodFinalize(io::Error), +} diff --git a/src/main.rs b/src/main.rs index 0274482..9b6481f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,13 @@ use anyhow::anyhow; use clap::Parser; -use log::debug; +use log::{debug, error, info}; use std::{error::Error, path::Path}; use crate::{ activator::activate_instance, cli::Args, instance::{files_to_install_mod, insert_mod_to_instance}, - nexus::{NexusAPI,download_nxm}, + nexus::{NexusAPI, download_nxm}, types::RootConfig, }; @@ -41,13 +41,40 @@ fn command_add(root_config: &RootConfig, instance_id: &str, mod_id: &str) -> any let files = files_to_install_mod(root_config, &instance, mod_to_install)?; - if !insert_mod_to_instance(&mut instance, mod_to_install, &files, 0) { - return Err(anyhow!("File conflict")); + match insert_mod_to_instance(&mut instance, mod_to_install, &files, 0) { + Ok(_) => { + instance.save_to_file()?; + Ok(()) + } + Err(err) => { + match &err { + instance::InststanceError::FileConflict { + lhs_mod_id, + rhs_mod_id, + path, + } => { + error!( + "File conflict between {} and {} at {}", + lhs_mod_id, + rhs_mod_id, + path.to_string_lossy() + ); + info!("To resolve file conflicts give one mod a higher priority in the config"); + } + instance::InststanceError::FomodRunInstaller => { + error!("Failed to run FOMod installer"); + } + instance::InststanceError::FomodFinalize(error) => { + error!( + "FOMod installer finished but failed to finalize result: {}", + error + ); + } + }; + + Err(err.into()) + } } - - instance.save_to_file()?; - - Ok(()) } fn command_order(root_config: &RootConfig, instance_id: &str) -> anyhow::Result<()> {