use std::io; use std::path::Path; pub mod env; pub mod hierarchical; #[derive(Debug, Clone, PartialEq, Eq)] pub enum ItemStatus { Present, MissingFromActive, MissingFromTemplate, Modified, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ValueType { String, Number, Bool, Null, } #[derive(Debug, Clone)] pub struct ConfigItem { pub key: String, pub path: String, pub value: Option, pub template_value: Option, pub default_value: Option, pub depth: usize, pub is_group: bool, pub status: ItemStatus, pub value_type: ValueType, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FormatType { Env, Json, Yaml, Toml, } pub trait FormatHandler { fn parse(&self, path: &Path) -> io::Result>; fn merge(&self, path: &Path, vars: &mut Vec) -> io::Result<()>; fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()>; } pub fn detect_format(path: &Path, override_format: Option) -> FormatType { if let Some(fmt) = override_format { match fmt.to_lowercase().as_str() { "env" => return FormatType::Env, "json" => return FormatType::Json, "yaml" | "yml" => return FormatType::Yaml, "toml" => return FormatType::Toml, _ => {} } } let file_name = path.file_name().unwrap_or_default().to_string_lossy(); if file_name.ends_with(".json") { FormatType::Json } else if file_name.ends_with(".yaml") || file_name.ends_with(".yml") { FormatType::Yaml } else if file_name.ends_with(".toml") { FormatType::Toml } else { FormatType::Env } } pub fn get_handler(format: FormatType) -> Box { match format { FormatType::Env => Box::new(env::EnvHandler), FormatType::Json => Box::new(hierarchical::HierarchicalHandler::new(FormatType::Json)), FormatType::Yaml => Box::new(hierarchical::HierarchicalHandler::new(FormatType::Yaml)), FormatType::Toml => Box::new(hierarchical::HierarchicalHandler::new(FormatType::Toml)), } }