From 4b182e71598c2eda5190b81708bafe6f9681999b Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Sun, 20 Nov 2022 13:34:23 -0600 Subject: feat: improve error handling --- src/config.rs | 6 ++++ src/error.rs | 22 ++++----------- src/lib.rs | 4 +-- src/logging.rs | 78 +++++++++++++++++++++++++++++++++++----------------- src/logging/error.rs | 10 +++++++ src/logging/level.rs | 1 - src/main.rs | 40 +++++++++++++-------------- src/paths/error.rs | 4 +-- 8 files changed, 98 insertions(+), 67 deletions(-) create mode 100644 src/logging/error.rs diff --git a/src/config.rs b/src/config.rs index 39c27fe..00aa1dc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,12 @@ pub struct Config { } impl Config { + // Provide a default provider, a `Figment`. + pub fn figment() -> Figment { + Figment::from(Config::default()) + } + + // Extract the configuration from any `Provider` pub fn extract(provider: T) -> figment::error::Result { Figment::from(provider).extract() } diff --git a/src/error.rs b/src/error.rs index a46285b..83a2ef7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,26 +1,16 @@ -use std::process::{ExitCode, Termination}; - pub type Result = std::result::Result; #[derive(thiserror::Error, Debug)] -#[repr(u8)] pub enum Error { - #[error("IO error: {0}")] - IO(#[from] std::io::Error), - - #[error("Config error: {0}")] - Config(#[from] figment::error::Error), + #[error(transparent)] + Logging(#[from] crate::logging::Error), - #[error("Paths error: {0}")] + #[error(transparent)] Paths(#[from] crate::paths::Error), - #[error("Finder error: {0}")] + #[error(transparent)] Finder(#[from] crate::finder::Error), -} -impl Termination for Error { - fn report(self) -> ExitCode { - eprintln!("{}", self); - ExitCode::FAILURE - } + #[error(transparent)] + Config(#[from] figment::error::Error), } diff --git a/src/lib.rs b/src/lib.rs index f7c3c4f..c4369eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,12 @@ pub use crate::cli::Cli; pub use crate::config::Config; pub use crate::error::{Error, Result}; pub use crate::finder::Finder; +pub use crate::logging::Logging; pub use crate::paths::Paths; -pub mod logging; - mod cli; mod config; mod error; mod finder; +mod logging; mod paths; diff --git a/src/logging.rs b/src/logging.rs index c97948f..15008be 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,36 +1,64 @@ -use crate::Result; use figment::Provider; -use std::{fs::File, sync::Arc}; +use std::{fs::File, ops::Deref, sync::Arc}; use tracing::metadata::LevelFilter; use tracing_subscriber::{prelude::*, Layer}; pub use config::Config; +pub use error::{Error, Result}; pub use level::Level; mod config; +mod error; mod level; -pub fn init_from_provider(provider: T) -> Result<()> { - let config = Config::extract(&provider)?; - - let stdout_layer = tracing_subscriber::fmt::layer() - .pretty() - .with_filter(LevelFilter::from(config.level)); - - let log_layer = if config.level.is_some() { - let file = File::create(&config.path)?; - tracing_subscriber::fmt::layer() - .with_writer(Arc::new(file)) - .with_filter(LevelFilter::from(config.level)) - .into() - } else { - None - }; - - tracing_subscriber::registry() - .with(stdout_layer) - .with(log_layer) - .init(); - - Ok(()) +pub struct Logging(Config); + +impl Logging { + pub fn new() -> Result { + Self::from_provider(Config::figment()) + } + + /// Extract `Config` from `provider` to construct new `Finder` + pub fn from_provider(provider: T) -> Result { + Config::extract(&provider) + .map_err(Into::into) + .map(Into::into) + } + + pub fn init(&self) -> Result<()> { + let stdout_layer = tracing_subscriber::fmt::layer() + .pretty() + .with_filter(LevelFilter::from(self.level)); + + let log_layer = if self.level.is_some() { + let file = File::create(&self.path)?; + tracing_subscriber::fmt::layer() + .with_writer(Arc::new(file)) + .with_filter(LevelFilter::from(self.level)) + .into() + } else { + None + }; + + tracing_subscriber::registry() + .with(stdout_layer) + .with(log_layer) + .init(); + + Ok(()) + } +} + +impl Deref for Logging { + type Target = Config; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for Logging { + fn from(value: Config) -> Self { + Self(value) + } } diff --git a/src/logging/error.rs b/src/logging/error.rs new file mode 100644 index 0000000..a38cdda --- /dev/null +++ b/src/logging/error.rs @@ -0,0 +1,10 @@ +pub type Result = std::result::Result; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Config(#[from] figment::error::Error), + + #[error(transparent)] + IO(#[from] std::io::Error), +} diff --git a/src/logging/level.rs b/src/logging/level.rs index 6134c24..38a0f7f 100644 --- a/src/logging/level.rs +++ b/src/logging/level.rs @@ -19,4 +19,3 @@ where }; s.parse().map_err(serde::de::Error::custom).map(Some) } - diff --git a/src/main.rs b/src/main.rs index c85bf2f..c682def 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,36 +1,34 @@ +use anyhow::{Context, Result}; use clap::Parser; -use figment::{ - providers::{Env, Format, Toml}, - Figment, -}; -use std::error::Error; -use tmuxr::{logging, Cli, Config, Finder, Paths, Result}; +use figment::providers::{Env, Format, Toml}; +use tmuxr::{Cli, Config, Finder, Logging, Paths}; use tracing::info; fn main() -> Result<()> { - let cli = Cli::parse(); - - let config = Figment::from(Config::default()) - .merge(cli) + let config = Config::figment() + .merge(Cli::parse()) .merge(Toml::file("tmuxr.toml")) .merge(Env::prefixed("TMUXR_")) .extract() - .map_err(eprintln)?; - - logging::init_from_provider(&config).map_err(eprintln)?; + .context("Failed to extract config")?; - run(&config).map_err(eprintln) -} + Logging::from_provider(&config) + .context("Failed to extract logging config")? + .init() + .context("Failed to initialize logging")?; -fn eprintln(err: E) -> E { - eprintln!("{}", err); - err + run(&config) } -#[tracing::instrument()] +#[tracing::instrument] pub fn run(config: &Config) -> Result<()> { - let paths = Paths::from_provider(config)?; - let selected = Finder::from_provider(config)?.spawn()?.find(paths)?; + let paths = Paths::from_provider(config).context("Failed to extract paths config")?; + let selected = Finder::from_provider(config) + .context("Failed to extract finder config")? + .spawn() + .context("Failed to spawn finder process")? + .find(paths) + .context("Failed to write paths to finder stdin")?; info!("{:?}", selected); diff --git a/src/paths/error.rs b/src/paths/error.rs index 3a5a580..4300e8a 100644 --- a/src/paths/error.rs +++ b/src/paths/error.rs @@ -2,9 +2,9 @@ pub type Result = std::result::Result; #[derive(thiserror::Error, Debug)] pub enum Error { - #[error("Config error: {0}")] + #[error(transparent)] Config(#[from] figment::error::Error), - #[error("Ignore error: {0}")] + #[error(transparent)] Ignore(#[from] ignore::Error), } -- cgit v1.2.3-70-g09d2