use serde::Deserialize;
use serde_yaml;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
pub fn load_config_from_file<T, P>(path: P) -> Option<T>
where
T: for<'de> Deserialize<'de>,
P: AsRef<Path> + std::fmt::Debug,
{
let path_buf: PathBuf = path.as_ref().to_path_buf();
let absolute_path = match path_buf.canonicalize() {
Ok(abs_path) => abs_path,
Err(e) => {
log::warn!(
"failed to convert path to absolute path: {:?}, error: {}",
path_buf,
e
);
return None;
}
};
log::debug!("trying to read config file from: {:?}", absolute_path);
let mut file = File::open(&absolute_path).ok()?;
let mut contents = String::new();
file.read_to_string(&mut contents).ok()?;
match serde_yaml::from_str(&contents) {
Ok(config) => Some(config),
Err(e) => {
log::error!(
"failed to deserialize config file: {:?}, error: {}",
absolute_path,
e
);
None
}
}
}
pub fn load_config<T>() -> Option<T>
where
T: for<'de> Deserialize<'de>,
{
let env_var = env::var("ENV").ok();
let candidates = match env_var.as_deref() {
Some(env) if !env.is_empty() => {
vec![
format!("config.{}.yml", env),
format!("config.{}.yaml", env),
]
}
_ => vec!["config.yml".to_string(), "config.yaml".to_string()],
};
for file_name in candidates {
if let Some(config) = load_config_from_file::<T, _>(&file_name) {
return Some(config);
}
}
None
}
pub fn load_named_config<T>(config_path: &Path) -> Option<T>
where
T: for<'de> Deserialize<'de>,
{
load_config_from_file(config_path)
}