#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/doc_assets/settings.svg"))]
use std::{
ffi::OsStr,
fs,
io::{self, Write},
};
use config::{Config, ConfigBuilder, builder::DefaultState};
use prosa_utils::config::observability::Observability;
use serde::Serialize;
pub use prosa_macros::settings;
pub trait Settings: Serialize {
fn get_prosa_name(&self) -> String;
fn set_prosa_name(&mut self, name: String);
fn get_observability(&self) -> &Observability;
fn write_config(&self, config_path: &str) -> io::Result<()> {
let mut f = std::fs::File::create(std::path::Path::new(config_path))?;
writeln!(f, "# ProSA default settings")?;
if config_path.ends_with(".toml") {
writeln!(
f,
"{}",
toml::to_string(&self)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
)
} else {
writeln!(
f,
"{}",
serde_yaml::to_string(&self)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
)
}
}
}
pub fn get_config_builder(path: &str) -> io::Result<ConfigBuilder<DefaultState>> {
let mut builder = Config::builder();
let mut path_attr = std::fs::metadata(path)?;
if path_attr.is_symlink() {
path_attr = std::fs::metadata(fs::read_link(path)?)?;
}
if path_attr.is_file() {
Ok(builder.add_source(config::File::with_name(path)))
} else if path_attr.is_dir() {
for entry in fs::read_dir(path)? {
let path_subdir = entry?.path();
if path_subdir.is_file()
&& path_subdir
.extension()
.and_then(OsStr::to_str)
.is_some_and(|ext| matches!(ext, "yml" | "yaml" | "toml"))
{
builder = builder.add_source(config::File::from(path_subdir));
}
}
Ok(builder)
} else {
Err(io::Error::new(
io::ErrorKind::Unsupported,
format!("Unrecognize filetype for path `{path}`"),
))
}
}
#[cfg(test)]
mod tests {
use super::*;
use prosa_macros::settings;
extern crate self as prosa;
#[test]
fn test_settings() {
#[settings]
#[derive(Debug, Serialize)]
struct TestSettings {
name_test: String,
name_test2: String,
}
#[settings]
impl Default for TestSettings {
fn default() -> Self {
let _test_settings = TestSettings {
name_test: "test".into(),
name_test2: "test2".into(),
};
TestSettings {
name_test: "test".into(),
name_test2: "test2".into(),
}
}
}
let test_settings = TestSettings::default();
assert_eq!("test", test_settings.name_test);
assert_eq!("test2", test_settings.name_test2);
}
}