From d1728a6aa360a6428b27ce02ae49230561b9d040 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 24 Jul 2016 18:04:51 +0200 Subject: [PATCH 1/4] Add error kinds for config override errors --- libimagrt/src/configuration.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libimagrt/src/configuration.rs b/libimagrt/src/configuration.rs index a2ee1fed..450755fc 100644 --- a/libimagrt/src/configuration.rs +++ b/libimagrt/src/configuration.rs @@ -6,7 +6,12 @@ use toml::{Parser, Value}; generate_error_module!( generate_error_types!(ConfigError, ConfigErrorKind, - NoConfigFileFound => "No config file found" + NoConfigFileFound => "No config file found", + + ConfigOverrideError => "Config override error", + ConfigOverrideKeyNotAvailable => "Key not available", + ConfigOverrideTypeNotMatching => "Configuration Type not matching" + ); ); From 783462899a187d7b6882362eb22ac0feebad1958 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 24 Jul 2016 18:05:06 +0200 Subject: [PATCH 2/4] Add config override functionality --- libimagrt/src/configuration.rs | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/libimagrt/src/configuration.rs b/libimagrt/src/configuration.rs index 450755fc..71056901 100644 --- a/libimagrt/src/configuration.rs +++ b/libimagrt/src/configuration.rs @@ -87,6 +87,72 @@ impl Configuration { } } + /// Override the configuration. + /// The `v` parameter is expected to contain 'key=value' pairs where the key is a path in the + /// TOML tree, the value to be an appropriate value. + /// + /// The override fails if the configuration which is about to be overridden does not exist or + /// the `value` part cannot be converted to the type of the configuration value. + /// + /// If `v` is empty, this is considered to be a successful `override_config()` call. + pub fn override_config(&mut self, v: Vec) -> Result<()> { + use libimagutil::key_value_split::*; + use libimagutil::iter::*; + use self::error::ConfigErrorKind as CEK; + use libimagerror::into::IntoError; + + v.into_iter() + .map(|s| { debug!("Trying to process '{}'", s); s }) + .filter_map(|s| { + match s.into_kv() { + Some(kv) => Some(kv.into()), + None => { + warn!("Could split at '=' - will be ignore override"); + None + } + } + }) + .map(|(k, v)| { + match self.config.lookup_mut(&k[..]) { + Some(value) => { + match into_value(value, v) { + Some(v) => { + *value = v; + info!("Successfully overridden: {} = {}", k, value); + Ok(()) + }, + None => Err(CEK::ConfigOverrideTypeNotMatching.into_error()), + } + }, + None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()), + } + }) + .fold_defresult(|i| i) + .map_err(Box::new) + .map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e)) + } +} + +/// Tries to convert the String `s` into the same type as `value`. +/// +/// Returns None if string cannot be converted. +/// +/// Arrays and Tables are not supported and will yield `None`. +fn into_value(value: &Value, s: String) -> Option { + use std::str::FromStr; + + match value { + &Value::String(_) => Some(Value::String(s)), + &Value::Integer(_) => FromStr::from_str(&s[..]).ok().map(|i| Value::Integer(i)), + &Value::Float(_) => FromStr::from_str(&s[..]).ok().map(|f| Value::Float(f)), + &Value::Boolean(_) => { + if s == "true" { Some(Value::Boolean(true)) } + else if s == "false" { Some(Value::Boolean(false)) } + else { None } + } + &Value::Datetime(_) => Some(Value::Datetime(s)), + _ => None, + } } impl Deref for Configuration { From 6f0670003be5958644d0853018452352f27ca97b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 24 Jul 2016 18:05:29 +0200 Subject: [PATCH 3/4] Add default commandline argument for configuration override --- libimagrt/src/runtime.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libimagrt/src/runtime.rs b/libimagrt/src/runtime.rs index 4f5a705f..e5b31898 100644 --- a/libimagrt/src/runtime.rs +++ b/libimagrt/src/runtime.rs @@ -179,6 +179,12 @@ impl<'a> Runtime<'a> { .required(false) .takes_value(true)) + .arg(Arg::with_name("config-override") + .long("override-config") + .help("Override a configuration settings. Use 'key=value' pairs, where the key is a path in the TOML configuration. The value must be present in the configuration and be convertible to the type of the configuration setting. If the argument does not contain a '=', it gets ignored. Setting Arrays and Tables is not yet supported.") + .required(false) + .takes_value(true)) + .arg(Arg::with_name("runtimepath") .long("rtp") .help("Alternative runtimepath") From 3eedab52064011f219d718bb0fff71ed41e7e1a3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 24 Jul 2016 18:06:01 +0200 Subject: [PATCH 4/4] Add Runtime functionality to patch in-memory-configuration-file-contents on loading application --- libimagrt/src/runtime.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libimagrt/src/runtime.rs b/libimagrt/src/runtime.rs index e5b31898..63678672 100644 --- a/libimagrt/src/runtime.rs +++ b/libimagrt/src/runtime.rs @@ -88,7 +88,16 @@ impl<'a> Runtime<'a> { None }, - Ok(cfg) => Some(cfg), + Ok(mut cfg) => { + if let Err(e) = cfg.override_config(get_override_specs(&matches)) { + error!("Could not apply config overrides"); + trace_error(&e); + + // TODO: continue question (interactive) + } + + Some(cfg) + } }; let store_config = match cfg { @@ -291,3 +300,19 @@ impl<'a> Runtime<'a> { } } +fn get_override_specs(matches: &ArgMatches) -> Vec { + matches + .values_of("config-override") + .map(|values| { + values + .filter(|s| { + let b = s.contains("="); + if !b { warn!("override '{}' does not contain '=' - will be ignored!", s); } + b + }) + .map(String::from) + .collect() + }) + .unwrap_or(vec![]) +} +