openapi_nexus_config/
loader.rs1use std::error::Error;
4use std::fmt;
5use std::fs;
6use std::io;
7use std::path::{Path, PathBuf};
8
9use crate::config::ConfigFile;
10use toml;
11
12pub struct ConfigLoader;
14
15impl ConfigLoader {
16 pub fn discover_config_file() -> Option<PathBuf> {
24 let current_dir_file = Path::new("openapi-nexus-config.toml");
26 if current_dir_file.exists() {
27 return Some(current_dir_file.to_path_buf());
28 }
29
30 let hidden_file = Path::new(".openapi-nexus-config.toml");
32 if hidden_file.exists() {
33 return Some(hidden_file.to_path_buf());
34 }
35
36 if let Some(config_dir) = dirs::config_dir() {
39 let user_config = config_dir.join("openapi-nexus").join("config.toml");
40 if user_config.exists() {
41 return Some(user_config);
42 }
43 }
44
45 let system_config = Path::new("/etc/openapi-nexus/config.toml");
47 if system_config.exists() {
48 return Some(system_config.to_path_buf());
49 }
50
51 None
52 }
53
54 pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<ConfigFile, LoadError> {
56 let content = fs::read_to_string(path.as_ref()).map_err(|e| LoadError::FileRead {
57 path: path.as_ref().to_path_buf(),
58 source: e,
59 })?;
60
61 toml::from_str(&content).map_err(|e| LoadError::Parse {
62 path: path.as_ref().to_path_buf(),
63 source: e,
64 })
65 }
66
67 pub fn load_or_default() -> ConfigFile {
69 Self::discover_config_file()
70 .and_then(|path| Self::load_from_file(&path).ok())
71 .unwrap_or_default()
72 }
73}
74
75#[derive(Debug)]
77pub enum LoadError {
78 FileRead {
79 path: PathBuf,
80 source: io::Error,
81 },
82 Parse {
83 path: PathBuf,
84 source: toml::de::Error,
85 },
86}
87
88impl fmt::Display for LoadError {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 match self {
91 LoadError::FileRead { path, source } => {
92 write!(f, "Failed to read config file at {:?}: {}", path, source)
93 }
94 LoadError::Parse { path, source } => {
95 write!(f, "Failed to parse config file at {:?}: {}", path, source)
96 }
97 }
98 }
99}
100
101impl Error for LoadError {
102 fn source(&self) -> Option<&(dyn Error + 'static)> {
103 match self {
104 LoadError::FileRead { source, .. } => Some(source),
105 LoadError::Parse { source, .. } => Some(source),
106 }
107 }
108}