summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Ignat <robert.ignat91@gmail.com>2017-06-08 23:35:15 +0200
committerMatthias Beyer <mail@beyermatthias.de>2017-07-13 18:24:20 +0200
commit6ded27c6eac230cbd0ef88793415e33199edaac1 (patch)
tree42fbab6d8e3ab28883607df0155b1445975d9e23
parent9a792324468388bed21dfb737a8c9310bc4aa392 (diff)
Add new `Runtime` constructor
that accepts a Configuration argument; removed `GetConfiguration` trait and all the previous changes needed for it
-rw-r--r--imag-link/src/main.rs21
-rw-r--r--imag-link/test_config.toml43
-rw-r--r--libimagrt/src/configuration.rs166
-rw-r--r--libimagrt/src/runtime.rs122
4 files changed, 163 insertions, 189 deletions
diff --git a/imag-link/src/main.rs b/imag-link/src/main.rs
index f254488b..18354bb0 100644
--- a/imag-link/src/main.rs
+++ b/imag-link/src/main.rs
@@ -350,14 +350,11 @@ mod tests {
use libimagrt::spec::CliSpec;
use libimagrt::runtime::Runtime;
use libimagrt::error::RuntimeError;
- use libimagrt::configuration::{Configuration, GetConfiguration, InternalConfiguration,
- Result as ConfigResult, ConfigErrorKind};
- use libimagrt::configuration::error::MapErrInto;
+ use libimagrt::configuration::{Configuration, InternalConfiguration};
use libimagstore::storeid::StoreId;
use libimagstore::store::{Result as StoreResult, FileLockEntry};
- static TOML_CONFIG_FILE: &[u8] = include_bytes!("../test_config.toml");
static DEFAULT_ENTRY: &str = "\
---\
[imag]\
@@ -392,20 +389,18 @@ version = \"0.3.0\"\
}
}
- impl<'a> GetConfiguration for MockLinkApp<'a> {
- fn get_configuration(&self, _: &PathBuf) -> ConfigResult<Configuration> {
- ::toml::de::from_slice(TOML_CONFIG_FILE)
- .map_err_into(ConfigErrorKind::TOMLParserError)
- .map(Configuration::new)
- }
- }
-
impl<'a> InternalConfiguration for MockLinkApp<'a> {
fn enable_logging(&self) -> bool {
false
}
}
+ fn generate_test_config() -> Option<Configuration> {
+ ::toml::de::from_str("[store]\nimplicit-create=true")
+ .map(Configuration::with_value)
+ .ok()
+ }
+
fn generate_test_runtime<'a>(mut args: Vec<&'static str>) -> Result<Runtime<'a>, RuntimeError> {
let mut cli_args = vec!["imag-link",
"--no-color",
@@ -417,7 +412,7 @@ version = \"0.3.0\"\
cli_args.append(&mut args);
let cli_app = MockLinkApp::new(cli_args);
- Runtime::new(cli_app)
+ Runtime::with_configuration(cli_app, generate_test_config())
}
fn create_test_entry<'a, S: AsRef<OsStr>>(rt: &'a Runtime, name: S) -> StoreResult<StoreId> {
diff --git a/imag-link/test_config.toml b/imag-link/test_config.toml
deleted file mode 100644
index 3041de6f..00000000
--- a/imag-link/test_config.toml
+++ /dev/null
@@ -1,43 +0,0 @@
-[store]
-implicit-create = true
-store-unload-hook-aspects = []
-pre-create-hook-aspects = []
-post-create-hook-aspects = []
-pre-move-hook-aspects = []
-post-move-hook-aspects = []
-pre-retrieve-hook-aspects = []
-post-retrieve-hook-aspects = []
-pre-update-hook-aspects = []
-post-update-hook-aspects = []
-pre-delete-hook-aspects = []
-post-delete-hook-aspects = []
-
-[store.aspects.debug]
-parallel = false
-
-[store.aspects.vcs]
-parallel = false
-
-[store.hooks.stdhook_debug]
-aspect = "vcs"
-
-[store.hooks.stdhook_git_update]
-aspect = "vcs"
-enabled = false
-
-[store.hooks.stdhook_git_update.commit]
-enabled = false
-
-[store.hooks.stdhook_git_delete]
-aspect = "vcs"
-enabled = false
-
-[store.hooks.stdhook_git_delete.commit]
-enabled = false
-
-[store.hooks.stdhook_git_storeunload]
-aspect = "vcs"
-enabled = false
-
-[store.hooks.stdhook_git_storeunload.commit]
-enabled = false
diff --git a/libimagrt/src/configuration.rs b/libimagrt/src/configuration.rs
index 78902c41..15e54356 100644
--- a/libimagrt/src/configuration.rs
+++ b/libimagrt/src/configuration.rs
@@ -73,21 +73,33 @@ impl Configuration {
/// with all variants.
///
/// If that doesn't work either, an error is returned.
- pub fn new(toml_config: Value) -> Configuration {
- let verbosity = get_verbosity(&toml_config);
- let editor = get_editor(&toml_config);
- let editor_opts = get_editor_opts(&toml_config);
-
- debug!("Building configuration");
- debug!(" - verbosity : {:?}", verbosity);
- debug!(" - editor : {:?}", editor);
- debug!(" - editor-opts: {}", editor_opts);
-
- Configuration {
- config: toml_config,
- verbosity: verbosity,
- editor: editor,
- editor_opts: editor_opts,
+ pub fn new(rtp: &PathBuf) -> Result<Configuration> {
+ fetch_config(&rtp).map(|cfg| {
+ let verbosity = get_verbosity(&cfg);
+ let editor = get_editor(&cfg);
+ let editor_opts = get_editor_opts(&cfg);
+
+ debug!("Building configuration");
+ debug!(" - verbosity : {:?}", verbosity);
+ debug!(" - editor : {:?}", editor);
+ debug!(" - editor-opts: {}", editor_opts);
+
+ Configuration {
+ config: cfg,
+ verbosity: verbosity,
+ editor: editor,
+ editor_opts: editor_opts,
+ }
+ })
+ }
+
+ /// Get a new configuration object built from the given toml value.
+ pub fn with_value(value: Value) -> Configuration {
+ Configuration{
+ verbosity: get_verbosity(&value),
+ editor: get_editor(&value),
+ editor_opts: get_editor_opts(&value),
+ config: value,
}
}
@@ -211,74 +223,68 @@ fn get_editor_opts(v: &Value) -> String {
}
}
-pub trait GetConfiguration {
- /// Helper to fetch the config file
- ///
- /// Default implementation tests several variants for the config file path and uses the first
- /// one which works.
- fn get_configuration(&self, rtp: &PathBuf) -> Result<Configuration> {
- use std::env;
- use std::fs::File;
- use std::io::Read;
- use std::io::Write;
- use std::io::stderr;
-
- use xdg_basedir;
- use itertools::Itertools;
-
- use libimagutil::variants::generate_variants as gen_vars;
- use libimagerror::trace::trace_error;
-
- let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
- let modifier = |base: &PathBuf, v: &'static str| {
- let mut base = base.clone();
- base.push(String::from(v));
- base
- };
-
- vec![
- vec![rtp.clone()],
- gen_vars(rtp.clone(), variants.clone(), &modifier),
-
- env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
- .unwrap_or(vec![]),
-
- xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
- .unwrap_or(vec![]),
- ].iter()
- .flatten()
- .filter(|path| path.exists() && path.is_file())
- .map(|path| {
- let content = {
- let mut s = String::new();
- let f = File::open(path);
- if f.is_err() {
- return None
- }
- let mut f = f.unwrap();
- f.read_to_string(&mut s).ok();
- s
- };
-
- match ::toml::de::from_str(&content[..]) {
- Ok(res) => res,
- Err(e) => {
- write!(stderr(), "Config file parser error:").ok();
- trace_error(&e);
- None
- }
+/// Helper to fetch the config file
+///
+/// Tests several variants for the config file path and uses the first one which works.
+fn fetch_config(rtp: &PathBuf) -> Result<Value> {
+ use std::env;
+ use std::fs::File;
+ use std::io::Read;
+ use std::io::Write;
+ use std::io::stderr;
+
+ use xdg_basedir;
+ use itertools::Itertools;
+
+ use libimagutil::variants::generate_variants as gen_vars;
+ use libimagerror::trace::trace_error;
+
+ let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
+ let modifier = |base: &PathBuf, v: &'static str| {
+ let mut base = base.clone();
+ base.push(String::from(v));
+ base
+ };
+
+ vec![
+ vec![rtp.clone()],
+ gen_vars(rtp.clone(), variants.clone(), &modifier),
+
+ env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
+ .unwrap_or(vec![]),
+
+ xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
+ .unwrap_or(vec![]),
+ ].iter()
+ .flatten()
+ .filter(|path| path.exists() && path.is_file())
+ .map(|path| {
+ let content = {
+ let mut s = String::new();
+ let f = File::open(path);
+ if f.is_err() {
+ return None
}
- })
- .filter(|loaded| loaded.is_some())
- .nth(0)
- .map(|inner| Value::Table(inner.unwrap()))
- .ok_or(ConfigErrorKind::NoConfigFileFound.into())
- .map(Configuration::new)
- }
+ let mut f = f.unwrap();
+ f.read_to_string(&mut s).ok();
+ s
+ };
+
+ match ::toml::de::from_str(&content[..]) {
+ Ok(res) => res,
+ Err(e) => {
+ write!(stderr(), "Config file parser error:").ok();
+ trace_error(&e);
+ None
+ }
+ }
+ })
+ .filter(|loaded| loaded.is_some())
+ .nth(0)
+ .map(|inner| Value::Table(inner.unwrap()))
+ .ok_or(ConfigErrorKind::NoConfigFileFound.into())
}
-impl<'a> GetConfiguration for App<'a, 'a> {}
-
pub trait InternalConfiguration {
fn enable_logging(&self) -> bool {
true
diff --git a/libimagrt/src/runtime.rs b/libimagrt/src/runtime.rs
index 57f4f170..0ec1de19 100644
--- a/libimagrt/src/runtime.rs
+++ b/libimagrt/src/runtime.rs
@@ -29,7 +29,7 @@ use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;
-use configuration::{Configuration, GetConfiguration, InternalConfiguration};
+use configuration::{Configuration, InternalConfiguration};
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::MapErrInto;
@@ -56,14 +56,9 @@ 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<C>(mut cli_app: C) -> Result<Runtime<'a>, RuntimeError>
- where C: Clone + CliSpec<'a> + GetConfiguration + InternalConfiguration
+ pub fn new<C>(cli_app: C) -> Result<Runtime<'a>, RuntimeError>
+ where C: Clone + CliSpec<'a> + InternalConfiguration
{
- use std::env;
- use std::io::stdout;
-
- use clap::Shell;
-
use libimagerror::trace::trace_error;
use libimagerror::into::IntoError;
@@ -71,11 +66,51 @@ impl<'a> Runtime<'a> {
let matches = cli_app.clone().matches();
- let is_debugging = matches.is_present("debugging");
- let is_verbose = matches.is_present("verbosity");
- let colored = !matches.is_present("no-color-output");
+ let rtp = get_rtp_match(&matches);
+
+ let configpath = matches.value_of(Runtime::arg_config_name())
+ .map_or_else(|| rtp.clone(), PathBuf::from);
+
+ let config = match Configuration::new(&configpath) {
+ Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
+ return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
+ } else {
+ warn!("No config file found.");
+ warn!("Continuing without configuration file");
+ None
+ },
+
+ Ok(mut config) => {
+ if let Err(e) = config.override_config(get_override_specs(&matches)) {
+ error!("Could not apply config overrides");
+ trace_error(&e);
+
+ // TODO: continue question (interactive)
+ }
+
+ Some(config)
+ }
+ };
+
+ Runtime::with_configuration(cli_app, config)
+ }
+
+ /// Builds the Runtime object using the given `config`.
+ pub fn with_configuration<C>(mut cli_app: C, config: Option<Configuration>) -> Result<Runtime<'a>, RuntimeError>
+ where C: Clone + CliSpec<'a> + InternalConfiguration
+ {
+ use std::io::stdout;
+
+ use clap::Shell;
+
+ let matches = cli_app.clone().matches();
+
+ let is_debugging = matches.is_present(Runtime::arg_debugging_name());
if cli_app.enable_logging() {
+ let is_verbose = matches.is_present(Runtime::arg_verbosity_name());
+ let colored = !matches.is_present(Runtime::arg_no_color_output_name());
+
Runtime::init_logger(is_debugging, is_verbose, colored);
}
@@ -89,64 +124,29 @@ impl<'a> Runtime<'a> {
_ => debug!("Not generating shell completion script"),
}
- let rtp : PathBuf = matches.value_of("runtimepath")
- .map_or_else(|| {
- env::var("HOME")
- .map(PathBuf::from)
- .map(|mut p| { p.push(".imag"); p})
- .unwrap_or_else(|_| {
- panic!("You seem to be $HOME-less. Please get a $HOME before using this software. We are sorry for you and hope you have some accommodation anyways.");
- })
- }, PathBuf::from);
- let storepath = matches.value_of("storepath")
+ let rtp = get_rtp_match(&matches);
+
+ let storepath = matches.value_of(Runtime::arg_storepath_name())
.map_or_else(|| {
let mut spath = rtp.clone();
spath.push("store");
spath
}, PathBuf::from);
- let configpath = matches.value_of("config")
- .map_or_else(|| rtp.clone(), PathBuf::from);
-
- debug!("RTP path = {:?}", rtp);
- debug!("Store path = {:?}", storepath);
- debug!("Config path = {:?}", configpath);
-
- let cfg = match cli_app.get_configuration(&configpath) {
- Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
- return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
- } else {
- warn!("No config file found.");
- warn!("Continuing without configuration file");
- None
- },
-
- 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 {
+ let store_config = match config {
Some(ref c) => c.store_config().cloned(),
None => None,
};
if is_debugging {
- write!(stderr(), "Config: {:?}\n", cfg).ok();
+ write!(stderr(), "Config: {:?}\n", config).ok();
write!(stderr(), "Store-config: {:?}\n", store_config).ok();
}
- Store::new(storepath.clone(), store_config).map(|store| {
+ Store::new(storepath, store_config).map(|store| {
Runtime {
cli_matches: matches,
- configuration: cfg,
+ configuration: config,
rtp: rtp,
store: store,
}
@@ -408,6 +408,22 @@ impl<'a> Runtime<'a> {
}
}
+fn get_rtp_match<'a>(matches: &ArgMatches<'a>) -> PathBuf {
+ use std::env;
+
+ matches.value_of(Runtime::arg_runtimepath_name())
+ .map_or_else(|| {
+ env::var("HOME")
+ .map(PathBuf::from)
+ .map(|mut p| { p.push(".imag"); p })
+ .unwrap_or_else(|_| {
+ panic!("You seem to be $HOME-less. Please get a $HOME before using this \
+ software. We are sorry for you and hope you have some \
+ accommodation anyways.");
+ })
+ }, PathBuf::from)
+}
+
fn get_override_specs(matches: &ArgMatches) -> Vec<String> {
matches
.values_of("config-override")