From 866b9e16a866a51644d10760ea2fdd062f0c902f Mon Sep 17 00:00:00 2001 From: sharkdp Date: Thu, 11 Oct 2018 22:50:37 +0200 Subject: [PATCH] Add error handling --- src/app.rs | 15 ++++++++------- src/config.rs | 38 ++++++++++++++++++++++++-------------- src/main.rs | 2 +- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/app.rs b/src/app.rs index 0d32bab7..d5dd2b8f 100644 --- a/src/app.rs +++ b/src/app.rs @@ -81,19 +81,19 @@ pub struct App { } impl App { - pub fn new() -> Self { + pub fn new() -> Result { #[cfg(windows)] let _ = ansi_term::enable_ansi_support(); let interactive_output = atty::is(Stream::Stdout); - App { - matches: Self::matches(interactive_output), + Ok(App { + matches: Self::matches(interactive_output)?, interactive_output, - } + }) } - fn matches(interactive_output: bool) -> ArgMatches<'static> { + fn matches(interactive_output: bool) -> Result> { let args = if wild::args_os().nth(1) == Some("cache".into()) || wild::args_os().any(|arg| arg == OsStr::new("--no-config")) { @@ -104,7 +104,8 @@ impl App { let mut cli_args = wild::args_os(); // Read arguments from bats config file - let mut args = get_args_from_config_file(); + let mut args = + get_args_from_config_file().chain_err(|| "Could not parse configuration file")?; // Put the zero-th CLI argument (program name) first args.insert(0, cli_args.next().unwrap()); @@ -115,7 +116,7 @@ impl App { args }; - clap_app::build_app(interactive_output).get_matches_from(args) + Ok(clap_app::build_app(interactive_output).get_matches_from(args)) } pub fn config(&self) -> Result { diff --git a/src/config.rs b/src/config.rs index 9cf3eb70..b5833f5c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,44 +1,54 @@ +use std::env; use std::ffi::OsString; use std::fs; use shell_words; use dirs::PROJECT_DIRS; +use util::transpose; -pub fn get_args_from_config_file() -> Vec { +pub fn get_args_from_config_file() -> Result, shell_words::ParseError> { let config_file = PROJECT_DIRS.config_dir().join("config"); - fs::read_to_string(config_file) - .map(|content| get_args_from_str(&content)) - .unwrap_or(vec![]) + Ok(transpose( + fs::read_to_string(config_file) + .ok() + .map(|content| get_args_from_str(&content)), + )? + .unwrap_or(vec![])) } -fn get_args_from_str<'a>(content: &'a str) -> Vec { - content +fn get_args_from_str<'a>(content: &'a str) -> Result, shell_words::ParseError> { + let args_per_line = content .split('\n') .map(|line| line.trim()) .filter(|line| !line.is_empty()) .filter(|line| !line.starts_with("#")) - .flat_map(|line| shell_words::split(line).unwrap()) + .map(|line| shell_words::split(line)) + .collect::, _>>()?; + + Ok(args_per_line + .iter() + .flatten() .map(|line| line.into()) - .collect() + .collect()) } #[test] fn empty() { - let args = get_args_from_str(""); + let args = get_args_from_str("").unwrap(); assert!(args.is_empty()); } #[test] fn single() { - assert_eq!(vec!["--plain"], get_args_from_str("--plain")); + assert_eq!(vec!["--plain"], get_args_from_str("--plain").unwrap()); } #[test] fn multiple() { assert_eq!( vec!["--plain", "--language=cpp"], - get_args_from_str("--plain --language=cpp") + get_args_from_str("--plain --language=cpp").unwrap() ); } @@ -46,7 +56,7 @@ fn multiple() { fn quotes() { assert_eq!( vec!["--theme", "Sublime Snazzy"], - get_args_from_str("--theme \"Sublime Snazzy\"") + get_args_from_str("--theme \"Sublime Snazzy\"").unwrap() ); } @@ -60,7 +70,7 @@ fn multi_line() { "; assert_eq!( vec!["-p", "--style", "numbers,changes", "--color=always"], - get_args_from_str(config) + get_args_from_str(config).unwrap() ); } @@ -78,6 +88,6 @@ fn comments() { "; assert_eq!( vec!["-p", "--style", "numbers,changes", "--color=always"], - get_args_from_str(config) + get_args_from_str(config).unwrap() ); } diff --git a/src/main.rs b/src/main.rs index a5484193..31f9503f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -196,7 +196,7 @@ fn run_controller(config: &Config) -> Result { /// Returns `Err(..)` upon fatal errors. Otherwise, returns `Some(true)` on full success and /// `Some(false)` if any intermediate errors occurred (were printed). fn run() -> Result { - let app = App::new(); + let app = App::new()?; match app.matches.subcommand() { ("cache", Some(cache_matches)) => {