omni_dev/utils/
settings.rs1use std::collections::HashMap;
7use std::env;
8use std::fs;
9use std::path::{Path, PathBuf};
10
11use anyhow::{Context, Result};
12use serde::Deserialize;
13
14#[derive(Debug, Deserialize)]
16pub struct Settings {
17 #[serde(default)]
19 pub env: HashMap<String, String>,
20}
21
22impl Settings {
23 pub fn load() -> Result<Self> {
25 let settings_path = Self::get_settings_path()?;
26 Self::load_from_path(&settings_path)
27 }
28
29 pub fn load_from_path<P: AsRef<Path>>(path: P) -> Result<Self> {
31 let path = path.as_ref();
32
33 if !path.exists() {
35 return Ok(Settings {
36 env: HashMap::new(),
37 });
38 }
39
40 let content = fs::read_to_string(path)
42 .with_context(|| format!("Failed to read settings file: {}", path.display()))?;
43
44 serde_json::from_str::<Settings>(&content)
45 .with_context(|| format!("Failed to parse settings file: {}", path.display()))
46 }
47
48 pub fn get_settings_path() -> Result<PathBuf> {
50 let home_dir = dirs::home_dir().context("Failed to determine home directory")?;
51
52 Ok(home_dir.join(".omni-dev").join("settings.json"))
53 }
54
55 pub fn get_env_var(&self, key: &str) -> Option<String> {
57 match env::var(key) {
59 Ok(value) => Some(value),
60 Err(_) => {
61 self.env.get(key).cloned()
63 }
64 }
65 }
66}
67
68pub fn get_env_var(key: &str) -> Result<String> {
70 match env::var(key) {
72 Ok(value) => Ok(value),
73 Err(_) => {
74 match Settings::load() {
76 Ok(settings) => settings
77 .env
78 .get(key)
79 .cloned()
80 .ok_or_else(|| anyhow::anyhow!("Environment variable not found: {}", key)),
81 Err(err) => {
82 Err(anyhow::anyhow!("Environment variable not found: {}", key).context(err))
84 }
85 }
86 }
87 }
88}
89
90pub fn get_env_vars(keys: &[&str]) -> Result<String> {
92 for key in keys {
93 match get_env_var(key) {
94 Ok(value) => return Ok(value),
95 Err(_) => continue,
96 }
97 }
98
99 Err(anyhow::anyhow!(
100 "None of the environment variables found: {:?}",
101 keys
102 ))
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use std::fs;
109 use tempfile::TempDir;
110
111 #[test]
112 fn settings_load_from_path() {
113 let temp_dir = TempDir::new().unwrap();
115 let settings_path = temp_dir.path().join("settings.json");
116
117 let settings_json = r#"{
119 "env": {
120 "TEST_VAR": "test_value",
121 "CLAUDE_API_KEY": "test_api_key"
122 }
123 }"#;
124 fs::write(&settings_path, settings_json).unwrap();
125
126 let settings = Settings::load_from_path(&settings_path).unwrap();
128
129 assert_eq!(settings.env.get("TEST_VAR").unwrap(), "test_value");
131 assert_eq!(settings.env.get("CLAUDE_API_KEY").unwrap(), "test_api_key");
132 }
133
134 #[test]
135 fn settings_get_env_var() {
136 let temp_dir = TempDir::new().unwrap();
138 let settings_path = temp_dir.path().join("settings.json");
139
140 let settings_json = r#"{
142 "env": {
143 "TEST_VAR": "test_value",
144 "CLAUDE_API_KEY": "test_api_key"
145 }
146 }"#;
147 fs::write(&settings_path, settings_json).unwrap();
148
149 let settings = Settings::load_from_path(&settings_path).unwrap();
151
152 env::set_var("TEST_VAR_ENV", "env_value");
154
155 env::set_var("TEST_VAR", "env_override");
157 assert_eq!(settings.get_env_var("TEST_VAR").unwrap(), "env_override");
158
159 env::remove_var("TEST_VAR"); assert_eq!(settings.get_env_var("TEST_VAR").unwrap(), "test_value");
162
163 assert_eq!(settings.get_env_var("TEST_VAR_ENV").unwrap(), "env_value");
165
166 env::remove_var("TEST_VAR_ENV");
168 }
169}