summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-02-05 14:54:27 +0100
committerGitHub <noreply@github.com>2017-02-05 14:54:27 +0100
commit63ffbf62de95dfed62d3c41588472c3c8056a5a6 (patch)
treebd0f3cc265c1d012cbdb2ae1979b0ae309fdb581
parent2ca89b73291a33d8209890b762343460ccc68604 (diff)
parent6f1a510c7069097e9fadbe1a9e493bc84ec23c13 (diff)
downloadimag-63ffbf62de95dfed62d3c41588472c3c8056a5a6.zip
imag-63ffbf62de95dfed62d3c41588472c3c8056a5a6.tar.gz
Merge pull request #836 from matthiasbeyer/libimagstore/eliminate-header-type
libimagstore: Eliminate EntryHeader type
-rw-r--r--imag-store/Cargo.toml3
-rw-r--r--imag-store/src/create.rs13
-rw-r--r--imag-store/src/retrieve.rs4
-rw-r--r--imag-store/src/util.rs20
-rw-r--r--libimagentryfilter/src/builtin/header/field_exists.rs1
-rw-r--r--libimagentryfilter/src/builtin/header/field_isempty.rs1
-rw-r--r--libimagentryfilter/src/builtin/header/field_predicate.rs1
-rw-r--r--libimagentryfilter/src/builtin/header/version/eq.rs1
-rw-r--r--libimagentryfilter/src/builtin/header/version/gt.rs1
-rw-r--r--libimagentryfilter/src/builtin/header/version/lt.rs1
-rw-r--r--libimagentrylink/src/external.rs1
-rw-r--r--libimagentrylink/src/internal.rs4
-rw-r--r--libimagentrytag/src/tagable.rs5
-rw-r--r--libimagentryview/src/builtin/plain.rs2
-rw-r--r--libimagentryview/src/builtin/stdout.rs2
-rw-r--r--libimagnotes/src/note.rs1
-rw-r--r--libimagref/src/reference.rs1
-rw-r--r--libimagruby/src/entry.rs13
-rw-r--r--libimagstore/Cargo.toml25
-rw-r--r--libimagstore/src/lib.rs4
-rw-r--r--libimagstore/src/store.rs218
-rw-r--r--libimagstore/src/toml_ext.rs140
-rw-r--r--libimagstore/src/util.rs35
23 files changed, 242 insertions, 255 deletions
diff --git a/imag-store/Cargo.toml b/imag-store/Cargo.toml
index 66648cb..13e8eba 100644
--- a/imag-store/Cargo.toml
+++ b/imag-store/Cargo.toml
@@ -34,3 +34,6 @@ path = "../libimagutil"
[dependencies.libimagerror]
path = "../libimagerror"
+[features]
+early-panic = [ "libimagstore/early-panic" ]
+
diff --git a/imag-store/src/create.rs b/imag-store/src/create.rs
index cfdbd01..e015595 100644
--- a/imag-store/src/create.rs
+++ b/imag-store/src/create.rs
@@ -28,10 +28,10 @@ use std::io::stderr;
use std::process::exit;
use clap::ArgMatches;
+use toml::Value;
use libimagrt::runtime::Runtime;
use libimagstore::store::Entry;
-use libimagstore::store::EntryHeader;
use libimagstore::storeid::StoreId;
use libimagerror::trace::trace_error_exit;
use libimagutil::debug_result::*;
@@ -70,10 +70,11 @@ pub fn create(rt: &Runtime) {
.or_else(|_| create_with_content_and_header(rt,
&path,
String::new(),
- EntryHeader::new()))
+ Entry::default_header()))
} else {
debug!("Creating entry");
- create_with_content_and_header(rt, &path, String::new(), EntryHeader::new())
+ create_with_content_and_header(rt, &path, String::new(),
+ Entry::default_header())
}
.unwrap_or_else(|e| {
error!("Error building Entry");
@@ -100,8 +101,8 @@ fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> R
debug!("Got content with len = {}", content.len());
let header = matches.subcommand_matches("entry")
- .map_or_else(EntryHeader::new,
- |entry_matches| build_toml_header(entry_matches, EntryHeader::new()));
+ .map_or_else(|| Entry::default_header(),
+ |entry_matches| build_toml_header(entry_matches, Entry::default_header()));
create_with_content_and_header(rt, path, content, header)
}
@@ -138,7 +139,7 @@ fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Res
fn create_with_content_and_header(rt: &Runtime,
path: &StoreId,
content: String,
- header: EntryHeader) -> Result<()>
+ header: Value) -> Result<()>
{
debug!("Creating entry with content at {:?}", path);
rt.store()
diff --git a/imag-store/src/retrieve.rs b/imag-store/src/retrieve.rs
index 4d17e81..19c85b1 100644
--- a/imag-store/src/retrieve.rs
+++ b/imag-store/src/retrieve.rs
@@ -20,7 +20,6 @@
use std::path::PathBuf;
use clap::ArgMatches;
-use toml::Value;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
@@ -70,8 +69,7 @@ pub fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) {
unimplemented!()
} else {
debug!("Printing header as TOML...");
- // We have to Value::Table() for Display
- println!("{}", Value::Table(e.get_header().clone().into()))
+ println!("{}", e.get_header())
}
}
diff --git a/imag-store/src/util.rs b/imag-store/src/util.rs
index 8e7002c..5da0466 100644
--- a/imag-store/src/util.rs
+++ b/imag-store/src/util.rs
@@ -24,13 +24,11 @@ use std::str::Split;
use clap::ArgMatches;
use toml::Value;
-use libimagstore::store::EntryHeader;
use libimagutil::key_value_split::IntoKeyValue;
-pub fn build_toml_header(matches: &ArgMatches, header: EntryHeader) -> EntryHeader {
+pub fn build_toml_header(matches: &ArgMatches, mut header: Value) -> Value {
debug!("Building header from cli spec");
if let Some(headerspecs) = matches.values_of("header") {
- let mut main = header.into();
let kvs = headerspecs.into_iter()
.filter_map(|hs| {
debug!("- Processing: '{}'", hs);
@@ -42,18 +40,16 @@ pub fn build_toml_header(matches: &ArgMatches, header: EntryHeader) -> EntryHead
let (key, value) = tpl.into();
debug!("Splitting: {:?}", key);
let mut split = key.split('.');
- let current = split.next();
- if current.is_some() {
- insert_key_into(String::from(current.unwrap()), &mut split, Cow::Owned(value), &mut main);
+ match (split.next(), &mut header) {
+ (Some(cur), &mut Value::Table(ref mut hdr)) =>
+ insert_key_into(String::from(cur), &mut split, Cow::Owned(value), hdr),
+ _ => { }
}
}
-
- debug!("Header = {:?}", main);
- EntryHeader::from(main)
- } else {
- debug!("Header = {:?}", header);
- header
}
+
+ debug!("Header = {:?}", header);
+ header
}
fn insert_key_into<'a>(current: String,
diff --git a/libimagentryfilter/src/builtin/header/field_exists.rs b/libimagentryfilter/src/builtin/header/field_exists.rs
index 9999b3d..5fe672d 100644
--- a/libimagentryfilter/src/builtin/header/field_exists.rs
+++ b/libimagentryfilter/src/builtin/header/field_exists.rs
@@ -18,6 +18,7 @@
//
use libimagstore::store::Entry;
+use libimagstore::toml_ext::TomlValueExt;
use builtin::header::field_path::FieldPath;
use filters::filter::Filter;
diff --git a/libimagentryfilter/src/builtin/header/field_isempty.rs b/libimagentryfilter/src/builtin/header/field_isempty.rs
index d243d78..7a9c652 100644
--- a/libimagentryfilter/src/builtin/header/field_isempty.rs
+++ b/libimagentryfilter/src/builtin/header/field_isempty.rs
@@ -18,6 +18,7 @@
//
use libimagstore::store::Entry;
+use libimagstore::toml_ext::TomlValueExt;
use builtin::header::field_path::FieldPath;
use filters::filter::Filter;
diff --git a/libimagentryfilter/src/builtin/header/field_predicate.rs b/libimagentryfilter/src/builtin/header/field_predicate.rs
index 361ed0f..45aa332 100644
--- a/libimagentryfilter/src/builtin/header/field_predicate.rs
+++ b/libimagentryfilter/src/builtin/header/field_predicate.rs
@@ -18,6 +18,7 @@
//
use libimagstore::store::Entry;
+use libimagstore::toml_ext::TomlValueExt;
use builtin::header::field_path::FieldPath;
use filters::filter::Filter;
diff --git a/libimagentryfilter/src/builtin/header/version/eq.rs b/libimagentryfilter/src/builtin/header/version/eq.rs
index ac805a6..1ca38f8 100644
--- a/libimagentryfilter/src/builtin/header/version/eq.rs
+++ b/libimagentryfilter/src/builtin/header/version/eq.rs
@@ -21,6 +21,7 @@ use semver::Version;
use toml::Value;
use libimagstore::store::Entry;
+use libimagstore::toml_ext::TomlValueExt;
use filters::filter::Filter;
diff --git a/libimagentryfilter/src/builtin/header/version/gt.rs b/libimagentryfilter/src/builtin/header/version/gt.rs
index daded75..8e3873f 100644
--- a/libimagentryfilter/src/builtin/header/version/gt.rs
+++ b/libimagentryfilter/src/builtin/header/version/gt.rs
@@ -21,6 +21,7 @@ use semver::Version;
use toml::Value;
use libimagstore::store::Entry;
+use libimagstore::toml_ext::TomlValueExt;
use filters::filter::Filter;
diff --git a/libimagentryfilter/src/builtin/header/version/lt.rs b/libimagentryfilter/src/builtin/header/version/lt.rs
index 02c35cd..c475b43 100644
--- a/libimagentryfilter/src/builtin/header/version/lt.rs
+++ b/libimagentryfilter/src/builtin/header/version/lt.rs
@@ -21,6 +21,7 @@ use semver::Version;
use toml::Value;
use libimagstore::store::Entry;
+use libimagstore::toml_ext::TomlValueExt;
use filters::filter::Filter;
diff --git a/libimagentrylink/src/external.rs b/libimagentrylink/src/external.rs
index 4959428..0d6aab0 100644
--- a/libimagentrylink/src/external.rs
+++ b/libimagentrylink/src/external.rs
@@ -38,6 +38,7 @@ 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 error::LinkError as LE;
diff --git a/libimagentrylink/src/internal.rs b/libimagentrylink/src/internal.rs
index 48f5d81..83add03 100644
--- a/libimagentrylink/src/internal.rs
+++ b/libimagentrylink/src/internal.rs
@@ -19,8 +19,8 @@
use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;
-use libimagstore::store::EntryHeader;
use libimagstore::store::Result as StoreResult;
+use libimagstore::toml_ext::TomlValueExt;
use libimagerror::into::IntoError;
use error::LinkErrorKind as LEK;
@@ -337,7 +337,7 @@ impl InternalLinker for Entry {
}
-fn rewrite_links<I: Iterator<Item = Link>>(header: &mut EntryHeader, links: I) -> Result<()> {
+fn rewrite_links<I: Iterator<Item = Link>>(header: &mut Value, links: I) -> Result<()> {
let links = try!(links.into_values()
.fold(Ok(vec![]), |acc, elem| {
acc.and_then(move |mut v| {
diff --git a/libimagentrytag/src/tagable.rs b/libimagentrytag/src/tagable.rs
index bff7793..9e0fa2f 100644
--- a/libimagentrytag/src/tagable.rs
+++ b/libimagentrytag/src/tagable.rs
@@ -19,8 +19,9 @@
use itertools::Itertools;
-use libimagstore::store::{Entry, EntryHeader};
+use libimagstore::store::Entry;
use libimagerror::into::IntoError;
+use libimagstore::toml_ext::TomlValueExt;
use error::TagErrorKind;
use error::MapErrInto;
@@ -43,7 +44,7 @@ pub trait Tagable {
}
-impl Tagable for EntryHeader {
+impl Tagable for Value {
fn get_tags(&self) -> Result<Vec<Tag>> {
let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));
diff --git a/libimagentryview/src/builtin/plain.rs b/libimagentryview/src/builtin/plain.rs
index d96f460..f40b252 100644
--- a/libimagentryview/src/builtin/plain.rs
+++ b/libimagentryview/src/builtin/plain.rs
@@ -40,7 +40,7 @@ impl Viewer for PlainViewer {
fn view_entry(&self, e: &Entry) -> Result<()> {
if self.show_header {
- println!("{}", e.get_header().header());
+ println!("{}", e.get_header());
}
println!("{}", e.get_content());
Ok(())
diff --git a/libimagentryview/src/builtin/stdout.rs b/libimagentryview/src/builtin/stdout.rs
index 703281f..4d431f2 100644
--- a/libimagentryview/src/builtin/stdout.rs
+++ b/libimagentryview/src/builtin/stdout.rs
@@ -44,7 +44,7 @@ impl Viewer for StdoutViewer {
fn view_entry(&self, e: &Entry) -> Result<()> {
if self.view_header {
- println!("{}", encode_str(e.get_header().header()));
+ println!("{}", encode_str(e.get_header()));
}
if self.view_content {
diff --git a/libimagnotes/src/note.rs b/libimagnotes/src/note.rs
index 2397948..2edf1d6 100644
--- a/libimagnotes/src/note.rs
+++ b/libimagnotes/src/note.rs
@@ -30,6 +30,7 @@ use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
+use libimagstore::toml_ext::TomlValueExt;
use libimagentrytag::tag::{Tag, TagSlice};
use libimagentrytag::tagable::Tagable;
use libimagentrytag::result::Result as TagResult;
diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs
index 0b39285..1b307ba 100644
--- a/libimagref/src/reference.rs
+++ b/libimagref/src/reference.rs
@@ -33,6 +33,7 @@ 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;
diff --git a/libimagruby/src/entry.rs b/libimagruby/src/entry.rs
index 7eb6b67..0ac88c0 100644
--- a/libimagruby/src/entry.rs
+++ b/libimagruby/src/entry.rs
@@ -21,11 +21,12 @@ use std::collections::BTreeMap;
use std::error::Error;
use ruru::{Class, Object, AnyObject, Boolean, RString, VM, Hash, NilClass, VerifiedObject};
+use toml::Value;
-use libimagstore::store::EntryHeader;
use libimagstore::store::EntryContent;
use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;
+use libimagstore::toml_ext::TomlValueExt;
use ruby_utils::IntoToml;
use toml_utils::IntoRuby;
@@ -130,7 +131,7 @@ methods!(
use toml::Value;
let entryheader = match typecheck!(hdr or return NilClass::new()).into_toml() {
- Value::Table(t) => EntryHeader::from(t),
+ Value::Table(t) => Value::Table(t),
_ => {
let ec = Class::from_existing("RuntimeError");
VM::raise(ec, "Something weird happened. Hash seems to be not a Hash");
@@ -175,10 +176,10 @@ methods!(
);
-wrappable_struct!(EntryHeader, EntryHeaderWrapper, ENTRY_HEADER_WRAPPER);
+wrappable_struct!(Value, EntryHeaderWrapper, ENTRY_HEADER_WRAPPER);
class!(REntryHeader);
-impl_wrap!(EntryHeader => ENTRY_HEADER_WRAPPER);
-impl_unwrap!(REntryHeader => EntryHeader => ENTRY_HEADER_WRAPPER);
+impl_wrap!(Value => ENTRY_HEADER_WRAPPER);
+impl_unwrap!(REntryHeader => Value => ENTRY_HEADER_WRAPPER);
impl_verified_object!(REntryHeader);
methods!(
@@ -186,7 +187,7 @@ methods!(
itself,
fn r_entry_header_new() -> AnyObject {
- EntryHeader::new().wrap()
+ Entry::default_header().wrap()
}
fn r_entry_header_insert(spec: RString, obj: AnyObject) -> Boolean {
diff --git a/libimagstore/Cargo.toml b/libimagstore/Cargo.toml
index 656092f..5e19899 100644
--- a/libimagstore/Cargo.toml
+++ b/libimagstore/Cargo.toml
@@ -39,3 +39,28 @@ env_logger = "0.3"
default = []
verify = []
+# Enable panic!()s if critical errors occur.
+#
+# # Howto
+#
+# To enable this, put
+#
+# ```toml
+# [features]
+# early-panic = [ "libimagstore/early-panic" ]
+# ```
+#
+# In the crate depending on this library and compile your crate with
+# `cargo build --features early-panic`. This way, the `libimagstore`
+# implementation fails via `panic!()` instead of propagating errors which have
+# to be printed somewhere to be visible.
+#
+# # WARNING
+#
+# The behaviour of the store implementation might be broken with this, resulting
+# in partially written store entries and/or worse, so this is
+#
+# _NOT INTENDED FOR PRODUCTION USE_!
+#
+early-panic=[]
+
diff --git a/libimagstore/src/lib.rs b/libimagstore/src/lib.rs
index a696f7c..56c3a74 100644
--- a/libimagstore/src/lib.rs
+++ b/libimagstore/src/lib.rs
@@ -46,11 +46,13 @@ extern crate walkdir;
#[macro_use] extern crate libimagerror;
#[macro_use] extern crate libimagutil;
+#[macro_use] mod util;
+
pub mod storeid;
pub mod error;
pub mod hook;
pub mod store;
mod configuration;
mod file_abstraction;
-mod toml_ext;
+pub mod toml_ext;
diff --git a/libimagstore/src/store.rs b/libimagstore/src/store.rs
index de9988d..d245feb 100644
--- a/libimagstore/src/store.rs
+++ b/libimagstore/src/store.rs
@@ -23,7 +23,6 @@ use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::RwLock;
-use std::collections::BTreeMap;
use std::io::Read;
use std::convert::From;
use std::convert::Into;
@@ -34,13 +33,12 @@ use std::fmt::Formatter;
use std::fmt::Debug;
use std::fmt::Error as FMTError;
-use toml::{Table, Value};
+use toml::Value;
use regex::Regex;
use glob::glob;
use walkdir::WalkDir;
use walkdir::Iter as WalkDirIter;
-use error::{ParserErrorKind, ParserError};
use error::{StoreError as SE, StoreErrorKind as SEK};
use error::MapErrInto;
use storeid::{IntoStoreId, StoreId, StoreIdIterator};
@@ -944,7 +942,15 @@ impl<'a> DerefMut for FileLockEntry<'a> {
impl<'a> Drop for FileLockEntry<'a> {
/// This will silently ignore errors, use `Store::update` if you want to catch the errors
fn drop(&mut self) {
- let _ = self.store._update(self, true);
+ use libimagerror::trace::trace_error_dbg;
+
+ match self.store._update(self, true) {
+ Err(e) => {
+ trace_error_dbg(&e);
+ if_cfg_panic!("ERROR WHILE DROPPING: {:?}", e);
+ },
+ Ok(_) => { },
+ }
}
}
@@ -960,176 +966,6 @@ impl<'a> Drop for FileLockEntry<'a> {
/// `EntryContent` type
pub type EntryContent = String;
-/// `EntryHeader`
-///
-/// This is basically a wrapper around `toml::Table` which provides convenience to the user of the
-/// library.
-#[derive(Debug, Clone, PartialEq)]
-pub struct EntryHeader(Value);
-
-pub type EntryResult<V> = RResult<V, ParserError>;
-
-/**
- * Wrapper type around file header (TOML) object
- */
-impl EntryHeader {
-
- pub fn new() -> EntryHeader {
- EntryHeader(build_default_header())
- }
-
- pub fn header(&self) -> &Value {
- &self.0
- }
-
- fn from_table(t: Table) -> EntryHeader {
- EntryHeader(Value::Table(t))
- }
-
- pub fn parse(s: &str) -> EntryResult<EntryHeader> {
- use toml::Parser;
-
- let mut parser = Parser::new(s);
- parser.parse()
- .ok_or(ParserErrorKind::TOMLParserErrors.into())
- .and_then(verify_header_consistency)
- .map(EntryHeader::from_table)
- }
-
- pub fn verify(&self) -> Result<()> {
- match self.0 {
- Value::Table(ref t) => verify_header(&t),
- _ => Err(SE::new(SEK::HeaderTypeFailure, None)),
- }
- }
-
- #[inline]
- pub fn insert_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result<bool> {
- self.0.insert_with_sep(spec, sep, v)
- }
-
- #[inline]
- pub fn set_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result<Option<Value>> {
- self.0.set_with_sep(spec, sep, v)
- }
-
- #[inline]
- pub fn read_with_sep(&self, spec: &str, splitchr: char) -> Result<Option<Value>> {
- self.0.read_with_sep(spec, splitchr)
- }
-
- #[inline]
- pub fn delete_with_sep(&mut self, spec: &str, splitchr: char) -> Result<Option<Value>> {
- self.0.delete_with_sep(spec, splitchr)
- }
-
- #[inline]
- pub fn insert(&mut self, spec: &str, v: Value) -> Result<bool> {
- self.0.insert(spec, v)
- }
-
- #[inline]
- pub fn set(&mut self, spec: &str, v: Value) -> Result<Option<Value>> {
- self.0.set(spec, v)
- }
-
- #[inline]
- pub fn read(&self, spec: &str) -> Result<Option<Value>> {
- self.0.read(spec)
- }
-
- #[inline]
- pub fn delete(&mut self, spec: &str) -> Result<Option<Value>> {
- self.0.delete(spec)
- }
-
-}
-
-impl Into<Table> for EntryHeader {
-
- fn into(self) -> Table {
- match self.0 {
- Value::Table(t) => t,
- _ => panic!("EntryHeader is not a table!"),
- }
- }
-
-}
-
-impl From<Table> for EntryHeader {
-
- fn from(t: Table) -> EntryHeader {
- EntryHeader(Value::Table(t))
- }
-
-}
-
-fn build_default_header() -> Value { // BTreeMap<String, 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(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 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 has_only_tables(t: &Table) -> bool {
- debug!("Verifying that table has only tables");
- t.iter().all(|(_, x)| if let Value::Table(_) = *x { true } else { false })
-}
-
-fn has_main_section(t: &Table) -> bool {
- t.contains_key("imag") &&
- match t.get("imag") {
- Some(&Value::Table(_)) => true,
- Some(_) => false,
- None => false,
- }
-}
-
-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,
- }
-}
-
/**
* An Entry of the store
*
@@ -1138,7 +974,7 @@ fn has_imag_version_in_main_section(t: &Table) -> bool {
#[derive(Debug, Clone)]
pub struct Entry {
location: StoreId,
- header: EntryHeader,
+ header: Value,
content: EntryContent,
}
@@ -1147,11 +983,15 @@ impl Entry {
pub fn new(loc: StoreId) -> Entry {
Entry {
location: loc,
- header: EntryHeader::new(),
+ header: Entry::default_header(),
content: EntryContent::new()
}
}
+ pub fn default_header() -> Value { // BTreeMap<String, Value>
+ Value::default_header()
+ }
+
pub fn from_reader<S: IntoStoreId>(loc: S, file: &mut Read) -> Result<Entry> {
let text = {
let mut s = String::new();
@@ -1187,14 +1027,14 @@ impl Entry {
debug!("Header and content found. Yay! Building Entry object now");
Ok(Entry {
location: try!(loc.into_storeid()),
- header: try!(EntryHeader::parse(header.as_str())),
+ header: try!(Value::parse(header.as_str())),
content: String::from(content),
})
}
pub fn to_str(&self) -> String {
format!("---\n{header}---\n{content}",
- header = ::toml::encode_str(&self.header.0),
+ header = ::toml::encode_str(&self.header),
content = self.content)
}
@@ -1202,11 +1042,11 @@ impl Entry {
&self.location
}
- pub fn get_header(&self) -> &EntryHeader {
+ pub fn get_header(&self) -> &Value {
&self.header
}
- pub fn get_header_mut(&mut self) -> &mut EntryHeader {
+ pub fn get_header_mut(&mut self) -> &mut Value {
&mut self.header
}
@@ -1314,7 +1154,7 @@ mod test {
#[test]
fn test_imag_section() {
- use super::has_main_section;
+ use toml_ext::has_main_section;
let mut map = BTreeMap::new();
map.insert("imag".into(), Value::Table(BTreeMap::new()));
@@ -1324,7 +1164,7 @@ mod test {
#[test]
fn test_imag_invalid_section_type() {
- use super::has_main_section;
+ use toml_ext::has_main_section;
let mut map = BTreeMap::new();
map.insert("imag".into(), Value::Boolean(false));
@@ -1334,7 +1174,7 @@ mod test {
#[test]
fn test_imag_abscent_main_section() {
- use super::has_main_section;
+ use toml_ext::has_main_section;
let mut map = BTreeMap::new();
map.insert("not_imag".into(), Value::Boolean(false));
@@ -1344,7 +1184,7 @@ mod test {
#[test]
fn test_main_section_without_version() {
- use super::has_imag_version_in_main_section;
+ use toml_ext::has_imag_version_in_main_section;
let mut map = BTreeMap::new();
map.insert("imag".into(), Value::Table(BTreeMap::new()));
@@ -1354,7 +1194,7 @@ mod test {
#[test]
fn test_main_section_with_version() {
- use super::has_imag_version_in_main_section;
+ use toml_ext::has_imag_version_in_main_section;
let mut map = BTreeMap::new();
let mut sub = BTreeMap::new();
@@ -1366,7 +1206,7 @@ mod test {
#[test]
fn test_main_section_with_version_in_wrong_type() {
- use super::has_imag_version_in_main_section;
+ use toml_ext::has_imag_version_in_main_section;
let mut map = BTreeMap::new();
let mut sub = BTreeMap::new();
@@ -1378,7 +1218,7 @@ mod test {
#[test]
fn test_verification_good() {
- use super::verify_header_consistency;
+ use toml_ext::verify_header_consistency;
let mut header = BTreeMap::new();
let sub = {
@@ -1395,7 +1235,7 @@ mod test {
#[test]
fn test_verification_invalid_versionstring() {
- use super::verify_header_consistency;
+ use toml_ext::verify_header_consistency;
let mut header = BTreeMap::new();
let sub = {
@@ -1413,7 +1253,7 @@ mod test {
#[test]
fn test_verification_current_version() {
- use super::verify_header_consistency;
+ use toml_ext::verify_header_consistency;
let mut header = BTreeMap::new();
let sub = {
diff --git a/libimagstore/src/toml_ext.rs b/libimagstore/src/toml_ext.rs
index c0bd79b..1ac4cf1 100644
--- a/libimagstore/src/toml_ext.rs
+++ b/libimagstore/src/toml_ext.rs
@@ -17,10 +17,15 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
-use toml::Value;
+use std::result::Result as RResult;
+use std::collections::BTreeMap;
+
+use toml::{Table, Value};
use store::Result;
+use error::StoreError as SE;
use error::StoreErrorKind as SEK;
+use error::{ParserErrorKind, ParserError};
use libimagerror::into::IntoError;
pub trait TomlValueExt {
@@ -353,10 +358,104 @@ impl Extract for Value {
}
}
+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::Parser;
+
+ let mut parser = Parser::new(s);
+ parser.parse()
+ .ok_or(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 store::EntryHeader;
+ use super::TomlValueExt;
use super::{tokenize, walk_header};
use super::Token;
@@ -619,11 +718,7 @@ mod test {
#[test]
fn test_header_read() {
- let v = create_header();
- let h = match v {
- Value::Table(t) => EntryHeader::from(t),
- _ => panic!("create_header() doesn't return a table!"),
- };
+ 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 });
@@ -656,11 +751,7 @@ mod test {
#[test]
fn test_header_set_override() {
let _ = env_logger::init();
- let v = create_header();
- let mut h = match v {
- Value::Table(t) => EntryHeader::from(t),
- _ => panic!("create_header() doesn't return a table!"),
- };
+ let mut h = create_header();
println!("Testing index 0");
assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(0));
@@ -686,11 +777,7 @@ mod test {
#[test]
fn test_header_set_new() {
let _ = env_logger::init();
- let v = create_header();
- let mut h = match v {
- Value::Table(t) => EntryHeader::from(t),
- _ => panic!("create_header() doesn't return a table!"),
- };
+ let mut h = create_header();
assert!(h.read("a.foo").is_ok());
assert!(h.read("a.foo").unwrap().is_none());
@@ -727,11 +814,7 @@ mod test {
#[test]
fn test_header_insert_override() {
let _ = env_logger::init();
- let v = create_header();
- let mut h = match v {
- Value::Table(t) => EntryHeader::from(t),
- _ => panic!("create_header() doesn't return a table!"),
- };
+ let mut h = create_header();
println!("Testing index 0");
assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(0));
@@ -756,11 +839,7 @@ mod test {
#[test]
fn test_header_insert_new() {
let _ = env_logger::init();
- let v = create_header();
- let mut h = match v {
- Value::Table(t) => EntryHeader::from(t),
- _ => panic!("create_header() doesn't return a table!"),
- };
+ let mut h = create_header();
assert!(h.read("a.foo").is_ok());
assert!(h.read("a.foo").unwrap().is_none());
@@ -796,11 +875,7 @@ mod test {
#[test]
fn test_header_delete() {
let _ = env_logger::init();
- let v = create_header();
- let mut h = match v {
- Value::Table(t) => EntryHeader::from(t),
- _ => panic!("create_header() doesn't return a table!"),
- };
+ 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 });
@@ -815,3 +890,4 @@ mod test {
}
}
+
diff --git a/libimagstore/src/util.rs b/libimagstore/src/util.rs
new file mode 100644
index 0000000..9ff4a14
--- /dev/null
+++ b/libimagstore/src/util.rs
@@ -0,0 +1,35 @@
+//
+// 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
+//
+
+#[cfg(feature = "early-panic")]
+#[macro_export]
+macro_rules! if_cfg_panic {
+ () => { panic!() };
+ ($msg:expr) => { panic!($msg) };
+ ($fmt:expr, $($arg:tt)+) => { panic!($fmt, $($($arg),*)) };
+}
+
+#[cfg(not(feature = "early-panic"))]
+#[macro_export]
+macro_rules! if_cfg_panic {
+ () => { };
+ ($msg:expr) => { };
+ ($fmt:expr, $($arg:tt)+) => { };
+}
+