From 536d1c1face3b40290bd52acaa28db983edb2d39 Mon Sep 17 00:00:00 2001 From: aawsome <37850842+aawsome@users.noreply.github.com> Date: Sun, 3 Dec 2023 23:19:02 +0100 Subject: [PATCH] fix: log config file logs after reading config files (#961) --- src/application.rs | 42 ++----------------------------- src/commands.rs | 63 +++++++++++++++++++++++++++++++++++++++++----- src/config.rs | 34 ++++++++++++++----------- 3 files changed, 79 insertions(+), 60 deletions(-) diff --git a/src/application.rs b/src/application.rs index 17b77f3..63513b6 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,17 +1,14 @@ //! Rustic Abscissa Application use std::env; -use std::fs::File; -use std::str::FromStr; use abscissa_core::{ application::{self, AppCell}, config::{self, CfgCell}, - terminal::{component::Terminal, ColorChoice}, - Application, Component, FrameworkError, FrameworkErrorKind, StandardPaths, + terminal::component::Terminal, + Application, Component, FrameworkError, StandardPaths, }; use anyhow::Result; -use simplelog::{CombinedLogger, LevelFilter, TermLogger, TerminalMode, WriteLogger}; // use crate::helpers::*; use crate::{commands::EntryPoint, config::RusticConfig}; @@ -98,41 +95,6 @@ impl Application for RusticApp { env::set_var(env, value); } - // start logger - let level_filter = match &config.global.log_level { - Some(level) => LevelFilter::from_str(level) - .map_err(|e| FrameworkErrorKind::ConfigError.context(e))?, - None => LevelFilter::Info, - }; - match &config.global.log_file { - None => TermLogger::init( - level_filter, - simplelog::ConfigBuilder::new() - .set_time_level(LevelFilter::Off) - .build(), - TerminalMode::Stderr, - ColorChoice::Auto, - ) - .map_err(|e| FrameworkErrorKind::ConfigError.context(e))?, - - Some(file) => CombinedLogger::init(vec![ - TermLogger::new( - level_filter.min(LevelFilter::Warn), - simplelog::ConfigBuilder::new() - .set_time_level(LevelFilter::Off) - .build(), - TerminalMode::Stderr, - ColorChoice::Auto, - ), - WriteLogger::new( - level_filter, - simplelog::Config::default(), - File::options().create(true).append(true).open(file)?, - ), - ]) - .map_err(|e| FrameworkErrorKind::ConfigError.context(e))?, - } - self.config.set_once(config); Ok(()) diff --git a/src/commands.rs b/src/commands.rs index 07473d3..5046037 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -23,7 +23,9 @@ pub(crate) mod show_config; pub(crate) mod snapshots; pub(crate) mod tag; +use std::fs::File; use std::path::PathBuf; +use std::str::FromStr; use std::sync::Arc; use crate::{ @@ -38,10 +40,15 @@ use crate::{ {Application, RUSTIC_APP}, }; -use abscissa_core::{config::Override, Command, Configurable, FrameworkError, Runnable, Shutdown}; +use abscissa_core::{ + config::Override, terminal::ColorChoice, Command, Configurable, FrameworkError, + FrameworkErrorKind, Runnable, Shutdown, +}; use anyhow::{anyhow, Result}; use dialoguer::Password; +use log::{log, Level}; use rustic_core::{OpenStatus, Repository}; +use simplelog::{CombinedLogger, LevelFilter, TermLogger, TerminalMode, WriteLogger}; pub(super) mod constants { pub(super) const MAX_PASSWORD_RETRIES: usize = 5; @@ -153,13 +160,57 @@ impl Configurable for EntryPoint { // rustic logic and merged with the CLI options. // That's why it says `_config`, because it's not read at all and therefore not needed. let mut config = self.config.clone(); - if config.global.use_profile.is_empty() { - config.global.use_profile.push("rustic".to_string()); - } + + // collect logs during merging as we start the logger *after* merging + let mut merge_logs = Vec::new(); // get global options from command line / env and config file - for profile in &config.global.use_profile.clone() { - config.merge_profile(profile)?; + if config.global.use_profile.is_empty() { + config.merge_profile("rustic", &mut merge_logs, Level::Info)?; + } else { + for profile in &config.global.use_profile.clone() { + config.merge_profile(profile, &mut merge_logs, Level::Warn)?; + } + } + + // start logger + let level_filter = match &config.global.log_level { + Some(level) => LevelFilter::from_str(level) + .map_err(|e| FrameworkErrorKind::ConfigError.context(e))?, + None => LevelFilter::Info, + }; + match &config.global.log_file { + None => TermLogger::init( + level_filter, + simplelog::ConfigBuilder::new() + .set_time_level(LevelFilter::Off) + .build(), + TerminalMode::Stderr, + ColorChoice::Auto, + ) + .map_err(|e| FrameworkErrorKind::ConfigError.context(e))?, + + Some(file) => CombinedLogger::init(vec![ + TermLogger::new( + level_filter.min(LevelFilter::Warn), + simplelog::ConfigBuilder::new() + .set_time_level(LevelFilter::Off) + .build(), + TerminalMode::Stderr, + ColorChoice::Auto, + ), + WriteLogger::new( + level_filter, + simplelog::Config::default(), + File::options().create(true).append(true).open(file)?, + ), + ]) + .map_err(|e| FrameworkErrorKind::ConfigError.context(e))?, + } + + // display logs from merging + for (level, merge_log) in merge_logs { + log!(level, "{}", merge_log); } match &self.commands { diff --git a/src/config.rs b/src/config.rs index 0aaf841..2546699 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,6 +17,7 @@ use abscissa_core::path::AbsPathBuf; use abscissa_core::FrameworkError; use clap::Parser; use itertools::Itertools; +use log::Level; use rustic_core::RepositoryOptions; use serde::{Deserialize, Serialize}; @@ -61,35 +62,40 @@ pub struct RusticConfig { } impl RusticConfig { - /// Merge a profile into the current config + /// Merge a profile into the current config by reading the corresponding config file. + /// Also recursively merge all profiles given within this config file. /// /// # Arguments /// /// * `profile` - name of the profile to merge - /// - // TODO!: Explain more - pub fn merge_profile(&mut self, profile: &str) -> Result<(), FrameworkError> { + /// * `merge_logs` - Vector to collect logs during merging + /// * `level_missing` - The log level to use if this profile is missing. Recursive calls will produce a Warning. + pub fn merge_profile( + &mut self, + profile: &str, + merge_logs: &mut Vec<(Level, String)>, + level_missing: Level, + ) -> Result<(), FrameworkError> { let profile_filename = profile.to_string() + ".toml"; let paths = get_config_paths(&profile_filename); if let Some(path) = paths.iter().find(|path| path.exists()) { - // TODO: This should be log::info! - however, the logging config - // can be stored in the config file and is needed to initialize the logger - eprintln!("using config {}", path.display()); + merge_logs.push((Level::Info, format!("using config {}", path.display()))); let mut config = Self::load_toml_file(AbsPathBuf::canonicalize(path)?)?; // if "use_profile" is defined in config file, merge the referenced profiles first for profile in &config.global.use_profile.clone() { - config.merge_profile(profile)?; + config.merge_profile(profile, merge_logs, Level::Warn)?; } self.merge(config); } else { let paths_string = paths.iter().map(|path| path.display()).join(", "); - // TODO: This should be log::warn! - however, the logging config - // can be stored in the config file and is needed to initialize the logger - eprintln!( - "using no config file, none of these exist: {}", - &paths_string - ); + merge_logs.push(( + level_missing, + format!( + "using no config file, none of these exist: {}", + &paths_string + ), + )); }; Ok(()) }