diff --git a/modda-lib/src/apply_patch.rs b/modda-lib/src/apply_patch.rs index 4788f72..bdc60c2 100644 --- a/modda-lib/src/apply_patch.rs +++ b/modda-lib/src/apply_patch.rs @@ -8,15 +8,17 @@ use patch::{Patch, Line}; use crate::args::Install; use crate::canon_path::CanonPath; +use crate::global::Global; use crate::lowercase::LwcString; use crate::patch_source::{PatchDesc, PatchEncoding, PatchSource}; -pub async fn patch_module(game_dir: &CanonPath, module_name: &LwcString, patch: &PatchDesc, opts: &Install) -> Result<()> { +pub async fn patch_module(game_dir: &CanonPath, module_name: &LwcString, patch: &PatchDesc, + opts: &Install, global: &Global) -> Result<()> { info!("mod {} needs patching", module_name); let patch_content = match &patch.patch_source { PatchSource::Http { http: _http } => { bail!("not implemented yet - patch from source {:?}", patch); } PatchSource::Relative { relative } => { - let diff = match read_patch_relative(relative, game_dir, opts, patch.encoding) { + let diff = match read_patch_relative(relative, game_dir, opts, global, patch.encoding) { Ok(diff) => diff, Err(error) => bail!("Error reading relative patch at {} for {}\n -> {:?}", relative, module_name, error), @@ -156,26 +158,33 @@ fn apply_patch<'a>(old_lines: &'a[String], diff: &'a Patch) -> Result Result { +fn read_patch_relative(relative: &str, game_dir: &CanonPath, opts: &Install, + global: &Global, encoding: PatchEncoding) -> Result { let relative_path = PathBuf::from(relative); if !relative_path.is_relative() { bail!("path is not relative: {:?}", relative); } - match PathBuf::from(&opts.manifest_path).parent() { - None => info!("Couldn't get manifest file parent - continue search with other locations"), - Some(parent) => { - let parent = match CanonPath::new(parent) { + let manifest_loc = match PathBuf::from(&opts.manifest_path).parent() { + Some(path) => match CanonPath::new(path) { Ok(parent) => parent, Err(error) => bail!("failed to canonalize manifest parent\n -> {:?}", error), - }; - if let Ok(diff) = read_patch_from(relative_path.as_path(), &parent, encoding) { - return Ok(diff); - } - } + }, + None => game_dir.to_owned(), + }; + let local_patches_loc = match &global.local_patches { + Some(path) => match manifest_loc.join(path) { + Err(err) => bail!("Could not canonicalize local patches path\n{err}"), + Ok(path) => path + }, + None => manifest_loc + }; + if !local_patches_loc.path().exists() { + bail!("Local patches path {local_patches_loc:?} doesn't exist"); } - match read_patch_from(&relative_path, game_dir, encoding) { + + match read_patch_from(relative_path.as_path(), &local_patches_loc, encoding) { Ok(diff) => Ok(diff), - Err(_error) => bail!("Couldn't find relative patch file {}", relative), + Err(error) => bail!("Couldn't find relative patch file {}\n{error}", relative), } } diff --git a/modda-lib/src/global.rs b/modda-lib/src/global.rs index 325b3b6..cae2e0e 100644 --- a/modda-lib/src/global.rs +++ b/modda-lib/src/global.rs @@ -18,7 +18,7 @@ pub struct Global { /// syntax here https://docs.rs/regex/1.5.4/regex/#syntax /// ex. `["#rx#^fran[cç]ais", french, english]` pub lang_preferences: Option>, - pub patch_path: Option, + pub local_patches: Option, /// Path from manifest root (yml file location directory) where "local" mods can be found. pub local_mods: Option, pub local_files: Option, diff --git a/modda-lib/src/module/manifest.rs b/modda-lib/src/module/manifest.rs index 57fc009..6961319 100644 --- a/modda-lib/src/module/manifest.rs +++ b/modda-lib/src/module/manifest.rs @@ -280,7 +280,7 @@ mod test_deserialize { global : super::Global { game_language: "fr_FR".to_string(), lang_preferences: Some(vec!["french".to_string()]), - patch_path: None, + local_patches: None, local_mods: None, local_files: None, }, @@ -302,7 +302,7 @@ mod test_deserialize { global : super::Global { game_language: "fr_FR".to_string(), lang_preferences: Some(vec!["french".to_string()]), - patch_path: None, + local_patches: None, local_mods: Some("mods".to_string()), local_files: None, }, @@ -379,7 +379,7 @@ mod test_deserialize { global : super::Global { game_language: "fr_FR".to_string(), lang_preferences: Some(vec!["french".to_string()]), - patch_path: None, + local_patches: None, local_mods: Some("mods".to_string()), local_files: None, }, @@ -451,7 +451,7 @@ mod test_deserialize { global : super::Global { game_language: "fr_FR".to_string(), lang_preferences: Some(vec!["french".to_string()]), - patch_path: None, + local_patches: None, local_mods: Some("mods".to_string()), local_files: None, }, @@ -481,7 +481,7 @@ mod test_deserialize { global : super::Global { game_language: "fr_FR".to_string(), lang_preferences: Some(vec!["french".to_string()]), - patch_path: None, + local_patches: None, local_mods: Some("mods".to_string()), local_files: None, }, @@ -505,7 +505,7 @@ mod test_deserialize { global : super::Global { game_language: "fr_FR".to_string(), lang_preferences: Some(vec!["french".to_string()]), - patch_path: None, + local_patches: None, local_mods: Some("mods".to_string()), local_files: None, }, diff --git a/modda-lib/src/obtain/get_module.rs b/modda-lib/src/obtain/get_module.rs index 7dca3a1..c375b9f 100644 --- a/modda-lib/src/obtain/get_module.rs +++ b/modda-lib/src/obtain/get_module.rs @@ -97,14 +97,14 @@ impl <'a> ModuleDownload<'a> { // modifications : patch then patches (in order) the replace if let Some(patch) = &location.patch { - patch_module(&dest, &mod_name , &patch, &self.opts).await?; + patch_module(&dest, &mod_name , &patch, &self.opts, &self.global).await?; info!("Single patch applied (`patch` property)") } if location.patches.is_empty() { info!("No `patches` property (or empty).") } else { for patch in &location.patches { - patch_module(&dest, &mod_name , &patch, &self.opts).await?; + patch_module(&dest, &mod_name , &patch, &self.opts,&self.global).await?; } info!("Patches applied (`patches` property)") }