improved instance module

This commit is contained in:
2026-03-10 00:51:08 +01:00
parent 257ff66af8
commit d806b331db
2 changed files with 69 additions and 23 deletions

View File

@@ -5,7 +5,8 @@ use std::{
}; };
use globset::{Glob, GlobSet, GlobSetBuilder}; use globset::{Glob, GlobSet, GlobSetBuilder};
use log::{error, warn}; use log::warn;
use thiserror::Error;
use crate::{ use crate::{
file_conflict_solver::ConflictSolver, file_conflict_solver::ConflictSolver,
@@ -20,7 +21,7 @@ pub fn insert_mod_to_instance(
from_mod: &ModConfig, from_mod: &ModConfig,
files: &[ModFile], files: &[ModFile],
priority: isize, priority: isize,
) -> bool { ) -> Result<(), InststanceError> {
let mut solver = ConflictSolver::new(); let mut solver = ConflictSolver::new();
let mut installed_files: Vec<(ModFile, &InstalledMod)> = Vec::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 { for (file, from_mod) in &installed_files {
if let Some(conflict) = solver.add_file(file, from_mod) { 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); let new_mod = InstalledMod::new(from_mod.id(), priority);
for file in files { for file in files {
if let Some(conflict) = solver.add_file(file, &new_mod) { if let Some(conflict) = solver.add_file(file, &new_mod) {
error!( return Err(InststanceError::FileConflict {
"File conflict detected at: {} between {} and {}", lhs_mod_id: conflict.lhs_mod.mod_id().to_owned(),
conflict.rhs_file.dst().to_string_lossy(), rhs_mod_id: conflict.rhs_mod.mod_id().to_owned(),
conflict.lhs_mod.mod_id(), path: conflict.rhs_file.dst().to_owned(),
conflict.rhs_mod.mod_id() });
);
return false;
} }
} }
@@ -72,7 +70,7 @@ pub fn insert_mod_to_instance(
instance.update_or_create_mod(&installed_mod); instance.update_or_create_mod(&installed_mod);
} }
true Ok(())
} }
pub fn files_to_install_mod( pub fn files_to_install_mod(
@@ -123,13 +121,18 @@ fn install_fomod(
let module_config = fomod::Config::load_from_file(module_config_path)?; let module_config = fomod::Config::load_from_file(module_config_path)?;
// TODO: add active plugins from instance config // 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 let mod_files: Vec<_> = files
.iter() .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::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.collect(); .collect();
Ok(mod_files) Ok(mod_files)
} }
@@ -202,3 +205,19 @@ fn should_be_included(path: impl AsRef<Path>) -> 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),
}

View File

@@ -1,13 +1,13 @@
use anyhow::anyhow; use anyhow::anyhow;
use clap::Parser; use clap::Parser;
use log::debug; use log::{debug, error, info};
use std::{error::Error, path::Path}; use std::{error::Error, path::Path};
use crate::{ use crate::{
activator::activate_instance, activator::activate_instance,
cli::Args, cli::Args,
instance::{files_to_install_mod, insert_mod_to_instance}, instance::{files_to_install_mod, insert_mod_to_instance},
nexus::{NexusAPI,download_nxm}, nexus::{NexusAPI, download_nxm},
types::RootConfig, 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)?; let files = files_to_install_mod(root_config, &instance, mod_to_install)?;
if !insert_mod_to_instance(&mut instance, mod_to_install, &files, 0) { match insert_mod_to_instance(&mut instance, mod_to_install, &files, 0) {
return Err(anyhow!("File conflict")); 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<()> { fn command_order(root_config: &RootConfig, instance_id: &str) -> anyhow::Result<()> {