Skip to content

Commit

Permalink
✨ Add support for multiple patches for one mod
Browse files Browse the repository at this point in the history
  • Loading branch information
mleduque committed Jul 8, 2024
1 parent 8b5cf6d commit 29b5436
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 19 deletions.
31 changes: 13 additions & 18 deletions modda-lib/src/apply_patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,21 @@ use crate::canon_path::CanonPath;
use crate::lowercase::LwcString;
use crate::patch_source::{PatchDesc, PatchEncoding, PatchSource};

pub async fn patch_module(game_dir: &CanonPath, module_name: &LwcString, patch_loc: &Option<PatchDesc>, opts: &Install) -> Result<()> {
match patch_loc {
None => Ok(()),
Some(patch) => {
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) {
Ok(diff) => diff,
Err(error) => bail!("Error reading relative patch at {} for {}\n -> {:?}",
relative, module_name, error),
};
Cow::Owned(diff)
}
PatchSource::Inline { inline } => Cow::Borrowed(inline),
pub async fn patch_module(game_dir: &CanonPath, module_name: &LwcString, patch: &PatchDesc, opts: &Install) -> 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) {
Ok(diff) => diff,
Err(error) => bail!("Error reading relative patch at {} for {}\n -> {:?}",
relative, module_name, error),
};
patch_module_with_content(game_dir, module_name, &*patch_content, patch.encoding)
Cow::Owned(diff)
}
}
PatchSource::Inline { inline } => Cow::Borrowed(inline),
};
patch_module_with_content(game_dir, module_name, &*patch_content, patch.encoding)
}

fn patch_module_with_content(game_dir: &CanonPath, module_name: &LwcString, patch: &str, encoding: PatchEncoding) -> Result<()> {
Expand Down
17 changes: 16 additions & 1 deletion modda-lib/src/get_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::path::PathBuf;

use anyhow::{bail, Result};
use chrono::Local;
use log::info;
use path_clean::PathClean;

use crate::apply_patch::patch_module;
Expand Down Expand Up @@ -90,10 +91,24 @@ impl <'a> ModuleDownload<'a> {
let dest = CanonPath::new(dest)?;
self.extractor.extract_files(&archive, &mod_name , location)?;
let copied = Some(Local::now());
patch_module(&dest, &mod_name , &location.patch, &self.opts).await?;

// modifications : patch then patches (in order) the replace
if let Some(patch) = &location.patch {
patch_module(&dest, &mod_name , &patch, &self.opts).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?;
}
info!("Patches applied (`patches` property)")
}
let patched = Some(Local::now());
replace_module(&dest, &mod_name , &location.replace)?;
let replaced = Some(Local::now());

Ok(SetupTimeline { start, downloaded, copied, patched, replaced, configured: None })
}

Expand Down
2 changes: 2 additions & 0 deletions modda-lib/src/module/location/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub struct ConcreteLocation {
#[serde(default)]
pub layout: Layout,
pub patch: Option<PatchDesc>,
#[serde(default)]
pub patches: Vec<PatchDesc>,
/// regex-based search and replace, runs after patch.
pub replace: Option<Vec<ReplaceSpec>>,
pub precopy: Option<PrecopyCommand>,
Expand Down
87 changes: 87 additions & 0 deletions modda-lib/src/module/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,93 @@ mod test_deserialize {
);
}

#[test]
fn deserialize_mod_with_relative_file_patch() {
let yaml = r#"
name: DlcMerger
location:
http: https://module.location
patch:
relative: patches/my_patch.diff
components:
- 1
"#;
let module: WeiduMod = serde_yaml::from_str(yaml).unwrap();
assert_eq!(
module,
WeiduMod {
name: lwc!("DlcMerger"),
components: Components::List(vec! [ Component::Simple(1) ]),
location: Some(Location::Concrete {
concrete: ConcreteLocation {
source: Source::Http(Http {
http: "https://module.location".to_owned(),
rename: None,
..Default::default()
}),
layout: Layout::default(),
patch: Some(PatchDesc {
patch_source: PatchSource::Relative {
relative: "patches/my_patch.diff".to_owned(),
},
encoding: PatchEncoding::UTF8,
}),
..ConcreteLocation::default()
}
}),
..WeiduMod::default()
}
);
}

#[test]
fn deserialize_mod_with_relative_file_patch_list() {
let yaml = r#"
name: DlcMerger
location:
http: https://module.location
patches:
- relative: patches/my_patch1.diff
- relative: patches/my_patch2.diff
components:
- 1
"#;
let module: WeiduMod = serde_yaml::from_str(yaml).unwrap();
assert_eq!(
module,
WeiduMod {
name: lwc!("DlcMerger"),
components: Components::List(vec! [ Component::Simple(1) ]),
location: Some(Location::Concrete {
concrete: ConcreteLocation {
source: Source::Http(Http {
http: "https://module.location".to_owned(),
rename: None,
..Default::default()
}),
layout: Layout::default(),
patches: vec![
PatchDesc {
patch_source: PatchSource::Relative {
relative: "patches/my_patch1.diff".to_owned(),
},
encoding: PatchEncoding::UTF8,
},
PatchDesc {
patch_source: PatchSource::Relative {
relative: "patches/my_patch2.diff".to_owned(),
},
encoding: PatchEncoding::UTF8,
},
],
..ConcreteLocation::default()
}
}),
..WeiduMod::default()
}
);
}

#[test]
fn deserialize_mod_with_inline_patch() {
let yaml = include_str!("../../resources/test/read_inline_patch/module_with_inline_patch.yaml");
Expand Down

0 comments on commit 29b5436

Please sign in to comment.