use std::path::{Path, PathBuf};
use tracing::{debug, info, warn};
use crate::error::{OrchestratorError, Result};
use super::defaults::PROJECT_CONFIG_FILE;
use super::jsonc;
use super::types::{OrchestratorConfig, ProposalSessionConfig, ServerConfig};
use super::get_global_config_paths;
impl OrchestratorConfig {
pub fn load_from_file(path: &Path) -> Result<Self> {
let content = std::fs::read_to_string(path).map_err(|e| {
OrchestratorError::ConfigLoad(format!("Failed to read config file {:?}: {}", path, e))
})?;
Self::parse_jsonc(&content).map_err(|err| match err {
OrchestratorError::ConfigParse(msg) => OrchestratorError::ConfigParse(format!(
"Failed to parse config file {:?}: {}",
path, msg
)),
other => other,
})
}
pub fn parse_jsonc(content: &str) -> Result<Self> {
jsonc::parse(content)
}
#[allow(dead_code)]
pub fn load_server_config_from_global() -> ServerConfig {
let (server_config, _, _) = Self::load_server_config_and_resolve_command_from_global();
server_config
}
pub fn load_server_config_and_resolve_command_from_global(
) -> (ServerConfig, Option<String>, ProposalSessionConfig) {
let mut merged = OrchestratorConfig::default();
for path in get_global_config_paths() {
if path.exists() {
match Self::load_from_file(&path) {
Ok(c) => merged.merge(c),
Err(err) => {
warn!(
path = ?path,
error = %err,
"Failed to load global server config candidate; skipping"
);
}
}
}
}
let resolve_command = merged.resolve_command.clone();
let proposal_session = merged.proposal_session.clone().unwrap_or_default();
(
merged.server.unwrap_or_default(),
resolve_command,
proposal_session,
)
}
pub fn load(custom_path: Option<&Path>) -> Result<Self> {
let mut config = Self::default();
for path in get_global_config_paths() {
if path.exists() {
debug!("Loading global config from: {:?}", path);
let loaded_config = Self::load_from_file(&path)?;
config.merge(loaded_config);
}
}
let project_config_path = PathBuf::from(PROJECT_CONFIG_FILE);
if project_config_path.exists() {
debug!("Loading project config from: {:?}", project_config_path);
let project_config = Self::load_from_file(&project_config_path)?;
config.merge(project_config);
}
if let Some(path) = custom_path {
debug!("Loading custom config from: {:?}", path);
let custom_config = Self::load_from_file(path)?;
config.merge(custom_config);
}
config.validate_required_commands()?;
info!("Configuration loaded and merged successfully");
Ok(config)
}
}