diff --git a/doc/src/09020-changelog.md b/doc/src/09020-changelog.md index 8ab0270f..7f4aace2 100644 --- a/doc/src/09020-changelog.md +++ b/doc/src/09020-changelog.md @@ -29,6 +29,11 @@ This section contains the changelog from the last release to the next release. stderr) * `imag-store` can dump all storeids now +* Minor changes + * `libimagentryannotation` got a rewrite, is not based on `libimagnotes` + anymore. This is minor because `libimagentryanntation` is not yet used by + any other crate. + ## 0.4.0 * Major changes diff --git a/lib/entry/libimagentryannotation/Cargo.toml b/lib/entry/libimagentryannotation/Cargo.toml index bc738f42..430c5095 100644 --- a/lib/entry/libimagentryannotation/Cargo.toml +++ b/lib/entry/libimagentryannotation/Cargo.toml @@ -17,5 +17,4 @@ error-chain = "0.11" libimagstore = { version = "0.5.0", path = "../../../lib/core/libimagstore" } libimagerror = { version = "0.5.0", path = "../../../lib/core/libimagerror" } -libimagnotes = { version = "0.5.0", path = "../../../lib/domain/libimagnotes" } libimagentrylink = { version = "0.5.0", path = "../../../lib/entry/libimagentrylink" } diff --git a/lib/entry/libimagentryannotation/src/annotateable.rs b/lib/entry/libimagentryannotation/src/annotateable.rs index d51380cc..bc2aaa4b 100644 --- a/lib/entry/libimagentryannotation/src/annotateable.rs +++ b/lib/entry/libimagentryannotation/src/annotateable.rs @@ -17,13 +17,13 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -use std::path::PathBuf; - use toml::Value; use libimagstore::store::Entry; use libimagstore::store::FileLockEntry; use libimagstore::store::Store; +use libimagstore::storeid::IntoStoreId; +use libimagstore::storeid::StoreIdIterator; use libimagentrylink::internal::InternalLinker; use toml_query::read::TomlValueReadExt; @@ -34,29 +34,29 @@ use error::AnnotationErrorKind as AEK; use error::AnnotationError as AE; use error::ResultExt; +use iter::*; + pub trait Annotateable { - - /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in - /// libimagentrylink). - /// - /// A new annotation also has the field `annotation.is_annotation` set to `true`. fn annotate<'a>(&mut self, store: &'a Store, ann_name: &str) -> Result>; - - /// Check whether an entry is an annotation + fn denotate<'a>(&mut self, store: &'a Store, ann_name: &str) -> Result>>; + fn annotations<'a>(&self, store: &'a Store) -> Result>; fn is_annotation(&self) -> Result; - } impl Annotateable for Entry { + /// Annotate an entry, returns the new entry which is used to annotate fn annotate<'a>(&mut self, store: &'a Store, ann_name: &str) -> Result> { - store.retrieve(PathBuf::from(ann_name)) - .chain_err(|| AEK::StoreWriteError) + use module_path::ModuleEntryPath; + store.retrieve(try!(ModuleEntryPath::new(ann_name).into_storeid())) + .map_err(From::from) .and_then(|mut anno| { - anno.get_header_mut() - .insert("annotation.is_annotation", Value::Boolean(true)) - .chain_err(|| AEK::HeaderWriteError) - .map(|_| anno) + { + let header = anno.get_header_mut(); + try!(header.insert("annotation.is_annotation", Value::Boolean(true))); + try!(header.insert("annotation.name", Value::String(String::from(ann_name)))); + } + Ok(anno) }) .and_then(|mut anno| { anno.add_internal_link(self) @@ -65,10 +65,39 @@ impl Annotateable for Entry { }) } + /// Checks the current entry for all annotations and removes the one where the name is + /// `ann_name`, which is then returned + fn denotate<'a>(&mut self, store: &'a Store, ann_name: &str) -> Result>> { + for annotation in self.annotations(store)? { + let mut anno = try!(annotation); + let name = match anno.get_header().read("annotation.name")? { + None => continue, + Some(val) => match *val { + Value::String(ref name) => name.clone(), + _ => return Err(AE::from_kind(AEK::HeaderTypeError)), + }, + }; + + if name == ann_name { + let _ = try!(self.remove_internal_link(&mut anno)); + } + } + + Ok(None) + } + + /// Get all annotations of an entry + fn annotations<'a>(&self, store: &'a Store) -> Result> { + self.get_internal_links() + .map_err(From::from) + .map(|iter| StoreIdIterator::new(Box::new(iter.map(|e| e.get_store_id().clone())))) + .map(|i| AnnotationIter::new(i, store)) + } + fn is_annotation(&self) -> Result { self.get_header() .read("annotation.is_annotation") - .chain_err(|| AEK::StoreReadError) + .map_err(From::from) .and_then(|res| match res { Some(&Value::Boolean(b)) => Ok(b), None => Ok(false), diff --git a/lib/entry/libimagentryannotation/src/annotation_fetcher.rs b/lib/entry/libimagentryannotation/src/annotation_fetcher.rs index afdec887..a19b6ccc 100644 --- a/lib/entry/libimagentryannotation/src/annotation_fetcher.rs +++ b/lib/entry/libimagentryannotation/src/annotation_fetcher.rs @@ -17,100 +17,23 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -use libimagstore::store::Entry; use libimagstore::store::Store; -use libimagentrylink::internal::InternalLinker; -use libimagnotes::notestore::NoteStore; -use libimagnotes::iter::NoteIterator; -use libimagstore::storeid::StoreIdIterator; use error::Result; -use error::AnnotationErrorKind as AEK; -use error::ResultExt; - -use self::iter::*; +use iter::*; pub trait AnnotationFetcher<'a> { fn all_annotations(&'a self) -> Result>; - fn annotations_for_entry(&'a self, entry: &Entry) -> Result>; - } impl<'a> AnnotationFetcher<'a> for Store { - /// Wrapper around `Note::all_notes()` of `libimagnotes` which filters out normal notes and - /// leaves only annotations in the iterator. fn all_annotations(&'a self) -> Result> { - NoteStore::all_notes(self) + self.retrieve_for_module("annotations") .map(|iter| AnnotationIter::new(iter, self)) - .chain_err(|| AEK::StoreReadError) - } - - /// Get all annotations (in an iterator) for an entry - /// - /// Internally, this fetches the links of the entry, fetches all the entries behind the links - /// and filters them for annotations. - /// - /// This might result in some heavy IO operations if a lot of stuff is linked to a single - /// entry, but should normally be not that heavy. - fn annotations_for_entry(&'a self, entry: &Entry) -> Result> { - entry.get_internal_links() - .chain_err(|| AEK::StoreReadError) - .map(|iter| StoreIdIterator::new(Box::new(iter.map(|e| e.get_store_id().clone())))) - .map(NoteIterator::new) - .map(|i| AnnotationIter::new(i, self)) - } - -} - -pub mod iter { - use toml::Value; - - use toml_query::read::TomlValueReadExt; - - use libimagnotes::iter::NoteIterator; - use libimagstore::store::Store; - use libimagstore::store::FileLockEntry; - - use error::Result; - use error::AnnotationErrorKind as AEK; - use error::AnnotationError as AE; - use error::ResultExt; - - #[derive(Debug)] - pub struct AnnotationIter<'a>(NoteIterator, &'a Store); - - impl<'a> AnnotationIter<'a> { - - pub fn new(noteiter: NoteIterator, store: &'a Store) -> AnnotationIter<'a> { - AnnotationIter(noteiter, store) - } - - } - - impl<'a> Iterator for AnnotationIter<'a> { - type Item = Result>; - - fn next(&mut self) -> Option { - loop { - match self.0.next().map(|id| self.1.get(id)) { - Some(Ok(Some(note))) => { - 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(_)) => return Some(Err(AE::from_kind(AEK::HeaderTypeError))), - Err(e) => return Some(Err(e).chain_err(|| AEK::HeaderReadError)), - } - }, - Some(Ok(None)) => continue, - Some(Err(e)) => return Some(Err(e).chain_err(|| AEK::StoreReadError)), - None => return None, // iterator consumed - } - } - } - + .map_err(Into::into) } } diff --git a/lib/entry/libimagentryannotation/src/error.rs b/lib/entry/libimagentryannotation/src/error.rs index 8a349b71..8e250044 100644 --- a/lib/entry/libimagentryannotation/src/error.rs +++ b/lib/entry/libimagentryannotation/src/error.rs @@ -22,6 +22,15 @@ error_chain! { AnnotationError, AnnotationErrorKind, ResultExt, Result; } + links { + StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind); + LinkError(::libimagentrylink::error::LinkError, ::libimagentrylink::error::LinkErrorKind); + } + + foreign_links { + TomlQueryError(::toml_query::error::Error); + } + errors { StoreReadError { description("Store read error") diff --git a/lib/entry/libimagentryannotation/src/iter.rs b/lib/entry/libimagentryannotation/src/iter.rs new file mode 100644 index 00000000..04dc8e28 --- /dev/null +++ b/lib/entry/libimagentryannotation/src/iter.rs @@ -0,0 +1,65 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer 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 toml::Value; +use toml_query::read::TomlValueReadExt; + +use libimagstore::store::Store; +use libimagstore::store::FileLockEntry; +use libimagstore::storeid::StoreIdIterator; + +use error::Result; +use error::AnnotationErrorKind as AEK; +use error::AnnotationError as AE; +use error::ResultExt; + +#[derive(Debug)] +pub struct AnnotationIter<'a>(StoreIdIterator, &'a Store); + +impl<'a> AnnotationIter<'a> { + + pub fn new(iter: StoreIdIterator, store: &'a Store) -> AnnotationIter<'a> { + AnnotationIter(iter, store) + } + +} + +impl<'a> Iterator for AnnotationIter<'a> { + type Item = Result>; + + fn next(&mut self) -> Option { + loop { + match self.0.next().map(|id| self.1.get(id)) { + Some(Ok(Some(entry))) => { + match entry.get_header().read("annotation.is_annotation") { + Ok(None) => continue, // not an annotation + Ok(Some(&Value::Boolean(true))) => return Some(Ok(entry)), + Ok(Some(_)) => return Some(Err(AE::from_kind(AEK::HeaderTypeError))), + Err(e) => return Some(Err(e).chain_err(|| AEK::HeaderReadError)), + } + }, + Some(Ok(None)) => continue, + Some(Err(e)) => return Some(Err(e).chain_err(|| AEK::StoreReadError)), + None => return None, // iterator consumed + } + } + } + +} + diff --git a/lib/entry/libimagentryannotation/src/lib.rs b/lib/entry/libimagentryannotation/src/lib.rs index bd1e9ed5..3bc5ad48 100644 --- a/lib/entry/libimagentryannotation/src/lib.rs +++ b/lib/entry/libimagentryannotation/src/lib.rs @@ -39,12 +39,14 @@ extern crate toml; extern crate toml_query; #[macro_use] extern crate error_chain; +#[macro_use] extern crate libimagstore; extern crate libimagerror; -extern crate libimagstore; extern crate libimagentrylink; -extern crate libimagnotes; + +module_entry_path_mod!("annotations"); pub mod annotateable; pub mod annotation_fetcher; pub mod error; +pub mod iter;