From d249f604d83f4c7af92201501713ea52b254468a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 5 Mar 2016 15:02:29 +0100 Subject: [PATCH] Implement: config_is_valid() --- libimagstore/src/configuration.rs | 119 +++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/libimagstore/src/configuration.rs b/libimagstore/src/configuration.rs index c1d91a05..e6f3e619 100644 --- a/libimagstore/src/configuration.rs +++ b/libimagstore/src/configuration.rs @@ -1,8 +1,125 @@ use toml::Value; use hook::position::HookPosition; +/// 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 = " setting +/// * Whether each hook congfiguration has a "aspect = " 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 { - unimplemented!() + use std::collections::BTreeMap; + + fn has_key_with_map(v: &BTreeMap, 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, 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(store_config: &BTreeMap, + 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, + } } pub fn get_pre_read_aspect_names(value: &Value) -> Vec {