use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GlobalConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub default_project_root: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_harness: Option<String>,
}
pub fn global_config_path_for(home_dir: Option<&std::path::Path>) -> std::path::PathBuf {
let home = match home_dir {
Some(p) => p.to_path_buf(),
None => std::path::PathBuf::from(std::env::var("HOME").unwrap_or_else(|_| ".".to_string())),
};
home.join(".config").join("o7").join("config.toml")
}
pub fn global_config_path() -> std::path::PathBuf {
global_config_path_for(None)
}
pub fn load_global_config() -> Result<GlobalConfig, String> {
let path = global_config_path();
if !path.exists() {
return Ok(GlobalConfig::default());
}
let raw = std::fs::read_to_string(&path)
.map_err(|e| format!("Failed to read global config: {}", e))?;
toml::from_str(&raw).map_err(|e| format!("Invalid global config: {}", e))
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_load_missing_global_config_returns_default() {
let dir = TempDir::new().unwrap();
let path = global_config_path_for(Some(dir.path()));
assert!(!path.exists());
let cfg: GlobalConfig = if path.exists() {
let raw = std::fs::read_to_string(&path).unwrap();
toml::from_str(&raw).unwrap()
} else {
GlobalConfig::default()
};
assert!(cfg.default_project_root.is_none());
assert!(cfg.default_harness.is_none());
}
#[test]
fn test_load_existing_global_config() {
let dir = TempDir::new().unwrap();
let config_path = global_config_path_for(Some(dir.path()));
let config_dir = config_path.parent().unwrap();
std::fs::create_dir_all(config_dir).unwrap();
std::fs::write(
&config_path,
"default_harness = \"claude\"\ndefault_project_root = \"/tmp/proj\"\n",
)
.unwrap();
let raw = std::fs::read_to_string(&config_path).unwrap();
let cfg: GlobalConfig = toml::from_str(&raw).unwrap();
assert_eq!(cfg.default_harness.as_deref(), Some("claude"));
assert_eq!(cfg.default_project_root.as_deref(), Some("/tmp/proj"));
}
}