~matthiasbeyer/imag

a6ad19a14f16c5344ea65df3efcc00464b2ad9aa — Matthias Beyer 2 years ago 08b7a46 + 6fd2c9b
Merge branch 'redefine-storeid'

Finally merging the redefine of the StoreId implementation, which allows
easier handling of StoreId objects.

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
40 files changed, 296 insertions(+), 415 deletions(-)

M bin/core/imag-annotate/src/main.rs
M bin/core/imag-ids/src/main.rs
M bin/core/imag-link/src/main.rs
M bin/core/imag-mv/src/main.rs
M bin/core/imag-store/src/create.rs
M bin/core/imag-store/src/delete.rs
M bin/core/imag-store/src/get.rs
M bin/core/imag-store/src/retrieve.rs
M bin/core/imag-store/src/update.rs
M bin/core/imag-tag/src/main.rs
M bin/domain/imag-contact/src/main.rs
M lib/core/libimagrt/src/runtime.rs
M lib/core/libimagstore/src/file_abstraction/fs.rs
M lib/core/libimagstore/src/file_abstraction/inmemory.rs
M lib/core/libimagstore/src/file_abstraction/iter.rs
M lib/core/libimagstore/src/file_abstraction/mod.rs
M lib/core/libimagstore/src/iter.rs
M lib/core/libimagstore/src/lib.rs
M lib/core/libimagstore/src/store.rs
M lib/core/libimagstore/src/storeid.rs
M lib/domain/libimagcontact/src/store.rs
M lib/domain/libimagdiary/src/diary.rs
M lib/domain/libimaghabit/src/iter.rs
M lib/domain/libimaghabit/src/store.rs
M lib/domain/libimagnotes/src/notestore.rs
M lib/domain/libimagtimetrack/src/iter/mod.rs
M lib/domain/libimagtimetrack/src/tag.rs
M lib/domain/libimagtodo/src/iter.rs
M lib/domain/libimagtodo/src/taskstore.rs
M lib/domain/libimagwiki/src/wiki.rs
M lib/entry/libimagentryannotation/src/annotation_fetcher.rs
M lib/entry/libimagentrycategory/src/store.rs
M lib/entry/libimagentrydatetime/src/datepath/compiler.rs
M lib/entry/libimagentrydatetime/src/datetime.rs
M lib/entry/libimagentrygps/src/entry.rs
M lib/entry/libimagentrylink/src/external.rs
M lib/entry/libimagentrylink/src/internal.rs
M lib/entry/libimagentrymarkdown/src/processor.rs
M lib/entry/libimagentryref/src/refstore.rs
M lib/etc/libimaginteraction/src/ui.rs
M bin/core/imag-annotate/src/main.rs => bin/core/imag-annotate/src/main.rs +1 -1
@@ 208,7 208,7 @@ fn list(rt: &Runtime) {
        rt.store()
            .all_annotations()
            .map_err_trace_exit_unwrap()
            .into_get_iter(rt.store())
            .into_get_iter()
            .trace_unwrap_exit()
            .map(|opt| opt.ok_or_else(|| format_err!("Cannot find entry")))
            .trace_unwrap_exit()

M bin/core/imag-ids/src/main.rs => bin/core/imag-ids/src/main.rs +12 -8
@@ 118,23 118,27 @@ fn main() {
        }
    })
    .map(|id| if print_storepath {
        id
        (Some(rt.store().path()), id)
    } else {
        id.without_base()
        (None, id)
    });

    let mut stdout = rt.stdout();
    trace!("Got output: {:?}", stdout);

    iterator.for_each(|id| {
        let _ = rt.report_touched(&id).unwrap_or_exit(); // .map_err_trace_exit_unwrap();

    iterator.for_each(|(storepath, id)| {
        rt.report_touched(&id).unwrap_or_exit();
        if !rt.output_is_pipe() {
            let id = id.to_str().map_err_trace_exit_unwrap();
            trace!("Writing to {:?}", stdout);
            writeln!(stdout, "{}", id)
                .to_exit_code()
                .unwrap_or_exit();

            let result = if let Some(store) = storepath {
                writeln!(stdout, "{}/{}", store.display(), id)
            } else {
                writeln!(stdout, "{}", id)
            };

            result.to_exit_code().unwrap_or_exit();
        }
    })
}

M bin/core/imag-link/src/main.rs => bin/core/imag-link/src/main.rs +5 -6
@@ 132,8 132,7 @@ fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockE
    use libimagstore::storeid::StoreId;

    debug!("Getting: {:?}", name);
    let result = StoreId::new(Some(rt.store().path().clone()), PathBuf::from(name))
        .and_then(|id| rt.store().get(id));
    let result = StoreId::new(PathBuf::from(name)).and_then(|id| rt.store().get(id));

    debug!(" => : {:?}", result);
    result


@@ 168,8 167,8 @@ fn link_from_to<'a, I>(rt: &'a Runtime, from: &'a str, to: I)
        } else {
            debug!("Linking internally: {:?} -> {:?}", from, entry);

            let from_id = StoreId::new_baseless(PathBuf::from(from)).map_err_trace_exit_unwrap();
            let entr_id = StoreId::new_baseless(PathBuf::from(entry)).map_err_trace_exit_unwrap();
            let from_id = StoreId::new(PathBuf::from(from)).map_err_trace_exit_unwrap();
            let entr_id = StoreId::new(PathBuf::from(entry)).map_err_trace_exit_unwrap();

            if from_id == entr_id {
                error!("Cannot link entry with itself. Exiting");


@@ 366,13 365,13 @@ mod tests {
        let mut path = PathBuf::new();
        path.set_file_name(name);

        let default_entry = Entry::new(StoreId::new_baseless(PathBuf::from("")).unwrap())
        let default_entry = Entry::new(StoreId::new(PathBuf::from("")).unwrap())
            .to_str()
            .unwrap();

        debug!("Default entry constructed");

        let id = StoreId::new_baseless(path)?;
        let id = StoreId::new(path)?;
        debug!("StoreId constructed: {:?}", id);

        let mut entry = rt.store().create(id.clone())?;

M bin/core/imag-mv/src/main.rs => bin/core/imag-mv/src/main.rs +2 -2
@@ 72,7 72,7 @@ fn main() {
        .cli()
        .value_of("source")
        .map(PathBuf::from)
        .map(StoreId::new_baseless)
        .map(StoreId::new)
        .unwrap() // unwrap safe by clap
        .map_err_trace_exit_unwrap();



@@ 80,7 80,7 @@ fn main() {
        .cli()
        .value_of("dest")
        .map(PathBuf::from)
        .map(StoreId::new_baseless)
        .map(StoreId::new)
        .unwrap() // unwrap safe by clap
        .map_err_trace_exit_unwrap();


M bin/core/imag-store/src/create.rs => bin/core/imag-store/src/create.rs +1 -2
@@ 44,8 44,7 @@ pub fn create(rt: &Runtime) {
    // unwrap is safe as value is required
    let path  = scmd.value_of("path").unwrap();
    let path  = PathBuf::from(path);
    let store = Some(rt.store().path().clone());
    let path  = StoreId::new(store, path).map_err_trace_exit_unwrap();
    let path  = StoreId::new(path).map_err_trace_exit_unwrap();

    debug!("path = {:?}", path);


M bin/core/imag-store/src/delete.rs => bin/core/imag-store/src/delete.rs +1 -2
@@ 28,8 28,7 @@ pub fn delete(rt: &Runtime) {
    let scmd  = rt.cli().subcommand_matches("delete").unwrap();
    let id    = scmd.value_of("id").unwrap(); // safe by clap
    let path  = PathBuf::from(id);
    let store = Some(rt.store().path().clone());
    let path  = StoreId::new(store, path).map_err_trace_exit_unwrap();
    let path  = StoreId::new(path).map_err_trace_exit_unwrap();
    debug!("Deleting file at {:?}", id);

    let _ = rt.store()

M bin/core/imag-store/src/get.rs => bin/core/imag-store/src/get.rs +1 -2
@@ 31,8 31,7 @@ pub fn get(rt: &Runtime) {

    let id    = scmd.value_of("id").unwrap(); // safe by clap
    let path  = PathBuf::from(id);
    let store = Some(rt.store().path().clone());
    let path  = StoreId::new(store, path).map_err_trace_exit_unwrap();
    let path  = StoreId::new(path).map_err_trace_exit_unwrap();
    debug!("path = {:?}", path);

    let _ = match rt.store().get(path.clone()).map_err_trace_exit_unwrap() {

M bin/core/imag-store/src/retrieve.rs => bin/core/imag-store/src/retrieve.rs +1 -2
@@ 37,8 37,7 @@ pub fn retrieve(rt: &Runtime) {
            // unwrap() is safe as arg is required
            let id    = scmd.value_of("id").unwrap();
            let path  = PathBuf::from(id);
            let store = Some(rt.store().path().clone());
            let path  = StoreId::new(store, path).map_err_trace_exit_unwrap();
            let path  = StoreId::new(path).map_err_trace_exit_unwrap();
            debug!("path = {:?}", path);

            rt.store()

M bin/core/imag-store/src/update.rs => bin/core/imag-store/src/update.rs +1 -2
@@ 31,8 31,7 @@ pub fn update(rt: &Runtime) {
    let scmd  = rt.cli().subcommand_matches("update").unwrap();
    let id    = scmd.value_of("id").unwrap(); // Safe by clap
    let path  = PathBuf::from(id);
    let store = Some(rt.store().path().clone());
    let path  = StoreId::new(store, path).map_err_trace_exit_unwrap();
    let path  = StoreId::new(path).map_err_trace_exit_unwrap();

    let _ = rt.store()
        .retrieve(path)

M bin/core/imag-tag/src/main.rs => bin/core/imag-tag/src/main.rs +6 -6
@@ 264,11 264,11 @@ mod tests {
        let mut path = PathBuf::new();
        path.set_file_name(name);

        let default_entry = Entry::new(StoreId::new_baseless(PathBuf::from("")).unwrap())
        let default_entry = Entry::new(StoreId::new(PathBuf::from("")).unwrap())
            .to_str()
            .unwrap();

        let id = StoreId::new_baseless(path)?;
        let id = StoreId::new(path)?;
        let mut entry = rt.store().create(id.clone())?;
        entry.get_content_mut().push_str(&default_entry);



@@ 303,7 303,7 @@ mod tests {
        debug!("Add-tags: {:?}", add);

        debug!("Altering things");
        alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, None);
        alter(&rt, StoreId::new(id.clone()).unwrap(), add, None);
        debug!("Altered");

        let test_entry = rt.store().get(id).unwrap().unwrap();


@@ 338,7 338,7 @@ mod tests {
        debug!("Rem-tags: {:?}", rem);

        debug!("Altering things");
        alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
        alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
        debug!("Altered");

        let test_entry = rt.store().get(id).unwrap().unwrap();


@@ 366,7 366,7 @@ mod tests {
        debug!("Rem-tags: {:?}", rem);

        debug!("Altering things");
        alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
        alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
        debug!("Altered");

        let test_entry = rt.store().get(id).unwrap().unwrap();


@@ 394,7 394,7 @@ mod tests {
        debug!("Rem-tags: {:?}", rem);

        debug!("Altering things");
        alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
        alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
        debug!("Altered");

        let test_entry = rt.store().get(id).unwrap().unwrap();

M bin/domain/imag-contact/src/main.rs => bin/domain/imag-contact/src/main.rs +3 -4
@@ 73,7 73,6 @@ use libimagerror::iter::TraceIterator;
use libimagcontact::store::ContactStore;
use libimagcontact::contact::Contact;
use libimagcontact::deser::DeserVcard;
use libimagstore::iter::get::StoreIdGetIteratorExtension;

mod ui;
mod util;


@@ 120,7 119,7 @@ fn list(rt: &Runtime) {
        .store()
        .all_contacts()
        .map_err_trace_exit_unwrap()
        .into_get_iter(rt.store())
        .into_get_iter()
        .trace_unwrap_exit()
        .map(|fle| fle.ok_or_else(|| Error::from(err_msg("StoreId not found".to_owned()))))
        .trace_unwrap_exit()


@@ 206,7 205,7 @@ fn show(rt: &Runtime) {
    rt.store()
        .all_contacts()
        .map_err_trace_exit_unwrap()
        .into_get_iter(rt.store())
        .into_get_iter()
        .trace_unwrap_exit()
        .map(|o| o.unwrap_or_else(|| {
            error!("Failed to get entry");


@@ 257,7 256,7 @@ fn find(rt: &Runtime) {
        .store()
        .all_contacts()
        .map_err_trace_exit_unwrap()
        .into_get_iter(rt.store())
        .into_get_iter()
        .map(|el| {
            el.map_err_trace_exit_unwrap()
                .ok_or_else(|| {

M lib/core/libimagrt/src/runtime.rs => lib/core/libimagrt/src/runtime.rs +2 -6
@@ 22,7 22,6 @@ use std::process::Command;
use std::env;
use std::process::exit;
use std::io::Stdin;
use std::sync::Arc;
use std::io::StdoutLock;
use std::borrow::Borrow;
use std::result::Result as RResult;


@@ 48,7 47,6 @@ use libimagerror::trace::*;
use libimagerror::io::ToExitCode;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::file_abstraction::InMemoryFileAbstraction;
use libimagutil::debug_result::DebugResult;
use spec::CliSpec;
use atty;


@@ 143,9 141,7 @@ impl<'a> Runtime<'a> {
        trace!("Config      = {:#?}", config);

        let store_result = if cli_app.use_inmemory_fs() {
            Store::new_with_backend(storepath,
                                    &config,
                                    Arc::new(InMemoryFileAbstraction::default()))
            Store::new_inmemory(storepath, &config)
        } else {
            Store::new(storepath, &config)
        };


@@ 418,7 414,7 @@ impl<'a> Runtime<'a> {
                    trace!("Got IDs = {}", buf);
                    buf.lines()
                        .map(PathBuf::from)
                        .map(|id| StoreId::new_baseless(id).map_err(Error::from))
                        .map(|id| StoreId::new(id).map_err(Error::from))
                        .collect()
                })
        } else {

M lib/core/libimagstore/src/file_abstraction/fs.rs => lib/core/libimagstore/src/file_abstraction/fs.rs +6 -6
@@ 28,7 28,7 @@ use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
use storeid::StoreId;
use storeid::StoreIdWithBase;
use file_abstraction::iter::PathIterator;
use file_abstraction::iter::PathIterBuilder;



@@ 45,7 45,7 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
    /**
     * Get the content behind this file
     */
    fn get_file_content(&mut self, id: StoreId) -> Result<Option<Entry>> {
    fn get_file_content<'a>(&mut self, id: StoreIdWithBase<'a>) -> Result<Option<Entry>> {
        debug!("Getting lazy file: {:?}", self);

        let mut file = match open_file(&self.0) {


@@ 153,18 153,18 @@ impl FileAbstraction for FSFileAbstraction {
        })
    }

    fn pathes_recursively(&self,
    fn pathes_recursively<'a>(&self,
                          basepath: PathBuf,
                          storepath: PathBuf,
                          storepath: &'a PathBuf,
                          backend: Arc<FileAbstraction>)
        -> Result<PathIterator>
        -> Result<PathIterator<'a>>
    {
        trace!("Building PathIterator object");
        Ok(PathIterator::new(Box::new(WalkDirPathIterBuilder { basepath }), storepath, backend))
    }
}

pub(crate) struct WalkDirPathIterBuilder {
pub struct WalkDirPathIterBuilder {
    basepath: PathBuf
}


M lib/core/libimagstore/src/file_abstraction/inmemory.rs => lib/core/libimagstore/src/file_abstraction/inmemory.rs +4 -4
@@ 33,7 33,7 @@ use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
use storeid::StoreId;
use storeid::StoreIdWithBase;
use file_abstraction::iter::PathIterator;
use file_abstraction::iter::PathIterBuilder;



@@ 64,7 64,7 @@ impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
    /**
     * Get the mutable file behind a InMemoryFileAbstraction object
     */
    fn get_file_content(&mut self, _: StoreId) -> Result<Option<Entry>> {
    fn get_file_content(&mut self, _: StoreIdWithBase<'_>) -> Result<Option<Entry>> {
        debug!("Getting lazy file: {:?}", self);

        self.fs_abstraction


@@ 187,7 187,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
        Ok(())
    }

    fn pathes_recursively(&self, _basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator> {
    fn pathes_recursively<'a>(&self, _basepath: PathBuf, storepath: &'a PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator<'a>> {
        trace!("Building PathIterator object (inmemory implementation)");
        let keys : Vec<PathBuf> = self
            .backend()


@@ 203,7 203,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
    }
}

pub(crate) struct InMemPathIterBuilder(Vec<PathBuf>);
pub struct InMemPathIterBuilder(Vec<PathBuf>);

impl PathIterBuilder for InMemPathIterBuilder {
    fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>> {

M lib/core/libimagstore/src/file_abstraction/iter.rs => lib/core/libimagstore/src/file_abstraction/iter.rs +22 -10
@@ 22,11 22,11 @@ use std::sync::Arc;

use failure::Fallible as Result;

use storeid::StoreId;
use storeid::StoreIdWithBase;
use file_abstraction::FileAbstraction;

/// See documentation for PathIterator
pub trait PathIterBuilder {
pub(crate) trait PathIterBuilder {
    fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>>;
    fn in_collection(&mut self, c: &str);
}


@@ 45,19 45,19 @@ pub trait PathIterBuilder {
///
/// This means quite a few allocations down the road, as the PathIterator itself is not generic, but
/// this seems to be the best way to implement this.
pub struct PathIterator {
pub(crate) struct PathIterator<'a> {
    iter_builder: Box<PathIterBuilder>,
    iter:         Box<Iterator<Item = Result<PathBuf>>>,
    storepath:    PathBuf,
    storepath:    &'a PathBuf,
    backend:      Arc<FileAbstraction>,
}

impl PathIterator {
impl<'a> PathIterator<'a> {

    pub fn new(iter_builder: Box<PathIterBuilder>,
               storepath: PathBuf,
               storepath: &'a PathBuf,
               backend: Arc<FileAbstraction>)
        -> PathIterator
        -> PathIterator<'a>
    {
        trace!("Generating iterator object with PathIterBuilder");
        let iter = iter_builder.build_iter();


@@ 71,10 71,22 @@ impl PathIterator {
        self
    }

    /// Turn iterator into its internals
    ///
    /// Used for `Entries::into_storeid_iter()`
    ///
    /// # TODO
    ///
    /// Revisit whether this can be done in a cleaner way. See commit message for why this is
    /// needed.
    pub(crate) fn into_inner(self) -> Box<Iterator<Item = Result<PathBuf>>> {
        self.iter
    }

}

impl Iterator for PathIterator {
    type Item = Result<StoreId>;
impl<'a> Iterator for PathIterator<'a> {
    type Item = Result<StoreIdWithBase<'a>>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(next) = self.iter.next() {


@@ 82,7 94,7 @@ impl Iterator for PathIterator {
                Err(e)   => return Some(Err(e)),
                Ok(next) => match self.backend.is_file(&next) {
                    Err(e)    => return Some(Err(e)),
                    Ok(true)  => return Some(StoreId::from_full_path(&self.storepath, next)),
                    Ok(true)  => return Some(StoreIdWithBase::from_full_path(&self.storepath, next)),
                    Ok(false) => { continue },
                }
            }

M lib/core/libimagstore/src/file_abstraction/mod.rs => lib/core/libimagstore/src/file_abstraction/mod.rs +16 -17
@@ 25,20 25,16 @@ use std::sync::Arc;
use failure::Fallible as Result;

use store::Entry;
use storeid::StoreId;
use storeid::StoreIdWithBase;

mod fs;
mod inmemory;
pub(crate) mod iter;
pub mod fs;
pub mod inmemory;
pub mod iter;

pub use self::fs::FSFileAbstraction;
pub use self::fs::FSFileAbstractionInstance;
pub use self::inmemory::InMemoryFileAbstraction;
pub use self::inmemory::InMemoryFileAbstractionInstance;
use self::iter::PathIterator;

/// An abstraction trait over filesystem actions
pub trait FileAbstraction : Debug {
pub(crate) trait FileAbstraction : Debug {
    fn remove_file(&self, path: &PathBuf) -> Result<()>;
    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;
    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;


@@ 52,17 48,17 @@ pub trait FileAbstraction : Debug {
    fn drain(&self) -> Result<Drain>;
    fn fill<'a>(&'a mut self, d: Drain) -> Result<()>;

    fn pathes_recursively(&self, basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator>;
    fn pathes_recursively<'a>(&self, basepath: PathBuf, storepath: &'a PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator<'a>>;
}

/// An abstraction trait over actions on files
pub trait FileAbstractionInstance : Debug {
pub(crate) trait FileAbstractionInstance : Debug {

    /// Get the contents of the FileAbstractionInstance, as Entry object.
    ///
    /// The `StoreId` is passed because the backend does not know where the Entry lives, but the
    /// The `StoreIdWithBase` is passed because the backend does not know where the Entry lives, but the
    /// Entry type itself must be constructed with the id.
    fn get_file_content(&mut self, id: StoreId) -> Result<Option<Entry>>;
    fn get_file_content<'a>(&mut self, id: StoreIdWithBase<'a>) -> Result<Option<Entry>>;
    fn write_file_content(&mut self, buf: &Entry) -> Result<()>;
}



@@ 101,18 97,19 @@ mod test {
    use super::FileAbstractionInstance;
    use super::inmemory::InMemoryFileAbstraction;
    use super::inmemory::InMemoryFileAbstractionInstance;
    use storeid::StoreId;
    use storeid::StoreIdWithBase;
    use store::Entry;

    #[test]
    fn lazy_file() {
        let store_path = PathBuf::from("/");
        let fs = InMemoryFileAbstraction::default();

        let mut path = PathBuf::from("tests");
        path.set_file_name("test1");
        let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());

        let loca = StoreId::new_baseless(path).unwrap();
        let loca = StoreIdWithBase::new(&store_path, path);
        let file = Entry::from_str(loca.clone(), &format!(r#"---
[imag]
version = "{}"


@@ 126,13 123,14 @@ Hello World"#, env!("CARGO_PKG_VERSION"))).unwrap();

    #[test]
    fn lazy_file_multiline() {
        let store_path = PathBuf::from("/");
        let fs = InMemoryFileAbstraction::default();

        let mut path = PathBuf::from("tests");
        path.set_file_name("test1");
        let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());

        let loca = StoreId::new_baseless(path).unwrap();
        let loca = StoreIdWithBase::new(&store_path, path);
        let file = Entry::from_str(loca.clone(), &format!(r#"---
[imag]
version = "{}"


@@ 147,13 145,14 @@ baz"#, env!("CARGO_PKG_VERSION"))).unwrap();

    #[test]
    fn lazy_file_multiline_trailing_newlines() {
        let store_path = PathBuf::from("/");
        let fs = InMemoryFileAbstraction::default();

        let mut path = PathBuf::from("tests");
        path.set_file_name("test1");
        let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());

        let loca = StoreId::new_baseless(path).unwrap();
        let loca = StoreIdWithBase::new(&store_path, path);
        let file = Entry::from_str(loca.clone(), &format!(r#"---
[imag]
version = "{}"

M lib/core/libimagstore/src/iter.rs => lib/core/libimagstore/src/iter.rs +19 -10
@@ 167,11 167,11 @@ use failure::Fallible as Result;
///
/// Functionality to exclude subdirectories is not possible with the current implementation and has
/// to be done during iteration, with filtering (as usual).
pub struct Entries<'a>(PathIterator, &'a Store);
pub struct Entries<'a>(PathIterator<'a>, &'a Store);

impl<'a> Entries<'a> {

    pub(crate) fn new(pi: PathIterator, store: &'a Store) -> Self {
    pub(crate) fn new(pi: PathIterator<'a>, store: &'a Store) -> Self {
        Entries(pi, store)
    }



@@ 179,29 179,38 @@ impl<'a> Entries<'a> {
        Entries(self.0.in_collection(c), self.1)
    }

    pub fn without_store(self) -> StoreIdIterator {
        StoreIdIterator::new(Box::new(self.0))
    /// Turn `Entries` iterator into generic `StoreIdIterator`
    ///
    /// # TODO
    ///
    /// Revisit whether this can be done in a cleaner way. See commit message for why this is
    /// needed.
    pub fn into_storeid_iter(self) -> StoreIdIterator {
        let iter = self.0
            .into_inner()
            .map(|r| r.and_then(StoreId::new));
        StoreIdIterator::new(Box::new(iter))
    }

    /// Transform the iterator into a StoreDeleteIterator
    ///
    /// This immitates the API from `libimagstore::iter`.
    pub fn into_delete_iter(self) -> StoreDeleteIterator<'a> {
        StoreDeleteIterator::new(Box::new(self.0), self.1)
        StoreDeleteIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))), self.1)
    }

    /// Transform the iterator into a StoreGetIterator
    ///
    /// This immitates the API from `libimagstore::iter`.
    pub fn into_get_iter(self) -> StoreGetIterator<'a> {
        StoreGetIterator::new(Box::new(self.0), self.1)
        StoreGetIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))), self.1)
    }

    /// Transform the iterator into a StoreRetrieveIterator
    ///
    /// This immitates the API from `libimagstore::iter`.
    pub fn into_retrieve_iter(self) -> StoreRetrieveIterator<'a> {
        StoreRetrieveIterator::new(Box::new(self.0), self.1)
        StoreRetrieveIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))), self.1)
    }

}


@@ 210,7 219,7 @@ impl<'a> Iterator for Entries<'a> {
    type Item = Result<StoreId>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
        self.0.next().map(|r| r.map(|id| id.without_base()))
    }
}



@@ 227,7 236,7 @@ mod tests {

    use store::Store;
    use storeid::StoreId;
    use file_abstraction::InMemoryFileAbstraction;
    use file_abstraction::inmemory::InMemoryFileAbstraction;
    use libimagutil::variants::generate_variants;

    pub fn get_store() -> Store {


@@ 244,7 253,7 @@ mod tests {
            let base = String::from("entry");
            let variants = vec!["coll_1", "coll_2", "coll_3"];
            let modifier = |base: &String, v: &&str| {
                StoreId::new(Some(store.path().clone()), PathBuf::from(format!("{}/{}", *v, base))).unwrap()
                StoreId::new(PathBuf::from(format!("{}/{}", *v, base))).unwrap()
            };

            generate_variants(&base, variants.iter(), &modifier)

M lib/core/libimagstore/src/lib.rs => lib/core/libimagstore/src/lib.rs +1 -1
@@ 58,5 58,5 @@ pub mod storeid;
pub mod iter;
pub mod store;
mod configuration;
pub mod file_abstraction;
mod file_abstraction;


M lib/core/libimagstore/src/store.rs => lib/core/libimagstore/src/store.rs +52 -51
@@ 43,12 43,10 @@ use failure::Error;

use storeid::{IntoStoreId, StoreId};
use iter::Entries;
use file_abstraction::FileAbstraction;
use file_abstraction::FileAbstractionInstance;

// We re-export the following things so tests can use them
pub use file_abstraction::FileAbstraction;
pub use file_abstraction::FSFileAbstraction;
pub use file_abstraction::InMemoryFileAbstraction;
use file_abstraction::fs::FSFileAbstraction;
use file_abstraction::inmemory::InMemoryFileAbstraction;

use libimagutil::debug_result::*;



@@ 64,14 62,15 @@ enum StoreEntryStatus {
#[derive(Debug)]
struct StoreEntry {
    id: StoreId,
    store_base: PathBuf, // small sacrefice over lifetimes on the Store type
    file: Box<FileAbstractionInstance>,
    status: StoreEntryStatus,
}

impl StoreEntry {

    fn new(id: StoreId, backend: &Arc<FileAbstraction>) -> Result<StoreEntry> {
        let pb = id.clone().into_pathbuf()?;
    fn new(store_base: PathBuf, id: StoreId, backend: &Arc<FileAbstraction>) -> Result<StoreEntry> {
        let pb = id.clone().with_base(&store_base).into_pathbuf()?;

        #[cfg(feature = "fs-lock")]
        {


@@ 82,6 81,7 @@ impl StoreEntry {

        Ok(StoreEntry {
            id,
            store_base,
            file: backend.new_instance(pb),
            status: StoreEntryStatus::Present,
        })


@@ 95,7 95,7 @@ impl StoreEntry {

    fn get_entry(&mut self) -> Result<Entry> {
        if !self.is_borrowed() {
            match self.file.get_file_content(self.id.clone())? {
            match self.file.get_file_content(self.id.clone().with_base(&self.store_base))? {
                Some(file) => Ok(file),
                None       => Ok(Entry::new(self.id.clone()))
            }


@@ 170,13 170,24 @@ impl Store {
        Store::new_with_backend(location, store_config, backend)
    }

    /// Create the store with an in-memory filesystem
    ///
    /// # Usage
    ///
    /// this is for testing purposes only
    #[inline]
    pub fn new_inmemory(location: PathBuf, store_config: &Option<Value>) -> Result<Store> {
        let backend = Arc::new(InMemoryFileAbstraction::default());
        Self::new_with_backend(location, store_config, backend)
    }

    /// Create a Store object as descripbed in `Store::new()` documentation, but with an alternative
    /// backend implementation.
    ///
    /// Do not use directly, only for testing purposes.
    pub fn new_with_backend(location: PathBuf,
                            store_config: &Option<Value>,
                            backend: Arc<FileAbstraction>) -> Result<Store> {
    pub(crate) fn new_with_backend(location: PathBuf,
                        store_config: &Option<Value>,
                        backend: Arc<FileAbstraction>) -> Result<Store> {
        use configuration::*;

        debug!("Building new Store object");


@@ 218,7 229,7 @@ impl Store {
    /// On success: FileLockEntry
    ///
    pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
        let id = id.into_storeid()?.with_base(self.path().clone());
        let id = id.into_storeid()?;

        debug!("Creating id: '{}'", id);



@@ 244,7 255,7 @@ impl Store {
            }
            hsmap.insert(id.clone(), {
                debug!("Creating: '{}'", id);
                let mut se = StoreEntry::new(id.clone(), &self.backend)?;
                let mut se = StoreEntry::new(self.path().clone(), id.clone(), &self.backend)?;
                se.status = StoreEntryStatus::Borrowed;
                se
            });


@@ 266,14 277,14 @@ impl Store {
    /// On success: FileLockEntry
    ///
    pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
        let id = id.into_storeid()?.with_base(self.path().clone());
        let id = id.into_storeid()?;
        debug!("Retrieving id: '{}'", id);
        let entry = self
            .entries
            .write()
            .map_err(|_| Error::from(EM::LockError))
            .and_then(|mut es| {
                let new_se = StoreEntry::new(id.clone(), &self.backend)?;
                let new_se = StoreEntry::new(self.path().clone(), id.clone(), &self.backend)?;
                let se = es.entry(id.clone()).or_insert(new_se);
                let entry = se.get_entry();
                se.status = StoreEntryStatus::Borrowed;


@@ 296,7 307,7 @@ impl Store {
    ///  - Errors Store::retrieve() might return
    ///
    pub fn get<'a, S: IntoStoreId + Clone>(&'a self, id: S) -> Result<Option<FileLockEntry<'a>>> {
        let id = id.into_storeid()?.with_base(self.path().clone());
        let id = id.into_storeid()?;

        debug!("Getting id: '{}'", id);



@@ 409,7 420,7 @@ impl Store {
    /// On success: Entry
    ///
    pub fn get_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
        let id = id.into_storeid()?.with_base(self.path().clone());
        let id = id.into_storeid()?;
        debug!("Retrieving copy of '{}'", id);
        let entries = self.entries.write()
            .map_err(|_| Error::from(EM::LockError))


@@ 422,7 433,7 @@ impl Store {
                .map_err(Error::from)
        }

        StoreEntry::new(id, &self.backend)?.get_entry()
        StoreEntry::new(self.path().clone(), id, &self.backend)?.get_entry()
    }

    /// Delete an entry and the corrosponding file on disk


@@ 432,7 443,7 @@ impl Store {
    /// On success: ()
    ///
    pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
        let id = id.into_storeid()?.with_base(self.path().clone());
        let id = id.into_storeid()?;

        debug!("Deleting id: '{}'", id);



@@ 440,7 451,7 @@ impl Store {
        // StoreId::exists(), a PathBuf object gets allocated. So we simply get a
        // PathBuf here, check whether it is there and if it is, we can re-use it to
        // delete the filesystem file.
        let pb = id.clone().into_pathbuf()?;
        let pb = id.clone().with_base(self.path()).into_pathbuf()?;

        {
            let mut entries = self


@@ 507,7 518,6 @@ impl Store {
    fn save_to_other_location(&self, entry: &FileLockEntry, new_id: StoreId, remove_old: bool)
        -> Result<()>
    {
        let new_id = new_id.with_base(self.path().clone());
        let hsmap = self
            .entries
            .write()


@@ 522,8 532,8 @@ impl Store {

        let old_id = entry.get_location().clone();

        let old_id_as_path = old_id.clone().with_base(self.path().clone()).into_pathbuf()?;
        let new_id_as_path = new_id.clone().with_base(self.path().clone()).into_pathbuf()?;
        let old_id_as_path = old_id.clone().with_base(self.path()).into_pathbuf()?;
        let new_id_as_path = new_id.clone().with_base(self.path()).into_pathbuf()?;
        self.backend
            .copy(&old_id_as_path, &new_id_as_path)
            .and_then(|_| if remove_old {


@@ 571,9 581,6 @@ impl Store {
    /// So the link is _partly dangling_, so to say.
    ///
    pub fn move_by_id(&self, old_id: StoreId, new_id: StoreId) -> Result<()> {
        let new_id = new_id.with_base(self.path().clone());
        let old_id = old_id.with_base(self.path().clone());

        debug!("Moving '{}' to '{}'", old_id, new_id);

        {


@@ 594,8 601,8 @@ impl Store {

            debug!("Old id is not yet borrowed");

            let old_id_pb = old_id.clone().with_base(self.path().clone()).into_pathbuf()?;
            let new_id_pb = new_id.clone().with_base(self.path().clone()).into_pathbuf()?;
            let old_id_pb = old_id.clone().with_base(self.path()).into_pathbuf()?;
            let new_id_pb = new_id.clone().with_base(self.path()).into_pathbuf()?;

            if self.backend.exists(&new_id_pb)? {
                return Err(format_err!("Entry already exists: {}", new_id));


@@ 618,8 625,8 @@ impl Store {
            assert!(hsmap
                    .remove(&old_id)
                    .and_then(|mut entry| {
                        entry.id = new_id.clone();
                        hsmap.insert(new_id.clone(), entry)
                        entry.id = new_id.clone().into();
                        hsmap.insert(new_id.clone().into(), entry)
                    }).is_none())
        }



@@ 631,7 638,7 @@ impl Store {
    pub fn entries<'a>(&'a self) -> Result<Entries<'a>> {
        trace!("Building 'Entries' iterator");
        self.backend
            .pathes_recursively(self.path().clone(), self.path().clone(), self.backend.clone())
            .pathes_recursively(self.path().clone(), self.path(), self.backend.clone())
            .map(|i| Entries::new(i, self))
    }



@@ 645,7 652,7 @@ impl Store {
                .context(format_err!("CreateCallError: {}", id));

        let backend_has_entry = |id: StoreId|
            self.backend.exists(&id.with_base(self.path().to_path_buf()).into_pathbuf()?);
            self.backend.exists(&id.with_base(self.path()).into_pathbuf()?);

        Ok(cache_has_entry(&id)? || backend_has_entry(id)?)
    }


@@ 1000,7 1007,7 @@ Hai
        setup_logging();

        debug!("{}", TEST_ENTRY);
        let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
        let entry = Entry::from_str(StoreId::new(PathBuf::from("test/foo~1.3")).unwrap(),
                                    TEST_ENTRY).unwrap();

        assert_eq!(entry.content, "Hai");


@@ 1014,7 1021,7 @@ Hai
        setup_logging();

        debug!("{}", TEST_ENTRY);
        let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
        let entry = Entry::from_str(StoreId::new(PathBuf::from("test/foo~1.3")).unwrap(),
                                    TEST_ENTRY).unwrap();
        let string = entry.to_str().unwrap();



@@ 1029,7 1036,7 @@ Hai
        setup_logging();

        debug!("{}", TEST_ENTRY_TNL);
        let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
        let entry = Entry::from_str(StoreId::new(PathBuf::from("test/foo~1.3")).unwrap(),
                                    TEST_ENTRY_TNL).unwrap();
        let string = entry.to_str().unwrap();



@@ 1049,9 1056,9 @@ mod store_tests {
    }

    use super::Store;
    use file_abstraction::InMemoryFileAbstraction;

    pub fn get_store() -> Store {
        use file_abstraction::inmemory::InMemoryFileAbstraction;
        let backend = Arc::new(InMemoryFileAbstraction::default());
        Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
    }


@@ 1072,7 1079,7 @@ mod store_tests {
            let s = format!("test-{}", n);
            let entry = store.create(PathBuf::from(s.clone())).unwrap();
            assert!(entry.verify().is_ok());
            let loc = entry.get_location().clone().into_pathbuf().unwrap();
            let loc = entry.get_location().clone().with_base(store.path()).into_pathbuf().unwrap();
            assert!(loc.starts_with("/"));
            assert!(loc.ends_with(s));
        }


@@ 1093,7 1100,7 @@ mod store_tests {

            assert!(entry.verify().is_ok());

            let loc = entry.get_location().clone().into_pathbuf().unwrap();
            let loc = entry.get_location().clone().with_base(store.path()).into_pathbuf().unwrap();

            assert!(loc.starts_with("/"));
            assert!(loc.ends_with(s));


@@ 1125,7 1132,7 @@ mod store_tests {
                .ok()
                .map(|entry| {
                    assert!(entry.verify().is_ok());
                    let loc = entry.get_location().clone().into_pathbuf().unwrap();
                    let loc = entry.get_location().clone().with_base(store.path()).into_pathbuf().unwrap();
                    assert!(loc.starts_with("/"));
                    assert!(loc.ends_with(s));
                });


@@ 1139,12 1146,10 @@ mod store_tests {
        let store = get_store();

        for n in 1..100 {
            let pb = StoreId::new_baseless(PathBuf::from(format!("test-{}", n))).unwrap();
            let pb = StoreId::new(PathBuf::from(format!("test-{}", n))).unwrap();

            assert!(store.entries.read().unwrap().get(&pb).is_none());
            assert!(store.create(pb.clone()).is_ok());

            let pb = pb.with_base(store.path().clone());
            assert!(store.entries.read().unwrap().get(&pb).is_some());
        }
    }


@@ 1156,12 1161,10 @@ mod store_tests {
        let store = get_store();

        for n in 1..100 {
            let pb = StoreId::new_baseless(PathBuf::from(format!("test-{}", n))).unwrap();
            let pb = StoreId::new(PathBuf::from(format!("test-{}", n))).unwrap();

            assert!(store.entries.read().unwrap().get(&pb).is_none());
            assert!(store.retrieve(pb.clone()).is_ok());

            let pb = pb.with_base(store.path().clone());
            assert!(store.entries.read().unwrap().get(&pb).is_some());
        }
    }


@@ 1199,8 1202,8 @@ mod store_tests {

        for n in 1..100 {
            if n % 2 == 0 { // every second
                let id    = StoreId::new_baseless(PathBuf::from(format!("t-{}", n))).unwrap();
                let id_mv = StoreId::new_baseless(PathBuf::from(format!("t-{}", n - 1))).unwrap();
                let id    = StoreId::new(PathBuf::from(format!("t-{}", n))).unwrap();
                let id_mv = StoreId::new(PathBuf::from(format!("t-{}", n - 1))).unwrap();

                {
                    assert!(store.entries.read().unwrap().get(&id).is_none());


@@ 1211,16 1214,14 @@ mod store_tests {
                }

                {
                    let id_with_base = id.clone().with_base(store.path().clone());
                    assert!(store.entries.read().unwrap().get(&id_with_base).is_some());
                    assert!(store.entries.read().unwrap().get(&id).is_some());
                }

                let r = store.move_by_id(id.clone(), id_mv.clone());
                assert!(r.map_err(|e| debug!("ERROR: {:?}", e)).is_ok());

                {
                    let id_mv_with_base = id_mv.clone().with_base(store.path().clone());
                    assert!(store.entries.read().unwrap().get(&id_mv_with_base).is_some());
                    assert!(store.entries.read().unwrap().get(&id_mv).is_some());
                }

                let res = store.get(id.clone());

M lib/core/libimagstore/src/storeid.rs => lib/core/libimagstore/src/storeid.rs +70 -166
@@ 43,87 43,28 @@ use iter::retrieve::StoreRetrieveIterator;
/// A StoreId object is a unique identifier for one entry in the store which might be present or
/// not.
///
#[derive(Debug, Clone, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    base: Option<PathBuf>,
    id:   PathBuf,
}

impl PartialEq for StoreId {
    fn eq(&self, other: &StoreId) -> bool {
        self.id == other.id
    }
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct StoreId(PathBuf);

impl StoreId {

    pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
        StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
    }

    /// Try to create a StoreId object from a filesystem-absolute path.
    ///
    /// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping
    /// the `store_part` from the `full_path` succeeded.
    pub fn from_full_path<D>(store_part: &PathBuf, full_path: D) -> Result<StoreId>
        where D: Deref<Target = Path>
    {
        let p = full_path
            .strip_prefix(store_part)
            .map_err(Error::from)
            .context(err_msg("Error building Store Id from full path"))?;
        StoreId::new(Some(store_part.clone()), PathBuf::from(p))
    }

    pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
    pub fn new(id: PathBuf) -> Result<StoreId> {
        debug!("Trying to get a new baseless id from: {:?}", id);
        if id.is_absolute() {
            debug!("Error: Id is absolute!");
            Err(format_err!("Store Id local part is absolute: {}", id.display()))
        } else {
            debug!("Building Storeid object baseless");
            Ok(StoreId {
                base: None,
                id
            })
            Ok(StoreId(id))
        }
    }

    pub fn without_base(mut self) -> StoreId {
        self.base = None;
        self
    }

    pub fn with_base(mut self, base: PathBuf) -> Self {
        self.base = Some(base);
        self
    }

    /// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
    /// specified.
    pub fn into_pathbuf(mut self) -> Result<PathBuf> {
        let base = self.base.take();
        let mut base = base.ok_or_else(|| {
            format_err!("Store Id has no base: {:?}", self.id.display().to_string())
        })?;
        base.push(self.id);
        Ok(base)
    }

    /// Check whether the StoreId exists (as in whether the file exists)
    ///
    /// # Warning
    ///
    /// Should be considered deprecated
    pub fn exists(&self) -> Result<bool> {
        self.clone().into_pathbuf().map(|pb| pb.exists())
    pub(crate) fn with_base<'a>(self, base: &'a PathBuf) -> StoreIdWithBase<'a> {
        StoreIdWithBase(base, self.0)
    }

    pub fn to_str(&self) -> Result<String> {
        match self.base.as_ref() {
            None           => Ok(self.id.display().to_string()),
            Some(ref base) => Ok(format!("{}/{}", base.display(), self.id.display())),
        }
        Ok(self.0.display().to_string())
    }

    /// Helper function for creating a displayable String from StoreId


@@ 145,12 86,12 @@ impl StoreId {
    /// Can be used to check whether a StoreId points to an entry in a specific collection of
    /// StoreIds.
    pub fn components(&self) -> Components {
        self.id.components()
        self.0.components()
    }

    /// Get the _local_ part of a StoreId object, as in "the part from the store root to the entry".
    pub fn local(&self) -> &PathBuf {
        &self.id
        &self.0
    }

    /// Check whether a StoreId points to an entry in a specific collection.


@@ 166,7 107,7 @@ impl StoreId {
    pub fn is_in_collection<S: AsRef<str>, V: AsRef<[S]>>(&self, colls: &V) -> bool {
        use std::path::Component;

        self.id
        self.0
            .components()
            .zip(colls.as_ref().iter())
            .all(|(component, pred_coll)| match component {


@@ 179,7 120,7 @@ impl StoreId {
    }

    pub fn local_push<P: AsRef<Path>>(&mut self, path: P) {
        self.id.push(path)
        self.0.push(path)
    }

}


@@ 187,7 128,7 @@ impl StoreId {
impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "{}", self.id.display())
        write!(fmt, "{}", self.0.display())
    }

}


@@ 206,10 147,65 @@ impl IntoStoreId for StoreId {

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> Result<StoreId> {
        StoreId::new_baseless(self)
        StoreId::new(self)
    }
}

#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct StoreIdWithBase<'a>(&'a PathBuf, PathBuf);

impl<'a> StoreIdWithBase<'a> {
    #[cfg(test)]
    pub(crate) fn new(base: &'a PathBuf, path: PathBuf) -> Self {
        StoreIdWithBase(base, path)
    }

    pub(crate) fn without_base(self) -> StoreId {
        StoreId(self.1)
    }

    /// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
    /// specified.
    pub(crate) fn into_pathbuf(self) -> Result<PathBuf> {
        let mut base = self.0.clone();
        base.push(self.1);
        Ok(base)
    }

    /// Try to create a StoreId object from a filesystem-absolute path.
    ///
    /// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping
    /// the `store_part` from the `full_path` succeeded.
    pub(crate) fn from_full_path<D>(store_part: &'a PathBuf, full_path: D) -> Result<StoreIdWithBase<'a>>
        where D: Deref<Target = Path>
    {
        let p = full_path
            .strip_prefix(store_part)
            .map_err(Error::from)
            .context(err_msg("Error building Store Id from full path"))?;
        Ok(StoreIdWithBase(store_part, PathBuf::from(p)))
    }
}

impl<'a> IntoStoreId for StoreIdWithBase<'a> {
    fn into_storeid(self) -> Result<StoreId> {
        Ok(StoreId(self.1))
    }
}

impl<'a> Into<StoreId> for StoreIdWithBase<'a> {
    fn into(self) -> StoreId {
        StoreId(self.1)
    }
}

impl<'a> Display for StoreIdWithBase<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "{}/{}", self.0.display(), self.1.display())
    }
}


#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr) => (


@@ 249,7 245,7 @@ macro_rules! module_entry_path_mod {

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
                    StoreId::new(None, self.0)
                    StoreId::new(self.0)
                }
            }
        }


@@ 313,7 309,7 @@ impl<'a> StoreIdIteratorWithStore<'a> {
        StoreIdIteratorWithStore(StoreIdIterator::new(iter), store)
    }

    pub fn without_store(self) -> StoreIdIterator {
    pub fn into_storeid_iter(self) -> StoreIdIterator {
        self.0
    }



@@ 352,9 348,6 @@ impl<'a> StoreIdIteratorWithStore<'a> {

#[cfg(test)]
mod test {
    use std::path::PathBuf;

    use storeid::StoreId;
    use storeid::IntoStoreId;

    module_entry_path_mod!("test");


@@ 367,95 360,6 @@ mod test {
    }

    #[test]
    fn test_baseless_path() {
        let id = StoreId::new_baseless(PathBuf::from("test"));
        assert!(id.is_ok());
        assert_eq!(id.unwrap(), StoreId {
            base: None,
            id: PathBuf::from("test")
        });
    }

    #[test]
    fn test_base_path() {
        let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));
        assert!(id.is_ok());
        assert_eq!(id.unwrap(), StoreId {
            base: Some(PathBuf::from("/tmp/")),
            id: PathBuf::from("test")
        });
    }

    #[test]
    fn test_adding_base_to_baseless_path() {
        let id = StoreId::new_baseless(PathBuf::from("test"));

        assert!(id.is_ok());
        let id = id.unwrap();

        assert_eq!(id, StoreId { base: None, id: PathBuf::from("test") });

        let id = id.with_base(PathBuf::from("/tmp/"));
        assert_eq!(id, StoreId {
            base: Some(PathBuf::from("/tmp/")),
            id: PathBuf::from("test")
        });
    }

    #[test]
    fn test_removing_base_from_base_path() {
        let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));

        assert!(id.is_ok());
        let id = id.unwrap();

        assert_eq!(id, StoreId {
            base: Some(PathBuf::from("/tmp/")),
            id: PathBuf::from("test")
        });

        let id = id.without_base();
        assert_eq!(id, StoreId {
            base: None,
            id: PathBuf::from("test")
        });
    }

    #[test]
    fn test_baseless_into_pathbuf_is_err() {
        let id = StoreId::new_baseless(PathBuf::from("test"));
        assert!(id.is_ok());
        assert!(id.unwrap().into_pathbuf().is_err());
    }

    #[test]
    fn test_baseless_into_pathbuf_is_storeidhasnobaseerror() {
        let id = StoreId::new_baseless(PathBuf::from("test"));
        assert!(id.is_ok());

        let pb = id.unwrap().into_pathbuf();
        assert!(pb.is_err());
    }

    #[test]
    fn test_basefull_into_pathbuf_is_ok() {
        let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));
        assert!(id.is_ok());
        assert!(id.unwrap().into_pathbuf().is_ok());
    }

    #[test]
    fn test_basefull_into_pathbuf_is_correct() {
        let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));
        assert!(id.is_ok());

        let pb = id.unwrap().into_pathbuf();
        assert!(pb.is_ok());

        assert_eq!(pb.unwrap(), PathBuf::from("/tmp/test"));
    }

    #[test]
    fn storeid_in_collection() {
        let p = module_path::ModuleEntryPath::new("1/2/3/4/5/6/7/8/9/0").into_storeid().unwrap();


M lib/domain/libimagcontact/src/store.rs => lib/domain/libimagcontact/src/store.rs +4 -4
@@ 29,9 29,9 @@ use failure::Fallible as Result;

use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::iter::Entries;
use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreIdIterator;
use libimagentryutil::isa::Is;

use contact::IsContact;


@@ 51,7 51,7 @@ pub trait ContactStore<'a> {

    // getting

    fn all_contacts(&'a self) -> Result<StoreIdIterator>;
    fn all_contacts(&'a self) -> Result<Entries<'a>>;
}

/// The extension for the Store to work with contacts


@@ 76,8 76,8 @@ impl<'a> ContactStore<'a> for Store {
        postprocess_fetched_entry(self.retrieve(sid)?, value)
    }

    fn all_contacts(&'a self) -> Result<StoreIdIterator> {
        self.entries().map(|iter| iter.in_collection("contact").without_store())
    fn all_contacts(&'a self) -> Result<Entries<'a>> {
        self.entries().map(|ent| ent.in_collection("contact"))
    }

}

M lib/domain/libimagdiary/src/diary.rs => lib/domain/libimagdiary/src/diary.rs +2 -2
@@ 95,7 95,7 @@ impl Diary for Store {
    fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator> {
        debug!("Building iterator for module 'diary' with diary name = '{}'", diary_name);
        Store::entries(self)
            .map(|iter| DiaryEntryIterator::new(String::from(diary_name), iter.without_store()))
            .map(|iter| DiaryEntryIterator::new(String::from(diary_name), iter.into_storeid_iter()))
    }

    /// get the id of the youngest entry


@@ 151,7 151,7 @@ impl Diary for Store {
    /// Get all diary names
    fn diary_names(&self) -> Result<DiaryNameIterator> {
        self.entries()
            .map(|it| DiaryNameIterator::new(it.without_store()))
            .map(|it| DiaryNameIterator::new(it.into_storeid_iter()))
            .map_err(Error::from)
    }


M lib/domain/libimaghabit/src/iter.rs => lib/domain/libimaghabit/src/iter.rs +2 -2
@@ 52,7 52,7 @@ impl From<StoreIdIterator> for HabitTemplateStoreIdIterator {

impl<'a> From<StoreIdIteratorWithStore<'a>> for HabitTemplateStoreIdIterator {
    fn from(sii: StoreIdIteratorWithStore<'a>) -> Self {
        HabitTemplateStoreIdIterator(sii.without_store())
        HabitTemplateStoreIdIterator(sii.into_storeid_iter())
    }
}



@@ 88,7 88,7 @@ impl From<StoreIdIterator> for HabitInstanceStoreIdIterator {

impl<'a> From<StoreIdIteratorWithStore<'a>> for HabitInstanceStoreIdIterator {
    fn from(sii: StoreIdIteratorWithStore<'a>) -> Self {
        HabitInstanceStoreIdIterator(sii.without_store())
        HabitInstanceStoreIdIterator(sii.into_storeid_iter())
    }
}


M lib/domain/libimaghabit/src/store.rs => lib/domain/libimaghabit/src/store.rs +2 -2
@@ 49,11 49,11 @@ pub trait HabitStore {
impl HabitStore for Store {
    /// Get an iterator over all habits
    fn all_habit_templates(&self) -> Result<HabitTemplateStoreIdIterator> {
        Ok(HabitTemplateStoreIdIterator::from(self.entries()?.without_store()))
        Ok(HabitTemplateStoreIdIterator::from(self.entries()?.into_storeid_iter()))
    }

    fn all_habit_instances(&self) -> Result<HabitInstanceStoreIdIterator> {
        Ok(HabitInstanceStoreIdIterator::from(self.entries()?.without_store()))
        Ok(HabitInstanceStoreIdIterator::from(self.entries()?.into_storeid_iter()))
    }
}


M lib/domain/libimagnotes/src/notestore.rs => lib/domain/libimagnotes/src/notestore.rs +1 -1
@@ 74,7 74,7 @@ impl<'a> NoteStore<'a> for Store {
    }

    fn all_notes(&'a self) -> Result<NoteIterator> {
        self.entries().map(|it| it.without_store()).map(NoteIterator::new)
        self.entries().map(|it| it.into_storeid_iter()).map(NoteIterator::new)
    }

}

M lib/domain/libimagtimetrack/src/iter/mod.rs => lib/domain/libimagtimetrack/src/iter/mod.rs +1 -6
@@ 26,8 26,6 @@ pub mod tag;

#[cfg(test)]
mod test {
    use std::sync::Arc;

    use chrono::naive::NaiveDate;

    use libimagstore::store::Store;


@@ 37,10 35,7 @@ mod test {

    fn get_store() -> Store {
        use std::path::PathBuf;
        use libimagstore::file_abstraction::InMemoryFileAbstraction;

        let backend = Arc::new(InMemoryFileAbstraction::default());
        Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
        Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
    }

    #[test]

M lib/domain/libimagtimetrack/src/tag.rs => lib/domain/libimagtimetrack/src/tag.rs +1 -1
@@ 65,7 65,7 @@ impl<'a> From<&'a String> for TimeTrackingTag {

impl IntoStoreId for TimeTrackingTag {
    fn into_storeid(self) -> Result<StoreId> {
        StoreId::new_baseless(PathBuf::from(self.0))
        StoreId::new(PathBuf::from(self.0))
    }
}


M lib/domain/libimagtodo/src/iter.rs => lib/domain/libimagtodo/src/iter.rs +5 -5
@@ 17,22 17,22 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::storeid::StoreIdIterator;
use libimagstore::iter::Entries;
use libimagstore::storeid::StoreId;

use failure::Fallible as Result;

pub struct TaskIdIterator(StoreIdIterator);
pub struct TaskIdIterator<'a>(Entries<'a>);

impl TaskIdIterator {
impl<'a> TaskIdIterator<'a> {

    pub fn new(inner: StoreIdIterator) -> Self {
    pub fn new(inner: Entries<'a>) -> Self {
        TaskIdIterator(inner)
    }

}

impl Iterator for TaskIdIterator {
impl<'a> Iterator for TaskIdIterator<'a> {
    type Item = Result<StoreId>;

    fn next(&mut self) -> Option<Self::Item> {

M lib/domain/libimagtodo/src/taskstore.rs => lib/domain/libimagtodo/src/taskstore.rs +1 -1
@@ 162,7 162,7 @@ impl<'a> TaskStore<'a> for Store {
    }

    fn all_tasks(&self) -> Result<TaskIdIterator> {
        self.entries().map(|i| TaskIdIterator::new(i.without_store()))
        self.entries().map(|i| TaskIdIterator::new(i))
    }

    fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>> {

M lib/domain/libimagwiki/src/wiki.rs => lib/domain/libimagwiki/src/wiki.rs +3 -3
@@ 22,7 22,7 @@ use std::path::PathBuf;
use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::iter::Entries;
use libimagentrylink::internal::InternalLinker;

use failure::Fallible as Result;


@@ 91,8 91,8 @@ impl<'a, 'b> Wiki<'a, 'b> {
        entry.add_internal_link(&mut index).map(|_| entry)
    }

    pub fn all_ids(&self) -> Result<StoreIdIterator> {
        self.0.entries().map(|iter| iter.in_collection("wiki").without_store())
    pub fn all_ids(&self) -> Result<Entries<'a>> {
        self.0.entries().map(|iter| iter.in_collection("wiki"))
    }

    pub fn delete_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<()> {

M lib/entry/libimagentryannotation/src/annotation_fetcher.rs => lib/entry/libimagentryannotation/src/annotation_fetcher.rs +6 -6
@@ 17,18 17,18 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::iter::Entries;
use libimagstore::store::Store;
use libimagstore::storeid::StoreIdIterator;

use failure::Fallible as Result;

pub trait AnnotationFetcher {
    fn all_annotations(&self) -> Result<StoreIdIterator>;
pub trait AnnotationFetcher<'a> {
    fn all_annotations(&'a self) -> Result<Entries<'a>>;
}

impl<'a> AnnotationFetcher for Store {
    fn all_annotations(&self) -> Result<StoreIdIterator> {
        self.entries().map(|iter| iter.in_collection("annotation").without_store())
impl<'a> AnnotationFetcher<'a> for Store {
    fn all_annotations(&'a self) -> Result<Entries<'a>> {
        self.entries().map(|iter| iter.in_collection("annotation"))
    }
}


M lib/entry/libimagentrycategory/src/store.rs => lib/entry/libimagentrycategory/src/store.rs +2 -6
@@ 109,7 109,7 @@ impl CategoryStore for Store {
    /// Get all category names
    fn all_category_names(&self) -> Result<CategoryNameIter> {
        trace!("Getting all category names");
        Ok(CategoryNameIter::new(self, self.entries()?.without_store()))
        Ok(CategoryNameIter::new(self, self.entries()?.into_storeid_iter()))
    }

    /// Get a category by its name


@@ 130,16 130,13 @@ impl CategoryStore for Store {
mod tests {
    extern crate env_logger;
    use std::path::PathBuf;
    use std::sync::Arc;

    use super::*;

    use libimagstore::store::Store;

    pub fn get_store() -> Store {
        use libimagstore::store::InMemoryFileAbstraction;
        let backend = Arc::new(InMemoryFileAbstraction::default());
        Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
        Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
    }

    #[test]


@@ 216,7 213,6 @@ fn mk_category_storeid(base: PathBuf, s: &str) -> Result<StoreId> {
    use libimagstore::storeid::IntoStoreId;
    ::module_path::ModuleEntryPath::new(s)
        .into_storeid()
        .map(|id| id.with_base(base))
        .context(err_msg("Store id handling error"))
        .map_err(Error::from)
}

M lib/entry/libimagentrydatetime/src/datepath/compiler.rs => lib/entry/libimagentrydatetime/src/datepath/compiler.rs +1 -1
@@ 119,7 119,7 @@ impl DatePathCompiler {
            }
        }

        StoreId::new_baseless(PathBuf::from(s))
        StoreId::new(PathBuf::from(s))
    }

}

M lib/entry/libimagentrydatetime/src/datetime.rs => lib/entry/libimagentrydatetime/src/datetime.rs +1 -4
@@ 209,7 209,6 @@ fn val_to_ndt(v: &Value) -> Result<NaiveDateTime> {
#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use std::sync::Arc;

    use super::*;



@@ 221,9 220,7 @@ mod tests {
    use toml_query::read::TomlValueReadExt;

    pub fn get_store() -> Store {
        use libimagstore::store::InMemoryFileAbstraction;
        let backend = Arc::new(InMemoryFileAbstraction::default());
        Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
        Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
    }

    #[test]

M lib/entry/libimagentrygps/src/entry.rs => lib/entry/libimagentrygps/src/entry.rs +1 -4
@@ 104,7 104,6 @@ impl GPSEntry for Entry {
#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use std::sync::Arc;

    use libimagstore::store::Store;



@@ 115,9 114,7 @@ mod tests {
    }

    fn get_store() -> Store {
        use libimagstore::file_abstraction::InMemoryFileAbstraction;
        let backend = Arc::new(InMemoryFileAbstraction::default());
        Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
        Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
    }

    #[test]

M lib/entry/libimagentrylink/src/external.rs => lib/entry/libimagentrylink/src/external.rs +1 -4
@@ 447,7 447,6 @@ impl ExternalLinker for Entry {
mod tests {
    use super::*;
    use std::path::PathBuf;
    use std::sync::Arc;

    use libimagstore::store::Store;



@@ 457,9 456,7 @@ mod tests {
    }

    pub fn get_store() -> Store {
        use libimagstore::file_abstraction::InMemoryFileAbstraction;
        let backend = Arc::new(InMemoryFileAbstraction::default());
        Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
        Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
    }



M lib/entry/libimagentrylink/src/internal.rs => lib/entry/libimagentrylink/src/internal.rs +25 -40
@@ 18,8 18,6 @@
//

use std::collections::BTreeMap;
#[cfg(test)]
use std::path::PathBuf;

use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;


@@ 47,10 45,10 @@ pub enum Link {

impl Link {

    pub fn exists(&self) -> Result<bool> {
    pub fn exists(&self, store: &Store) -> Result<bool> {
        match *self {
            Link::Id { ref link }             => link.exists(),
            Link::Annotated { ref link, .. }  => link.exists(),
            Link::Id { ref link }             => store.exists(link.clone()),
            Link::Annotated { ref link, .. }  => store.exists(link.clone()),
        }
        .map_err(From::from)
    }


@@ 82,19 80,9 @@ impl Link {
    /// Helper wrapper around Link for StoreId
    fn without_base(self) -> Link {
        match self {
            Link::Id { link: s } => Link::Id { link: s.without_base() },
            Link::Annotated { link: s, annotation: ann } =>
                Link::Annotated { link: s.without_base(), annotation: ann },
        }
    }

    /// Helper wrapper around Link for StoreId
    #[cfg(test)]
    fn with_base(self, pb: PathBuf) -> Link {
        match self {
            Link::Id { link: s } => Link::Id { link: s.with_base(pb) },
            Link::Id { link: s } => Link::Id { link: s },
            Link::Annotated { link: s, annotation: ann } =>
                Link::Annotated { link: s.with_base(pb), annotation: ann },
                Link::Annotated { link: s, annotation: ann },
        }
    }



@@ 447,24 435,24 @@ impl InternalLinker for Entry {

    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        debug!("Removing internal link: {:?}", link);
        let own_loc   = self.get_location().clone().without_base();
        let other_loc = link.get_location().clone().without_base();

        // Cloning because of borrowing
        let own_loc   = self.get_location().clone();
        let other_loc = link.get_location().clone();

        debug!("Removing internal link from {:?} to {:?}", own_loc, other_loc);

        link.get_internal_links()
        let links = link.get_internal_links()?;
        debug!("Rewriting own links for {:?}, without {:?}", other_loc, own_loc);

        let links = links.filter(|l| !l.eq_store_id(&own_loc));
        let _     = rewrite_links(link.get_header_mut(), links)?;

        self.get_internal_links()
            .and_then(|links| {
                debug!("Rewriting own links for {:?}, without {:?}", other_loc, own_loc);
                let links = links.filter(|l| !l.eq_store_id(&own_loc));
                rewrite_links(link.get_header_mut(), links)
            })
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|links| {
                        debug!("Rewriting own links for {:?}, without {:?}", own_loc, other_loc);
                        let links = links.filter(|l| !l.eq_store_id(&other_loc));
                        rewrite_links(self.get_header_mut(), links)
                    })
                debug!("Rewriting own links for {:?}, without {:?}", own_loc, other_loc);
                let links = links.filter(|l| !l.eq_store_id(&other_loc));
                rewrite_links(self.get_header_mut(), links)
            })
    }



@@ 580,7 568,7 @@ fn process_rw_result(links: Result<Option<Value>>) -> Result<LinkIter> {
        .map(|link| {
            debug!("Matching the link: {:?}", link);
            match link {
                Value::String(s) => StoreId::new_baseless(PathBuf::from(s))
                Value::String(s) => StoreId::new(PathBuf::from(s))
                    .map(|s| Link::Id { link: s })
                    .map_err(From::from)
                    ,


@@ 600,7 588,7 @@ fn process_rw_result(links: Result<Option<Value>>) -> Result<LinkIter> {
                        debug!("Ok, here we go with building a Link::Annotated");
                        match (link, anno) {
                            (Value::String(link), Value::String(anno)) => {
                                StoreId::new_baseless(PathBuf::from(link))
                                StoreId::new(PathBuf::from(link))
                                    .map_err(From::from)
                                    .map(|link| {
                                        Link::Annotated {


@@ 694,7 682,7 @@ pub mod store_check {
                    if is_match!(self.get(id.clone()), Ok(Some(_))) {
                        debug!("Exists in store: {:?}", id);

                        if !id.exists()? {
                        if !self.exists(id.clone())? {
                            warn!("Does exist in store but not on FS: {:?}", id);
                            return Err(err_msg("Link target does not exist"))
                        }


@@ 783,7 771,6 @@ pub mod store_check {
#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use std::sync::Arc;

    use libimagstore::store::Store;



@@ 795,9 782,7 @@ mod test {
    }

    pub fn get_store() -> Store {
        use libimagstore::file_abstraction::InMemoryFileAbstraction;
        let backend = Arc::new(InMemoryFileAbstraction::default());
        Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
        Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
    }

    #[test]


@@ 833,8 818,8 @@ mod test {
            assert_eq!(e1_links.len(), 1);
            assert_eq!(e2_links.len(), 1);

            assert!(e1_links.first().map(|l| l.clone().with_base(store.path().clone()).eq_store_id(e2.get_location())).unwrap_or(false));
            assert!(e2_links.first().map(|l| l.clone().with_base(store.path().clone()).eq_store_id(e1.get_location())).unwrap_or(false));
            assert!(e1_links.first().map(|l| l.clone().eq_store_id(e2.get_location())).unwrap_or(false));
            assert!(e2_links.first().map(|l| l.clone().eq_store_id(e1.get_location())).unwrap_or(false));
        }

        {

M lib/entry/libimagentrymarkdown/src/processor.rs => lib/entry/libimagentrymarkdown/src/processor.rs +7 -11
@@ 133,8 133,7 @@ impl LinkProcessor {
                        continue
                    }

                    let spath      = Some(store.path().clone());
                    let id         = StoreId::new(spath, PathBuf::from(&link.link))?;
                    let id         = StoreId::new(PathBuf::from(&link.link))?;
                    let mut target = if self.create_internal_targets {
                        store.retrieve(id)?
                    } else {


@@ 232,7 231,6 @@ mod tests {
    use super::*;

    use std::path::PathBuf;
    use std::sync::Arc;

    use libimagstore::store::Store;
    use libimagentrylink::internal::InternalLinker;


@@ 242,9 240,7 @@ mod tests {
    }

    pub fn get_store() -> Store {
        use libimagstore::file_abstraction::InMemoryFileAbstraction;
        let fs = InMemoryFileAbstraction::default();
        Store::new_with_backend(PathBuf::from("/"), &None, Arc::new(fs)).unwrap()
        Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
    }

    #[test]


@@ 401,7 397,7 @@ mod tests {

        let entries = store.entries();
        assert!(entries.is_ok());
        let entries : Vec<_> = entries.unwrap().without_store().collect();
        let entries : Vec<_> = entries.unwrap().into_storeid_iter().collect();

        assert_eq!(2, entries.len(), "Expected 2 links, got: {:?}", entries);



@@ 440,7 436,7 @@ mod tests {

        let entries = store.entries();
        assert!(entries.is_ok());
        let entries : Vec<_> = entries.unwrap().without_store().collect();
        let entries : Vec<_> = entries.unwrap().into_storeid_iter().collect();

        assert_eq!(2, entries.len(), "Expected 2 links, got: {:?}", entries);
        debug!("{:?}", entries);


@@ 473,7 469,7 @@ mod tests {

        let entries = store.entries();
        assert!(entries.is_ok());
        let entries : Vec<_> = entries.unwrap().without_store().collect();
        let entries : Vec<_> = entries.unwrap().into_storeid_iter().collect();

        assert_eq!(3, entries.len(), "Expected 3 links, got: {:?}", entries);
        debug!("{:?}", entries);


@@ 506,7 502,7 @@ mod tests {

        let entries = store.entries();
        assert!(entries.is_ok());
        let entries : Vec<_> = entries.unwrap().without_store().collect();
        let entries : Vec<_> = entries.unwrap().into_storeid_iter().collect();

        assert_eq!(1, entries.len(), "Expected 1 entries, got: {:?}", entries);
        debug!("{:?}", entries);


@@ 534,7 530,7 @@ mod tests {

        let entries = store.entries();
        assert!(entries.is_ok());
        let entries : Vec<_> = entries.unwrap().without_store().collect();
        let entries : Vec<_> = entries.unwrap().into_storeid_iter().collect();

        assert_eq!(1, entries.len(), "Expected 1 entries, got: {:?}", entries);
    }

M lib/entry/libimagentryref/src/refstore.rs => lib/entry/libimagentryref/src/refstore.rs +2 -2
@@ 91,7 91,7 @@ impl<'a> RefStore<'a> for Store {
    fn get_ref<RPG: UniqueRefPathGenerator, H: AsRef<str>>(&'a self, hash: H)
        -> Result<Option<FileLockEntry<'a>>>
    {
        let sid = StoreId::new_baseless(PathBuf::from(format!("{}/{}", RPG::collection(), hash.as_ref())))
        let sid = StoreId::new(PathBuf::from(format!("{}/{}", RPG::collection(), hash.as_ref())))
            .map_err(Error::from)?;

        debug!("Getting: {:?}", sid);


@@ 104,7 104,7 @@ impl<'a> RefStore<'a> for Store {
    {
        let hash     = RPG::unique_hash(&path)?;
        let pathbuf  = PathBuf::from(format!("{}/{}", RPG::collection(), hash));
        let sid      = StoreId::new_baseless(pathbuf.clone())?;
        let sid      = StoreId::new(pathbuf.clone())?;

        debug!("Creating: {:?}", sid);
        self.create(sid)

M lib/etc/libimaginteraction/src/ui.rs => lib/etc/libimaginteraction/src/ui.rs +2 -2
@@ 55,7 55,7 @@ pub fn get_id(matches: &ArgMatches) -> Result<Vec<StoreId>> {
            vals.into_iter()
                .fold(Ok(vec![]), |acc, elem| {
                    acc.and_then(|mut v| {
                        let elem = StoreId::new_baseless(PathBuf::from(String::from(elem)))?;
                        let elem = StoreId::new(PathBuf::from(String::from(elem)))?;
                        v.push(elem);
                        Ok(v)
                    })


@@ 70,7 70,7 @@ pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Ve
        .or_else(|_| {
            let path = store_path.clone();
            let p    = pick_file(default_menu_cmd, path)?;
            let id   = StoreId::new_baseless(p)?;
            let id   = StoreId::new(p)?;
            Ok(vec![id])
        })
}