imag/libimagstore/src/configuration.rs

234 lines
8.0 KiB
Rust
Raw Normal View History

use toml::Value;
2016-03-05 10:37:06 +00:00
use hook::position::HookPosition;
2016-03-05 14:02:29 +00:00
/// Check whether the configuration is valid for the store
///
/// The passed `Value` _must be_ the `[store]` sub-tree of the configuration. Otherwise this will
/// fail.
///
/// It checks whether the configuration looks like the store wants it to be:
///
/// ```toml
/// [store]
/// pre-create-hook-aspects = [ "misc", "encryption", "version-control"]
///
/// [[aspects.misc]]
/// parallel = true
/// [[aspects.encryption]]
/// parallel = false
/// [[aspects.version-control]]
/// parallel = false
///
/// [[hooks.gnupg]]
/// aspect = "encryption"
/// key = "0x123456789"
///
/// [[hooks.git]]
/// aspect = "version-control"
/// ```
///
/// It checks:
/// * Whether all the maps are there (whether store, store.aspects, store.aspects.example are all
/// maps)
/// * Whether each aspect configuration has a "parallel = <Boolean>" setting
/// * Whether each hook congfiguration has a "aspect = <String>" setting
///
/// It does NOT check:
/// * Whether all aspects which are used in the hook configuration are also configured
///
pub fn config_is_valid(config: &Value) -> bool {
2016-03-05 14:02:29 +00:00
use std::collections::BTreeMap;
fn has_key_with_map(v: &BTreeMap<String, Value>, key: &str) -> bool {
v.get(key).map(|t| match t { &Value::Table(_) => true, _ => false }).unwrap_or(false)
}
fn has_key_with_string_ary(v: &BTreeMap<String, Value>, key: &str) -> bool {
v.get(key)
.map(|t| match t {
&Value::Array(ref a) => a.iter().all(|elem| {
match elem {
&Value::String(_) => true,
_ => false,
}
}),
_ => false
}).unwrap_or(false)
}
/// Check that
/// * the top-level configuration
/// * is a table
/// * where all entries of a key `section` (eg. "hooks" or "aspects")
/// * Are maps
/// * where each has a key `key` (eg. "aspect" or "parallel")
/// * which fullfills constraint `f` (typecheck)
fn check_all_inner_maps_have_key_with<F>(store_config: &BTreeMap<String, Value>,
section: &str,
key: &str,
f: F)
-> bool
where F: Fn(&Value) -> bool
{
store_config.get(section) // The store config has the section `section`
.map(|section_table| {
match section_table { // which is
&Value::Table(ref section_table) => // a table
section_table
.values() // which has values,
.all(|cfg| { // and all of these values
match cfg {
&Value::Table(ref hook_config) => { // are tables
hook_config.get(key) // with a key
// fullfilling this constraint
.map(|hook_aspect| f(&hook_aspect))
.unwrap_or(false)
},
_ => false,
}
}),
_ => false,
}
})
.unwrap_or(false)
}
match config {
&Value::Table(ref t) => {
has_key_with_string_ary(t, "pre-read-hook-aspects") &&
has_key_with_string_ary(t, "post-read-hook-aspects") &&
has_key_with_string_ary(t, "pre-create-hook-aspects") &&
has_key_with_string_ary(t, "post-create-hook-aspects") &&
has_key_with_string_ary(t, "pre-retrieve-hook-aspects") &&
has_key_with_string_ary(t, "post-retrieve-hook-aspects") &&
has_key_with_string_ary(t, "pre-update-hook-aspects") &&
has_key_with_string_ary(t, "post-update-hook-aspects") &&
has_key_with_string_ary(t, "pre-delete-hook-aspects") &&
has_key_with_string_ary(t, "post-delete-hook-aspects") &&
// The section "hooks" has maps which have a key "aspect" which has a value of type
// String
check_all_inner_maps_have_key_with(t, "hooks", "aspect", |asp| {
match asp { &Value::String(_) => true, _ => false }
}) &&
// The section "aspects" has maps which have a key "parllel" which has a value of type
// Boolean
check_all_inner_maps_have_key_with(t, "aspects", "parallel", |asp| {
match asp { &Value::Boolean(_) => true, _ => false, }
})
}
_ => false,
}
2016-03-05 10:37:06 +00:00
}
pub fn get_pre_read_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("pre-read-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_post_read_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("post-read-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_pre_create_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("pre-create-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_post_create_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("post-create-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_pre_retrieve_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("pre-retrieve-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_post_retrieve_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("post-retrieve-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_pre_update_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("pre-update-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_post_update_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("post-update-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_pre_delete_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("pre-delete-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
pub fn get_post_delete_aspect_names(value: &Value) -> Vec<String> {
2016-03-05 15:05:31 +00:00
get_aspect_names_for_aspect_position("post-delete-hook-aspects", value)
2016-03-05 10:37:06 +00:00
}
2016-03-05 15:17:07 +00:00
#[derive(Debug)]
pub struct AspectConfig {
parallel: bool,
config: Value,
}
impl AspectConfig {
pub fn new(init: Value) -> AspectConfig {
let parallel = AspectConfig::is_parallel(&init);
AspectConfig {
config: init,
parallel: parallel,
}
}
pub fn config(&self) -> &Value {
&self.config
}
fn is_parallel(init: &Value) -> bool {
match init {
&Value::Table(ref t) =>
t.get("parallel")
.map(|value| {
match value {
&Value::Boolean(b) => b,
_ => false,
}
})
.unwrap_or(false),
_ => false,
}
}
/// Get the aspect configuration for an aspect.
///
/// Pass the store configuration object, this searches in `[aspects][<aspect_name>]`.
///
/// Returns `None` if one of the keys in the chain is not available
fn get_for(v: Value, aspect_name: &str) -> Option<AspectConfig> {
unimplemented!()
}
}
2016-03-05 15:05:31 +00:00
fn get_aspect_names_for_aspect_position(config_name: &'static str, value: &Value) -> Vec<String> {
let mut v = vec![];
match value {
&Value::Table(ref t) => {
match t.get(config_name) {
Some(&Value::Array(ref a)) => {
for elem in a {
match elem {
&Value::String(ref s) => v.push(s.clone()),
_ => warn!("Non-String in configuration, inside '{}'", config_name),
}
}
},
_ => warn!("'{}' configuration key should contain Array, does not", config_name),
};
},
_ => warn!("Configuration is not a table"),
}
v
2016-03-05 10:37:06 +00:00
}
2016-03-05 15:05:31 +00:00