From 72b55d39828be91d8452c2cca9a5bf09db48231e Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 24 Nov 2019 08:28:30 -0800 Subject: [PATCH] config: lay foundation for config reloading --- src/config/mod.rs | 113 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 10 ++-- 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index e623254ba..59960c496 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -15,6 +15,7 @@ use std::ffi::{OsStr, OsString}; use std::fs; use std::io::prelude::*; use std::path::PathBuf; +use std::sync::{Arc, Mutex}; use term; use termwiz::hyperlink; use termwiz::input::{KeyCode, Modifiers}; @@ -38,6 +39,118 @@ pub use unix::*; lazy_static! { static ref HOME_DIR: PathBuf = dirs::home_dir().expect("can't find HOME dir"); static ref RUNTIME_DIR: PathBuf = compute_runtime_dir().unwrap(); + static ref CONFIG: ConfigHandle = ConfigHandle::new(); +} + +/// Discard the current configuration and replace it with +/// the default configuration +pub fn use_default_configuration() { + CONFIG.use_defaults(); +} + +/// Returns a handle to the current configuration +pub fn configuration() -> Arc { + CONFIG.get() +} + +/// If there was an error loading the preferred configuration, +/// return it, otherwise return the current configuration +pub fn configuration_result() -> Result, Error> { + if let Some(error) = CONFIG.get_error() { + failure::bail!("{}", error); + } + Ok(CONFIG.get()) +} + +struct ConfigInner { + config: Arc, + error: Option, +} + +impl ConfigInner { + /// Attempt to load the user's configuration. + /// On failure, capture the error message and load the + /// default configuration instead. + fn load() -> Self { + match Config::load() { + Ok(config) => Self { + config: Arc::new(config), + error: None, + }, + Err(err) => Self { + config: Arc::new(Config::default_config()), + error: Some(err.to_string()), + }, + } + } + + /// Attempt to load the user's configuration. + /// On success, clear any error and replace the current + /// configuration. + /// On failure, retain the existing configuration but + /// replace any captured error message. + fn reload(&mut self) { + match Config::load() { + Ok(config) => { + self.config = Arc::new(config); + self.error.take(); + } + Err(err) => { + self.error.replace(err.to_string()); + } + } + } + + /// Discard the current configuration and any recorded + /// error message; replace them with the default + /// configuration + fn use_defaults(&mut self) { + self.config = Arc::new(Config::default_config()); + self.error.take(); + } +} + +pub struct ConfigHandle { + inner: Mutex, +} + +impl ConfigHandle { + pub fn new() -> Self { + Self { + inner: Mutex::new(ConfigInner::load()), + } + } + + /// Returns the effective configuration. + pub fn get(&self) -> Arc { + Arc::clone(&self.inner.lock().unwrap().config) + } + + /// Reset the configuration to defaults + pub fn use_defaults(&self) { + let mut inner = self.inner.lock().unwrap(); + inner.use_defaults(); + } + + /// Reload the configuration + pub fn reload(&self) { + let mut inner = self.inner.lock().unwrap(); + inner.reload(); + } + + /// Returns a copy of any captured error message. + /// The error message is not cleared. + pub fn get_error(&self) -> Option { + let inner = self.inner.lock().unwrap(); + inner.error.as_ref().cloned() + } + + /// Returns any captured error message, and clears + /// it from the config state. + pub fn clear_error(&self) -> Option { + let mut inner = self.inner.lock().unwrap(); + inner.error.take() + } } #[derive(Debug, Deserialize, Clone)] diff --git a/src/main.rs b/src/main.rs index 3f44aff21..d53377633 100644 --- a/src/main.rs +++ b/src/main.rs @@ -636,11 +636,11 @@ fn run() -> Result<(), Error> { pretty_env_logger::init(); let opts = Opt::from_args(); - let config = Arc::new(if opts.skip_config { - config::Config::default_config() - } else { - config::Config::load()? - }); + + if opts.skip_config { + config::use_default_configuration(); + } + let config = config::configuration_result()?; match opts .cmd