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