From 4d7f6ed14ef726b494b9fefe0cfb37bf586f5d3d Mon Sep 17 00:00:00 2001 From: Warren Hood Date: Wed, 9 Oct 2024 00:42:50 +0200 Subject: [PATCH] Added WIP initial toml merging --- mcmpmgr/src/file_merge.rs | 120 +++++++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 2 deletions(-) diff --git a/mcmpmgr/src/file_merge.rs b/mcmpmgr/src/file_merge.rs index 03efaa9..2862e87 100644 --- a/mcmpmgr/src/file_merge.rs +++ b/mcmpmgr/src/file_merge.rs @@ -244,8 +244,119 @@ fn test_merge_yaml() { ); } +fn merge_toml( + src: &toml::Value, + dst: &mut toml::Value, + overwrite_existing: bool, +) -> anyhow::Result<()> { + if src.is_table() && dst.is_table() { + let src = src.as_table().unwrap(); + let dst = dst.as_table_mut().unwrap(); + + for (k, v) in src.iter() { + if v.is_table() { + let dst_v = dst.entry(k.clone()).or_insert(serde_yaml::from_str("{}")?); + merge_toml(v, dst_v, overwrite_existing)?; + } else { + if overwrite_existing || !dst.contains_key(k) { + dst.insert(k.clone(), v.clone()); + } + } + } + } else { + // TODO: Keep track of path for better errors + anyhow::bail!("Cannot merge non-objects: {src:#?} and {dst:#?}") + } + Ok(()) +} + +#[test] +fn test_merge_toml() { + let src: toml::Value = toml::from_str( + r#" + a = 3 + + [b] + [b.x] + + [b.y] + test = "thing" + + [c] + "#, + ) + .unwrap(); + + let mut dst: toml::Value = toml::from_str( + r#" + [b] + [b.y] + test = "something" + + [c] + foo = "bar" + "#, + ) + .unwrap(); + + let mut merged_overwrite = dst.clone(); + let mut merged_retained = dst.clone(); + merge_toml(&src, &mut merged_overwrite, true).unwrap(); + merge_toml(&src, &mut merged_retained, false).unwrap(); + + assert!( + merged_overwrite["b"]["y"]["test"] == "thing".into(), + "//b/y/test wasn't overwritten with \"thing\". src={:#?}, dst={:#?}", + src, + merged_overwrite + ); + assert!( + merged_overwrite["a"] == 3.into(), + "//a was not set to 3. src={:#?}, dst={:#?}", + src, + merged_overwrite + ); + assert!( + merged_overwrite["b"]["x"].is_table(), + "//b/x is not a mapping. src={:#?}, dst={:#?}", + src, + merged_overwrite + ); + assert!( + merged_overwrite["c"]["foo"] == "bar".into(), + "//c/foo != bar. src={:#?}, dst={:#?}", + src, + merged_overwrite + ); + + assert!( + merged_retained["b"]["y"]["test"] == "something".into(), + "//b/y/test was overwritten. src={:#?}, dst={:#?}", + src, + merged_retained + ); + assert!( + merged_retained["a"] == 3.into(), + "//a was not set to 3. src={:#?}, dst={:#?}", + src, + merged_retained + ); + assert!( + merged_retained["b"]["x"].is_table(), + "//b/x is not a mapping. src={:#?}, dst={:#?}", + src, + merged_retained + ); + assert!( + merged_retained["c"]["foo"] == "bar".into(), + "//c/foo != bar. src={:#?}, dst={:#?}", + src, + merged_retained + ); +} + /// Merge `src` into `dst` if it is a supported file type -fn merge_files( +pub fn merge_files( src: &str, dst: &str, overwrite_existing: bool, @@ -264,6 +375,11 @@ fn merge_files( merge_yaml(&src_val, &mut dst_val, overwrite_existing)?; serde_yaml::to_string(&dst_val)? } - FileType::Toml => todo!(), + FileType::Toml => { + let src_val: toml::Value = toml::from_str(src)?; + let mut dst_val: toml::Value = toml::from_str(dst)?; + merge_toml(&src_val, &mut dst_val, overwrite_existing)?; + dst_val.to_string() + } }) }