diff --git a/src/activator.rs b/src/activator.rs index c73b6e0..00e1a06 100644 --- a/src/activator.rs +++ b/src/activator.rs @@ -1,5 +1,5 @@ -use anyhow::Context; use log::{debug, trace}; +use thiserror::Error; use crate::types::{Game, Link, ModdedInstance, RootConfig}; use std::collections::HashMap; @@ -11,17 +11,22 @@ pub fn activate_instance( root_config: &RootConfig, instance: &ModdedInstance, target: impl AsRef, -) -> anyhow::Result<()> { - let game = root_config.game_by_id(instance.game_id()).unwrap(); +) -> Result<(), ActivationError> { + let game = root_config + .game_by_id(instance.game_id()) + .ok_or(ActivationError::GameNotFound)?; + + check_target_valid(&target)?; let resolved_links = resolve_links(root_config, instance, game)?; resolved_links .iter() .try_for_each(|link| apply_link(link, &target)) - .with_context(|| "Creating links")?; - create_plugins_txt(instance, target.as_ref()).with_context(|| "Creating Pluginx.txt")?; + .map_err(ActivationError::Linking)?; + create_plugins_txt(instance, target.as_ref()).map_err(ActivationError::PluginsTXT)?; + debug!("Finished activating instance"); Ok(()) } @@ -29,8 +34,10 @@ fn resolve_links( root_config: &RootConfig, instance: &ModdedInstance, game: &Game, -) -> anyhow::Result> { - let game_links = game.export_links()?; +) -> Result, ActivationError> { + let game_links = game + .export_links() + .map_err(ActivationError::ExportGameLinks)?; let mod_links = resolve_link_for_instance(root_config, instance)?; let overrides: Vec = instance.game_file_overrides().to_owned(); @@ -51,11 +58,15 @@ fn resolve_links( fn resolve_link_for_instance( root_config: &RootConfig, instance: &ModdedInstance, -) -> anyhow::Result> { +) -> Result, ActivationError> { + debug!("Resolving links for instance"); + let mut links: Vec = Vec::new(); for installed_mod in instance.mods() { - let mod_config = root_config.get_mod_by_id(installed_mod.mod_id()).unwrap(); + let mod_config = root_config + .get_mod_by_id(installed_mod.mod_id()) + .ok_or(ActivationError::ModNotFound)?; let mod_source_root = root_config.mod_location().join(mod_config.path()); for link in installed_mod.files() { @@ -78,8 +89,8 @@ fn create_plugins_txt( instance: &ModdedInstance, target: impl AsRef, ) -> Result<(), io::Error> { - debug!("Generating plugins.txt"); - let mut file = fs::File::create(target.as_ref().join("plugins.txt"))?; + debug!("Generating Plugins.txt"); + let mut file = fs::File::create(target.as_ref().join("Plugins.txt"))?; writeln!(file, "# Auto generated. DO NOT EDIT MANUALLY!")?; @@ -93,6 +104,7 @@ fn create_plugins_txt( fn link_file(target: &Path, link_name: &Path) -> Result<(), io::Error> { if let Some(parent) = link_name.parent() { fs::create_dir_all(parent)?; + trace!("Creating parent dir for {}", link_name.to_string_lossy()); } create_symlink_for_file(target, link_name)?; @@ -116,3 +128,44 @@ fn create_symlink_for_file(target: &Path, link_name: &Path) -> io::Result<()> { std::os::windows::fs::symlink_file(target, link_name) } } + +fn check_target_valid(target: impl AsRef) -> Result<(), ActivationError> { + match fs::read_dir(&target) { + Ok(entries) => { + if entries.count() == 0 { + debug!( + "Target {} is a valid target", + &target.as_ref().to_string_lossy() + ); + Ok(()) + } else { + Err(ActivationError::TargetNotEmpty) + } + } + Err(e) => Err(ActivationError::TargetNotValid(e)), + } +} + +#[derive(Debug, Error)] +pub enum ActivationError { + #[error("Could not find game in instance config")] + GameNotFound, + + #[error("Could not find mod in instance config")] + ModNotFound, + + #[error("The target is not empty")] + TargetNotEmpty, + + #[error("The target is not valid")] + TargetNotValid(io::Error), + + #[error("Failed to create symlink")] + Linking(io::Error), + + #[error("Failed to create Plugins.txt")] + PluginsTXT(io::Error), + + #[error("Failed to export files in game installation")] + ExportGameLinks(io::Error), +}