Merge pull request #1018 from matthiasbeyer/remove-toml-ext

Remove toml ext
This commit is contained in:
Matthias Beyer 2017-08-28 14:10:40 +02:00 committed by GitHub
commit c987130cc1
38 changed files with 219 additions and 999 deletions

View file

@ -23,6 +23,7 @@ itertools = "0.5"
tempfile = "2.1"
ansi_term = "0.9"
is-match = "0.1"
toml-query = "0.3.0"
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }

View file

@ -133,7 +133,8 @@ impl Configuration {
use self::error::ConfigErrorKind as CEK;
use self::error::MapErrInto;
use libimagerror::into::IntoError;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
v.into_iter()
.map(|s| { debug!("Trying to process '{}'", s); s })
@ -170,10 +171,10 @@ impl Configuration {
/// 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<Value> {
fn into_value(value: &Value, s: String) -> Option<Value> {
use std::str::FromStr;
match value {
match *value {
Value::String(_) => Some(Value::String(s)),
Value::Integer(_) => FromStr::from_str(&s[..]).ok().map(Value::Integer),
Value::Float(_) => FromStr::from_str(&s[..]).ok().map(Value::Float),

View file

@ -42,6 +42,7 @@ extern crate ansi_term;
extern crate clap;
extern crate toml;
extern crate toml_query;
#[macro_use] extern crate is_match;
extern crate libimagstore;

View file

@ -60,5 +60,4 @@ pub mod error;
pub mod store;
mod configuration;
pub mod file_abstraction;
pub mod toml_ext;

View file

@ -18,6 +18,7 @@
//
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
@ -32,15 +33,16 @@ use std::fmt::Debug;
use std::fmt::Error as FMTError;
use toml::Value;
use toml::value::Table;
use glob::glob;
use walkdir::WalkDir;
use walkdir::Iter as WalkDirIter;
use error::{StoreError as SE, StoreErrorKind as SEK};
use error::{StoreError as SE, StoreErrorKind as SEK, ParserError, ParserErrorKind};
use error::MapErrInto;
use storeid::{IntoStoreId, StoreId, StoreIdIterator};
use file_abstraction::FileAbstractionInstance;
use toml_ext::*;
// We re-export the following things so tests can use them
pub use file_abstraction::FileAbstraction;
pub use file_abstraction::FSFileAbstraction;
@ -1115,6 +1117,96 @@ mod glob_store_iter {
}
/// Extension trait for top-level toml::Value::Table, will only yield correct results on the
/// top-level Value::Table, but not on intermediate tables.
pub trait Header {
fn verify(&self) -> Result<()>;
fn parse(s: &str) -> RResult<Value, ParserError>;
fn default_header() -> Value;
}
impl Header for Value {
fn verify(&self) -> Result<()> {
match *self {
Value::Table(ref t) => verify_header(&t),
_ => Err(SE::new(SEK::HeaderTypeFailure, None)),
}
}
fn parse(s: &str) -> RResult<Value, ParserError> {
use toml::de::from_str;
from_str(s)
.map_err(|_| ParserErrorKind::TOMLParserErrors.into())
.and_then(verify_header_consistency)
.map(Value::Table)
}
fn default_header() -> Value {
let mut m = BTreeMap::new();
m.insert(String::from("imag"), {
let mut imag_map = BTreeMap::<String, Value>::new();
imag_map.insert(String::from("version"), Value::String(String::from(version!())));
imag_map.insert(String::from("links"), Value::Array(vec![]));
Value::Table(imag_map)
});
Value::Table(m)
}
}
fn verify_header_consistency(t: Table) -> RResult<Table, ParserError> {
verify_header(&t)
.map_err(Box::new)
.map_err(|e| ParserErrorKind::HeaderInconsistency.into_error_with_cause(e))
.map(|_| t)
}
fn verify_header(t: &Table) -> Result<()> {
if !has_main_section(t) {
Err(SE::from(ParserErrorKind::MissingMainSection.into_error()))
} else if !has_imag_version_in_main_section(t) {
Err(SE::from(ParserErrorKind::MissingVersionInfo.into_error()))
} else if !has_only_tables(t) {
debug!("Could not verify that it only has tables in its base table");
Err(SE::from(ParserErrorKind::NonTableInBaseTable.into_error()))
} else {
Ok(())
}
}
fn has_only_tables(t: &Table) -> bool {
debug!("Verifying that table has only tables");
t.iter().all(|(_, x)| is_match!(*x, Value::Table(_)))
}
fn has_main_section(t: &Table) -> bool {
t.contains_key("imag") && is_match!(t.get("imag"), Some(&Value::Table(_)))
}
fn has_imag_version_in_main_section(t: &Table) -> bool {
use semver::Version;
match *t.get("imag").unwrap() {
Value::Table(ref sec) => {
sec.get("version")
.and_then(|v| {
match *v {
Value::String(ref s) => Some(Version::parse(&s[..]).is_ok()),
_ => Some(false),
}
})
.unwrap_or(false)
}
_ => false,
}
}
#[cfg(test)]
mod test {
@ -1122,13 +1214,14 @@ mod test {
use std::collections::BTreeMap;
use storeid::StoreId;
use store::has_main_section;
use store::has_imag_version_in_main_section;
use store::verify_header_consistency;
use toml::Value;
#[test]
fn test_imag_section() {
use toml_ext::has_main_section;
let mut map = BTreeMap::new();
map.insert("imag".into(), Value::Table(BTreeMap::new()));
@ -1137,8 +1230,6 @@ mod test {
#[test]
fn test_imag_invalid_section_type() {
use toml_ext::has_main_section;
let mut map = BTreeMap::new();
map.insert("imag".into(), Value::Boolean(false));
@ -1147,8 +1238,6 @@ mod test {
#[test]
fn test_imag_abscent_main_section() {
use toml_ext::has_main_section;
let mut map = BTreeMap::new();
map.insert("not_imag".into(), Value::Boolean(false));
@ -1157,8 +1246,6 @@ mod test {
#[test]
fn test_main_section_without_version() {
use toml_ext::has_imag_version_in_main_section;
let mut map = BTreeMap::new();
map.insert("imag".into(), Value::Table(BTreeMap::new()));
@ -1167,8 +1254,6 @@ mod test {
#[test]
fn test_main_section_with_version() {
use toml_ext::has_imag_version_in_main_section;
let mut map = BTreeMap::new();
let mut sub = BTreeMap::new();
sub.insert("version".into(), Value::String("0.0.0".into()));
@ -1179,8 +1264,6 @@ mod test {
#[test]
fn test_main_section_with_version_in_wrong_type() {
use toml_ext::has_imag_version_in_main_section;
let mut map = BTreeMap::new();
let mut sub = BTreeMap::new();
sub.insert("version".into(), Value::Boolean(false));
@ -1191,8 +1274,6 @@ mod test {
#[test]
fn test_verification_good() {
use toml_ext::verify_header_consistency;
let mut header = BTreeMap::new();
let sub = {
let mut sub = BTreeMap::new();
@ -1208,8 +1289,6 @@ mod test {
#[test]
fn test_verification_invalid_versionstring() {
use toml_ext::verify_header_consistency;
let mut header = BTreeMap::new();
let sub = {
let mut sub = BTreeMap::new();
@ -1226,8 +1305,6 @@ mod test {
#[test]
fn test_verification_current_version() {
use toml_ext::verify_header_consistency;
let mut header = BTreeMap::new();
let sub = {
let mut sub = BTreeMap::new();

View file

@ -1,894 +0,0 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 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
//
use std::result::Result as RResult;
use std::collections::BTreeMap;
use toml::Value;
use store::Result;
use error::StoreError as SE;
use error::StoreErrorKind as SEK;
use error::{ParserErrorKind, ParserError};
use libimagerror::into::IntoError;
type Table = BTreeMap<String, Value>;
pub trait TomlValueExt {
fn insert_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result<bool>;
fn set_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result<Option<Value>>;
fn read_with_sep(&self, spec: &str, splitchr: char) -> Result<Option<Value>>;
fn delete_with_sep(&mut self, spec: &str, splitchr: char) -> Result<Option<Value>>;
#[inline]
fn insert(&mut self, spec: &str, v: Value) -> Result<bool> {
self.insert_with_sep(spec, '.', v)
}
#[inline]
fn set(&mut self, spec: &str, v: Value) -> Result<Option<Value>> {
self.set_with_sep(spec, '.', v)
}
#[inline]
fn read(&self, spec: &str) -> Result<Option<Value>> {
self.read_with_sep(spec, '.')
}
#[inline]
fn delete(&mut self, spec: &str) -> Result<Option<Value>> {
self.delete_with_sep(spec, '.')
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Token {
Key(String),
Index(usize),
}
impl TomlValueExt for Value {
/**
* Insert a header field by a string-spec
*
* ```ignore
* insert("something.in.a.field", Boolean(true));
* ```
*
* If an array field was accessed which is _out of bounds_ of the array available, the element
* is appended to the array.
*
* Inserts a Boolean in the section "something" -> "in" -> "a" -> "field"
* A JSON equivalent would be
*
* {
* something: {
* in: {
* a: {
* field: true
* }
* }
* }
* }
*
* Returns true if header field was set, false if there is already a value
*/
fn insert_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result<bool> {
let (destination, value) = try!(setup(self, spec, sep));
// There is already an value at this place
if value.extract(&destination).is_ok() {
return Ok(false);
}
match destination {
// if the destination shall be an map key
Token::Key(ref s) => match *value {
/*
* Put it in there if we have a map
*/
Value::Table(ref mut t) => { t.insert(s.clone(), v); },
/*
* Fail if there is no map here
*/
_ => return Err(SEK::HeaderPathTypeFailure.into_error()),
},
// if the destination shall be an array
Token::Index(i) => match *value {
/*
* Put it in there if we have an array
*/
Value::Array(ref mut a) => {
a.push(v); // push to the end of the array
// if the index is inside the array, we swap-remove the element at this
// index
if a.len() < i {
a.swap_remove(i);
}
},
/*
* Fail if there is no array here
*/
_ => return Err(SEK::HeaderPathTypeFailure.into_error()),
},
}
Ok(true)
}
/**
* Set a header field by a string-spec
*
* ```ignore
* set("something.in.a.field", Boolean(true));
* ```
*
* Sets a Boolean in the section "something" -> "in" -> "a" -> "field"
* A JSON equivalent would be
*
* {
* something: {
* in: {
* a: {
* field: true
* }
* }
* }
* }
*
* If there is already a value at this place, this value will be overridden and the old value
* will be returned
*/
fn set_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result<Option<Value>> {
let (destination, value) = try!(setup(self, spec, sep));
match destination {
// if the destination shall be an map key->value
Token::Key(ref s) => match *value {
/*
* Put it in there if we have a map
*/
Value::Table(ref mut t) => {
debug!("Matched Key->Table");
return Ok(t.insert(s.clone(), v));
}
/*
* Fail if there is no map here
*/
_ => {
debug!("Matched Key->NON-Table");
return Err(SEK::HeaderPathTypeFailure.into_error());
}
},
// if the destination shall be an array
Token::Index(i) => match *value {
/*
* Put it in there if we have an array
*/
Value::Array(ref mut a) => {
debug!("Matched Index->Array");
a.push(v); // push to the end of the array
// if the index is inside the array, we swap-remove the element at this
// index
if a.len() > i {
debug!("Swap-Removing in Array {:?}[{:?}] <- {:?}", a, i, a[a.len()-1]);
return Ok(Some(a.swap_remove(i)));
}
debug!("Appended");
return Ok(None);
},
/*
* Fail if there is no array here
*/
_ => {
debug!("Matched Index->NON-Array");
return Err(SEK::HeaderPathTypeFailure.into_error());
},
},
}
}
/**
* Read a header field by a string-spec
*
* ```ignore
* let value = read("something.in.a.field");
* ```
*
* Reads a Value in the section "something" -> "in" -> "a" -> "field"
* A JSON equivalent would be
*
* {
* something: {
* in: {
* a: {
* field: true
* }
* }
* }
* }
*
* If there is no a value at this place, None will be returned. This also holds true for Arrays
* which are accessed at an index which is not yet there, even if the accessed index is much
* larger than the array length.
*/
fn read_with_sep(&self, spec: &str, splitchr: char) -> Result<Option<Value>> {
let tokens = try!(tokenize(spec, splitchr));
let mut header_clone = self.clone(); // we clone as READing is simpler this way
// walk N-1 tokens
match walk_header(&mut header_clone, tokens) {
Err(e) => match e.err_type() {
// We cannot find the header key, as there is no path to it
SEK::HeaderKeyNotFound => Ok(None),
_ => Err(e),
},
Ok(v) => Ok(Some(v.clone())),
}
}
fn delete_with_sep(&mut self, spec: &str, splitchr: char) -> Result<Option<Value>> {
let (destination, value) = try!(setup(self, spec, splitchr));
match destination {
// if the destination shall be an map key->value
Token::Key(ref s) => match *value {
Value::Table(ref mut t) => {
debug!("Matched Key->Table, removing {:?}", s);
return Ok(t.remove(s));
},
_ => {
debug!("Matched Key->NON-Table");
return Err(SEK::HeaderPathTypeFailure.into_error());
}
},
// if the destination shall be an array
Token::Index(i) => match *value {
// if the index is inside the array, we swap-remove the element at this
// index
Value::Array(ref mut a) => if a.len() > i {
debug!("Removing in Array {:?}[{:?}]", a, i);
return Ok(Some(a.remove(i)));
} else {
return Ok(None);
},
_ => {
debug!("Matched Index->NON-Array");
return Err(SEK::HeaderPathTypeFailure.into_error());
},
},
}
}
}
fn setup<'a>(v: &'a mut Value, spec: &str, sep: char)
-> Result<(Token, &'a mut Value)>
{
let tokens = try!(tokenize(spec, sep));
debug!("tokens = {:?}", tokens);
let destination = try!(tokens.iter().last().cloned().ok_or(SEK::HeaderPathSyntaxError.into_error()));
debug!("destination = {:?}", destination);
let path_to_dest : Vec<Token> = tokens[..(tokens.len() - 1)].into(); // N - 1 tokens
let value = try!(walk_header(v, path_to_dest)); // walk N-1 tokens
debug!("walked value = {:?}", value);
Ok((destination, value))
}
fn tokenize(spec: &str, splitchr: char) -> Result<Vec<Token>> {
use std::str::FromStr;
spec.split(splitchr)
.map(|s| usize::from_str(s).map(Token::Index).or_else(|_| Ok(Token::Key(String::from(s)))))
.collect()
}
fn walk_header(v: &mut Value, tokens: Vec<Token>) -> Result<&mut Value> {
use std::vec::IntoIter;
fn walk_iter<'a>(v: Result<&'a mut Value>, i: &mut IntoIter<Token>) -> Result<&'a mut Value> {
let next = i.next();
v.and_then(move |value| if let Some(token) = next {
walk_iter(value.extract(&token), i)
} else {
Ok(value)
})
}
walk_iter(Ok(v), &mut tokens.into_iter())
}
trait Extract {
fn extract<'a>(&'a mut self, &Token) -> Result<&'a mut Self>;
}
impl Extract for Value {
fn extract<'a>(&'a mut self, token: &Token) -> Result<&'a mut Value> {
match *token {
// on Token::Key extract from Value::Table
Token::Key(ref s) => match *self {
Value::Table(ref mut t) =>
t.get_mut(&s[..]).ok_or(SEK::HeaderKeyNotFound.into_error()),
_ => Err(SEK::HeaderPathTypeFailure.into_error()),
},
// on Token::Index extract from Value::Array
Token::Index(i) => match *self {
Value::Array(ref mut a) => if a.len() < i {
Err(SEK::HeaderKeyNotFound.into_error())
} else {
Ok(&mut a[i])
},
_ => Err(SEK::HeaderPathTypeFailure.into_error()),
}
}
}
}
pub type EntryResult<T> = RResult<T, ParserError>;
/// Extension trait for top-level toml::Value::Table, will only yield correct results on the
/// top-level Value::Table, but not on intermediate tables.
pub trait Header {
fn verify(&self) -> Result<()>;
fn parse(s: &str) -> EntryResult<Value>;
fn default_header() -> Value;
}
impl Header for Value {
fn verify(&self) -> Result<()> {
match *self {
Value::Table(ref t) => verify_header(&t),
_ => Err(SE::new(SEK::HeaderTypeFailure, None)),
}
}
fn parse(s: &str) -> EntryResult<Value> {
use toml::de::from_str;
from_str(s)
.map_err(|_| ParserErrorKind::TOMLParserErrors.into())
.and_then(verify_header_consistency)
.map(Value::Table)
}
fn default_header() -> Value {
let mut m = BTreeMap::new();
m.insert(String::from("imag"), {
let mut imag_map = BTreeMap::<String, Value>::new();
imag_map.insert(String::from("version"), Value::String(String::from(version!())));
imag_map.insert(String::from("links"), Value::Array(vec![]));
Value::Table(imag_map)
});
Value::Table(m)
}
}
pub fn verify_header_consistency(t: Table) -> EntryResult<Table> {
verify_header(&t)
.map_err(Box::new)
.map_err(|e| ParserErrorKind::HeaderInconsistency.into_error_with_cause(e))
.map(|_| t)
}
fn verify_header(t: &Table) -> Result<()> {
if !has_main_section(t) {
Err(SE::from(ParserErrorKind::MissingMainSection.into_error()))
} else if !has_imag_version_in_main_section(t) {
Err(SE::from(ParserErrorKind::MissingVersionInfo.into_error()))
} else if !has_only_tables(t) {
debug!("Could not verify that it only has tables in its base table");
Err(SE::from(ParserErrorKind::NonTableInBaseTable.into_error()))
} else {
Ok(())
}
}
fn has_only_tables(t: &Table) -> bool {
debug!("Verifying that table has only tables");
t.iter().all(|(_, x)| is_match!(*x, Value::Table(_)))
}
pub fn has_main_section(t: &Table) -> bool {
t.contains_key("imag") && is_match!(t.get("imag"), Some(&Value::Table(_)))
}
pub fn has_imag_version_in_main_section(t: &Table) -> bool {
use semver::Version;
match *t.get("imag").unwrap() {
Value::Table(ref sec) => {
sec.get("version")
.and_then(|v| {
match *v {
Value::String(ref s) => Some(Version::parse(&s[..]).is_ok()),
_ => Some(false),
}
})
.unwrap_or(false)
}
_ => false,
}
}
#[cfg(test)]
mod test {
extern crate env_logger;
use super::TomlValueExt;
use super::{tokenize, walk_header};
use super::Token;
use std::collections::BTreeMap;
use toml::Value;
#[test]
fn test_walk_header_simple() {
let tokens = tokenize("a", '.').unwrap();
assert!(tokens.len() == 1, "1 token was expected, {} were parsed", tokens.len());
assert!(tokens.iter().next().unwrap() == &Token::Key(String::from("a")),
"'a' token was expected, {:?} was parsed", tokens.iter().next());
let mut header = BTreeMap::new();
header.insert(String::from("a"), Value::Integer(1));
let mut v_header = Value::Table(header);
let res = walk_header(&mut v_header, tokens);
assert_eq!(&mut Value::Integer(1), res.unwrap());
}
#[test]
fn test_walk_header_with_array() {
let tokens = tokenize("a.0", '.').unwrap();
assert!(tokens.len() == 2, "2 token was expected, {} were parsed", tokens.len());
assert!(tokens.iter().next().unwrap() == &Token::Key(String::from("a")),
"'a' token was expected, {:?} was parsed", tokens.iter().next());
let mut header = BTreeMap::new();
let ary = Value::Array(vec![Value::Integer(1)]);
header.insert(String::from("a"), ary);
let mut v_header = Value::Table(header);
let res = walk_header(&mut v_header, tokens);
assert_eq!(&mut Value::Integer(1), res.unwrap());
}
#[test]
fn test_walk_header_extract_array() {
let tokens = tokenize("a", '.').unwrap();
assert!(tokens.len() == 1, "1 token was expected, {} were parsed", tokens.len());
assert!(tokens.iter().next().unwrap() == &Token::Key(String::from("a")),
"'a' token was expected, {:?} was parsed", tokens.iter().next());
let mut header = BTreeMap::new();
let ary = Value::Array(vec![Value::Integer(1)]);
header.insert(String::from("a"), ary);
let mut v_header = Value::Table(header);
let res = walk_header(&mut v_header, tokens);
assert_eq!(&mut Value::Array(vec![Value::Integer(1)]), res.unwrap());
}
/**
* Creates a big testing header.
*
* JSON equivalent:
*
* ```json
* {
* "a": {
* "array": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
* },
* "b": {
* "array": [ "string1", "string2", "string3", "string4" ]
* },
* "c": {
* "array": [ 1, "string2", 3, "string4" ]
* },
* "d": {
* "array": [
* {
* "d1": 1
* },
* {
* "d2": 2
* },
* {
* "d3": 3
* },
* ],
*
* "something": "else",
*
* "and": {
* "something": {
* "totally": "different"
* }
* }
* }
* }
* ```
*
* The sections "a", "b", "c", "d" are created in the respective helper functions
* create_header_section_a, create_header_section_b, create_header_section_c and
* create_header_section_d.
*
* These functions can also be used for testing.
*
*/
fn create_header() -> Value {
let a = create_header_section_a();
let b = create_header_section_b();
let c = create_header_section_c();
let d = create_header_section_d();
let mut header = BTreeMap::new();
header.insert(String::from("a"), a);
header.insert(String::from("b"), b);
header.insert(String::from("c"), c);
header.insert(String::from("d"), d);
Value::Table(header)
}
fn create_header_section_a() -> Value {
// 0..10 is exclusive 10
let a_ary = Value::Array((0..10).map(|x| Value::Integer(x)).collect());
let mut a_obj = BTreeMap::new();
a_obj.insert(String::from("array"), a_ary);
Value::Table(a_obj)
}
fn create_header_section_b() -> Value {
let b_ary = Value::Array((0..9)
.map(|x| Value::String(format!("string{}", x)))
.collect());
let mut b_obj = BTreeMap::new();
b_obj.insert(String::from("array"), b_ary);
Value::Table(b_obj)
}
fn create_header_section_c() -> Value {
let c_ary = Value::Array(
vec![
Value::Integer(1),
Value::String(String::from("string2")),
Value::Integer(3),
Value::String(String::from("string4"))
]);
let mut c_obj = BTreeMap::new();
c_obj.insert(String::from("array"), c_ary);
Value::Table(c_obj)
}
fn create_header_section_d() -> Value {
let d_ary = Value::Array(
vec![
{
let mut tab = BTreeMap::new();
tab.insert(String::from("d1"), Value::Integer(1));
tab
},
{
let mut tab = BTreeMap::new();
tab.insert(String::from("d2"), Value::Integer(2));
tab
},
{
let mut tab = BTreeMap::new();
tab.insert(String::from("d3"), Value::Integer(3));
tab
},
].into_iter().map(Value::Table).collect());
let and_obj = Value::Table({
let mut tab = BTreeMap::new();
let something_tab = Value::Table({
let mut tab = BTreeMap::new();
tab.insert(String::from("totally"), Value::String(String::from("different")));
tab
});
tab.insert(String::from("something"), something_tab);
tab
});
let mut d_obj = BTreeMap::new();
d_obj.insert(String::from("array"), d_ary);
d_obj.insert(String::from("something"), Value::String(String::from("else")));
d_obj.insert(String::from("and"), and_obj);
Value::Table(d_obj)
}
#[test]
fn test_walk_header_big_a() {
test_walk_header_extract_section("a", &create_header_section_a());
}
#[test]
fn test_walk_header_big_b() {
test_walk_header_extract_section("b", &create_header_section_b());
}
#[test]
fn test_walk_header_big_c() {
test_walk_header_extract_section("c", &create_header_section_c());
}
#[test]
fn test_walk_header_big_d() {
test_walk_header_extract_section("d", &create_header_section_d());
}
fn test_walk_header_extract_section(secname: &str, expected: &Value) {
let tokens = tokenize(secname, '.').unwrap();
assert!(tokens.len() == 1, "1 token was expected, {} were parsed", tokens.len());
assert!(tokens.iter().next().unwrap() == &Token::Key(String::from(secname)),
"'{}' token was expected, {:?} was parsed", secname, tokens.iter().next());
let mut header = create_header();
let res = walk_header(&mut header, tokens);
assert_eq!(expected, res.unwrap());
}
#[test]
fn test_walk_header_extract_numbers() {
test_extract_number("a", 0, 0);
test_extract_number("a", 1, 1);
test_extract_number("a", 2, 2);
test_extract_number("a", 3, 3);
test_extract_number("a", 4, 4);
test_extract_number("a", 5, 5);
test_extract_number("a", 6, 6);
test_extract_number("a", 7, 7);
test_extract_number("a", 8, 8);
test_extract_number("a", 9, 9);
test_extract_number("c", 0, 1);
test_extract_number("c", 2, 3);
}
fn test_extract_number(sec: &str, idx: usize, exp: i64) {
let tokens = tokenize(&format!("{}.array.{}", sec, idx)[..], '.').unwrap();
assert!(tokens.len() == 3, "3 token was expected, {} were parsed", tokens.len());
{
let mut iter = tokens.iter();
let tok = iter.next().unwrap();
let exp = Token::Key(String::from(sec));
assert!(tok == &exp, "'{}' token was expected, {:?} was parsed", sec, tok);
let tok = iter.next().unwrap();
let exp = Token::Key(String::from("array"));
assert!(tok == &exp, "'array' token was expected, {:?} was parsed", tok);
let tok = iter.next().unwrap();
let exp = Token::Index(idx);
assert!(tok == &exp, "'{}' token was expected, {:?} was parsed", idx, tok);
}
let mut header = create_header();
let res = walk_header(&mut header, tokens);
assert_eq!(&mut Value::Integer(exp), res.unwrap());
}
#[test]
fn test_header_read() {
let h = create_header();
assert!(if let Ok(Some(Value::Table(_))) = h.read("a") { true } else { false });
assert!(if let Ok(Some(Value::Array(_))) = h.read("a.array") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("a.array.1") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("a.array.9") { true } else { false });
assert!(if let Ok(Some(Value::Table(_))) = h.read("c") { true } else { false });
assert!(if let Ok(Some(Value::Array(_))) = h.read("c.array") { true } else { false });
assert!(if let Ok(Some(Value::String(_))) = h.read("c.array.1") { true } else { false });
assert!(if let Ok(None) = h.read("c.array.9") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("d.array.0.d1") { true } else { false });
assert!(if let Ok(None) = h.read("d.array.0.d2") { true } else { false });
assert!(if let Ok(None) = h.read("d.array.0.d3") { true } else { false });
assert!(if let Ok(None) = h.read("d.array.1.d1") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("d.array.1.d2") { true } else { false });
assert!(if let Ok(None) = h.read("d.array.1.d3") { true } else { false });
assert!(if let Ok(None) = h.read("d.array.2.d1") { true } else { false });
assert!(if let Ok(None) = h.read("d.array.2.d2") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("d.array.2.d3") { true } else { false });
assert!(if let Ok(Some(Value::String(_))) = h.read("d.something") { true } else { false });
assert!(if let Ok(Some(Value::Table(_))) = h.read("d.and") { true } else { false });
assert!(if let Ok(Some(Value::Table(_))) = h.read("d.and.something") { true } else { false });
assert!(if let Ok(Some(Value::String(_))) = h.read("d.and.something.totally") { true } else { false });
}
#[test]
fn test_header_set_override() {
let _ = env_logger::init();
let mut h = create_header();
println!("Testing index 0");
assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(0));
println!("Altering index 0");
assert_eq!(h.set("a.array.0", Value::Integer(42)).unwrap().unwrap(), Value::Integer(0));
println!("Values now: {:?}", h);
println!("Testing all indexes");
assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(42));
assert_eq!(h.read("a.array.1").unwrap().unwrap(), Value::Integer(1));
assert_eq!(h.read("a.array.2").unwrap().unwrap(), Value::Integer(2));
assert_eq!(h.read("a.array.3").unwrap().unwrap(), Value::Integer(3));
assert_eq!(h.read("a.array.4").unwrap().unwrap(), Value::Integer(4));
assert_eq!(h.read("a.array.5").unwrap().unwrap(), Value::Integer(5));
assert_eq!(h.read("a.array.6").unwrap().unwrap(), Value::Integer(6));
assert_eq!(h.read("a.array.7").unwrap().unwrap(), Value::Integer(7));
assert_eq!(h.read("a.array.8").unwrap().unwrap(), Value::Integer(8));
assert_eq!(h.read("a.array.9").unwrap().unwrap(), Value::Integer(9));
}
#[test]
fn test_header_set_new() {
let _ = env_logger::init();
let mut h = create_header();
assert!(h.read("a.foo").is_ok());
assert!(h.read("a.foo").unwrap().is_none());
{
let v = h.set("a.foo", Value::Integer(42));
assert!(v.is_ok());
assert!(v.unwrap().is_none());
assert!(if let Ok(Some(Value::Table(_))) = h.read("a") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("a.foo") { true } else { false });
}
{
let v = h.set("new", Value::Table(BTreeMap::new()));
assert!(v.is_ok());
assert!(v.unwrap().is_none());
let v = h.set("new.subset", Value::Table(BTreeMap::new()));
assert!(v.is_ok());
assert!(v.unwrap().is_none());
let v = h.set("new.subset.dest", Value::Integer(1337));
assert!(v.is_ok());
assert!(v.unwrap().is_none());
assert!(if let Ok(Some(Value::Table(_))) = h.read("new") { true } else { false });
assert!(if let Ok(Some(Value::Table(_))) = h.read("new.subset") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("new.subset.dest") { true } else { false });
}
}
#[test]
fn test_header_insert_override() {
let _ = env_logger::init();
let mut h = create_header();
println!("Testing index 0");
assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(0));
println!("Altering index 0");
assert_eq!(h.insert("a.array.0", Value::Integer(42)).unwrap(), false);
println!("...should have failed");
println!("Testing all indexes");
assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(0));
assert_eq!(h.read("a.array.1").unwrap().unwrap(), Value::Integer(1));
assert_eq!(h.read("a.array.2").unwrap().unwrap(), Value::Integer(2));
assert_eq!(h.read("a.array.3").unwrap().unwrap(), Value::Integer(3));
assert_eq!(h.read("a.array.4").unwrap().unwrap(), Value::Integer(4));
assert_eq!(h.read("a.array.5").unwrap().unwrap(), Value::Integer(5));
assert_eq!(h.read("a.array.6").unwrap().unwrap(), Value::Integer(6));
assert_eq!(h.read("a.array.7").unwrap().unwrap(), Value::Integer(7));
assert_eq!(h.read("a.array.8").unwrap().unwrap(), Value::Integer(8));
assert_eq!(h.read("a.array.9").unwrap().unwrap(), Value::Integer(9));
}
#[test]
fn test_header_insert_new() {
let _ = env_logger::init();
let mut h = create_header();
assert!(h.read("a.foo").is_ok());
assert!(h.read("a.foo").unwrap().is_none());
{
let v = h.insert("a.foo", Value::Integer(42));
assert!(v.is_ok());
assert_eq!(v.unwrap(), true);
assert!(if let Ok(Some(Value::Table(_))) = h.read("a") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("a.foo") { true } else { false });
}
{
let v = h.insert("new", Value::Table(BTreeMap::new()));
assert!(v.is_ok());
assert_eq!(v.unwrap(), true);
let v = h.insert("new.subset", Value::Table(BTreeMap::new()));
assert!(v.is_ok());
assert_eq!(v.unwrap(), true);
let v = h.insert("new.subset.dest", Value::Integer(1337));
assert!(v.is_ok());
assert_eq!(v.unwrap(), true);
assert!(if let Ok(Some(Value::Table(_))) = h.read("new") { true } else { false });
assert!(if let Ok(Some(Value::Table(_))) = h.read("new.subset") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("new.subset.dest") { true } else { false });
}
}
#[test]
fn test_header_delete() {
let _ = env_logger::init();
let mut h = create_header();
assert!(if let Ok(Some(Value::Table(_))) = h.read("a") { true } else { false });
assert!(if let Ok(Some(Value::Array(_))) = h.read("a.array") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("a.array.1") { true } else { false });
assert!(if let Ok(Some(Value::Integer(_))) = h.read("a.array.9") { true } else { false });
assert!(if let Ok(Some(Value::Integer(1))) = h.delete("a.array.1") { true } else { false });
assert!(if let Ok(Some(Value::Integer(9))) = h.delete("a.array.8") { true } else { false });
assert!(if let Ok(Some(Value::Array(_))) = h.delete("a.array") { true } else { false });
assert!(if let Ok(Some(Value::Table(_))) = h.delete("a") { true } else { false });
}
}

View file

@ -23,8 +23,8 @@ use toml::Value;
use libimagerror::into::IntoError;
use store::Result;
use store::Header;
use error::StoreErrorKind as SEK;
use toml_ext::Header;
#[cfg(feature = "early-panic")]
#[macro_export]

View file

@ -17,6 +17,7 @@ homepage = "http://imag-pim.org"
semver = "0.5"
log = "0.3"
toml = "^0.4"
toml-query = "0.3.0"
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }

View file

@ -36,6 +36,7 @@
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
extern crate toml_query;
extern crate libimagrt;
#[macro_use] extern crate libimagstore;

View file

@ -30,7 +30,9 @@ use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt;
use module_path::ModuleEntryPath;
use result::Result;
@ -92,7 +94,7 @@ impl<'a> Note<'a> {
pub fn get_name(&self) -> Result<String> {
let header = self.entry.get_header();
match header.read("note.name") {
Ok(Some(Value::String(s))) => Ok(String::from(s)),
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
Ok(_) => {
let e = NE::new(NEK::HeaderTypeError, None);
Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))

View file

@ -13,6 +13,7 @@ license = "LGPL-2.1"
uuid = { version = "0.3.1", features = ["v4"] }
lazy_static = "0.1.15"
toml = "^0.4"
toml-query = "0.3.0"
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }

View file

@ -24,10 +24,12 @@ use toml::Value;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::toml_ext::TomlValueExt;
use libimagentrylink::internal::InternalLinker;
use libimagerror::into::IntoError;
use toml_query::read::TomlValueReadExt;
use toml_query::insert::TomlValueInsertExt;
use result::Result;
use error::AnnotationErrorKind as AEK;
use error::MapErrInto;
@ -53,14 +55,8 @@ impl Annotateable for Entry {
.and_then(|mut anno| {
anno.get_header_mut()
.insert("annotation.is_annotation", Value::Boolean(true))
.map_err_into(AEK::StoreWriteError)
.and_then(|succeeded| {
if succeeded {
Ok(anno)
} else {
Err(AEK::HeaderWriteError.into_error())
}
})
.map_err_into(AEK::HeaderWriteError)
.map(|_| anno)
})
.and_then(|mut anno| {
anno.add_internal_link(self)
@ -74,9 +70,9 @@ impl Annotateable for Entry {
.read("annotation.is_annotation")
.map_err_into(AEK::StoreReadError)
.and_then(|res| match res {
Some(Value::Boolean(b)) => Ok(b),
None => Ok(false),
_ => Err(AEK::HeaderTypeError.into_error()),
Some(&Value::Boolean(b)) => Ok(b),
None => Ok(false),
_ => Err(AEK::HeaderTypeError.into_error()),
})
}

View file

@ -68,7 +68,8 @@ impl<'a> AnnotationFetcher<'a> for Store {
pub mod iter {
use toml::Value;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use libimagerror::into::IntoError;
use libimagnotes::note::Note;
use libimagnotes::note::NoteIterator;
@ -95,10 +96,9 @@ pub mod iter {
loop {
match self.0.next() {
Some(Ok(note)) => {
let hdr = note.get_header().read("annotation.is_annotation");
match hdr {
match note.get_header().read("annotation.is_annotation") {
Ok(None) => continue, // not an annotation
Ok(Some(Value::Boolean(true))) => return Some(Ok(note)),
Ok(Some(&Value::Boolean(true))) => return Some(Ok(note)),
Ok(Some(_)) => return Some(Err(AEK::HeaderTypeError.into_error())),
Err(e) => return Some(Err(e).map_err_into(AEK::HeaderReadError)),
}

View file

@ -35,6 +35,7 @@
extern crate uuid;
extern crate toml;
extern crate toml_query;
#[macro_use] extern crate libimagerror;
extern crate libimagstore;

View file

@ -21,6 +21,7 @@ log = "0.3"
regex = "0.2"
semver = "0.5.*"
toml = "^0.4"
toml-query = "0.3.0"
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
libimagentrytag = { version = "0.4.0", path = "../../../lib/entry/libimagentrytag" }

View file

@ -32,8 +32,8 @@ struct EqPred {
impl Predicate for EqPred {
fn evaluate(&self, v: Value) -> bool {
self.expected == v
fn evaluate(&self, v: &Value) -> bool {
self.expected == *v
}
}

View file

@ -18,10 +18,11 @@
//
use libimagstore::store::Entry;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use filters::filter::Filter;
use builtin::header::field_path::FieldPath;
use filters::filter::Filter;
pub struct FieldExists {
header_field_path: FieldPath,

View file

@ -33,10 +33,10 @@ struct EqGrep{
impl Predicate for EqGrep {
fn evaluate(&self, v: Value) -> bool {
match v {
Value::String(s) => self.regex.captures(&s[..]).is_some(),
_ => false,
fn evaluate(&self, v: &Value) -> bool {
match *v {
Value::String(ref s) => self.regex.captures(&s[..]).is_some(),
_ => false,
}
}

View file

@ -32,17 +32,17 @@ struct EqGt {
impl Predicate for EqGt {
fn evaluate(&self, v: Value) -> bool {
fn evaluate(&self, v: &Value) -> bool {
match self.comp {
Value::Integer(i) => {
match v {
match *v {
Value::Integer(j) => i > j,
Value::Float(f) => (i as f64) > f,
_ => false,
}
},
Value::Float(f) => {
match v {
match *v {
Value::Integer(i) => f > (i as f64),
Value::Float(d) => f > d,
_ => false,

View file

@ -18,7 +18,7 @@
//
use libimagstore::store::Entry;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use builtin::header::field_path::FieldPath;
use filters::filter::Filter;
@ -46,12 +46,12 @@ impl Filter<Entry> for FieldIsEmpty {
.read(&self.header_field_path[..])
.map(|v| {
match v {
Some(Value::Array(a)) => a.is_empty(),
Some(Value::String(s)) => s.is_empty(),
Some(Value::Table(t)) => t.is_empty(),
Some(Value::Boolean(_)) |
Some(Value::Float(_)) |
Some(Value::Integer(_)) => false,
Some(&Value::Array(ref a)) => a.is_empty(),
Some(&Value::String(ref s)) => s.is_empty(),
Some(&Value::Table(ref t)) => t.is_empty(),
Some(&Value::Boolean(_)) |
Some(&Value::Float(_)) |
Some(&Value::Integer(_)) => false,
_ => true,
}
})

View file

@ -58,8 +58,8 @@ struct IsTypePred {
impl Predicate for IsTypePred {
fn evaluate(&self, v: Value) -> bool {
self.ty.matches(&v)
fn evaluate(&self, v: &Value) -> bool {
self.ty.matches(v)
}
}

View file

@ -32,17 +32,17 @@ struct EqLt {
impl Predicate for EqLt {
fn evaluate(&self, v: Value) -> bool {
fn evaluate(&self, v: &Value) -> bool {
match self.comp {
Value::Integer(i) => {
match v {
match *v {
Value::Integer(j) => i < j,
Value::Float(f) => (i as f64) < f,
_ => false,
}
},
Value::Float(f) => {
match v {
match *v {
Value::Integer(i) => f < (i as f64),
Value::Float(d) => f < d,
_ => false,

View file

@ -18,7 +18,8 @@
//
use libimagstore::store::Entry;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use builtin::header::field_path::FieldPath;
use filters::filter::Filter;
@ -26,7 +27,7 @@ use filters::filter::Filter;
use toml::Value;
pub trait Predicate {
fn evaluate(&self, Value) -> bool;
fn evaluate(&self, &Value) -> bool;
}
/// Check whether certain header field in a entry is equal to a value

View file

@ -21,8 +21,8 @@ use semver::Version;
use toml::Value;
use libimagstore::store::Entry;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use filters::filter::Filter;
pub struct VersionEq {
@ -44,8 +44,8 @@ impl Filter<Entry> for VersionEq {
.read("imag.version")
.map(|val| {
val.map_or(false, |v| {
match v {
Value::String(s) => {
match *v {
Value::String(ref s) => {
match Version::parse(&s[..]) {
Ok(v) => v == self.version,
_ => false

View file

@ -21,8 +21,8 @@ use semver::Version;
use toml::Value;
use libimagstore::store::Entry;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use filters::filter::Filter;
pub struct VersionGt {
@ -44,8 +44,8 @@ impl Filter<Entry> for VersionGt {
.read("imag.version")
.map(|val| {
val.map_or(false, |v| {
match v {
Value::String(s) => {
match *v {
Value::String(ref s) => {
match Version::parse(&s[..]) {
Ok(v) => v > self.version,
_ => false

View file

@ -21,8 +21,8 @@ use semver::Version;
use toml::Value;
use libimagstore::store::Entry;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use filters::filter::Filter;
pub struct VersionLt {
@ -44,8 +44,8 @@ impl Filter<Entry> for VersionLt {
.read("imag.version")
.map(|val| {
val.map_or(false, |v| {
match v {
Value::String(s) => {
match *v {
Value::String(ref s) => {
match Version::parse(&s[..]) {
Ok(v) => v < self.version,
_ => false

View file

@ -38,6 +38,7 @@ extern crate itertools;
extern crate regex;
extern crate semver;
extern crate toml;
extern crate toml_query;
extern crate libimagstore;
extern crate libimagentrytag;

View file

@ -22,6 +22,7 @@ url = "1.2"
rust-crypto = "0.2"
env_logger = "0.3"
is-match = "0.1"
toml-query = "0.3.0"
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }

View file

@ -39,9 +39,11 @@ use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::toml_ext::TomlValueExt;
use libimagutil::debug_result::*;
use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt;
use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use error::MapErrInto;
@ -73,7 +75,7 @@ impl<'a> Link<'a> {
.read("imag.content.url")
.ok()
.and_then(|opt| match opt {
Some(Value::String(s)) => {
Some(&Value::String(ref s)) => {
debug!("Found url, parsing: {:?}", s);
Url::parse(&s[..]).ok()
},
@ -87,7 +89,7 @@ impl<'a> Link<'a> {
.read("imag.content.url");
match opt {
Ok(Some(Value::String(s))) => {
Ok(Some(&Value::String(ref s))) => {
Url::parse(&s[..])
.map(Some)
.map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
@ -351,7 +353,7 @@ impl ExternalLinker for Entry {
let mut hdr = file.deref_mut().get_header_mut();
let mut table = match hdr.read("imag.content") {
Ok(Some(Value::Table(table))) => table,
Ok(Some(&Value::Table(ref table))) => table.clone(),
Ok(Some(_)) => {
warn!("There is a value at 'imag.content' which is not a table.");
warn!("Going to override this value");

View file

@ -25,9 +25,11 @@ use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Entry;
use libimagstore::store::Result as StoreResult;
use libimagstore::toml_ext::TomlValueExt;
use libimagerror::into::IntoError;
use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt;
use error::LinkErrorKind as LEK;
use error::MapErrInto;
use result::Result;
@ -388,7 +390,12 @@ pub mod iter {
impl InternalLinker for Entry {
fn get_internal_links(&self) -> Result<LinkIter> {
process_rw_result(self.get_header().read("imag.links"))
let res = self
.get_header()
.read("imag.links")
.map_err_into(LEK::EntryHeaderReadError)
.map(|r| r.cloned());
process_rw_result(res)
}
/// Set the links in a header and return the old links, if any.
@ -417,7 +424,11 @@ impl InternalLinker for Entry {
})
})
}));
process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
let res = self
.get_header_mut()
.set("imag.links", Value::Array(new_links))
.map_err_into(LEK::EntryHeaderReadError);
process_rw_result(res)
}
fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
@ -485,7 +496,9 @@ fn rewrite_links<I: Iterator<Item = Link>>(header: &mut Value, links: I) -> Resu
}));
debug!("Setting new link array: {:?}", links);
let process = header.set("imag.links", Value::Array(links));
let process = header
.set("imag.links", Value::Array(links))
.map_err_into(LEK::EntryHeaderReadError);
process_rw_result(process).map(|_| ())
}
@ -509,12 +522,17 @@ fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
})
}));
debug!("Setting links in {:?}: {:?}", target.get_location(), links);
process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
.map(|_| ())
let res = target
.get_header_mut()
.set("imag.links", Value::Array(links))
.map_err_into(LEK::EntryHeaderReadError);
process_rw_result(res).map(|_| ())
})
}
fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<LinkIter> {
fn process_rw_result(links: Result<Option<Value>>) -> Result<LinkIter> {
use std::path::PathBuf;
let links = match links {

View file

@ -36,6 +36,7 @@
extern crate itertools;
#[macro_use] extern crate log;
extern crate toml;
extern crate toml_query;
extern crate semver;
extern crate url;
extern crate crypto;

View file

@ -21,6 +21,7 @@ semver = "0.5"
toml = "^0.4"
version = "2.0.1"
walkdir = "1.0.*"
toml-query = "0.3.0"
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }

View file

@ -37,13 +37,13 @@ impl RefFlags {
/// It assumes that this is a Map with Key = <name of the setting> and Value = boolean.
pub fn read(v: &Value) -> Result<RefFlags> {
fn get_field(v: &Value, key: &str) -> Result<bool> {
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use error::MapErrInto;
v.read(key)
.map_err_into(REK::HeaderTomlError)
.and_then(|toml| match toml {
Some(Value::Boolean(b)) => Ok(b),
Some(&Value::Boolean(b)) => Ok(b),
Some(_) => Err(REK::HeaderTypeError.into()),
None => Err(REK::HeaderFieldMissingError.into()),
})

View file

@ -38,6 +38,7 @@ extern crate crypto;
extern crate itertools;
extern crate semver;
extern crate toml;
extern crate toml_query;
extern crate version;
extern crate walkdir;

View file

@ -33,10 +33,12 @@ use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Store;
use libimagstore::toml_ext::TomlValueExt;
use libimagerror::into::IntoError;
use toml::Value;
use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt;
use toml_query::insert::TomlValueInsertExt;
use error::RefErrorKind as REK;
use error::MapErrInto;
@ -89,7 +91,7 @@ impl<'a> Ref<'a> {
fn read_reference(fle: &FileLockEntry<'a>) -> Result<PathBuf> {
match fle.get_header().read("ref.path") {
Ok(Some(Value::String(s))) => Ok(PathBuf::from(s)),
Ok(Some(&Value::String(ref s))) => Ok(PathBuf::from(s)),
Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
Ok(None) => Err(REK::HeaderFieldMissingError.into_error()),
Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
@ -204,18 +206,17 @@ impl<'a> Ref<'a> {
match tpl {
&Some((ref s, ref v)) => {
match fle.get_header_mut().insert(s, v.clone()) {
Ok(false) => {
let e = REK::HeaderFieldAlreadyExistsError.into_error();
let e = Box::new(e);
let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
return Err(e);
Ok(None) => {
debug!("Header insert worked");
}
Ok(Some(val)) => {
debug!("Overwrote: {}, which was: {:?}", s, val);
},
Err(e) => {
let e = Box::new(e);
let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
return Err(e);
},
_ => (),
}
}
&None => {
@ -274,7 +275,7 @@ impl<'a> Ref<'a> {
pub fn get_stored_hash_with_hasher<H: Hasher>(&self, h: &H) -> Result<String> {
match self.0.get_header().read(&format!("ref.content_hash.{}", h.hash_name())[..]) {
// content hash stored...
Ok(Some(Value::String(s))) => Ok(s),
Ok(Some(&Value::String(ref s))) => Ok(s.clone()),
// content hash header field has wrong type
Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
@ -365,7 +366,7 @@ impl<'a> Ref<'a> {
.map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e))
.and_then(|ro| {
match ro {
Some(Value::Boolean(b)) => Ok(b),
Some(&Value::Boolean(b)) => Ok(b),
Some(_) => Err(REK::HeaderTypeError.into_error()),
None => Err(REK::HeaderFieldMissingError.into_error()),
}
@ -414,7 +415,7 @@ impl<'a> Ref<'a> {
/// Get the path of the file which is reffered to by this Ref
pub fn fs_file(&self) -> Result<PathBuf> {
match self.0.get_header().read("ref.path") {
Ok(Some(Value::String(ref s))) => Ok(PathBuf::from(s)),
Ok(Some(&Value::String(ref s))) => Ok(PathBuf::from(s)),
Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
Ok(None) => Err(REK::HeaderFieldMissingError.into_error()),
Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),

View file

@ -21,6 +21,7 @@ toml = "^0.4"
itertools = "0.5"
is-match = "0.1"
filters = "0.1"
toml-query = "0.3.0"
libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }

View file

@ -38,6 +38,7 @@ extern crate itertools;
#[macro_use] extern crate log;
extern crate regex;
extern crate toml;
extern crate toml_query;
#[macro_use] extern crate is_match;
extern crate filters;

View file

@ -21,7 +21,9 @@ use itertools::Itertools;
use libimagstore::store::Entry;
use libimagerror::into::IntoError;
use libimagstore::toml_ext::TomlValueExt;
use toml_query::read::TomlValueReadExt;
use toml_query::set::TomlValueSetExt;
use error::TagErrorKind;
use error::MapErrInto;
@ -50,7 +52,7 @@ impl Tagable for Value {
let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));
match tags {
Some(Value::Array(tags)) => {
Some(&Value::Array(ref tags)) => {
if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
return Err(TagErrorKind::TagTypeError.into());
}
@ -120,7 +122,7 @@ impl Tagable for Value {
fn has_tag(&self, t: TagSlice) -> Result<bool> {
let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));
if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
if !tags.iter().all(|t| is_match!(*t, &Value::String(_))) {
return Err(TagErrorKind::TagTypeError.into());
}
@ -128,7 +130,7 @@ impl Tagable for Value {
.iter()
.any(|tag| {
match *tag {
Value::String(ref s) => { s == t },
&Value::String(ref s) => { s == t },
_ => unreachable!()
}
}))