libimagrt: Move from error-chain to failure
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
09e8619cf5
commit
8236e73402
6 changed files with 135 additions and 258 deletions
|
@ -25,10 +25,10 @@ toml = "0.4"
|
||||||
xdg-basedir = "1.0"
|
xdg-basedir = "1.0"
|
||||||
itertools = "0.7"
|
itertools = "0.7"
|
||||||
ansi_term = "0.11"
|
ansi_term = "0.11"
|
||||||
is-match = "0.1"
|
toml-query = { git = "https://github.com/matthiasbeyer/toml-query", branch = "failure" }
|
||||||
toml-query = "0.7"
|
|
||||||
error-chain = "0.12"
|
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
|
failure = "0.1"
|
||||||
|
failure_derive = "0.1"
|
||||||
|
|
||||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -21,20 +21,19 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
use error::RuntimeError as RE;
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
use error::RuntimeErrorKind as REK;
|
|
||||||
use error::Result;
|
|
||||||
use error::ResultExt;
|
|
||||||
|
|
||||||
/// Get a new configuration object.
|
/// Get a new configuration object.
|
||||||
///
|
///
|
||||||
/// The passed runtimepath is used for searching the configuration file, whereas several file
|
/// 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
|
/// names are tested. If that does not work, the home directory and the XDG basedir are tested
|
||||||
/// with all variants.
|
/// with all variants.
|
||||||
///
|
pub fn fetch_config(searchpath: &PathBuf) -> Result<Option<Value>> {
|
||||||
/// If that doesn't work either, an error is returned.
|
|
||||||
pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
@ -65,7 +64,7 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
|
||||||
.unwrap_or(vec![]),
|
.unwrap_or(vec![]),
|
||||||
];
|
];
|
||||||
|
|
||||||
Itertools::flatten(vals.iter())
|
let config = Itertools::flatten(vals.iter())
|
||||||
.filter(|path| path.exists() && path.is_file())
|
.filter(|path| path.exists() && path.is_file())
|
||||||
.filter_map(|path| {
|
.filter_map(|path| {
|
||||||
let content = {
|
let content = {
|
||||||
|
@ -90,13 +89,14 @@ pub fn fetch_config(searchpath: &PathBuf) -> Result<Value> {
|
||||||
.unwrap_or_else(|| String::from("Line unknown, Column unknown"));
|
.unwrap_or_else(|| String::from("Line unknown, Column unknown"));
|
||||||
|
|
||||||
let _ = write!(stderr(), "Config file parser error at {}", line_col);
|
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);
|
trace_error(&e);
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.nth(0)
|
.nth(0);
|
||||||
.ok_or(RE::from_kind(REK::ConfigNoConfigFileFound))
|
|
||||||
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Override the configuration.
|
/// Override the configuration.
|
||||||
|
@ -120,16 +120,16 @@ pub fn override_config(val: &mut Value, v: Vec<String>) -> Result<()> {
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
let value = val
|
let value = val
|
||||||
.read(&k)
|
.read(&k)
|
||||||
.chain_err(|| REK::ConfigTOMLParserError)?
|
.context(EM::TomlQueryError)?
|
||||||
.ok_or(RE::from_kind(REK::ConfigOverrideKeyNotAvailable))?;
|
.ok_or_else(|| Error::from(err_msg("Confit parser error")))?;
|
||||||
|
|
||||||
into_value(value, v)
|
into_value(value, v)
|
||||||
.map(|v| info!("Successfully overridden: {} = {}", k, 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 {
|
for elem in iter {
|
||||||
let _ = try!(elem.chain_err(|| REK::ConfigOverrideError));
|
let _ = elem.context(err_msg("Config override error"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> 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")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,17 +36,16 @@
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate error_chain;
|
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
#[cfg(unix)] extern crate xdg_basedir;
|
#[cfg(unix)] extern crate xdg_basedir;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
extern crate handlebars;
|
extern crate handlebars;
|
||||||
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
#[macro_use] extern crate is_match;
|
|
||||||
extern crate atty;
|
extern crate atty;
|
||||||
|
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
@ -54,7 +53,6 @@ extern crate libimagutil;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimaginteraction;
|
extern crate libimaginteraction;
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
pub mod configuration;
|
pub mod configuration;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
|
|
@ -24,11 +24,12 @@ use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use error::RuntimeErrorKind as EK;
|
|
||||||
use error::RuntimeError as RE;
|
|
||||||
use error::ResultExt;
|
|
||||||
use runtime::Runtime;
|
use runtime::Runtime;
|
||||||
|
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use log::{Log, Level, Record, Metadata};
|
use log::{Log, Level, Record, Metadata};
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
@ -36,10 +37,10 @@ use toml_query::read::TomlValueReadExt;
|
||||||
use toml_query::read::TomlValueReadTypeExt;
|
use toml_query::read::TomlValueReadTypeExt;
|
||||||
use handlebars::Handlebars;
|
use handlebars::Handlebars;
|
||||||
|
|
||||||
type ModuleName = String;
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
type Result<T> = ::std::result::Result<T, RE>;
|
|
||||||
|
type ModuleName = String;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum LogDestination {
|
enum LogDestination {
|
||||||
Stderr,
|
Stderr,
|
||||||
File(Arc<Mutex<::std::fs::File>>),
|
File(Arc<Mutex<::std::fs::File>>),
|
||||||
|
@ -51,7 +52,6 @@ impl Default for LogDestination {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ModuleSettings {
|
struct ModuleSettings {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
level: Option<Level>,
|
level: Option<Level>,
|
||||||
|
@ -89,32 +89,39 @@ impl ImagLogger {
|
||||||
|
|
||||||
{
|
{
|
||||||
let fmt = aggregate_global_format_trace(config)?;
|
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)?;
|
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)?;
|
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)?;
|
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)?;
|
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 {
|
Ok(ImagLogger {
|
||||||
global_loglevel : aggregate_global_loglevel(matches, config)?,
|
global_loglevel : aggregate_global_loglevel(matches, config)?,
|
||||||
global_destinations : aggregate_global_destinations(matches, config)?,
|
global_destinations : aggregate_global_destinations(matches, config)?,
|
||||||
module_settings : module_settings,
|
module_settings : aggregate_module_settings(matches, config)?,
|
||||||
handlebars : handlebars,
|
handlebars : handlebars,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -179,35 +186,28 @@ impl Log for ImagLogger {
|
||||||
self.module_settings
|
self.module_settings
|
||||||
.get(record_target)
|
.get(record_target)
|
||||||
.map(|module_setting| {
|
.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 &&
|
let set = module_setting.enabled &&
|
||||||
module_setting.level.unwrap_or(self.global_loglevel) >= record.level();
|
module_setting.level.unwrap_or(self.global_loglevel) >= record.level();
|
||||||
|
|
||||||
if set { // if we want to log from a setting standpoint
|
if set {
|
||||||
// get the destinations for the module and log to all of them
|
|
||||||
module_setting.destinations.as_ref().map(|destinations| for d in destinations {
|
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() {
|
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(|| {
|
.unwrap_or_else(|| {
|
||||||
if self.global_loglevel >= record.level() { // if logging is enabled for that level
|
if self.global_loglevel >= record.level() {
|
||||||
self.global_destinations
|
// Yes, we log
|
||||||
.iter()
|
for d in self.global_destinations.iter() {
|
||||||
.for_each(|d| { // log to all global destinations
|
// If there's an error, we cannot do anything, can we?
|
||||||
let _ = log_to_destination(&d); // ignore errors, because what else?
|
let _ = log_to_destination(&d);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ fn match_log_level_str(s: &str) -> Result<Level> {
|
||||||
"info" => Ok(Level::Info),
|
"info" => Ok(Level::Info),
|
||||||
"warn" => Ok(Level::Warn),
|
"warn" => Ok(Level::Warn),
|
||||||
"error" => Ok(Level::Error),
|
"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 {
|
if let Some(cfg) = config {
|
||||||
let cfg_loglevel = cfg
|
let cfg_loglevel = cfg
|
||||||
.read_string("imag.logging.level")?
|
.read_string("imag.logging.level")
|
||||||
.ok_or(RE::from_kind(EK::GlobalLogLevelConfigMissing))
|
.map_err(Error::from)
|
||||||
|
.context(EM::TomlQueryError)?
|
||||||
|
.ok_or(err_msg("Global log level config missing"))
|
||||||
.and_then(|s| match_log_level_str(&s))?;
|
.and_then(|s| match_log_level_str(&s))?;
|
||||||
|
|
||||||
if let Some(cli_loglevel) = get_arg_loglevel(matches)? {
|
if let Some(cli_loglevel) = get_arg_loglevel(matches)? {
|
||||||
|
@ -273,7 +275,9 @@ fn translate_destination(raw: &str) -> Result<LogDestination> {
|
||||||
.map(Mutex::new)
|
.map(Mutex::new)
|
||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
.map(LogDestination::File)
|
.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<Value>) -> Result<Vec<LogDestination>> {
|
||||||
acc.and_then(|mut v| {
|
acc.and_then(|mut v| {
|
||||||
let dest = val.as_str()
|
let dest = val.as_str()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
let path = "imag.logging.modules.<mod>.destinations".to_owned();
|
let path = "imag.logging.modules.<mod>.destinations";
|
||||||
let ty = "Array<String>";
|
let ty = "Array<String>";
|
||||||
RE::from_kind(EK::ConfigTypeError(path, ty))
|
Error::from(format_err!("Type error at {}, expected {}", path, ty))
|
||||||
})
|
})
|
||||||
.and_then(translate_destination)?;
|
.and_then(translate_destination)?;
|
||||||
v.push(dest);
|
v.push(dest);
|
||||||
|
@ -299,16 +303,18 @@ fn translate_destinations(raw: &Vec<Value>) -> Result<Vec<LogDestination>> {
|
||||||
fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
|
fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
|
||||||
-> Result<Vec<LogDestination>>
|
-> Result<Vec<LogDestination>>
|
||||||
{
|
{
|
||||||
let config_log_dest_path = "imag.logging.destinations";
|
|
||||||
match config {
|
match config {
|
||||||
Some(cfg) => cfg
|
Some(cfg) => cfg
|
||||||
.read(&config_log_dest_path)?
|
.read("imag.logging.destinations")
|
||||||
.ok_or_else(|| RE::from_kind(EK::GlobalDestinationConfigMissing))?
|
.map_err(Error::from)
|
||||||
|
.context(EM::TomlQueryError)?
|
||||||
|
.ok_or_else(|| err_msg("Global log destination config missing"))?
|
||||||
.as_array()
|
.as_array()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
let path = config_log_dest_path.to_owned();
|
let path = "imag.logging.destinations";
|
||||||
let ty = "Array";
|
let ty = "Array";
|
||||||
RE::from_kind(EK::ConfigTypeError(path, ty))
|
Error::from(format_err!("Type error at {}, expected {}", path, ty))
|
||||||
})
|
})
|
||||||
.and_then(translate_destinations),
|
.and_then(translate_destinations),
|
||||||
None => {
|
None => {
|
||||||
|
@ -330,10 +336,12 @@ fn aggregate_global_destinations(matches: &ArgMatches, config: Option<&Value>)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! aggregate_global_format {
|
macro_rules! aggregate_global_format {
|
||||||
($read_str:expr, $error_kind_if_missing:expr, $config:expr) => {
|
($read_str:expr, $error_msg_if_missing:expr, $config:expr) => {
|
||||||
try!($config.ok_or(RE::from_kind($error_kind_if_missing)))
|
try!($config.ok_or_else(|| Error::from(err_msg($error_msg_if_missing))))
|
||||||
.read_string($read_str)?
|
.read_string($read_str)
|
||||||
.ok_or_else(|| RE::from_kind($error_kind_if_missing))
|
.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<String>
|
-> Result<String>
|
||||||
{
|
{
|
||||||
aggregate_global_format!("imag.logging.format.trace",
|
aggregate_global_format!("imag.logging.format.trace",
|
||||||
EK::ConfigMissingLoggingFormatTrace,
|
"Config missing: Logging format: Trace",
|
||||||
config)
|
config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aggregate_global_format_debug(config: Option<&Value>)
|
fn aggregate_global_format_debug(config: Option<&Value>)
|
||||||
-> Result<String>
|
-> Result<String>
|
||||||
{
|
{
|
||||||
aggregate_global_format!("imag.logging.format.debug",
|
aggregate_global_format!("imag.logging.format.debug",
|
||||||
EK::ConfigMissingLoggingFormatDebug,
|
"Config missing: Logging format: Debug",
|
||||||
config)
|
config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aggregate_global_format_info(config: Option<&Value>)
|
fn aggregate_global_format_info(config: Option<&Value>)
|
||||||
-> Result<String>
|
-> Result<String>
|
||||||
{
|
{
|
||||||
aggregate_global_format!("imag.logging.format.info",
|
aggregate_global_format!("imag.logging.format.info",
|
||||||
EK::ConfigMissingLoggingFormatInfo,
|
"Config missing: Logging format: Info",
|
||||||
config)
|
config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aggregate_global_format_warn(config: Option<&Value>)
|
fn aggregate_global_format_warn(config: Option<&Value>)
|
||||||
-> Result<String>
|
-> Result<String>
|
||||||
{
|
{
|
||||||
aggregate_global_format!("imag.logging.format.warn",
|
aggregate_global_format!("imag.logging.format.warn",
|
||||||
EK::ConfigMissingLoggingFormatWarn,
|
"Config missing: Logging format: Warn",
|
||||||
config)
|
config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aggregate_global_format_error(config: Option<&Value>)
|
fn aggregate_global_format_error(config: Option<&Value>)
|
||||||
-> Result<String>
|
-> Result<String>
|
||||||
{
|
{
|
||||||
aggregate_global_format!("imag.logging.format.error",
|
aggregate_global_format!("imag.logging.format.error",
|
||||||
EK::ConfigMissingLoggingFormatError,
|
"Config missing: Logging format: Error",
|
||||||
config)
|
config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>)
|
fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
|
||||||
-> Result<BTreeMap<ModuleName, ModuleSettings>>
|
-> Result<BTreeMap<ModuleName, ModuleSettings>>
|
||||||
{
|
{
|
||||||
// Helper macro to return the error from Some(Err(_)) and map everything else to an
|
// 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 {
|
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))) => {
|
Ok(Some(&Value::Table(ref t))) => {
|
||||||
// translate the module settings from the table `t`
|
// translate the module settings from the table `t`
|
||||||
let mut settings = BTreeMap::new();
|
let mut settings = BTreeMap::new();
|
||||||
|
|
||||||
for (module_name, v) in t {
|
for (module_name, v) in t {
|
||||||
let destinations = inner_try! {
|
let destinations = inner_try! {
|
||||||
v.read("destinations")?
|
v.read("destinations")
|
||||||
|
.map_err(Error::from)
|
||||||
|
.context(EM::TomlQueryError)?
|
||||||
.map(|val| {
|
.map(|val| {
|
||||||
val.as_array()
|
val.as_array()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
let path = "imag.logging.modules.<mod>.destinations".to_owned();
|
let path = "imag.logging.modules.<mod>.destinations";
|
||||||
let ty = "Array";
|
let ty = "Array";
|
||||||
RE::from_kind(EK::ConfigTypeError(path, ty))
|
Error::from(format_err!("Type error at {}, expected {}", path, ty))
|
||||||
})
|
})
|
||||||
.and_then(translate_destinations)
|
.and_then(translate_destinations)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let level = inner_try! {
|
||||||
let (pre_enabled, level) = if matches.is_present(Runtime::arg_debugging_name()) {
|
v.read_string("level")
|
||||||
(true, Some(Level::Debug))
|
.map_err(Error::from)
|
||||||
} else {
|
.context(EM::TomlQueryError)?
|
||||||
let level = inner_try! {
|
.map(|s| match_log_level_str(&s))
|
||||||
v.read_string("level")?.map(|s| match_log_level_str(&s))
|
|
||||||
};
|
|
||||||
|
|
||||||
(false, level)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let enabled = pre_enabled ||
|
let enabled = v.read("enabled")
|
||||||
v.read("enabled")?
|
.map_err(Error::from)
|
||||||
.map(|v| v.as_bool().unwrap_or(false))
|
.context(EM::TomlQueryError)?
|
||||||
.ok_or_else(|| {
|
.map(|v| v.as_bool().unwrap_or(false))
|
||||||
let path = "imag.logging.modules.<mod>.enabled".to_owned();
|
.ok_or_else(|| {
|
||||||
let ty = "Boolean";
|
let path = "imag.logging.modules.<mod>.enabled";
|
||||||
RE::from_kind(EK::ConfigTypeError(path, ty))
|
let ty = "Boolean";
|
||||||
})?;
|
Error::from(format_err!("Type error at {}, expected {}", path, ty))
|
||||||
|
})?;
|
||||||
|
|
||||||
let module_settings = ModuleSettings {
|
let module_settings = ModuleSettings {
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
|
@ -445,15 +452,15 @@ fn aggregate_module_settings(matches: &ArgMatches, config: Option<&Value>)
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
},
|
},
|
||||||
Ok(Some(_)) => {
|
Ok(Some(_)) => {
|
||||||
let path = "imag.logging.modules".to_owned();
|
let path = "imag.logging.modules";
|
||||||
let ty = "Table";
|
let ty = "Table";
|
||||||
Err(RE::from_kind(EK::ConfigTypeError(path, ty)))
|
Err(Error::from(format_err!("Type error at {}, expected {}", path, ty)))
|
||||||
},
|
},
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
// No modules configured. This is okay!
|
// No modules configured. This is okay!
|
||||||
Ok(BTreeMap::new())
|
Ok(BTreeMap::new())
|
||||||
},
|
},
|
||||||
Err(e) => Err(e).map_err(From::from),
|
Err(e) => Err(e).context(EM::TomlQueryError).map_err(Error::from),
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
write!(stderr(), "No Configuration.").ok();
|
write!(stderr(), "No Configuration.").ok();
|
||||||
|
|
|
@ -30,14 +30,16 @@ use toml::Value;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
|
||||||
use clap::{Arg, ArgMatches};
|
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 configuration::{fetch_config, override_config, InternalConfiguration};
|
||||||
use error::RuntimeError;
|
|
||||||
use error::RuntimeErrorKind;
|
|
||||||
use error::ResultExt;
|
|
||||||
use logger::ImagLogger;
|
use logger::ImagLogger;
|
||||||
use io::OutputProxy;
|
use io::OutputProxy;
|
||||||
|
|
||||||
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
use libimagerror::trace::*;
|
use libimagerror::trace::*;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
||||||
|
@ -62,7 +64,7 @@ impl<'a> Runtime<'a> {
|
||||||
/// and builds the Runtime object with it.
|
/// and builds the Runtime object with it.
|
||||||
///
|
///
|
||||||
/// The cli_app object should be initially build with the ::get_default_cli_builder() function.
|
/// The cli_app object should be initially build with the ::get_default_cli_builder() function.
|
||||||
pub fn new<C>(cli_app: C) -> Result<Runtime<'a>, RuntimeError>
|
pub fn new<C>(cli_app: C) -> Result<Runtime<'a>>
|
||||||
where C: Clone + CliSpec<'a> + InternalConfiguration
|
where C: Clone + CliSpec<'a> + InternalConfiguration
|
||||||
{
|
{
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error;
|
||||||
|
@ -76,17 +78,15 @@ impl<'a> Runtime<'a> {
|
||||||
|
|
||||||
debug!("Config path = {:?}", configpath);
|
debug!("Config path = {:?}", configpath);
|
||||||
|
|
||||||
let config = match fetch_config(&configpath) {
|
let config = match fetch_config(&configpath)? {
|
||||||
Err(e) => if !is_match!(e.kind(), &RuntimeErrorKind::ConfigNoConfigFileFound) {
|
None => {
|
||||||
return Err(e).chain_err(|| RuntimeErrorKind::Instantiate);
|
return Err(err_msg("No configuration file found"))
|
||||||
} else {
|
.context(err_msg("Maybe try to use 'imag-init' to initialize imag?"))
|
||||||
eprintln!("No config file found.");
|
.context(err_msg("Continuing without configuration file"))
|
||||||
eprintln!("Maybe try to use 'imag-init' to initialize imag?");
|
.context(err_msg("Cannot instantiate runtime"))
|
||||||
eprintln!("Continuing without configuration file");
|
.map_err(Error::from);
|
||||||
None
|
|
||||||
},
|
},
|
||||||
|
Some(mut config) => {
|
||||||
Ok(mut config) => {
|
|
||||||
if let Err(e) = override_config(&mut config, get_override_specs(&matches)) {
|
if let Err(e) = override_config(&mut config, get_override_specs(&matches)) {
|
||||||
error!("Could not apply config overrides");
|
error!("Could not apply config overrides");
|
||||||
trace_error(&e);
|
trace_error(&e);
|
||||||
|
@ -102,16 +102,14 @@ impl<'a> Runtime<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the Runtime object using the given `config`.
|
/// Builds the Runtime object using the given `config`.
|
||||||
pub fn with_configuration<C>(cli_app: C, config: Option<Value>)
|
pub fn with_configuration<C>(cli_app: C, config: Option<Value>) -> Result<Runtime<'a>>
|
||||||
-> Result<Runtime<'a>, RuntimeError>
|
|
||||||
where C: Clone + CliSpec<'a> + InternalConfiguration
|
where C: Clone + CliSpec<'a> + InternalConfiguration
|
||||||
{
|
{
|
||||||
let matches = cli_app.clone().matches();
|
let matches = cli_app.clone().matches();
|
||||||
Runtime::_new(cli_app, matches, config)
|
Runtime::_new(cli_app, matches, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _new<C>(cli_app: C, matches: ArgMatches<'a>, config: Option<Value>)
|
fn _new<C>(cli_app: C, matches: ArgMatches<'a>, config: Option<Value>) -> Result<Runtime<'a>>
|
||||||
-> Result<Runtime<'a>, RuntimeError>
|
|
||||||
where C: Clone + CliSpec<'a> + InternalConfiguration
|
where C: Clone + CliSpec<'a> + InternalConfiguration
|
||||||
{
|
{
|
||||||
if cli_app.enable_logging() {
|
if cli_app.enable_logging() {
|
||||||
|
@ -146,7 +144,8 @@ impl<'a> Runtime<'a> {
|
||||||
store: store,
|
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
|
/// Get a editor command object which can be called to open the $EDITOR
|
||||||
pub fn editor(&self) -> Result<Option<Command>, RuntimeError> {
|
pub fn editor(&self) -> Result<Option<Command>> {
|
||||||
self.cli()
|
self.cli()
|
||||||
.value_of("editor")
|
.value_of("editor")
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
|
@ -391,7 +390,7 @@ impl<'a> Runtime<'a> {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.or(env::var("EDITOR").ok())
|
.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))
|
.map_dbg(|s| format!("Editing with '{}'", s))
|
||||||
.and_then(|s| {
|
.and_then(|s| {
|
||||||
let mut split = s.split_whitespace();
|
let mut split = s.split_whitespace();
|
||||||
|
@ -401,7 +400,7 @@ impl<'a> Runtime<'a> {
|
||||||
}
|
}
|
||||||
let mut c = Command::new(command.unwrap()); // secured above
|
let mut c = Command::new(command.unwrap()); // secured above
|
||||||
c.args(split);
|
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());
|
c.stderr(::std::process::Stdio::inherit());
|
||||||
Ok(Some(c))
|
Ok(Some(c))
|
||||||
})
|
})
|
||||||
|
@ -442,8 +441,6 @@ impl<'a> Runtime<'a> {
|
||||||
/// # Return value
|
/// # Return value
|
||||||
///
|
///
|
||||||
/// On success, the exit status object of the `Command` invocation is returned.
|
/// 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
|
/// # Details
|
||||||
///
|
///
|
||||||
|
@ -457,7 +454,7 @@ impl<'a> Runtime<'a> {
|
||||||
command: S,
|
command: S,
|
||||||
subcommand: S,
|
subcommand: S,
|
||||||
args: &ArgMatches)
|
args: &ArgMatches)
|
||||||
-> Result<::std::process::ExitStatus, RuntimeError>
|
-> Result<::std::process::ExitStatus>
|
||||||
{
|
{
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
@ -465,8 +462,7 @@ impl<'a> Runtime<'a> {
|
||||||
let rtp_str = self.rtp()
|
let rtp_str = self.rtp()
|
||||||
.to_str()
|
.to_str()
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.ok_or(RuntimeErrorKind::IOError)
|
.ok_or_else(|| Error::from(EM::IO))?;
|
||||||
.map_err(RuntimeError::from_kind)?;
|
|
||||||
|
|
||||||
let command = format!("{}-{}", command.as_ref(), subcommand.as_ref());
|
let command = format!("{}-{}", command.as_ref(), subcommand.as_ref());
|
||||||
|
|
||||||
|
@ -497,7 +493,8 @@ impl<'a> Runtime<'a> {
|
||||||
},
|
},
|
||||||
_ => e,
|
_ => e,
|
||||||
})
|
})
|
||||||
.map_err(RuntimeError::from)
|
.context(EM::IO)
|
||||||
|
.map_err(Error::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue