use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::Value;
use std::error::Error;
use std::fs;
use std::path::PathBuf;
#[cfg(feature = "ddep")]
pub mod ddep;
pub mod email;
#[cfg(test)]
pub mod tests;
pub mod utils;
pub trait Config: Sized + Serialize + DeserializeOwned {
fn merge_configs(a: &mut Value, b: &Value) {
match (a, b) {
(Value::Object(a_obj), Value::Object(b_obj)) => {
for (k, v) in b_obj {
Self::merge_configs(a_obj.entry(k).or_insert(Value::Null), v);
}
}
(a, b) => {
*a = b.clone();
}
}
}
fn read(path: &str) -> Result<Self, Box<dyn Error>> {
let config_content = fs::read_to_string(path)?;
let config: Self = serde_yaml::from_str(&config_content)?;
Ok(config)
}
fn save(&self, path: &str) -> Result<(), Box<dyn Error>> {
let new_config_content = serde_yaml::to_string(self)?;
let new_config: Value = serde_yaml::from_str(&new_config_content)?;
let config_path = PathBuf::from(path);
if config_path.exists() {
let existing_config_content = fs::read_to_string(&config_path)?;
let mut existing_config: Value = serde_yaml::from_str(&existing_config_content)?;
Self::merge_configs(&mut existing_config, &new_config);
let merged_config_content = serde_yaml::to_string(&existing_config)?;
fs::write(config_path, merged_config_content)?;
} else {
if let Some(parent) = config_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(config_path, new_config_content)?;
}
Ok(())
}
}