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>
This commit is contained in:
commit
a6ad19a14f
40 changed files with 296 additions and 415 deletions
|
@ -208,7 +208,7 @@ fn list(rt: &Runtime) {
|
||||||
rt.store()
|
rt.store()
|
||||||
.all_annotations()
|
.all_annotations()
|
||||||
.map_err_trace_exit_unwrap()
|
.map_err_trace_exit_unwrap()
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter()
|
||||||
.trace_unwrap_exit()
|
.trace_unwrap_exit()
|
||||||
.map(|opt| opt.ok_or_else(|| format_err!("Cannot find entry")))
|
.map(|opt| opt.ok_or_else(|| format_err!("Cannot find entry")))
|
||||||
.trace_unwrap_exit()
|
.trace_unwrap_exit()
|
||||||
|
|
|
@ -118,23 +118,27 @@ fn main() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|id| if print_storepath {
|
.map(|id| if print_storepath {
|
||||||
id
|
(Some(rt.store().path()), id)
|
||||||
} else {
|
} else {
|
||||||
id.without_base()
|
(None, id)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut stdout = rt.stdout();
|
let mut stdout = rt.stdout();
|
||||||
trace!("Got output: {:?}", stdout);
|
trace!("Got output: {:?}", stdout);
|
||||||
|
|
||||||
iterator.for_each(|id| {
|
iterator.for_each(|(storepath, id)| {
|
||||||
let _ = rt.report_touched(&id).unwrap_or_exit(); // .map_err_trace_exit_unwrap();
|
rt.report_touched(&id).unwrap_or_exit();
|
||||||
|
|
||||||
if !rt.output_is_pipe() {
|
if !rt.output_is_pipe() {
|
||||||
let id = id.to_str().map_err_trace_exit_unwrap();
|
let id = id.to_str().map_err_trace_exit_unwrap();
|
||||||
trace!("Writing to {:?}", stdout);
|
trace!("Writing to {:?}", stdout);
|
||||||
|
|
||||||
|
let result = if let Some(store) = storepath {
|
||||||
|
writeln!(stdout, "{}/{}", store.display(), id)
|
||||||
|
} else {
|
||||||
writeln!(stdout, "{}", id)
|
writeln!(stdout, "{}", id)
|
||||||
.to_exit_code()
|
};
|
||||||
.unwrap_or_exit();
|
|
||||||
|
result.to_exit_code().unwrap_or_exit();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,8 +132,7 @@ fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockE
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
|
|
||||||
debug!("Getting: {:?}", name);
|
debug!("Getting: {:?}", name);
|
||||||
let result = StoreId::new(Some(rt.store().path().clone()), PathBuf::from(name))
|
let result = StoreId::new(PathBuf::from(name)).and_then(|id| rt.store().get(id));
|
||||||
.and_then(|id| rt.store().get(id));
|
|
||||||
|
|
||||||
debug!(" => : {:?}", result);
|
debug!(" => : {:?}", result);
|
||||||
result
|
result
|
||||||
|
@ -168,8 +167,8 @@ fn link_from_to<'a, I>(rt: &'a Runtime, from: &'a str, to: I)
|
||||||
} else {
|
} else {
|
||||||
debug!("Linking internally: {:?} -> {:?}", from, entry);
|
debug!("Linking internally: {:?} -> {:?}", from, entry);
|
||||||
|
|
||||||
let from_id = StoreId::new_baseless(PathBuf::from(from)).map_err_trace_exit_unwrap();
|
let from_id = StoreId::new(PathBuf::from(from)).map_err_trace_exit_unwrap();
|
||||||
let entr_id = StoreId::new_baseless(PathBuf::from(entry)).map_err_trace_exit_unwrap();
|
let entr_id = StoreId::new(PathBuf::from(entry)).map_err_trace_exit_unwrap();
|
||||||
|
|
||||||
if from_id == entr_id {
|
if from_id == entr_id {
|
||||||
error!("Cannot link entry with itself. Exiting");
|
error!("Cannot link entry with itself. Exiting");
|
||||||
|
@ -366,13 +365,13 @@ mod tests {
|
||||||
let mut path = PathBuf::new();
|
let mut path = PathBuf::new();
|
||||||
path.set_file_name(name);
|
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()
|
.to_str()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
debug!("Default entry constructed");
|
debug!("Default entry constructed");
|
||||||
|
|
||||||
let id = StoreId::new_baseless(path)?;
|
let id = StoreId::new(path)?;
|
||||||
debug!("StoreId constructed: {:?}", id);
|
debug!("StoreId constructed: {:?}", id);
|
||||||
|
|
||||||
let mut entry = rt.store().create(id.clone())?;
|
let mut entry = rt.store().create(id.clone())?;
|
||||||
|
|
|
@ -72,7 +72,7 @@ fn main() {
|
||||||
.cli()
|
.cli()
|
||||||
.value_of("source")
|
.value_of("source")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(StoreId::new_baseless)
|
.map(StoreId::new)
|
||||||
.unwrap() // unwrap safe by clap
|
.unwrap() // unwrap safe by clap
|
||||||
.map_err_trace_exit_unwrap();
|
.map_err_trace_exit_unwrap();
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ fn main() {
|
||||||
.cli()
|
.cli()
|
||||||
.value_of("dest")
|
.value_of("dest")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(StoreId::new_baseless)
|
.map(StoreId::new)
|
||||||
.unwrap() // unwrap safe by clap
|
.unwrap() // unwrap safe by clap
|
||||||
.map_err_trace_exit_unwrap();
|
.map_err_trace_exit_unwrap();
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,7 @@ pub fn create(rt: &Runtime) {
|
||||||
// unwrap is safe as value is required
|
// unwrap is safe as value is required
|
||||||
let path = scmd.value_of("path").unwrap();
|
let path = scmd.value_of("path").unwrap();
|
||||||
let path = PathBuf::from(path);
|
let path = PathBuf::from(path);
|
||||||
let store = Some(rt.store().path().clone());
|
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
||||||
let path = StoreId::new(store, path).map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
debug!("path = {:?}", path);
|
debug!("path = {:?}", path);
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,7 @@ pub fn delete(rt: &Runtime) {
|
||||||
let scmd = rt.cli().subcommand_matches("delete").unwrap();
|
let scmd = rt.cli().subcommand_matches("delete").unwrap();
|
||||||
let id = scmd.value_of("id").unwrap(); // safe by clap
|
let id = scmd.value_of("id").unwrap(); // safe by clap
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let store = Some(rt.store().path().clone());
|
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
||||||
let path = StoreId::new(store, path).map_err_trace_exit_unwrap();
|
|
||||||
debug!("Deleting file at {:?}", id);
|
debug!("Deleting file at {:?}", id);
|
||||||
|
|
||||||
let _ = rt.store()
|
let _ = rt.store()
|
||||||
|
|
|
@ -31,8 +31,7 @@ pub fn get(rt: &Runtime) {
|
||||||
|
|
||||||
let id = scmd.value_of("id").unwrap(); // safe by clap
|
let id = scmd.value_of("id").unwrap(); // safe by clap
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let store = Some(rt.store().path().clone());
|
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
||||||
let path = StoreId::new(store, path).map_err_trace_exit_unwrap();
|
|
||||||
debug!("path = {:?}", path);
|
debug!("path = {:?}", path);
|
||||||
|
|
||||||
let _ = match rt.store().get(path.clone()).map_err_trace_exit_unwrap() {
|
let _ = match rt.store().get(path.clone()).map_err_trace_exit_unwrap() {
|
||||||
|
|
|
@ -37,8 +37,7 @@ pub fn retrieve(rt: &Runtime) {
|
||||||
// unwrap() is safe as arg is required
|
// unwrap() is safe as arg is required
|
||||||
let id = scmd.value_of("id").unwrap();
|
let id = scmd.value_of("id").unwrap();
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let store = Some(rt.store().path().clone());
|
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
||||||
let path = StoreId::new(store, path).map_err_trace_exit_unwrap();
|
|
||||||
debug!("path = {:?}", path);
|
debug!("path = {:?}", path);
|
||||||
|
|
||||||
rt.store()
|
rt.store()
|
||||||
|
|
|
@ -31,8 +31,7 @@ pub fn update(rt: &Runtime) {
|
||||||
let scmd = rt.cli().subcommand_matches("update").unwrap();
|
let scmd = rt.cli().subcommand_matches("update").unwrap();
|
||||||
let id = scmd.value_of("id").unwrap(); // Safe by clap
|
let id = scmd.value_of("id").unwrap(); // Safe by clap
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let store = Some(rt.store().path().clone());
|
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
||||||
let path = StoreId::new(store, path).map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let _ = rt.store()
|
let _ = rt.store()
|
||||||
.retrieve(path)
|
.retrieve(path)
|
||||||
|
|
|
@ -264,11 +264,11 @@ mod tests {
|
||||||
let mut path = PathBuf::new();
|
let mut path = PathBuf::new();
|
||||||
path.set_file_name(name);
|
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()
|
.to_str()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let id = StoreId::new_baseless(path)?;
|
let id = StoreId::new(path)?;
|
||||||
let mut entry = rt.store().create(id.clone())?;
|
let mut entry = rt.store().create(id.clone())?;
|
||||||
entry.get_content_mut().push_str(&default_entry);
|
entry.get_content_mut().push_str(&default_entry);
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ mod tests {
|
||||||
debug!("Add-tags: {:?}", add);
|
debug!("Add-tags: {:?}", add);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, None);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, None);
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
|
@ -338,7 +338,7 @@ mod tests {
|
||||||
debug!("Rem-tags: {:?}", rem);
|
debug!("Rem-tags: {:?}", rem);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
|
@ -366,7 +366,7 @@ mod tests {
|
||||||
debug!("Rem-tags: {:?}", rem);
|
debug!("Rem-tags: {:?}", rem);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
|
@ -394,7 +394,7 @@ mod tests {
|
||||||
debug!("Rem-tags: {:?}", rem);
|
debug!("Rem-tags: {:?}", rem);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
|
|
|
@ -73,7 +73,6 @@ use libimagerror::iter::TraceIterator;
|
||||||
use libimagcontact::store::ContactStore;
|
use libimagcontact::store::ContactStore;
|
||||||
use libimagcontact::contact::Contact;
|
use libimagcontact::contact::Contact;
|
||||||
use libimagcontact::deser::DeserVcard;
|
use libimagcontact::deser::DeserVcard;
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
mod util;
|
mod util;
|
||||||
|
@ -120,7 +119,7 @@ fn list(rt: &Runtime) {
|
||||||
.store()
|
.store()
|
||||||
.all_contacts()
|
.all_contacts()
|
||||||
.map_err_trace_exit_unwrap()
|
.map_err_trace_exit_unwrap()
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter()
|
||||||
.trace_unwrap_exit()
|
.trace_unwrap_exit()
|
||||||
.map(|fle| fle.ok_or_else(|| Error::from(err_msg("StoreId not found".to_owned()))))
|
.map(|fle| fle.ok_or_else(|| Error::from(err_msg("StoreId not found".to_owned()))))
|
||||||
.trace_unwrap_exit()
|
.trace_unwrap_exit()
|
||||||
|
@ -206,7 +205,7 @@ fn show(rt: &Runtime) {
|
||||||
rt.store()
|
rt.store()
|
||||||
.all_contacts()
|
.all_contacts()
|
||||||
.map_err_trace_exit_unwrap()
|
.map_err_trace_exit_unwrap()
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter()
|
||||||
.trace_unwrap_exit()
|
.trace_unwrap_exit()
|
||||||
.map(|o| o.unwrap_or_else(|| {
|
.map(|o| o.unwrap_or_else(|| {
|
||||||
error!("Failed to get entry");
|
error!("Failed to get entry");
|
||||||
|
@ -257,7 +256,7 @@ fn find(rt: &Runtime) {
|
||||||
.store()
|
.store()
|
||||||
.all_contacts()
|
.all_contacts()
|
||||||
.map_err_trace_exit_unwrap()
|
.map_err_trace_exit_unwrap()
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter()
|
||||||
.map(|el| {
|
.map(|el| {
|
||||||
el.map_err_trace_exit_unwrap()
|
el.map_err_trace_exit_unwrap()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
|
|
|
@ -22,7 +22,6 @@ use std::process::Command;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::io::Stdin;
|
use std::io::Stdin;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::io::StdoutLock;
|
use std::io::StdoutLock;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::result::Result as RResult;
|
use std::result::Result as RResult;
|
||||||
|
@ -48,7 +47,6 @@ use libimagerror::trace::*;
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
|
||||||
use libimagutil::debug_result::DebugResult;
|
use libimagutil::debug_result::DebugResult;
|
||||||
use spec::CliSpec;
|
use spec::CliSpec;
|
||||||
use atty;
|
use atty;
|
||||||
|
@ -143,9 +141,7 @@ impl<'a> Runtime<'a> {
|
||||||
trace!("Config = {:#?}", config);
|
trace!("Config = {:#?}", config);
|
||||||
|
|
||||||
let store_result = if cli_app.use_inmemory_fs() {
|
let store_result = if cli_app.use_inmemory_fs() {
|
||||||
Store::new_with_backend(storepath,
|
Store::new_inmemory(storepath, &config)
|
||||||
&config,
|
|
||||||
Arc::new(InMemoryFileAbstraction::default()))
|
|
||||||
} else {
|
} else {
|
||||||
Store::new(storepath, &config)
|
Store::new(storepath, &config)
|
||||||
};
|
};
|
||||||
|
@ -418,7 +414,7 @@ impl<'a> Runtime<'a> {
|
||||||
trace!("Got IDs = {}", buf);
|
trace!("Got IDs = {}", buf);
|
||||||
buf.lines()
|
buf.lines()
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(|id| StoreId::new_baseless(id).map_err(Error::from))
|
.map(|id| StoreId::new(id).map_err(Error::from))
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,7 +28,7 @@ use super::FileAbstraction;
|
||||||
use super::FileAbstractionInstance;
|
use super::FileAbstractionInstance;
|
||||||
use super::Drain;
|
use super::Drain;
|
||||||
use store::Entry;
|
use store::Entry;
|
||||||
use storeid::StoreId;
|
use storeid::StoreIdWithBase;
|
||||||
use file_abstraction::iter::PathIterator;
|
use file_abstraction::iter::PathIterator;
|
||||||
use file_abstraction::iter::PathIterBuilder;
|
use file_abstraction::iter::PathIterBuilder;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
|
||||||
/**
|
/**
|
||||||
* Get the content behind this file
|
* 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);
|
debug!("Getting lazy file: {:?}", self);
|
||||||
|
|
||||||
let mut file = match open_file(&self.0) {
|
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,
|
basepath: PathBuf,
|
||||||
storepath: PathBuf,
|
storepath: &'a PathBuf,
|
||||||
backend: Arc<FileAbstraction>)
|
backend: Arc<FileAbstraction>)
|
||||||
-> Result<PathIterator>
|
-> Result<PathIterator<'a>>
|
||||||
{
|
{
|
||||||
trace!("Building PathIterator object");
|
trace!("Building PathIterator object");
|
||||||
Ok(PathIterator::new(Box::new(WalkDirPathIterBuilder { basepath }), storepath, backend))
|
Ok(PathIterator::new(Box::new(WalkDirPathIterBuilder { basepath }), storepath, backend))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct WalkDirPathIterBuilder {
|
pub struct WalkDirPathIterBuilder {
|
||||||
basepath: PathBuf
|
basepath: PathBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ use super::FileAbstraction;
|
||||||
use super::FileAbstractionInstance;
|
use super::FileAbstractionInstance;
|
||||||
use super::Drain;
|
use super::Drain;
|
||||||
use store::Entry;
|
use store::Entry;
|
||||||
use storeid::StoreId;
|
use storeid::StoreIdWithBase;
|
||||||
use file_abstraction::iter::PathIterator;
|
use file_abstraction::iter::PathIterator;
|
||||||
use file_abstraction::iter::PathIterBuilder;
|
use file_abstraction::iter::PathIterBuilder;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
|
||||||
/**
|
/**
|
||||||
* Get the mutable file behind a InMemoryFileAbstraction object
|
* 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);
|
debug!("Getting lazy file: {:?}", self);
|
||||||
|
|
||||||
self.fs_abstraction
|
self.fs_abstraction
|
||||||
|
@ -187,7 +187,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
||||||
Ok(())
|
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)");
|
trace!("Building PathIterator object (inmemory implementation)");
|
||||||
let keys : Vec<PathBuf> = self
|
let keys : Vec<PathBuf> = self
|
||||||
.backend()
|
.backend()
|
||||||
|
@ -203,7 +203,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct InMemPathIterBuilder(Vec<PathBuf>);
|
pub struct InMemPathIterBuilder(Vec<PathBuf>);
|
||||||
|
|
||||||
impl PathIterBuilder for InMemPathIterBuilder {
|
impl PathIterBuilder for InMemPathIterBuilder {
|
||||||
fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>> {
|
fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>> {
|
||||||
|
|
|
@ -22,11 +22,11 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
|
||||||
use storeid::StoreId;
|
use storeid::StoreIdWithBase;
|
||||||
use file_abstraction::FileAbstraction;
|
use file_abstraction::FileAbstraction;
|
||||||
|
|
||||||
/// See documentation for PathIterator
|
/// See documentation for PathIterator
|
||||||
pub trait PathIterBuilder {
|
pub(crate) trait PathIterBuilder {
|
||||||
fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>>;
|
fn build_iter(&self) -> Box<Iterator<Item = Result<PathBuf>>>;
|
||||||
fn in_collection(&mut self, c: &str);
|
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 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.
|
/// this seems to be the best way to implement this.
|
||||||
pub struct PathIterator {
|
pub(crate) struct PathIterator<'a> {
|
||||||
iter_builder: Box<PathIterBuilder>,
|
iter_builder: Box<PathIterBuilder>,
|
||||||
iter: Box<Iterator<Item = Result<PathBuf>>>,
|
iter: Box<Iterator<Item = Result<PathBuf>>>,
|
||||||
storepath: PathBuf,
|
storepath: &'a PathBuf,
|
||||||
backend: Arc<FileAbstraction>,
|
backend: Arc<FileAbstraction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathIterator {
|
impl<'a> PathIterator<'a> {
|
||||||
|
|
||||||
pub fn new(iter_builder: Box<PathIterBuilder>,
|
pub fn new(iter_builder: Box<PathIterBuilder>,
|
||||||
storepath: PathBuf,
|
storepath: &'a PathBuf,
|
||||||
backend: Arc<FileAbstraction>)
|
backend: Arc<FileAbstraction>)
|
||||||
-> PathIterator
|
-> PathIterator<'a>
|
||||||
{
|
{
|
||||||
trace!("Generating iterator object with PathIterBuilder");
|
trace!("Generating iterator object with PathIterBuilder");
|
||||||
let iter = iter_builder.build_iter();
|
let iter = iter_builder.build_iter();
|
||||||
|
@ -71,10 +71,22 @@ impl PathIterator {
|
||||||
self
|
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> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(next) = self.iter.next() {
|
while let Some(next) = self.iter.next() {
|
||||||
|
@ -82,7 +94,7 @@ impl Iterator for PathIterator {
|
||||||
Err(e) => return Some(Err(e)),
|
Err(e) => return Some(Err(e)),
|
||||||
Ok(next) => match self.backend.is_file(&next) {
|
Ok(next) => match self.backend.is_file(&next) {
|
||||||
Err(e) => return Some(Err(e)),
|
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 },
|
Ok(false) => { continue },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,20 +25,16 @@ use std::sync::Arc;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
|
||||||
use store::Entry;
|
use store::Entry;
|
||||||
use storeid::StoreId;
|
use storeid::StoreIdWithBase;
|
||||||
|
|
||||||
mod fs;
|
pub mod fs;
|
||||||
mod inmemory;
|
pub mod inmemory;
|
||||||
pub(crate) mod iter;
|
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;
|
use self::iter::PathIterator;
|
||||||
|
|
||||||
/// An abstraction trait over filesystem actions
|
/// An abstraction trait over filesystem actions
|
||||||
pub trait FileAbstraction : Debug {
|
pub(crate) trait FileAbstraction : Debug {
|
||||||
fn remove_file(&self, path: &PathBuf) -> Result<()>;
|
fn remove_file(&self, path: &PathBuf) -> Result<()>;
|
||||||
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;
|
fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()>;
|
||||||
fn rename(&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 drain(&self) -> Result<Drain>;
|
||||||
fn fill<'a>(&'a mut self, d: Drain) -> Result<()>;
|
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
|
/// 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.
|
/// 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.
|
/// 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<()>;
|
fn write_file_content(&mut self, buf: &Entry) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,18 +97,19 @@ mod test {
|
||||||
use super::FileAbstractionInstance;
|
use super::FileAbstractionInstance;
|
||||||
use super::inmemory::InMemoryFileAbstraction;
|
use super::inmemory::InMemoryFileAbstraction;
|
||||||
use super::inmemory::InMemoryFileAbstractionInstance;
|
use super::inmemory::InMemoryFileAbstractionInstance;
|
||||||
use storeid::StoreId;
|
use storeid::StoreIdWithBase;
|
||||||
use store::Entry;
|
use store::Entry;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lazy_file() {
|
fn lazy_file() {
|
||||||
|
let store_path = PathBuf::from("/");
|
||||||
let fs = InMemoryFileAbstraction::default();
|
let fs = InMemoryFileAbstraction::default();
|
||||||
|
|
||||||
let mut path = PathBuf::from("tests");
|
let mut path = PathBuf::from("tests");
|
||||||
path.set_file_name("test1");
|
path.set_file_name("test1");
|
||||||
let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());
|
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#"---
|
let file = Entry::from_str(loca.clone(), &format!(r#"---
|
||||||
[imag]
|
[imag]
|
||||||
version = "{}"
|
version = "{}"
|
||||||
|
@ -126,13 +123,14 @@ Hello World"#, env!("CARGO_PKG_VERSION"))).unwrap();
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lazy_file_multiline() {
|
fn lazy_file_multiline() {
|
||||||
|
let store_path = PathBuf::from("/");
|
||||||
let fs = InMemoryFileAbstraction::default();
|
let fs = InMemoryFileAbstraction::default();
|
||||||
|
|
||||||
let mut path = PathBuf::from("tests");
|
let mut path = PathBuf::from("tests");
|
||||||
path.set_file_name("test1");
|
path.set_file_name("test1");
|
||||||
let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());
|
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#"---
|
let file = Entry::from_str(loca.clone(), &format!(r#"---
|
||||||
[imag]
|
[imag]
|
||||||
version = "{}"
|
version = "{}"
|
||||||
|
@ -147,13 +145,14 @@ baz"#, env!("CARGO_PKG_VERSION"))).unwrap();
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lazy_file_multiline_trailing_newlines() {
|
fn lazy_file_multiline_trailing_newlines() {
|
||||||
|
let store_path = PathBuf::from("/");
|
||||||
let fs = InMemoryFileAbstraction::default();
|
let fs = InMemoryFileAbstraction::default();
|
||||||
|
|
||||||
let mut path = PathBuf::from("tests");
|
let mut path = PathBuf::from("tests");
|
||||||
path.set_file_name("test1");
|
path.set_file_name("test1");
|
||||||
let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());
|
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#"---
|
let file = Entry::from_str(loca.clone(), &format!(r#"---
|
||||||
[imag]
|
[imag]
|
||||||
version = "{}"
|
version = "{}"
|
||||||
|
|
|
@ -167,11 +167,11 @@ use failure::Fallible as Result;
|
||||||
///
|
///
|
||||||
/// Functionality to exclude subdirectories is not possible with the current implementation and has
|
/// Functionality to exclude subdirectories is not possible with the current implementation and has
|
||||||
/// to be done during iteration, with filtering (as usual).
|
/// 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> {
|
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)
|
Entries(pi, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,29 +179,38 @@ impl<'a> Entries<'a> {
|
||||||
Entries(self.0.in_collection(c), self.1)
|
Entries(self.0.in_collection(c), self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn without_store(self) -> StoreIdIterator {
|
/// Turn `Entries` iterator into generic `StoreIdIterator`
|
||||||
StoreIdIterator::new(Box::new(self.0))
|
///
|
||||||
|
/// # 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
|
/// Transform the iterator into a StoreDeleteIterator
|
||||||
///
|
///
|
||||||
/// This immitates the API from `libimagstore::iter`.
|
/// This immitates the API from `libimagstore::iter`.
|
||||||
pub fn into_delete_iter(self) -> StoreDeleteIterator<'a> {
|
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
|
/// Transform the iterator into a StoreGetIterator
|
||||||
///
|
///
|
||||||
/// This immitates the API from `libimagstore::iter`.
|
/// This immitates the API from `libimagstore::iter`.
|
||||||
pub fn into_get_iter(self) -> StoreGetIterator<'a> {
|
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
|
/// Transform the iterator into a StoreRetrieveIterator
|
||||||
///
|
///
|
||||||
/// This immitates the API from `libimagstore::iter`.
|
/// This immitates the API from `libimagstore::iter`.
|
||||||
pub fn into_retrieve_iter(self) -> StoreRetrieveIterator<'a> {
|
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>;
|
type Item = Result<StoreId>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
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 store::Store;
|
||||||
use storeid::StoreId;
|
use storeid::StoreId;
|
||||||
use file_abstraction::InMemoryFileAbstraction;
|
use file_abstraction::inmemory::InMemoryFileAbstraction;
|
||||||
use libimagutil::variants::generate_variants;
|
use libimagutil::variants::generate_variants;
|
||||||
|
|
||||||
pub fn get_store() -> Store {
|
pub fn get_store() -> Store {
|
||||||
|
@ -244,7 +253,7 @@ mod tests {
|
||||||
let base = String::from("entry");
|
let base = String::from("entry");
|
||||||
let variants = vec!["coll_1", "coll_2", "coll_3"];
|
let variants = vec!["coll_1", "coll_2", "coll_3"];
|
||||||
let modifier = |base: &String, v: &&str| {
|
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)
|
generate_variants(&base, variants.iter(), &modifier)
|
||||||
|
|
|
@ -58,5 +58,5 @@ pub mod storeid;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
pub mod store;
|
pub mod store;
|
||||||
mod configuration;
|
mod configuration;
|
||||||
pub mod file_abstraction;
|
mod file_abstraction;
|
||||||
|
|
||||||
|
|
|
@ -43,12 +43,10 @@ use failure::Error;
|
||||||
|
|
||||||
use storeid::{IntoStoreId, StoreId};
|
use storeid::{IntoStoreId, StoreId};
|
||||||
use iter::Entries;
|
use iter::Entries;
|
||||||
|
use file_abstraction::FileAbstraction;
|
||||||
use file_abstraction::FileAbstractionInstance;
|
use file_abstraction::FileAbstractionInstance;
|
||||||
|
use file_abstraction::fs::FSFileAbstraction;
|
||||||
// We re-export the following things so tests can use them
|
use file_abstraction::inmemory::InMemoryFileAbstraction;
|
||||||
pub use file_abstraction::FileAbstraction;
|
|
||||||
pub use file_abstraction::FSFileAbstraction;
|
|
||||||
pub use file_abstraction::InMemoryFileAbstraction;
|
|
||||||
|
|
||||||
use libimagutil::debug_result::*;
|
use libimagutil::debug_result::*;
|
||||||
|
|
||||||
|
@ -64,14 +62,15 @@ enum StoreEntryStatus {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct StoreEntry {
|
struct StoreEntry {
|
||||||
id: StoreId,
|
id: StoreId,
|
||||||
|
store_base: PathBuf, // small sacrefice over lifetimes on the Store type
|
||||||
file: Box<FileAbstractionInstance>,
|
file: Box<FileAbstractionInstance>,
|
||||||
status: StoreEntryStatus,
|
status: StoreEntryStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StoreEntry {
|
impl StoreEntry {
|
||||||
|
|
||||||
fn new(id: StoreId, backend: &Arc<FileAbstraction>) -> Result<StoreEntry> {
|
fn new(store_base: PathBuf, id: StoreId, backend: &Arc<FileAbstraction>) -> Result<StoreEntry> {
|
||||||
let pb = id.clone().into_pathbuf()?;
|
let pb = id.clone().with_base(&store_base).into_pathbuf()?;
|
||||||
|
|
||||||
#[cfg(feature = "fs-lock")]
|
#[cfg(feature = "fs-lock")]
|
||||||
{
|
{
|
||||||
|
@ -82,6 +81,7 @@ impl StoreEntry {
|
||||||
|
|
||||||
Ok(StoreEntry {
|
Ok(StoreEntry {
|
||||||
id,
|
id,
|
||||||
|
store_base,
|
||||||
file: backend.new_instance(pb),
|
file: backend.new_instance(pb),
|
||||||
status: StoreEntryStatus::Present,
|
status: StoreEntryStatus::Present,
|
||||||
})
|
})
|
||||||
|
@ -95,7 +95,7 @@ impl StoreEntry {
|
||||||
|
|
||||||
fn get_entry(&mut self) -> Result<Entry> {
|
fn get_entry(&mut self) -> Result<Entry> {
|
||||||
if !self.is_borrowed() {
|
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),
|
Some(file) => Ok(file),
|
||||||
None => Ok(Entry::new(self.id.clone()))
|
None => Ok(Entry::new(self.id.clone()))
|
||||||
}
|
}
|
||||||
|
@ -170,11 +170,22 @@ impl Store {
|
||||||
Store::new_with_backend(location, store_config, backend)
|
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
|
/// Create a Store object as descripbed in `Store::new()` documentation, but with an alternative
|
||||||
/// backend implementation.
|
/// backend implementation.
|
||||||
///
|
///
|
||||||
/// Do not use directly, only for testing purposes.
|
/// Do not use directly, only for testing purposes.
|
||||||
pub fn new_with_backend(location: PathBuf,
|
pub(crate) fn new_with_backend(location: PathBuf,
|
||||||
store_config: &Option<Value>,
|
store_config: &Option<Value>,
|
||||||
backend: Arc<FileAbstraction>) -> Result<Store> {
|
backend: Arc<FileAbstraction>) -> Result<Store> {
|
||||||
use configuration::*;
|
use configuration::*;
|
||||||
|
@ -218,7 +229,7 @@ impl Store {
|
||||||
/// On success: FileLockEntry
|
/// On success: FileLockEntry
|
||||||
///
|
///
|
||||||
pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
|
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);
|
debug!("Creating id: '{}'", id);
|
||||||
|
|
||||||
|
@ -244,7 +255,7 @@ impl Store {
|
||||||
}
|
}
|
||||||
hsmap.insert(id.clone(), {
|
hsmap.insert(id.clone(), {
|
||||||
debug!("Creating: '{}'", id);
|
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.status = StoreEntryStatus::Borrowed;
|
||||||
se
|
se
|
||||||
});
|
});
|
||||||
|
@ -266,14 +277,14 @@ impl Store {
|
||||||
/// On success: FileLockEntry
|
/// On success: FileLockEntry
|
||||||
///
|
///
|
||||||
pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
|
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);
|
debug!("Retrieving id: '{}'", id);
|
||||||
let entry = self
|
let entry = self
|
||||||
.entries
|
.entries
|
||||||
.write()
|
.write()
|
||||||
.map_err(|_| Error::from(EM::LockError))
|
.map_err(|_| Error::from(EM::LockError))
|
||||||
.and_then(|mut es| {
|
.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 se = es.entry(id.clone()).or_insert(new_se);
|
||||||
let entry = se.get_entry();
|
let entry = se.get_entry();
|
||||||
se.status = StoreEntryStatus::Borrowed;
|
se.status = StoreEntryStatus::Borrowed;
|
||||||
|
@ -296,7 +307,7 @@ impl Store {
|
||||||
/// - Errors Store::retrieve() might return
|
/// - Errors Store::retrieve() might return
|
||||||
///
|
///
|
||||||
pub fn get<'a, S: IntoStoreId + Clone>(&'a self, id: S) -> Result<Option<FileLockEntry<'a>>> {
|
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);
|
debug!("Getting id: '{}'", id);
|
||||||
|
|
||||||
|
@ -409,7 +420,7 @@ impl Store {
|
||||||
/// On success: Entry
|
/// On success: Entry
|
||||||
///
|
///
|
||||||
pub fn get_copy<S: IntoStoreId>(&self, id: S) -> Result<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);
|
debug!("Retrieving copy of '{}'", id);
|
||||||
let entries = self.entries.write()
|
let entries = self.entries.write()
|
||||||
.map_err(|_| Error::from(EM::LockError))
|
.map_err(|_| Error::from(EM::LockError))
|
||||||
|
@ -422,7 +433,7 @@ impl Store {
|
||||||
.map_err(Error::from)
|
.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
|
/// Delete an entry and the corrosponding file on disk
|
||||||
|
@ -432,7 +443,7 @@ impl Store {
|
||||||
/// On success: ()
|
/// On success: ()
|
||||||
///
|
///
|
||||||
pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
|
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);
|
debug!("Deleting id: '{}'", id);
|
||||||
|
|
||||||
|
@ -440,7 +451,7 @@ impl Store {
|
||||||
// StoreId::exists(), a PathBuf object gets allocated. So we simply get a
|
// 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
|
// PathBuf here, check whether it is there and if it is, we can re-use it to
|
||||||
// delete the filesystem file.
|
// delete the filesystem file.
|
||||||
let pb = id.clone().into_pathbuf()?;
|
let pb = id.clone().with_base(self.path()).into_pathbuf()?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut entries = self
|
let mut entries = self
|
||||||
|
@ -507,7 +518,6 @@ impl Store {
|
||||||
fn save_to_other_location(&self, entry: &FileLockEntry, new_id: StoreId, remove_old: bool)
|
fn save_to_other_location(&self, entry: &FileLockEntry, new_id: StoreId, remove_old: bool)
|
||||||
-> Result<()>
|
-> Result<()>
|
||||||
{
|
{
|
||||||
let new_id = new_id.with_base(self.path().clone());
|
|
||||||
let hsmap = self
|
let hsmap = self
|
||||||
.entries
|
.entries
|
||||||
.write()
|
.write()
|
||||||
|
@ -522,8 +532,8 @@ impl Store {
|
||||||
|
|
||||||
let old_id = entry.get_location().clone();
|
let old_id = entry.get_location().clone();
|
||||||
|
|
||||||
let old_id_as_path = old_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().clone()).into_pathbuf()?;
|
let new_id_as_path = new_id.clone().with_base(self.path()).into_pathbuf()?;
|
||||||
self.backend
|
self.backend
|
||||||
.copy(&old_id_as_path, &new_id_as_path)
|
.copy(&old_id_as_path, &new_id_as_path)
|
||||||
.and_then(|_| if remove_old {
|
.and_then(|_| if remove_old {
|
||||||
|
@ -571,9 +581,6 @@ impl Store {
|
||||||
/// So the link is _partly dangling_, so to say.
|
/// So the link is _partly dangling_, so to say.
|
||||||
///
|
///
|
||||||
pub fn move_by_id(&self, old_id: StoreId, new_id: StoreId) -> Result<()> {
|
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);
|
debug!("Moving '{}' to '{}'", old_id, new_id);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -594,8 +601,8 @@ impl Store {
|
||||||
|
|
||||||
debug!("Old id is not yet borrowed");
|
debug!("Old id is not yet borrowed");
|
||||||
|
|
||||||
let old_id_pb = old_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().clone()).into_pathbuf()?;
|
let new_id_pb = new_id.clone().with_base(self.path()).into_pathbuf()?;
|
||||||
|
|
||||||
if self.backend.exists(&new_id_pb)? {
|
if self.backend.exists(&new_id_pb)? {
|
||||||
return Err(format_err!("Entry already exists: {}", new_id));
|
return Err(format_err!("Entry already exists: {}", new_id));
|
||||||
|
@ -618,8 +625,8 @@ impl Store {
|
||||||
assert!(hsmap
|
assert!(hsmap
|
||||||
.remove(&old_id)
|
.remove(&old_id)
|
||||||
.and_then(|mut entry| {
|
.and_then(|mut entry| {
|
||||||
entry.id = new_id.clone();
|
entry.id = new_id.clone().into();
|
||||||
hsmap.insert(new_id.clone(), entry)
|
hsmap.insert(new_id.clone().into(), entry)
|
||||||
}).is_none())
|
}).is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,7 +638,7 @@ impl Store {
|
||||||
pub fn entries<'a>(&'a self) -> Result<Entries<'a>> {
|
pub fn entries<'a>(&'a self) -> Result<Entries<'a>> {
|
||||||
trace!("Building 'Entries' iterator");
|
trace!("Building 'Entries' iterator");
|
||||||
self.backend
|
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))
|
.map(|i| Entries::new(i, self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,7 +652,7 @@ impl Store {
|
||||||
.context(format_err!("CreateCallError: {}", id));
|
.context(format_err!("CreateCallError: {}", id));
|
||||||
|
|
||||||
let backend_has_entry = |id: StoreId|
|
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)?)
|
Ok(cache_has_entry(&id)? || backend_has_entry(id)?)
|
||||||
}
|
}
|
||||||
|
@ -1000,7 +1007,7 @@ Hai
|
||||||
setup_logging();
|
setup_logging();
|
||||||
|
|
||||||
debug!("{}", TEST_ENTRY);
|
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();
|
TEST_ENTRY).unwrap();
|
||||||
|
|
||||||
assert_eq!(entry.content, "Hai");
|
assert_eq!(entry.content, "Hai");
|
||||||
|
@ -1014,7 +1021,7 @@ Hai
|
||||||
setup_logging();
|
setup_logging();
|
||||||
|
|
||||||
debug!("{}", TEST_ENTRY);
|
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();
|
TEST_ENTRY).unwrap();
|
||||||
let string = entry.to_str().unwrap();
|
let string = entry.to_str().unwrap();
|
||||||
|
|
||||||
|
@ -1029,7 +1036,7 @@ Hai
|
||||||
setup_logging();
|
setup_logging();
|
||||||
|
|
||||||
debug!("{}", TEST_ENTRY_TNL);
|
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();
|
TEST_ENTRY_TNL).unwrap();
|
||||||
let string = entry.to_str().unwrap();
|
let string = entry.to_str().unwrap();
|
||||||
|
|
||||||
|
@ -1049,9 +1056,9 @@ mod store_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
use super::Store;
|
use super::Store;
|
||||||
use file_abstraction::InMemoryFileAbstraction;
|
|
||||||
|
|
||||||
pub fn get_store() -> Store {
|
pub fn get_store() -> Store {
|
||||||
|
use file_abstraction::inmemory::InMemoryFileAbstraction;
|
||||||
let backend = Arc::new(InMemoryFileAbstraction::default());
|
let backend = Arc::new(InMemoryFileAbstraction::default());
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -1072,7 +1079,7 @@ mod store_tests {
|
||||||
let s = format!("test-{}", n);
|
let s = format!("test-{}", n);
|
||||||
let entry = store.create(PathBuf::from(s.clone())).unwrap();
|
let entry = store.create(PathBuf::from(s.clone())).unwrap();
|
||||||
assert!(entry.verify().is_ok());
|
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.starts_with("/"));
|
||||||
assert!(loc.ends_with(s));
|
assert!(loc.ends_with(s));
|
||||||
}
|
}
|
||||||
|
@ -1093,7 +1100,7 @@ mod store_tests {
|
||||||
|
|
||||||
assert!(entry.verify().is_ok());
|
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.starts_with("/"));
|
||||||
assert!(loc.ends_with(s));
|
assert!(loc.ends_with(s));
|
||||||
|
@ -1125,7 +1132,7 @@ mod store_tests {
|
||||||
.ok()
|
.ok()
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
assert!(entry.verify().is_ok());
|
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.starts_with("/"));
|
||||||
assert!(loc.ends_with(s));
|
assert!(loc.ends_with(s));
|
||||||
});
|
});
|
||||||
|
@ -1139,12 +1146,10 @@ mod store_tests {
|
||||||
let store = get_store();
|
let store = get_store();
|
||||||
|
|
||||||
for n in 1..100 {
|
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.entries.read().unwrap().get(&pb).is_none());
|
||||||
assert!(store.create(pb.clone()).is_ok());
|
assert!(store.create(pb.clone()).is_ok());
|
||||||
|
|
||||||
let pb = pb.with_base(store.path().clone());
|
|
||||||
assert!(store.entries.read().unwrap().get(&pb).is_some());
|
assert!(store.entries.read().unwrap().get(&pb).is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1156,12 +1161,10 @@ mod store_tests {
|
||||||
let store = get_store();
|
let store = get_store();
|
||||||
|
|
||||||
for n in 1..100 {
|
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.entries.read().unwrap().get(&pb).is_none());
|
||||||
assert!(store.retrieve(pb.clone()).is_ok());
|
assert!(store.retrieve(pb.clone()).is_ok());
|
||||||
|
|
||||||
let pb = pb.with_base(store.path().clone());
|
|
||||||
assert!(store.entries.read().unwrap().get(&pb).is_some());
|
assert!(store.entries.read().unwrap().get(&pb).is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1199,8 +1202,8 @@ mod store_tests {
|
||||||
|
|
||||||
for n in 1..100 {
|
for n in 1..100 {
|
||||||
if n % 2 == 0 { // every second
|
if n % 2 == 0 { // every second
|
||||||
let id = StoreId::new_baseless(PathBuf::from(format!("t-{}", n))).unwrap();
|
let id = StoreId::new(PathBuf::from(format!("t-{}", n))).unwrap();
|
||||||
let id_mv = StoreId::new_baseless(PathBuf::from(format!("t-{}", n - 1))).unwrap();
|
let id_mv = StoreId::new(PathBuf::from(format!("t-{}", n - 1))).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
assert!(store.entries.read().unwrap().get(&id).is_none());
|
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).is_some());
|
||||||
assert!(store.entries.read().unwrap().get(&id_with_base).is_some());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = store.move_by_id(id.clone(), id_mv.clone());
|
let r = store.move_by_id(id.clone(), id_mv.clone());
|
||||||
assert!(r.map_err(|e| debug!("ERROR: {:?}", e)).is_ok());
|
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).is_some());
|
||||||
assert!(store.entries.read().unwrap().get(&id_mv_with_base).is_some());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = store.get(id.clone());
|
let res = store.get(id.clone());
|
||||||
|
|
|
@ -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
|
/// A StoreId object is a unique identifier for one entry in the store which might be present or
|
||||||
/// not.
|
/// not.
|
||||||
///
|
///
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct StoreId {
|
pub struct StoreId(PathBuf);
|
||||||
base: Option<PathBuf>,
|
|
||||||
id: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for StoreId {
|
|
||||||
fn eq(&self, other: &StoreId) -> bool {
|
|
||||||
self.id == other.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StoreId {
|
impl StoreId {
|
||||||
|
|
||||||
pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
|
pub fn new(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> {
|
|
||||||
debug!("Trying to get a new baseless id from: {:?}", id);
|
debug!("Trying to get a new baseless id from: {:?}", id);
|
||||||
if id.is_absolute() {
|
if id.is_absolute() {
|
||||||
debug!("Error: Id is absolute!");
|
debug!("Error: Id is absolute!");
|
||||||
Err(format_err!("Store Id local part is absolute: {}", id.display()))
|
Err(format_err!("Store Id local part is absolute: {}", id.display()))
|
||||||
} else {
|
} else {
|
||||||
debug!("Building Storeid object baseless");
|
debug!("Building Storeid object baseless");
|
||||||
Ok(StoreId {
|
Ok(StoreId(id))
|
||||||
base: None,
|
|
||||||
id
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn without_base(mut self) -> StoreId {
|
pub(crate) fn with_base<'a>(self, base: &'a PathBuf) -> StoreIdWithBase<'a> {
|
||||||
self.base = None;
|
StoreIdWithBase(base, self.0)
|
||||||
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 fn to_str(&self) -> Result<String> {
|
pub fn to_str(&self) -> Result<String> {
|
||||||
match self.base.as_ref() {
|
Ok(self.0.display().to_string())
|
||||||
None => Ok(self.id.display().to_string()),
|
|
||||||
Some(ref base) => Ok(format!("{}/{}", base.display(), self.id.display())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for creating a displayable String from StoreId
|
/// 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
|
/// Can be used to check whether a StoreId points to an entry in a specific collection of
|
||||||
/// StoreIds.
|
/// StoreIds.
|
||||||
pub fn components(&self) -> Components {
|
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".
|
/// Get the _local_ part of a StoreId object, as in "the part from the store root to the entry".
|
||||||
pub fn local(&self) -> &PathBuf {
|
pub fn local(&self) -> &PathBuf {
|
||||||
&self.id
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a StoreId points to an entry in a specific collection.
|
/// 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 {
|
pub fn is_in_collection<S: AsRef<str>, V: AsRef<[S]>>(&self, colls: &V) -> bool {
|
||||||
use std::path::Component;
|
use std::path::Component;
|
||||||
|
|
||||||
self.id
|
self.0
|
||||||
.components()
|
.components()
|
||||||
.zip(colls.as_ref().iter())
|
.zip(colls.as_ref().iter())
|
||||||
.all(|(component, pred_coll)| match component {
|
.all(|(component, pred_coll)| match component {
|
||||||
|
@ -179,7 +120,7 @@ impl StoreId {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_push<P: AsRef<Path>>(&mut self, path: P) {
|
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 {
|
impl Display for StoreId {
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
|
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 {
|
impl IntoStoreId for PathBuf {
|
||||||
fn into_storeid(self) -> Result<StoreId> {
|
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_export]
|
||||||
macro_rules! module_entry_path_mod {
|
macro_rules! module_entry_path_mod {
|
||||||
($name:expr) => (
|
($name:expr) => (
|
||||||
|
@ -249,7 +245,7 @@ macro_rules! module_entry_path_mod {
|
||||||
|
|
||||||
impl $crate::storeid::IntoStoreId for ModuleEntryPath {
|
impl $crate::storeid::IntoStoreId for ModuleEntryPath {
|
||||||
fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
|
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)
|
StoreIdIteratorWithStore(StoreIdIterator::new(iter), store)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn without_store(self) -> StoreIdIterator {
|
pub fn into_storeid_iter(self) -> StoreIdIterator {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,9 +348,6 @@ impl<'a> StoreIdIteratorWithStore<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use storeid::StoreId;
|
|
||||||
use storeid::IntoStoreId;
|
use storeid::IntoStoreId;
|
||||||
|
|
||||||
module_entry_path_mod!("test");
|
module_entry_path_mod!("test");
|
||||||
|
@ -366,95 +359,6 @@ mod test {
|
||||||
assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/test");
|
assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/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]
|
#[test]
|
||||||
fn storeid_in_collection() {
|
fn storeid_in_collection() {
|
||||||
let p = module_path::ModuleEntryPath::new("1/2/3/4/5/6/7/8/9/0").into_storeid().unwrap();
|
let p = module_path::ModuleEntryPath::new("1/2/3/4/5/6/7/8/9/0").into_storeid().unwrap();
|
||||||
|
|
|
@ -29,9 +29,9 @@ use failure::Fallible as Result;
|
||||||
|
|
||||||
use libimagstore::storeid::IntoStoreId;
|
use libimagstore::storeid::IntoStoreId;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
|
use libimagstore::iter::Entries;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
|
||||||
use libimagentryutil::isa::Is;
|
use libimagentryutil::isa::Is;
|
||||||
|
|
||||||
use contact::IsContact;
|
use contact::IsContact;
|
||||||
|
@ -51,7 +51,7 @@ pub trait ContactStore<'a> {
|
||||||
|
|
||||||
// getting
|
// 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
|
/// 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)
|
postprocess_fetched_entry(self.retrieve(sid)?, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_contacts(&'a self) -> Result<StoreIdIterator> {
|
fn all_contacts(&'a self) -> Result<Entries<'a>> {
|
||||||
self.entries().map(|iter| iter.in_collection("contact").without_store())
|
self.entries().map(|ent| ent.in_collection("contact"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl Diary for Store {
|
||||||
fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator> {
|
fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator> {
|
||||||
debug!("Building iterator for module 'diary' with diary name = '{}'", diary_name);
|
debug!("Building iterator for module 'diary' with diary name = '{}'", diary_name);
|
||||||
Store::entries(self)
|
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
|
/// get the id of the youngest entry
|
||||||
|
@ -151,7 +151,7 @@ impl Diary for Store {
|
||||||
/// Get all diary names
|
/// Get all diary names
|
||||||
fn diary_names(&self) -> Result<DiaryNameIterator> {
|
fn diary_names(&self) -> Result<DiaryNameIterator> {
|
||||||
self.entries()
|
self.entries()
|
||||||
.map(|it| DiaryNameIterator::new(it.without_store()))
|
.map(|it| DiaryNameIterator::new(it.into_storeid_iter()))
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl From<StoreIdIterator> for HabitTemplateStoreIdIterator {
|
||||||
|
|
||||||
impl<'a> From<StoreIdIteratorWithStore<'a>> for HabitTemplateStoreIdIterator {
|
impl<'a> From<StoreIdIteratorWithStore<'a>> for HabitTemplateStoreIdIterator {
|
||||||
fn from(sii: StoreIdIteratorWithStore<'a>) -> Self {
|
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 {
|
impl<'a> From<StoreIdIteratorWithStore<'a>> for HabitInstanceStoreIdIterator {
|
||||||
fn from(sii: StoreIdIteratorWithStore<'a>) -> Self {
|
fn from(sii: StoreIdIteratorWithStore<'a>) -> Self {
|
||||||
HabitInstanceStoreIdIterator(sii.without_store())
|
HabitInstanceStoreIdIterator(sii.into_storeid_iter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,11 +49,11 @@ pub trait HabitStore {
|
||||||
impl HabitStore for Store {
|
impl HabitStore for Store {
|
||||||
/// Get an iterator over all habits
|
/// Get an iterator over all habits
|
||||||
fn all_habit_templates(&self) -> Result<HabitTemplateStoreIdIterator> {
|
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> {
|
fn all_habit_instances(&self) -> Result<HabitInstanceStoreIdIterator> {
|
||||||
Ok(HabitInstanceStoreIdIterator::from(self.entries()?.without_store()))
|
Ok(HabitInstanceStoreIdIterator::from(self.entries()?.into_storeid_iter()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl<'a> NoteStore<'a> for Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_notes(&'a self) -> Result<NoteIterator> {
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@ pub mod tag;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use chrono::naive::NaiveDate;
|
use chrono::naive::NaiveDate;
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
@ -37,10 +35,7 @@ mod test {
|
||||||
|
|
||||||
fn get_store() -> Store {
|
fn get_store() -> Store {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
|
||||||
|
|
||||||
let backend = Arc::new(InMemoryFileAbstraction::default());
|
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -65,7 +65,7 @@ impl<'a> From<&'a String> for TimeTrackingTag {
|
||||||
|
|
||||||
impl IntoStoreId for TimeTrackingTag {
|
impl IntoStoreId for TimeTrackingTag {
|
||||||
fn into_storeid(self) -> Result<StoreId> {
|
fn into_storeid(self) -> Result<StoreId> {
|
||||||
StoreId::new_baseless(PathBuf::from(self.0))
|
StoreId::new(PathBuf::from(self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,22 +17,22 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// 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 libimagstore::storeid::StoreId;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
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)
|
TaskIdIterator(inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for TaskIdIterator {
|
impl<'a> Iterator for TaskIdIterator<'a> {
|
||||||
type Item = Result<StoreId>;
|
type Item = Result<StoreId>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
|
|
@ -162,7 +162,7 @@ impl<'a> TaskStore<'a> for Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_tasks(&self) -> Result<TaskIdIterator> {
|
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>> {
|
fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>> {
|
||||||
|
|
|
@ -22,7 +22,7 @@ use std::path::PathBuf;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::IntoStoreId;
|
use libimagstore::storeid::IntoStoreId;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::iter::Entries;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::internal::InternalLinker;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
@ -91,8 +91,8 @@ impl<'a, 'b> Wiki<'a, 'b> {
|
||||||
entry.add_internal_link(&mut index).map(|_| entry)
|
entry.add_internal_link(&mut index).map(|_| entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_ids(&self) -> Result<StoreIdIterator> {
|
pub fn all_ids(&self) -> Result<Entries<'a>> {
|
||||||
self.0.entries().map(|iter| iter.in_collection("wiki").without_store())
|
self.0.entries().map(|iter| iter.in_collection("wiki"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<()> {
|
pub fn delete_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<()> {
|
||||||
|
|
|
@ -17,18 +17,18 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use libimagstore::iter::Entries;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
|
||||||
pub trait AnnotationFetcher {
|
pub trait AnnotationFetcher<'a> {
|
||||||
fn all_annotations(&self) -> Result<StoreIdIterator>;
|
fn all_annotations(&'a self) -> Result<Entries<'a>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AnnotationFetcher for Store {
|
impl<'a> AnnotationFetcher<'a> for Store {
|
||||||
fn all_annotations(&self) -> Result<StoreIdIterator> {
|
fn all_annotations(&'a self) -> Result<Entries<'a>> {
|
||||||
self.entries().map(|iter| iter.in_collection("annotation").without_store())
|
self.entries().map(|iter| iter.in_collection("annotation"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ impl CategoryStore for Store {
|
||||||
/// Get all category names
|
/// Get all category names
|
||||||
fn all_category_names(&self) -> Result<CategoryNameIter> {
|
fn all_category_names(&self) -> Result<CategoryNameIter> {
|
||||||
trace!("Getting all category names");
|
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
|
/// Get a category by its name
|
||||||
|
@ -130,16 +130,13 @@ impl CategoryStore for Store {
|
||||||
mod tests {
|
mod tests {
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
|
||||||
pub fn get_store() -> Store {
|
pub fn get_store() -> Store {
|
||||||
use libimagstore::store::InMemoryFileAbstraction;
|
Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
|
||||||
let backend = Arc::new(InMemoryFileAbstraction::default());
|
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -216,7 +213,6 @@ fn mk_category_storeid(base: PathBuf, s: &str) -> Result<StoreId> {
|
||||||
use libimagstore::storeid::IntoStoreId;
|
use libimagstore::storeid::IntoStoreId;
|
||||||
::module_path::ModuleEntryPath::new(s)
|
::module_path::ModuleEntryPath::new(s)
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map(|id| id.with_base(base))
|
|
||||||
.context(err_msg("Store id handling error"))
|
.context(err_msg("Store id handling error"))
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl DatePathCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreId::new_baseless(PathBuf::from(s))
|
StoreId::new(PathBuf::from(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,6 @@ fn val_to_ndt(v: &Value) -> Result<NaiveDateTime> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -221,9 +220,7 @@ mod tests {
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
|
||||||
pub fn get_store() -> Store {
|
pub fn get_store() -> Store {
|
||||||
use libimagstore::store::InMemoryFileAbstraction;
|
Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
|
||||||
let backend = Arc::new(InMemoryFileAbstraction::default());
|
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -104,7 +104,6 @@ impl GPSEntry for Entry {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
|
||||||
|
@ -115,9 +114,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_store() -> Store {
|
fn get_store() -> Store {
|
||||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
|
||||||
let backend = Arc::new(InMemoryFileAbstraction::default());
|
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -447,7 +447,6 @@ impl ExternalLinker for Entry {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
|
||||||
|
@ -457,9 +456,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_store() -> Store {
|
pub fn get_store() -> Store {
|
||||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
|
||||||
let backend = Arc::new(InMemoryFileAbstraction::default());
|
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
#[cfg(test)]
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::storeid::IntoStoreId;
|
use libimagstore::storeid::IntoStoreId;
|
||||||
|
@ -47,10 +45,10 @@ pub enum Link {
|
||||||
|
|
||||||
impl Link {
|
impl Link {
|
||||||
|
|
||||||
pub fn exists(&self) -> Result<bool> {
|
pub fn exists(&self, store: &Store) -> Result<bool> {
|
||||||
match *self {
|
match *self {
|
||||||
Link::Id { ref link } => link.exists(),
|
Link::Id { ref link } => store.exists(link.clone()),
|
||||||
Link::Annotated { ref link, .. } => link.exists(),
|
Link::Annotated { ref link, .. } => store.exists(link.clone()),
|
||||||
}
|
}
|
||||||
.map_err(From::from)
|
.map_err(From::from)
|
||||||
}
|
}
|
||||||
|
@ -82,19 +80,9 @@ impl Link {
|
||||||
/// Helper wrapper around Link for StoreId
|
/// Helper wrapper around Link for StoreId
|
||||||
fn without_base(self) -> Link {
|
fn without_base(self) -> Link {
|
||||||
match self {
|
match self {
|
||||||
Link::Id { link: s } => Link::Id { link: s.without_base() },
|
Link::Id { link: s } => Link::Id { link: s },
|
||||||
Link::Annotated { link: s, annotation: ann } =>
|
Link::Annotated { link: s, annotation: ann } =>
|
||||||
Link::Annotated { link: s.without_base(), annotation: ann },
|
Link::Annotated { link: s, 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::Annotated { link: s, annotation: ann } =>
|
|
||||||
Link::Annotated { link: s.with_base(pb), annotation: ann },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,25 +435,25 @@ impl InternalLinker for Entry {
|
||||||
|
|
||||||
fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
|
fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
|
||||||
debug!("Removing internal link: {:?}", link);
|
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);
|
debug!("Removing internal link from {:?} to {:?}", own_loc, other_loc);
|
||||||
|
|
||||||
link.get_internal_links()
|
let links = link.get_internal_links()?;
|
||||||
.and_then(|links| {
|
|
||||||
debug!("Rewriting own links for {:?}, without {:?}", other_loc, own_loc);
|
debug!("Rewriting own links for {:?}, without {:?}", other_loc, own_loc);
|
||||||
|
|
||||||
let links = links.filter(|l| !l.eq_store_id(&own_loc));
|
let links = links.filter(|l| !l.eq_store_id(&own_loc));
|
||||||
rewrite_links(link.get_header_mut(), links)
|
let _ = rewrite_links(link.get_header_mut(), links)?;
|
||||||
})
|
|
||||||
.and_then(|_| {
|
|
||||||
self.get_internal_links()
|
self.get_internal_links()
|
||||||
.and_then(|links| {
|
.and_then(|links| {
|
||||||
debug!("Rewriting own links for {:?}, without {:?}", own_loc, other_loc);
|
debug!("Rewriting own links for {:?}, without {:?}", own_loc, other_loc);
|
||||||
let links = links.filter(|l| !l.eq_store_id(&other_loc));
|
let links = links.filter(|l| !l.eq_store_id(&other_loc));
|
||||||
rewrite_links(self.get_header_mut(), links)
|
rewrite_links(self.get_header_mut(), links)
|
||||||
})
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlink(&mut self, store: &Store) -> Result<()> {
|
fn unlink(&mut self, store: &Store) -> Result<()> {
|
||||||
|
@ -580,7 +568,7 @@ fn process_rw_result(links: Result<Option<Value>>) -> Result<LinkIter> {
|
||||||
.map(|link| {
|
.map(|link| {
|
||||||
debug!("Matching the link: {:?}", link);
|
debug!("Matching the link: {:?}", link);
|
||||||
match 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(|s| Link::Id { link: s })
|
||||||
.map_err(From::from)
|
.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");
|
debug!("Ok, here we go with building a Link::Annotated");
|
||||||
match (link, anno) {
|
match (link, anno) {
|
||||||
(Value::String(link), Value::String(anno)) => {
|
(Value::String(link), Value::String(anno)) => {
|
||||||
StoreId::new_baseless(PathBuf::from(link))
|
StoreId::new(PathBuf::from(link))
|
||||||
.map_err(From::from)
|
.map_err(From::from)
|
||||||
.map(|link| {
|
.map(|link| {
|
||||||
Link::Annotated {
|
Link::Annotated {
|
||||||
|
@ -694,7 +682,7 @@ pub mod store_check {
|
||||||
if is_match!(self.get(id.clone()), Ok(Some(_))) {
|
if is_match!(self.get(id.clone()), Ok(Some(_))) {
|
||||||
debug!("Exists in store: {:?}", id);
|
debug!("Exists in store: {:?}", id);
|
||||||
|
|
||||||
if !id.exists()? {
|
if !self.exists(id.clone())? {
|
||||||
warn!("Does exist in store but not on FS: {:?}", id);
|
warn!("Does exist in store but not on FS: {:?}", id);
|
||||||
return Err(err_msg("Link target does not exist"))
|
return Err(err_msg("Link target does not exist"))
|
||||||
}
|
}
|
||||||
|
@ -783,7 +771,6 @@ pub mod store_check {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
|
||||||
|
@ -795,9 +782,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_store() -> Store {
|
pub fn get_store() -> Store {
|
||||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
|
||||||
let backend = Arc::new(InMemoryFileAbstraction::default());
|
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, backend).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -833,8 +818,8 @@ mod test {
|
||||||
assert_eq!(e1_links.len(), 1);
|
assert_eq!(e1_links.len(), 1);
|
||||||
assert_eq!(e2_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!(e1_links.first().map(|l| l.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!(e2_links.first().map(|l| l.clone().eq_store_id(e1.get_location())).unwrap_or(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -133,8 +133,7 @@ impl LinkProcessor {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let spath = Some(store.path().clone());
|
let id = StoreId::new(PathBuf::from(&link.link))?;
|
||||||
let id = StoreId::new(spath, PathBuf::from(&link.link))?;
|
|
||||||
let mut target = if self.create_internal_targets {
|
let mut target = if self.create_internal_targets {
|
||||||
store.retrieve(id)?
|
store.retrieve(id)?
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,7 +231,6 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::internal::InternalLinker;
|
||||||
|
@ -242,9 +240,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_store() -> Store {
|
pub fn get_store() -> Store {
|
||||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
Store::new_inmemory(PathBuf::from("/"), &None).unwrap()
|
||||||
let fs = InMemoryFileAbstraction::default();
|
|
||||||
Store::new_with_backend(PathBuf::from("/"), &None, Arc::new(fs)).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -401,7 +397,7 @@ mod tests {
|
||||||
|
|
||||||
let entries = store.entries();
|
let entries = store.entries();
|
||||||
assert!(entries.is_ok());
|
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);
|
assert_eq!(2, entries.len(), "Expected 2 links, got: {:?}", entries);
|
||||||
|
|
||||||
|
@ -440,7 +436,7 @@ mod tests {
|
||||||
|
|
||||||
let entries = store.entries();
|
let entries = store.entries();
|
||||||
assert!(entries.is_ok());
|
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);
|
assert_eq!(2, entries.len(), "Expected 2 links, got: {:?}", entries);
|
||||||
debug!("{:?}", entries);
|
debug!("{:?}", entries);
|
||||||
|
@ -473,7 +469,7 @@ mod tests {
|
||||||
|
|
||||||
let entries = store.entries();
|
let entries = store.entries();
|
||||||
assert!(entries.is_ok());
|
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);
|
assert_eq!(3, entries.len(), "Expected 3 links, got: {:?}", entries);
|
||||||
debug!("{:?}", entries);
|
debug!("{:?}", entries);
|
||||||
|
@ -506,7 +502,7 @@ mod tests {
|
||||||
|
|
||||||
let entries = store.entries();
|
let entries = store.entries();
|
||||||
assert!(entries.is_ok());
|
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);
|
assert_eq!(1, entries.len(), "Expected 1 entries, got: {:?}", entries);
|
||||||
debug!("{:?}", entries);
|
debug!("{:?}", entries);
|
||||||
|
@ -534,7 +530,7 @@ mod tests {
|
||||||
|
|
||||||
let entries = store.entries();
|
let entries = store.entries();
|
||||||
assert!(entries.is_ok());
|
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);
|
assert_eq!(1, entries.len(), "Expected 1 entries, got: {:?}", entries);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl<'a> RefStore<'a> for Store {
|
||||||
fn get_ref<RPG: UniqueRefPathGenerator, H: AsRef<str>>(&'a self, hash: H)
|
fn get_ref<RPG: UniqueRefPathGenerator, H: AsRef<str>>(&'a self, hash: H)
|
||||||
-> Result<Option<FileLockEntry<'a>>>
|
-> 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)?;
|
.map_err(Error::from)?;
|
||||||
|
|
||||||
debug!("Getting: {:?}", sid);
|
debug!("Getting: {:?}", sid);
|
||||||
|
@ -104,7 +104,7 @@ impl<'a> RefStore<'a> for Store {
|
||||||
{
|
{
|
||||||
let hash = RPG::unique_hash(&path)?;
|
let hash = RPG::unique_hash(&path)?;
|
||||||
let pathbuf = PathBuf::from(format!("{}/{}", RPG::collection(), hash));
|
let pathbuf = PathBuf::from(format!("{}/{}", RPG::collection(), hash));
|
||||||
let sid = StoreId::new_baseless(pathbuf.clone())?;
|
let sid = StoreId::new(pathbuf.clone())?;
|
||||||
|
|
||||||
debug!("Creating: {:?}", sid);
|
debug!("Creating: {:?}", sid);
|
||||||
self.create(sid)
|
self.create(sid)
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub fn get_id(matches: &ArgMatches) -> Result<Vec<StoreId>> {
|
||||||
vals.into_iter()
|
vals.into_iter()
|
||||||
.fold(Ok(vec![]), |acc, elem| {
|
.fold(Ok(vec![]), |acc, elem| {
|
||||||
acc.and_then(|mut v| {
|
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);
|
v.push(elem);
|
||||||
Ok(v)
|
Ok(v)
|
||||||
})
|
})
|
||||||
|
@ -70,7 +70,7 @@ pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Ve
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
let path = store_path.clone();
|
let path = store_path.clone();
|
||||||
let p = pick_file(default_menu_cmd, path)?;
|
let p = pick_file(default_menu_cmd, path)?;
|
||||||
let id = StoreId::new_baseless(p)?;
|
let id = StoreId::new(p)?;
|
||||||
Ok(vec![id])
|
Ok(vec![id])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue