diff --git a/src/cli/config_merge.rs b/src/cli/config_merge.rs index 37ed776d..fb080fd7 100644 --- a/src/cli/config_merge.rs +++ b/src/cli/config_merge.rs @@ -16,6 +16,7 @@ use std::borrow::Cow; use std::io; use std::path::{Path, PathBuf}; use std::sync::Arc; +use tracing::{debug, debug_span, trace, warn}; use crate::localization::{self, keys}; @@ -45,9 +46,11 @@ fn env_config_path(var_os: F, var_name: &str) -> Option where F: Fn(&str) -> Option, { - var_os(var_name) + let path = var_os(var_name) .filter(|value| !value.is_empty()) - .map(PathBuf::from) + .map(PathBuf::from); + trace!(var_name, found = path.is_some(), path = ?path, "read config path variable"); + path } #[expect( @@ -58,11 +61,21 @@ fn resolve_config_path(cli: &Cli, var_os: F) -> Option where F: Fn(&str) -> Option, { - cli.config - .as_ref() - .cloned() - .or_else(|| env_config_path(&var_os, CONFIG_ENV_VAR)) - .or_else(|| env_config_path(var_os, CONFIG_ENV_VAR_LEGACY)) + let (selector, resolved_path) = cli.config.as_ref().cloned().map_or_else( + || { + env_config_path(&var_os, CONFIG_ENV_VAR).map_or_else( + || { + env_config_path(var_os, CONFIG_ENV_VAR_LEGACY) + .map_or(("none", None), |path| (CONFIG_ENV_VAR_LEGACY, Some(path))) + }, + |path| (CONFIG_ENV_VAR, Some(path)), + ) + }, + |path| ("cli_flag", Some(path)), + ); + + debug!(selector, path = ?resolved_path, "resolved config path"); + resolved_path } fn load_layers_from_path(path: &Path) -> OrthoResult>> { @@ -72,14 +85,21 @@ fn load_layers_from_path(path: &Path) -> OrthoResult>> { .into_iter() .map(|(value, layer_path)| MergeLayer::file(Cow::Owned(value), Some(layer_path))) .collect()), - Ok(None) => Err(Arc::new(OrthoError::File { - path: path.to_path_buf(), - source: Box::new(io::Error::new( - io::ErrorKind::NotFound, - "explicit configuration file not found", - )), - })), - Err(err) => Err(err), + Ok(None) => { + let error = Arc::new(OrthoError::File { + path: path.to_path_buf(), + source: Box::new(io::Error::new( + io::ErrorKind::NotFound, + "explicit configuration file not found", + )), + }); + warn!(path = ?path, error = %error, "explicit config load failed"); + Err(error) + } + Err(error) => { + warn!(path = ?path, error = %error, "explicit config load failed"); + Err(error) + } } } @@ -148,10 +168,14 @@ fn diag_json_from_layer(value: &serde_json::Value) -> Option { /// load failures so startup diagnostic-mode selection reports the same /// configuration errors as the full merge path. fn collect_diag_file_layers(cli: &Cli) -> OrthoResult>> { + let _span = debug_span!("collect_diag_file_layers").entered(); + if let Some(path) = resolve_config_path(cli, |name| std::env::var_os(name)) { + debug!(path = ?path, "using explicit config path"); return load_layers_from_path(&path); } + debug!("using config discovery"); let discovery = config_discovery(cli.directory.as_deref()); let file_layers = discovery.compose_layers().value; let project_file = project_scope_file_str(cli.directory.as_deref()); @@ -160,8 +184,10 @@ fn collect_diag_file_layers(cli: &Cli) -> OrthoResult>> .is_some_and(|p| project_file.as_deref() == Some(p.as_str())) }); if first_pass_found_project { + debug!(project_file = ?project_file, "discovery included project-scope layers"); Ok(file_layers) } else { + debug!(project_file = ?project_file, "appending project-scope layers"); project_scope_layers(cli.directory.as_deref()) .map(|project_layers| file_layers.into_iter().chain(project_layers).collect()) } @@ -243,10 +269,12 @@ fn push_file_layers( cli: &Cli, ) { if let Some(path) = resolve_config_path(cli, |name| std::env::var_os(name)) { + debug!(path = ?path, "using explicit config path"); push_layers_result(composer, errors, load_layers_from_path(&path)); return; } + debug!("using config discovery"); let discovery = config_discovery(cli.directory.as_deref()); let mut file_layers = discovery.compose_layers(); errors.append(&mut file_layers.required_errors);