use std::sync::{Arc, LazyLock, OnceLock};
use super::loader::ConfigFileLoader;
static CUSTOM_CONFIG_PATH: OnceLock<Option<String>> = OnceLock::new();
fn get_custom_config_path() -> Option<&'static str> {
CUSTOM_CONFIG_PATH
.get_or_init(|| {
if let Some(cli) = crate::cli::CLI.get()
&& let Some(config_path) = &cli.config
{
tracing::debug!("📁 Using custom config from CLI: {}", config_path);
return Some(config_path.clone());
}
if let Ok(config_path) = std::env::var("GUARDY_CONFIG") {
tracing::debug!("📁 Using custom config from GUARDY_CONFIG: {}", config_path);
return Some(config_path);
}
tracing::debug!("📁 No custom config specified, using discovery");
None
})
.as_deref()
}
fn should_use_recursive_config() -> bool {
if let Some(cli) = crate::cli::CLI.get()
&& let Some(recursive) = cli.recursive_config
{
tracing::debug!(
"📁 Recursive config set via CLI: --recursive-config={}",
recursive
);
return recursive;
}
if let Ok(value) = std::env::var("GUARDY_RECURSIVE_CONFIG") {
match value.as_str() {
"1" | "true" | "TRUE" | "yes" | "YES" | "on" | "ON" => {
tracing::debug!(
"📁 Recursive config enabled via GUARDY_RECURSIVE_CONFIG={}",
value
);
return true;
}
"0" | "false" | "FALSE" | "no" | "NO" | "off" | "OFF" => {
tracing::debug!(
"📁 Recursive config disabled via GUARDY_RECURSIVE_CONFIG={}",
value
);
return false;
}
_ => tracing::warn!(
"Invalid GUARDY_RECURSIVE_CONFIG value: {}, defaulting to true",
value
),
}
}
true
}
pub static MERGED_FILE_CONFIG: LazyLock<Arc<serde_json::Value>> = LazyLock::new(|| {
let start = std::time::Instant::now();
let config = Arc::new(load_merged_file_config());
let duration = start.elapsed();
tracing::debug!("⚡ File config cached in {:?}", duration);
config
});
fn load_merged_file_config() -> serde_json::Value {
let start = std::time::Instant::now();
let custom_config_path = get_custom_config_path();
let loader = ConfigFileLoader::new("guardy");
let result = if let Some(config_path) = custom_config_path {
let path = std::path::Path::new(&config_path);
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
if let Some(format) = super::loader::ConfigFileFormat::from_extension(ext) {
match loader.load_config_file::<serde_json::Value>(path, format) {
Ok(config) => {
tracing::debug!("✅ Custom config file loaded: {}", path.display());
config
}
Err(e) => {
tracing::warn!("⚠️ Failed to load custom config: {}", e);
serde_json::Value::Object(serde_json::Map::new())
}
}
} else {
tracing::warn!("⚠️ Unsupported config file format: {}", ext);
serde_json::Value::Object(serde_json::Map::new())
}
} else {
tracing::warn!("⚠️ Config file has no extension: {}", config_path);
serde_json::Value::Object(serde_json::Map::new())
}
} else {
let use_recursive = should_use_recursive_config();
if use_recursive {
match loader.discover_and_load_merged::<serde_json::Value>() {
Ok(Some(config)) => {
tracing::debug!("✅ File configuration discovered and merged (recursive mode)");
config
}
Ok(None) => {
tracing::debug!("📄 No config files found (recursive mode)");
serde_json::Value::Object(serde_json::Map::new())
}
Err(e) => {
tracing::warn!("⚠️ Failed to load file configuration: {}", e);
serde_json::Value::Object(serde_json::Map::new())
}
}
} else {
tracing::debug!("📄 Recursive config disabled - using defaults only");
serde_json::Value::Object(serde_json::Map::new())
}
};
let duration = start.elapsed();
tracing::debug!("⚡ File config loading completed in {:?}", duration);
result
}