diff --git a/paxy/src/app/config.rs b/paxy/src/app/config.rs index 640da68..1db8c3b 100644 --- a/paxy/src/app/config.rs +++ b/paxy/src/app/config.rs @@ -7,7 +7,7 @@ lazy_static! { /// local paths. overridden by environment variables starting with `PAXY_`, /// overridden by the configuration file specified by the commandline. /// Values from only files with supported file extensions would be merged. -pub fn init_config(cli_global_arguments: G) -> Result<(ConfigTemplate, Vec), Error> +pub fn init_config(console_global_arguments: &G) -> Result<(ConfigTemplate, Vec), Error> where G: ui::GlobalArguments, { @@ -45,42 +45,25 @@ where let mut config = Config::new(); // Merge configuration values from global and local filepaths - config.with_overriding_files(candidate_config_filepaths); + config = config.with_overriding_files(&candidate_config_filepaths); // Merge configuration values from environment variables - config.with_overriding_env(&format!("{}_", *app::APP_NAME)); + config = config.with_overriding_env(&format!("{}_", *app::APP_NAME)); // Merge configuration values from the CLI - config.with_overriding_args(cli_global_arguments); + config = config.with_overriding_args(console_global_arguments); Ok(( config - .object() - .context(ExtractConfigSnafu {})?, + .object()?, candidate_config_filepaths, )) } -fn admerge_from_stub(candidate_config_filepath_stub: &PathBuf, mut figment: Figment) -> Figment { - figment = figment.admerge(Toml::file( - candidate_config_filepath_stub.with_extension("toml"), - )); - figment = figment.admerge(Json::file( - candidate_config_filepath_stub.with_extension("json"), - )); - figment = figment.admerge(Yaml::file( - candidate_config_filepath_stub.with_extension("yml"), - )); - figment = figment.admerge(Yaml::file( - candidate_config_filepath_stub.with_extension("yaml"), - )); - figment -} - #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigTemplate { pub config_filepaths: Vec, - pub log_filepath_stub: PathBuf, + pub log_dirpath: PathBuf, pub console_output_format: ui::ConsoleOutputFormat, } @@ -88,7 +71,7 @@ impl Default for ConfigTemplate { fn default() -> Self { Self { config_filepaths: Vec::new(), - log_filepath_stub: PathBuf::default(), + log_dirpath: PathBuf::default(), console_output_format: ui::ConsoleOutputFormat::default(), } } @@ -101,11 +84,11 @@ pub struct Config { impl Config { pub fn new() -> Self { Self { - figment: Figment::from(ConfigTemplate::default()), + figment: Figment::new(), } } - pub fn with_overriding_file>(&mut self, filepath: P) -> &mut Self { + pub fn with_overriding_file>(mut self, filepath: P) -> Self { let filepath: &Path = filepath.as_ref(); if let Some(file_extension) = filepath.extension() { file_extension = file_extension @@ -133,60 +116,56 @@ impl Config { self } - pub fn with_overriding_files(&mut self, filepaths: I) -> &mut Self + pub fn with_overriding_files(self, filepaths: I) -> Self where P: AsRef, - I: Iterator, + I: IntoIterator, { - filepaths.for_each(|filepath| self.with_overriding_file(filepath)); - - self + filepaths.into_iter().fold(self, |config, filepath| config.with_overriding_file(filepath)) } pub fn with_overriding_filepath_stubs( - &mut self, + mut self, file_extensions: I1, filepath_stubs: I2, - ) -> &mut Self + ) -> Self where I1: IntoIterator, S: AsRef, I2: IntoIterator, P: Into, { - let filepath_stubs: Iterator = filepath_stubs + let filepath_stubs = filepath_stubs .into_iter() .map(Into::into); file_extensions .into_iter() - .map(AsRef::as_ref) - .cartesian_product(filepath_stubs) + .map(|file_extension| file_extension.as_ref()) + .cartesian_product(&filepath_stubs) .map(|(file_extension, filepath_stub)| { let filepath = filepath_stub; filepath.set_extension(file_extension); - self.with_overriding_file(filepath); + self = self.with_overriding_file(filepath); }); self } pub fn with_overriding_filepath_stub( - &mut self, + self, file_extensions: I, filepath_stub: P, - ) -> &mut Self + ) -> Self where I: IntoIterator, S: AsRef, P: Into, { - self.with_overriding_filepath_stubs(file_extensions, iter::once(filepath_stub)); - - self + self.with_overriding_filepath_stubs(file_extensions, iter::once(filepath_stub)) } - pub fn with_overriding_env>(&mut self, prefix: S) -> &mut Self { + pub fn with_overriding_env>(mut self, prefix: S) -> Self { let prefix = prefix.as_ref(); self.figment = self .figment @@ -198,14 +177,10 @@ impl Config { /// Merge configuration values from the CLI /// These are not set to be optional, so only action-required states are /// merged with the configuration - pub fn with_overriding_args( - &mut self, - console_arguments: A, - ) -> &mut Self { + pub fn with_overriding_args(mut self, console_arguments: A) -> Self { // Incorporate the extra config file specified through arguments if let Some(path) = console_arguments.config_filepath() { - self.figment = self - .figment + self.figment = self.figment .admerge(("config_filepaths", path)); } @@ -213,8 +188,7 @@ impl Config { // non-regular output mode is explicitly specified let console_output_mode = console_arguments.console_output_mode(); if console_output_mode != ConsoleOutputMode::Regular { - self.figment = self - .figment + self.figment = self.figment .admerge(("console_output_format.mode", console_output_mode)); } @@ -226,8 +200,7 @@ impl Config { let requested_max_verbosity = console_arguments.max_output_verbosity(); if let Ok(current_max_verbosity) = current_max_verbosity { if requested_max_verbosity > current_max_verbosity { - self.figment = self - .figment + self.figment = self.figment .admerge(( "console_output_format.max_verbosity", requested_max_verbosity, @@ -250,10 +223,9 @@ impl Config { String::from(*app::APP_NAME).to_uppercase() )) .is_ok() - || env::var("TERM").is_ok_and(|env_term_value| env_term_value.to_lowercase == "dumb"); + || env::var("TERM").is_ok_and(|env_term_value| env_term_value.to_lowercase() == "dumb"); if (requested_no_color || env_no_color) && !current_no_color.unwrap_or(false) { - self.figment = self - .figment + self.figment = self.figment .admerge(("console_output_format.no_color", true)); } @@ -261,7 +233,7 @@ impl Config { } pub fn object(&self) -> Result { - let mut config_object = self + let mut config_object: ConfigTemplate = self .figment .extract() .context(ExtractConfigSnafu {})?; @@ -291,7 +263,7 @@ use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use snafu::{OptionExt, ResultExt, Snafu}; -use super::ui::{ConsoleOutputMode, GlobalArguments}; +use super::ui::ConsoleOutputMode; use crate::app; use crate::app::ui; diff --git a/paxy/src/app/logging.rs b/paxy/src/app/logging.rs index d8d14e2..e6a1a2d 100644 --- a/paxy/src/app/logging.rs +++ b/paxy/src/app/logging.rs @@ -1,6 +1,6 @@ pub fn init_log(config: &config::ConfigTemplate) -> Result<(Handle, PathBuf), Error> { let log_filename = format!("{}.log", *app::APP_NAME); - let log_dirpath = obtain_log_dirpath(config.log_dirpath)?; + let log_dirpath = obtain_log_dirpath(config.log_dirpath.clone())?; let log_file_appender = tracing_appender::rolling::daily(log_dirpath.clone(), log_filename.clone()); let log_level_filter = tracing_level_filter_from_log_level_filter( @@ -156,7 +156,7 @@ pub fn init_log(config: &config::ConfigTemplate) -> Result<(Handle, PathBuf), Er )) } -fn obtain_log_dirpath(preferred_log_dirpath: Option) -> Result { +fn obtain_log_dirpath(preferred_log_dirpath: PathBuf) -> Result { let obtain_fallback_log_dirpath = || { let xdg_app_dirs = directories::BaseDirs::new().context(RetreiveLoggingUserAppBaseDirectoriesSnafu {})?; @@ -173,20 +173,16 @@ fn obtain_log_dirpath(preferred_log_dirpath: Option) -> Result { - if !fs::metadata(&preferred_log_dirpath) - .map(|m| m.permissions()) - .map(|p| p.readonly()) - .unwrap_or(true) - { - preferred_log_dirpath - } else { - obtain_fallback_log_dirpath()? - } - } - None => obtain_fallback_log_dirpath()?, - }) + + if !fs::metadata(&preferred_log_dirpath) + .map(|m| m.permissions()) + .map(|p| p.readonly()) + .unwrap_or(true) + { + Ok(preferred_log_dirpath) + } else { + Ok(obtain_fallback_log_dirpath()?) + } } fn tracing_level_filter_from_log_level_filter(level_filter: log::LevelFilter) -> LevelFilter { diff --git a/paxy/src/app/ui.rs b/paxy/src/app/ui.rs index 7ed0c30..b4ddd29 100644 --- a/paxy/src/app/ui.rs +++ b/paxy/src/app/ui.rs @@ -17,7 +17,7 @@ where .context(crate::AppSnafu {})?; // Adjust output formatting if requested - adjust_output_formatting(&config.console_output_format, &logging_handle); + adjust_output_formatting(&config.console_output_format, &mut logging_handle); emit_welcome_messages(); @@ -48,8 +48,7 @@ fn emit_diagnostic_messages( log_filepath: PathBuf, console_input: &C, ) where - C: clap::Parser + CliModifier + fmt::Debug, - ::L: LogLevel, + C: clap::Parser + fmt::Debug, { tracing::debug!( "{} The {} is {}... {}", @@ -126,8 +125,8 @@ fn emit_test_messages() { fn adjust_output_formatting( internally_consistent_console_output_format: &ConsoleOutputFormat, - mut logging_handle: &logging::Handle, -) { + logging_handle: &mut logging::Handle, +) -> Result<(), crate::Error> { // Turn off colors if requested if internally_consistent_console_output_format.no_color { anstream::ColorChoice::Never.write_global(); @@ -136,20 +135,22 @@ fn adjust_output_formatting( // Change output mode if requested match internally_consistent_console_output_format.mode { - &ConsoleOutputMode::Plain => logging_handle + ConsoleOutputMode::Plain => logging_handle .switch_to_plain() .context(app::LoggingSnafu {}) .context(crate::AppSnafu {})?, - &ConsoleOutputMode::Json => logging_handle + ConsoleOutputMode::Json => logging_handle .switch_to_json() .context(app::LoggingSnafu {}) .context(crate::AppSnafu {})?, - &ConsoleOutputMode::Test => logging_handle + ConsoleOutputMode::Test => logging_handle .switch_to_test() .context(app::LoggingSnafu {}) .context(crate::AppSnafu {})?, _ => {} - } + }; + + Ok(()) } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -215,7 +216,7 @@ impl ConsoleOutputFormat { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum ConsoleOutputMode { Regular, Plain, @@ -225,45 +226,7 @@ pub enum ConsoleOutputMode { impl Default for ConsoleOutputMode { fn default() -> Self { - CliOutputMode::Regular - } -} - -pub trait CliModifier: GlobalArguments -where - ::L: LogLevel, -{ - fn verbosity_filter(&self) -> Option { - let verbosity_flag_filter = self - .verbosity() - .log_level_filter(); - - if self.is_plain() || self.is_json() { - return Some(LevelFilter::Info); - } else if verbosity_flag_filter < clap_verbosity_flag::LevelFilter::Debug && self.is_debug() - { - return Some(LevelFilter::Debug); - } else { - return verbosity_flag_filter - .as_str() - .parse() - .ok(); - } - } - - fn is_uncolored(&self) -> bool { - self.is_plain() - || self.is_json() - || self.is_no_color() - || env::var(format!( - "{}_NO_COLOR", - String::from(*app::APP_NAME).to_uppercase() - )) - .map_or(false, |value| !value.is_empty()) - } - - fn is_colored(&self) -> bool { - !self.is_uncolored() + ConsoleOutputMode::Regular } } @@ -316,9 +279,8 @@ pub enum Error { // region: IMPORTS use core::fmt; -use std::{env, path::PathBuf}; +use std::path::PathBuf; -use log::LevelFilter; use owo_colors::OwoColorize; use serde::{Deserialize, Serialize}; use snafu::{ResultExt, Snafu}; @@ -392,9 +354,9 @@ pub mod cli_template { pub verbosity: clap_verbosity_flag::Verbosity, } - impl GlobalArguments for GlobalArgs { + impl GlobalArguments for GlobalArgs { fn config_filepath(&self) -> &Option { - self.config_filepath + &self.config_file } fn is_json(&self) -> bool { @@ -420,13 +382,6 @@ pub mod cli_template { fn verbosity_filter(&self) -> log::LevelFilter { self.verbosity .log_level_filter() - .and_then(|log_level_filter| { - log_level_filter - .as_str() - .parse() - .ok() - }) - .unwrap_or(log::LevelFilter::Info) } }