From 8236e7340225373698d045924cdaf711a0c49ec4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 30 Oct 2018 18:40:50 +0100 Subject: [PATCH] libimagrt: Move from error-chain to failure Signed-off-by: Matthias Beyer --- lib/core/libimagrt/Cargo.toml | 6 +- lib/core/libimagrt/src/configuration.rs | 30 ++-- lib/core/libimagrt/src/error.rs | 125 ----------------- lib/core/libimagrt/src/lib.rs | 4 +- lib/core/libimagrt/src/logger.rs | 175 ++++++++++++------------ lib/core/libimagrt/src/runtime.rs | 53 ++++--- 6 files changed, 135 insertions(+), 258 deletions(-) delete mode 100644 lib/core/libimagrt/src/error.rs diff --git a/lib/core/libimagrt/Cargo.toml b/lib/core/libimagrt/Cargo.toml index 2ab0b52a..7c31ae64 100644 --- a/lib/core/libimagrt/Cargo.toml +++ b/lib/core/libimagrt/Cargo.toml @@ -25,10 +25,10 @@ toml = "0.4" xdg-basedir = "1.0" itertools = "0.7" ansi_term = "0.11" -is-match = "0.1" -toml-query = "0.7" -error-chain = "0.12" +toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" } atty = "0.2" +failure = "0.1" +failure_derive = "0.1" libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" } libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" } diff --git a/lib/core/libimagrt/src/configuration.rs b/lib/core/libimagrt/src/configuration.rs index 70a13116..a667e446 100644 --- a/lib/core/libimagrt/src/configuration.rs +++ b/lib/core/libimagrt/src/configuration.rs @@ -21,20 +21,19 @@ use std::path::PathBuf; use toml::Value; use clap::App; +use failure::ResultExt; +use failure::Fallible as Result; +use failure::Error; +use failure::err_msg; -use error::RuntimeError as RE; -use error::RuntimeErrorKind as REK; -use error::Result; -use error::ResultExt; +use libimagerror::errors::ErrorMsg as EM; /// Get a new configuration object. /// /// The passed runtimepath is used for searching the configuration file, whereas several file /// names are tested. If that does not work, the home directory and the XDG basedir are tested /// with all variants. -/// -/// If that doesn't work either, an error is returned. -pub fn fetch_config(searchpath: &PathBuf) -> Result { +pub fn fetch_config(searchpath: &PathBuf) -> Result> { use std::env; use std::fs::File; use std::io::Read; @@ -65,7 +64,7 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result { .unwrap_or(vec![]), ]; - Itertools::flatten(vals.iter()) + let config = Itertools::flatten(vals.iter()) .filter(|path| path.exists() && path.is_file()) .filter_map(|path| { let content = { @@ -90,13 +89,14 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result { .unwrap_or_else(|| String::from("Line unknown, Column unknown")); let _ = write!(stderr(), "Config file parser error at {}", line_col); - let e : RE = RE::from(e); + let e = Error::from(EM::TomlDeserError); trace_error(&e); None }) }) - .nth(0) - .ok_or(RE::from_kind(REK::ConfigNoConfigFileFound)) + .nth(0); + + Ok(config) } /// Override the configuration. @@ -120,16 +120,16 @@ pub fn override_config(val: &mut Value, v: Vec) -> Result<()> { .map(|(k, v)| { let value = val .read(&k) - .chain_err(|| REK::ConfigTOMLParserError)? - .ok_or(RE::from_kind(REK::ConfigOverrideKeyNotAvailable))?; + .context(EM::TomlQueryError)? + .ok_or_else(|| Error::from(err_msg("Confit parser error")))?; into_value(value, v) .map(|v| info!("Successfully overridden: {} = {}", k, v)) - .ok_or_else(|| RE::from_kind(REK::ConfigOverrideTypeNotMatching)) + .ok_or_else(|| Error::from(err_msg("Config override type not matching"))) }); for elem in iter { - let _ = try!(elem.chain_err(|| REK::ConfigOverrideError)); + let _ = elem.context(err_msg("Config override error"))?; } Ok(()) diff --git a/lib/core/libimagrt/src/error.rs b/lib/core/libimagrt/src/error.rs deleted file mode 100644 index 35331c67..00000000 --- a/lib/core/libimagrt/src/error.rs +++ /dev/null @@ -1,125 +0,0 @@ -// -// imag - the personal information management suite for the commandline -// Copyright (C) 2015-2018 Matthias Beyer and contributors -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; version -// 2.1 of the License. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// - -error_chain! { - types { - RuntimeError, RuntimeErrorKind, ResultExt, Result; - } - - foreign_links { - IO(::std::io::Error); - TomlDeError(::toml::de::Error); - TomlQueryError(::toml_query::error::Error); - HandlebarsTemplateError(::handlebars::TemplateError); - } - - errors { - Instantiate { - description("Could not instantiate") - display("Could not instantiate") - } - - IOError { - description("IO Error") - display("IO Error") - } - - ProcessExitFailure { - description("Process exited with failure") - display("Process exited with failure") - } - - IOLogFileOpenError { - description("IO Error: Could not open logfile") - display("IO Error: Could not open logfile") - } - - ConfigTypeError(path: String, should_be_type: &'static str) { - description("Error while reading the configuration: Type Error") - display("Type Error: '{}' should be '{}'", path, should_be_type) - } - - GlobalLogLevelConfigMissing { - description("Global config 'imag.logging.level' missing") - display("Global config 'imag.logging.level' missing") - } - - GlobalDestinationConfigMissing { - description("Global config 'imag.logging.destinations' missing") - display("Global config 'imag.logging.destinations' missing") - } - - InvalidLogLevelSpec { - description("Invalid log level specification: Only 'trace', 'debug', 'info', 'warn', 'error' are allowed") - display("Invalid log level specification: Only 'trace', 'debug', 'info', 'warn', 'error' are allowed") - } - - ConfigMissingLoggingFormatTrace { - description("Missing config for logging format for trace logging") - display("Missing config for logging format for trace logging") - } - - ConfigMissingLoggingFormatDebug { - description("Missing config for logging format for debug logging") - display("Missing config for logging format for debug logging") - } - - ConfigMissingLoggingFormatInfo { - description("Missing config for logging format for info logging") - display("Missing config for logging format for info logging") - } - - ConfigMissingLoggingFormatWarn { - description("Missing config for logging format for warn logging") - display("Missing config for logging format for warn logging") - } - - ConfigMissingLoggingFormatError { - description("Missing config for logging format for error logging") - display("Missing config for logging format for error logging") - } - - ConfigTOMLParserError { - description("Configuration: TOML Parsing error") - display("Configuration: TOML Parsing error") - } - - ConfigNoConfigFileFound { - description("Configuration: No config file found") - display("Configuration: No config file found") - } - - ConfigOverrideError { - description("Configuration: Config override error") - display("Configuration: Config override error") - } - - ConfigOverrideKeyNotAvailable { - description("Configuration: Key not available") - display("Configuration: Key not available") - } - - ConfigOverrideTypeNotMatching { - description("Configuration: Configuration Type not matching") - display("Configuration: Configuration Type not matching") - } - - } -} - diff --git a/lib/core/libimagrt/src/lib.rs b/lib/core/libimagrt/src/lib.rs index d56d638c..aff768d5 100644 --- a/lib/core/libimagrt/src/lib.rs +++ b/lib/core/libimagrt/src/lib.rs @@ -36,17 +36,16 @@ )] #[macro_use] extern crate log; -#[macro_use] extern crate error_chain; extern crate itertools; #[cfg(unix)] extern crate xdg_basedir; extern crate env_logger; extern crate ansi_term; extern crate handlebars; +#[macro_use] extern crate failure; extern crate clap; extern crate toml; extern crate toml_query; -#[macro_use] extern crate is_match; extern crate atty; extern crate libimagstore; @@ -54,7 +53,6 @@ extern crate libimagutil; extern crate libimagerror; extern crate libimaginteraction; -pub mod error; pub mod configuration; pub mod logger; pub mod io; diff --git a/lib/core/libimagrt/src/logger.rs b/lib/core/libimagrt/src/logger.rs index 84b2ecc2..4fd773a6 100644 --- a/lib/core/libimagrt/src/logger.rs +++ b/lib/core/libimagrt/src/logger.rs @@ -24,11 +24,12 @@ use std::sync::Arc; use std::sync::Mutex; use std::ops::Deref; -use error::RuntimeErrorKind as EK; -use error::RuntimeError as RE; -use error::ResultExt; use runtime::Runtime; +use failure::ResultExt; +use failure::Fallible as Result; +use failure::Error; +use failure::err_msg; use clap::ArgMatches; use log::{Log, Level, Record, Metadata}; use toml::Value; @@ -36,10 +37,10 @@ use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadTypeExt; use handlebars::Handlebars; -type ModuleName = String; -type Result = ::std::result::Result; +use libimagerror::errors::ErrorMsg as EM; + +type ModuleName = String; -#[derive(Debug)] enum LogDestination { Stderr, File(Arc>), @@ -51,7 +52,6 @@ impl Default for LogDestination { } } -#[derive(Debug)] struct ModuleSettings { enabled: bool, level: Option, @@ -89,32 +89,39 @@ impl ImagLogger { { let fmt = aggregate_global_format_trace(config)?; - handlebars.register_template_string("TRACE", fmt)?; // name must be uppercase + handlebars.register_template_string("TRACE", fmt) + .map_err(Error::from) + .context(err_msg("Handlebars template error"))?; // name must be uppercase } { let fmt = aggregate_global_format_debug(config)?; - handlebars.register_template_string("DEBUG", fmt)?; // name must be uppercase + handlebars.register_template_string("DEBUG", fmt) + .map_err(Error::from) + .context(err_msg("Handlebars template error"))?; // name must be uppercase } { let fmt = aggregate_global_format_info(config)?; - handlebars.register_template_string("INFO", fmt)?; // name must be uppercase + handlebars.register_template_string("INFO", fmt) + .map_err(Error::from) + .context(err_msg("Handlebars template error"))?; // name must be uppercase } { let fmt = aggregate_global_format_warn(config)?; - handlebars.register_template_string("WARN", fmt)?; // name must be uppercase + handlebars.register_template_string("WARN", fmt) + .map_err(Error::from) + .context(err_msg("Handlebars template error"))?; // name must be uppercase } { let fmt = aggregate_global_format_error(config)?; - handlebars.register_template_string("ERROR", fmt)?; // name must be uppercase + handlebars.register_template_string("ERROR", fmt) + .map_err(Error::from) + .context(err_msg("Handlebars template error"))?; // name must be uppercase } - let module_settings = aggregate_module_settings(matches, config)?; - eprintln!("Logging: {:?}", module_settings); - Ok(ImagLogger { global_loglevel : aggregate_global_loglevel(matches, config)?, global_destinations : aggregate_global_destinations(matches, config)?, - module_settings : module_settings, + module_settings : aggregate_module_settings(matches, config)?, handlebars : handlebars, }) } @@ -179,35 +186,28 @@ impl Log for ImagLogger { self.module_settings .get(record_target) .map(|module_setting| { - // We have a module setting some - // * Check whether logging is enabled for this module and - // * check whether the module logging level is >= or, if there is no module logging - // level, - // * check whether the global logging level is >= the record level. let set = module_setting.enabled && module_setting.level.unwrap_or(self.global_loglevel) >= record.level(); - if set { // if we want to log from a setting standpoint - // get the destinations for the module and log to all of them + if set { module_setting.destinations.as_ref().map(|destinations| for d in destinations { - let _ = log_to_destination(&d); // ignore errors, because what else? + // If there's an error, we cannot do anything, can we? + let _ = log_to_destination(&d); }); - // after that, log to the global destinations as well for d in self.global_destinations.iter() { - let _ = log_to_destination(&d); // ignore errors, because what else? + // If there's an error, we cannot do anything, can we? + let _ = log_to_destination(&d); } } }) - - // if we do not have a setting for the record target .unwrap_or_else(|| { - if self.global_loglevel >= record.level() { // if logging is enabled for that level - self.global_destinations - .iter() - .for_each(|d| { // log to all global destinations - let _ = log_to_destination(&d); // ignore errors, because what else? - }); + if self.global_loglevel >= record.level() { + // Yes, we log + for d in self.global_destinations.iter() { + // If there's an error, we cannot do anything, can we? + let _ = log_to_destination(&d); + } } }); } @@ -220,7 +220,7 @@ fn match_log_level_str(s: &str) -> Result { "info" => Ok(Level::Info), "warn" => Ok(Level::Warn), "error" => Ok(Level::Error), - _ => return Err(RE::from_kind(EK::InvalidLogLevelSpec)), + lvl => return Err(format_err!("Invalid logging level: {}", lvl)), } } @@ -243,8 +243,10 @@ fn aggregate_global_loglevel(matches: &ArgMatches, config: Option<&Value>) -> Re if let Some(cfg) = config { let cfg_loglevel = cfg - .read_string("imag.logging.level")? - .ok_or(RE::from_kind(EK::GlobalLogLevelConfigMissing)) + .read_string("imag.logging.level") + .map_err(Error::from) + .context(EM::TomlQueryError)? + .ok_or(err_msg("Global log level config missing")) .and_then(|s| match_log_level_str(&s))?; if let Some(cli_loglevel) = get_arg_loglevel(matches)? { @@ -273,7 +275,9 @@ fn translate_destination(raw: &str) -> Result { .map(Mutex::new) .map(Arc::new) .map(LogDestination::File) - .chain_err(|| EK::IOLogFileOpenError) + .map_err(Error::from) + .context(EM::IO) + .map_err(Error::from) } } } @@ -285,9 +289,9 @@ fn translate_destinations(raw: &Vec) -> Result> { acc.and_then(|mut v| { let dest = val.as_str() .ok_or_else(|| { - let path = "imag.logging.modules..destinations".to_owned(); + let path = "imag.logging.modules..destinations"; let ty = "Array"; - RE::from_kind(EK::ConfigTypeError(path, ty)) + Error::from(format_err!("Type error at {}, expected {}", path, ty)) }) .and_then(translate_destination)?; v.push(dest); @@ -299,16 +303,18 @@ fn translate_destinations(raw: &Vec) -> Result> { fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>) -> Result> { - let config_log_dest_path = "imag.logging.destinations"; + match config { Some(cfg) => cfg - .read(&config_log_dest_path)? - .ok_or_else(|| RE::from_kind(EK::GlobalDestinationConfigMissing))? + .read("imag.logging.destinations") + .map_err(Error::from) + .context(EM::TomlQueryError)? + .ok_or_else(|| err_msg("Global log destination config missing"))? .as_array() .ok_or_else(|| { - let path = config_log_dest_path.to_owned(); + let path = "imag.logging.destinations"; let ty = "Array"; - RE::from_kind(EK::ConfigTypeError(path, ty)) + Error::from(format_err!("Type error at {}, expected {}", path, ty)) }) .and_then(translate_destinations), None => { @@ -330,10 +336,12 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>) } macro_rules! aggregate_global_format { - ($read_str:expr, $error_kind_if_missing:expr, $config:expr) => { - try!($config.ok_or(RE::from_kind($error_kind_if_missing))) - .read_string($read_str)? - .ok_or_else(|| RE::from_kind($error_kind_if_missing)) + ($read_str:expr, $error_msg_if_missing:expr, $config:expr) => { + try!($config.ok_or_else(|| Error::from(err_msg($error_msg_if_missing)))) + .read_string($read_str) + .map_err(Error::from) + .context(EM::TomlQueryError)? + .ok_or_else(|| Error::from(err_msg($error_msg_if_missing))) }; } @@ -341,43 +349,43 @@ fn aggregate_global_format_trace(config: Option<&Value>) -> Result { aggregate_global_format!("imag.logging.format.trace", - EK::ConfigMissingLoggingFormatTrace, - config) + "Config missing: Logging format: Trace", + config) } fn aggregate_global_format_debug(config: Option<&Value>) -> Result { aggregate_global_format!("imag.logging.format.debug", - EK::ConfigMissingLoggingFormatDebug, - config) + "Config missing: Logging format: Debug", + config) } fn aggregate_global_format_info(config: Option<&Value>) -> Result { aggregate_global_format!("imag.logging.format.info", - EK::ConfigMissingLoggingFormatInfo, - config) + "Config missing: Logging format: Info", + config) } fn aggregate_global_format_warn(config: Option<&Value>) -> Result { aggregate_global_format!("imag.logging.format.warn", - EK::ConfigMissingLoggingFormatWarn, - config) + "Config missing: Logging format: Warn", + config) } fn aggregate_global_format_error(config: Option<&Value>) -> Result { aggregate_global_format!("imag.logging.format.error", - EK::ConfigMissingLoggingFormatError, - config) + "Config missing: Logging format: Error", + config) } -fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>) +fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>) -> Result> { // Helper macro to return the error from Some(Err(_)) and map everything else to an @@ -393,44 +401,43 @@ fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>) }; match config { - Some(cfg) => match cfg.read("imag.logging.modules") { + Some(cfg) => match cfg.read("imag.logging.modules").map_err(Error::from) { Ok(Some(&Value::Table(ref t))) => { // translate the module settings from the table `t` let mut settings = BTreeMap::new(); for (module_name, v) in t { let destinations = inner_try! { - v.read("destinations")? + v.read("destinations") + .map_err(Error::from) + .context(EM::TomlQueryError)? .map(|val| { val.as_array() .ok_or_else(|| { - let path = "imag.logging.modules..destinations".to_owned(); + let path = "imag.logging.modules..destinations"; let ty = "Array"; - RE::from_kind(EK::ConfigTypeError(path, ty)) + Error::from(format_err!("Type error at {}, expected {}", path, ty)) }) .and_then(translate_destinations) }) }; - - let (pre_enabled, level) = if matches.is_present(Runtime::arg_debugging_name()) { - (true, Some(Level::Debug)) - } else { - let level = inner_try! { - v.read_string("level")?.map(|s| match_log_level_str(&s)) - }; - - (false, level) + let level = inner_try! { + v.read_string("level") + .map_err(Error::from) + .context(EM::TomlQueryError)? + .map(|s| match_log_level_str(&s)) }; - let enabled = pre_enabled || - v.read("enabled")? - .map(|v| v.as_bool().unwrap_or(false)) - .ok_or_else(|| { - let path = "imag.logging.modules..enabled".to_owned(); - let ty = "Boolean"; - RE::from_kind(EK::ConfigTypeError(path, ty)) - })?; + let enabled = v.read("enabled") + .map_err(Error::from) + .context(EM::TomlQueryError)? + .map(|v| v.as_bool().unwrap_or(false)) + .ok_or_else(|| { + let path = "imag.logging.modules..enabled"; + let ty = "Boolean"; + Error::from(format_err!("Type error at {}, expected {}", path, ty)) + })?; let module_settings = ModuleSettings { enabled: enabled, @@ -445,15 +452,15 @@ fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>) Ok(settings) }, Ok(Some(_)) => { - let path = "imag.logging.modules".to_owned(); + let path = "imag.logging.modules"; let ty = "Table"; - Err(RE::from_kind(EK::ConfigTypeError(path, ty))) + Err(Error::from(format_err!("Type error at {}, expected {}", path, ty))) }, Ok(None) => { // No modules configured. This is okay! Ok(BTreeMap::new()) }, - Err(e) => Err(e).map_err(From::from), + Err(e) => Err(e).context(EM::TomlQueryError).map_err(Error::from), }, None => { write!(stderr(), "No Configuration.").ok(); diff --git a/lib/core/libimagrt/src/runtime.rs b/lib/core/libimagrt/src/runtime.rs index 4e72404d..4dfe3b5f 100644 --- a/lib/core/libimagrt/src/runtime.rs +++ b/lib/core/libimagrt/src/runtime.rs @@ -30,14 +30,16 @@ use toml::Value; use toml_query::read::TomlValueReadExt; use clap::{Arg, ArgMatches}; +use failure::ResultExt; +use failure::Fallible as Result; +use failure::Error; +use failure::err_msg; use configuration::{fetch_config, override_config, InternalConfiguration}; -use error::RuntimeError; -use error::RuntimeErrorKind; -use error::ResultExt; use logger::ImagLogger; use io::OutputProxy; +use libimagerror::errors::ErrorMsg as EM; use libimagerror::trace::*; use libimagstore::store::Store; use libimagstore::file_abstraction::InMemoryFileAbstraction; @@ -62,7 +64,7 @@ impl<'a> Runtime<'a> { /// and builds the Runtime object with it. /// /// The cli_app object should be initially build with the ::get_default_cli_builder() function. - pub fn new(cli_app: C) -> Result, RuntimeError> + pub fn new(cli_app: C) -> Result> where C: Clone + CliSpec<'a> + InternalConfiguration { use libimagerror::trace::trace_error; @@ -76,17 +78,15 @@ impl<'a> Runtime<'a> { debug!("Config path = {:?}", configpath); - let config = match fetch_config(&configpath) { - Err(e) => if !is_match!(e.kind(), &RuntimeErrorKind::ConfigNoConfigFileFound) { - return Err(e).chain_err(|| RuntimeErrorKind::Instantiate); - } else { - eprintln!("No config file found."); - eprintln!("Maybe try to use 'imag-init' to initialize imag?"); - eprintln!("Continuing without configuration file"); - None + let config = match fetch_config(&configpath)? { + None => { + return Err(err_msg("No configuration file found")) + .context(err_msg("Maybe try to use 'imag-init' to initialize imag?")) + .context(err_msg("Continuing without configuration file")) + .context(err_msg("Cannot instantiate runtime")) + .map_err(Error::from); }, - - Ok(mut config) => { + Some(mut config) => { if let Err(e) = override_config(&mut config, get_override_specs(&matches)) { error!("Could not apply config overrides"); trace_error(&e); @@ -102,16 +102,14 @@ impl<'a> Runtime<'a> { } /// Builds the Runtime object using the given `config`. - pub fn with_configuration(cli_app: C, config: Option) - -> Result, RuntimeError> + pub fn with_configuration(cli_app: C, config: Option) -> Result> where C: Clone + CliSpec<'a> + InternalConfiguration { let matches = cli_app.clone().matches(); Runtime::_new(cli_app, matches, config) } - fn _new(cli_app: C, matches: ArgMatches<'a>, config: Option) - -> Result, RuntimeError> + fn _new(cli_app: C, matches: ArgMatches<'a>, config: Option) -> Result> where C: Clone + CliSpec<'a> + InternalConfiguration { if cli_app.enable_logging() { @@ -146,7 +144,8 @@ impl<'a> Runtime<'a> { store: store, } }) - .chain_err(|| RuntimeErrorKind::Instantiate) + .context(err_msg("Cannot instantiate runtime")) + .map_err(Error::from) } /// @@ -379,7 +378,7 @@ impl<'a> Runtime<'a> { } /// Get a editor command object which can be called to open the $EDITOR - pub fn editor(&self) -> Result, RuntimeError> { + pub fn editor(&self) -> Result> { self.cli() .value_of("editor") .map(String::from) @@ -391,7 +390,7 @@ impl<'a> Runtime<'a> { }) }) .or(env::var("EDITOR").ok()) - .ok_or_else(|| RuntimeErrorKind::IOError.into()) + .ok_or_else(|| Error::from(EM::IO)) .map_dbg(|s| format!("Editing with '{}'", s)) .and_then(|s| { let mut split = s.split_whitespace(); @@ -401,7 +400,7 @@ impl<'a> Runtime<'a> { } let mut c = Command::new(command.unwrap()); // secured above c.args(split); - c.stdin(::std::fs::File::open("/dev/tty")?); + c.stdin(::std::fs::File::open("/dev/tty").context(EM::IO)?); c.stderr(::std::process::Stdio::inherit()); Ok(Some(c)) }) @@ -442,8 +441,6 @@ impl<'a> Runtime<'a> { /// # Return value /// /// On success, the exit status object of the `Command` invocation is returned. - /// On Error, a RuntimeError object is returned. This is also the case if writing the error - /// message does not work. /// /// # Details /// @@ -457,7 +454,7 @@ impl<'a> Runtime<'a> { command: S, subcommand: S, args: &ArgMatches) - -> Result<::std::process::ExitStatus, RuntimeError> + -> Result<::std::process::ExitStatus> { use std::io::Write; use std::io::ErrorKind; @@ -465,8 +462,7 @@ impl<'a> Runtime<'a> { let rtp_str = self.rtp() .to_str() .map(String::from) - .ok_or(RuntimeErrorKind::IOError) - .map_err(RuntimeError::from_kind)?; + .ok_or_else(|| Error::from(EM::IO))?; let command = format!("{}-{}", command.as_ref(), subcommand.as_ref()); @@ -497,7 +493,8 @@ impl<'a> Runtime<'a> { }, _ => e, }) - .map_err(RuntimeError::from) + .context(EM::IO) + .map_err(Error::from) } }