Rewrite Store::entries() implementation

As we rely on the filesystem in Store::entries(), which is a bug and
shouldn't be done, we rewrite this function and use the file_abstraction
framework.
This commit is contained in:
Matthias Beyer 2017-09-05 23:13:01 +02:00
parent e6d96c9f83
commit b10d63c134
7 changed files with 104 additions and 7 deletions

View file

@ -29,6 +29,7 @@ use super::FileAbstractionInstance;
use super::Drain; use super::Drain;
use store::Entry; use store::Entry;
use storeid::StoreId; use storeid::StoreId;
use file_abstraction::iter::PathIterator;
#[derive(Debug)] #[derive(Debug)]
pub enum FSFileAbstractionInstance { pub enum FSFileAbstractionInstance {
@ -99,7 +100,6 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
} }
unreachable!(); unreachable!();
} }
} }
/// `FSFileAbstraction` state type /// `FSFileAbstraction` state type
@ -150,6 +150,24 @@ impl FileAbstraction for FSFileAbstraction {
acc.and_then(|_| self.new_instance(path).write_file_content(&element)) acc.and_then(|_| self.new_instance(path).write_file_content(&element))
}) })
} }
fn pathes_recursively(&self, basepath: PathBuf) -> Result<PathIterator, SE> {
use walkdir::WalkDir;
let i : Result<Vec<PathBuf>, SE> = WalkDir::new(basepath)
.into_iter()
.map(|r| {
r.map(|e| PathBuf::from(e.path()))
.chain_err(|| SE::from_kind(SEK::FileError))
})
.fold(Ok(vec![]), |acc, e| {
acc.and_then(move |mut a| {
a.push(try!(e));
Ok(a)
})
});
Ok(PathIterator::new(Box::new(try!(i).into_iter())))
}
} }
fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> { fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {

View file

@ -32,6 +32,7 @@ use super::FileAbstractionInstance;
use super::Drain; use super::Drain;
use store::Entry; use store::Entry;
use storeid::StoreId; use storeid::StoreId;
use file_abstraction::iter::PathIterator;
type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Entry>>>>; type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Entry>>>>;
@ -171,5 +172,20 @@ impl FileAbstraction for InMemoryFileAbstraction {
Ok(()) Ok(())
} }
fn pathes_recursively(&self, _basepath: PathBuf) -> Result<PathIterator, SE> {
debug!("Getting all pathes");
let keys : Vec<PathBuf> = self
.backend()
.lock()
.map_err(|_| SE::from_kind(SEK::FileError))?
.get_mut()
.keys()
.map(PathBuf::from)
.collect();
// we collect here as this happens only in tests and in memory anyways, so no problem
Ok(PathIterator::new(Box::new(keys.into_iter())))
}
} }

View file

@ -0,0 +1,41 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
use std::path::PathBuf;
/// A wrapper for an iterator over `PathBuf`s
pub struct PathIterator(Box<Iterator<Item = PathBuf>>);
impl PathIterator {
pub fn new(iter: Box<Iterator<Item = PathBuf>>) -> PathIterator {
PathIterator(iter)
}
}
impl Iterator for PathIterator {
type Item = PathBuf;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}

View file

@ -27,12 +27,14 @@ use storeid::StoreId;
mod fs; mod fs;
mod inmemory; mod inmemory;
mod iter;
pub mod stdio; pub mod stdio;
pub use self::fs::FSFileAbstraction; pub use self::fs::FSFileAbstraction;
pub use self::fs::FSFileAbstractionInstance; pub use self::fs::FSFileAbstractionInstance;
pub use self::inmemory::InMemoryFileAbstraction; pub use self::inmemory::InMemoryFileAbstraction;
pub use self::inmemory::InMemoryFileAbstractionInstance; pub use self::inmemory::InMemoryFileAbstractionInstance;
use self::iter::PathIterator;
/// An abstraction trait over filesystem actions /// An abstraction trait over filesystem actions
pub trait FileAbstraction : Debug { pub trait FileAbstraction : Debug {
@ -45,6 +47,8 @@ pub trait FileAbstraction : Debug {
fn drain(&self) -> Result<Drain, SE>; fn drain(&self) -> Result<Drain, SE>;
fn fill<'a>(&'a mut self, d: Drain) -> Result<(), SE>; fn fill<'a>(&'a mut self, d: Drain) -> Result<(), SE>;
fn pathes_recursively(&self, basepath: PathBuf) -> Result<PathIterator, SE>;
} }
/// An abstraction trait over actions on files /// An abstraction trait over actions on files

View file

@ -36,6 +36,7 @@ use super::FileAbstractionInstance;
use super::Drain; use super::Drain;
use super::InMemoryFileAbstraction; use super::InMemoryFileAbstraction;
use store::Entry; use store::Entry;
use file_abstraction::iter::PathIterator;
pub mod mapper; pub mod mapper;
pub mod out; pub mod out;
@ -121,5 +122,9 @@ impl<W: Write, M: Mapper> FileAbstraction for StdIoFileAbstraction<W, M> {
fn fill(&mut self, d: Drain) -> Result<(), SE> { fn fill(&mut self, d: Drain) -> Result<(), SE> {
self.0.fill(d) self.0.fill(d)
} }
fn pathes_recursively(&self, basepath: PathBuf) -> Result<PathIterator, SE> {
self.0.pathes_recursively(basepath)
}
} }

View file

@ -40,6 +40,7 @@ use super::FileAbstractionInstance;
use super::Drain; use super::Drain;
use super::InMemoryFileAbstraction; use super::InMemoryFileAbstraction;
use store::Entry; use store::Entry;
use file_abstraction::iter::PathIterator;
use super::mapper::Mapper; use super::mapper::Mapper;
@ -151,6 +152,10 @@ impl<W: Write, M: Mapper> FileAbstraction for StdoutFileAbstraction<W, M> {
Ok(()) Ok(())
} }
fn pathes_recursively(&self, basepath: PathBuf) -> Result<PathIterator, SE> {
self.mem.pathes_recursively(basepath)
}
} }

View file

@ -785,13 +785,21 @@ impl Store {
/// Get _all_ entries in the store (by id as iterator) /// Get _all_ entries in the store (by id as iterator)
pub fn entries(&self) -> Result<StoreIdIterator> { pub fn entries(&self) -> Result<StoreIdIterator> {
let iter = Walk::new(self.path().clone(), "") self.backend
.filter_map(|id| match id { .pathes_recursively(self.path().clone())
StoreObject::Id(sid) => Some(sid), .and_then(|iter| {
_ => None let iter : Result<Vec<StoreId>> = iter
}); .map(|path| StoreId::from_full_path(self.path(), path))
.fold(Ok(vec![]), |acc, elem| {
acc.and_then(move |mut a| {
a.push(try!(elem));
Ok(a)
})
});
Ok(StoreIdIterator::new(Box::new(iter))) let iter = try!(iter);
Ok(StoreIdIterator::new(Box::new(iter.into_iter())))
})
} }