vfs: Flesh out MemoryBackend

This commit is contained in:
Lucien Greathouse
2020-02-21 23:52:11 -08:00
parent fefc7a69cd
commit bb2dcbaea0
2 changed files with 109 additions and 50 deletions

View File

@@ -65,7 +65,7 @@ pub trait VfsBackend: sealed::Sealed + Send + 'static {
/// ///
/// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html /// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html
pub struct DirEntry { pub struct DirEntry {
path: PathBuf, pub(crate) path: PathBuf,
} }
impl DirEntry { impl DirEntry {
@@ -78,7 +78,7 @@ impl DirEntry {
/// ///
/// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html /// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html
pub struct ReadDir { pub struct ReadDir {
inner: Box<dyn Iterator<Item = io::Result<DirEntry>>>, pub(crate) inner: Box<dyn Iterator<Item = io::Result<DirEntry>>>,
} }
impl Iterator for ReadDir { impl Iterator for ReadDir {
@@ -94,7 +94,7 @@ impl Iterator for ReadDir {
/// [std::fs::Metadata]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html /// [std::fs::Metadata]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html
#[derive(Debug)] #[derive(Debug)]
pub struct Metadata { pub struct Metadata {
is_file: bool, pub(crate) is_file: bool,
} }
impl Metadata { impl Metadata {

View File

@@ -1,8 +1,8 @@
use std::collections::{BTreeSet, HashMap}; use std::collections::{BTreeSet, HashMap, VecDeque};
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use crate::{Metadata, ReadDir, VfsBackend, VfsEvent, VfsSnapshot}; use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent, VfsSnapshot};
/// `VfsBackend` that reads from an in-memory filesystem, intended for setting /// `VfsBackend` that reads from an in-memory filesystem, intended for setting
/// up testing scenarios quickly. /// up testing scenarios quickly.
@@ -20,7 +20,11 @@ impl MemoryBackend {
} }
} }
pub fn load_snapshot<P: Into<PathBuf>>(&mut self, path: P, snapshot: VfsSnapshot) { pub fn load_snapshot<P: Into<PathBuf>>(
&mut self,
path: P,
snapshot: VfsSnapshot,
) -> io::Result<()> {
let path = path.into(); let path = path.into();
if let Some(parent_path) = path.parent() { if let Some(parent_path) = path.parent() {
@@ -28,10 +32,7 @@ impl MemoryBackend {
if let Entry::Dir { children } = parent_entry { if let Entry::Dir { children } = parent_entry {
children.insert(path.clone()); children.insert(path.clone());
} else { } else {
panic!( return must_be_dir(parent_path);
"Tried to load snapshot as child of file, {}",
parent_path.display()
);
} }
} else { } else {
self.orphans.insert(path.clone()); self.orphans.insert(path.clone());
@@ -54,10 +55,25 @@ impl MemoryBackend {
for (child_name, child) in children { for (child_name, child) in children {
let full_path = path.join(child_name); let full_path = path.join(child_name);
self.load_snapshot(full_path, child); self.load_snapshot(full_path, child)?;
} }
} }
}; }
Ok(())
}
fn remove(&mut self, root_path: PathBuf) {
self.orphans.remove(&root_path);
let mut to_remove = VecDeque::new();
to_remove.push_back(root_path);
while let Some(path) = to_remove.pop_front() {
if let Some(Entry::Dir { children }) = self.entries.remove(&path) {
to_remove.extend(children);
}
}
} }
} }
@@ -69,46 +85,68 @@ enum Entry {
} }
impl VfsBackend for MemoryBackend { impl VfsBackend for MemoryBackend {
fn read(&mut self, _path: &Path) -> io::Result<Vec<u8>> { fn read(&mut self, path: &Path) -> io::Result<Vec<u8>> {
Err(io::Error::new( match self.entries.get(path) {
io::ErrorKind::Other, Some(Entry::File { contents }) => Ok(contents.clone()),
"MemoryBackend doesn't do anything", Some(Entry::Dir { .. }) => must_be_file(path),
)) None => not_found(path),
}
} }
fn write(&mut self, _path: &Path, _data: &[u8]) -> io::Result<()> { fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
Err(io::Error::new( self.load_snapshot(
io::ErrorKind::Other, path,
"MemoryBackend doesn't do anything", VfsSnapshot::File {
)) contents: data.to_owned(),
},
)
} }
fn read_dir(&mut self, _path: &Path) -> io::Result<ReadDir> { fn read_dir(&mut self, path: &Path) -> io::Result<ReadDir> {
Err(io::Error::new( match self.entries.get(path) {
io::ErrorKind::Other, Some(Entry::Dir { children }) => {
"MemoryBackend doesn't do anything", let iter = children
)) .clone()
.into_iter()
.map(|path| Ok(DirEntry { path }));
Ok(ReadDir {
inner: Box::new(iter),
})
}
Some(Entry::File { .. }) => must_be_dir(path),
None => not_found(path),
}
} }
fn remove_file(&mut self, _path: &Path) -> io::Result<()> { fn remove_file(&mut self, path: &Path) -> io::Result<()> {
Err(io::Error::new( match self.entries.get(path) {
io::ErrorKind::Other, Some(Entry::File { .. }) => {
"MemoryBackend doesn't do anything", self.remove(path.to_owned());
)) Ok(())
}
Some(Entry::Dir { .. }) => must_be_file(path),
None => not_found(path),
}
} }
fn remove_dir_all(&mut self, _path: &Path) -> io::Result<()> { fn remove_dir_all(&mut self, path: &Path) -> io::Result<()> {
Err(io::Error::new( match self.entries.get(path) {
io::ErrorKind::Other, Some(Entry::Dir { .. }) => {
"MemoryBackend doesn't do anything", self.remove(path.to_owned());
)) Ok(())
}
Some(Entry::File { .. }) => must_be_dir(path),
None => not_found(path),
}
} }
fn metadata(&mut self, _path: &Path) -> io::Result<Metadata> { fn metadata(&mut self, path: &Path) -> io::Result<Metadata> {
Err(io::Error::new( match self.entries.get(path) {
io::ErrorKind::Other, Some(Entry::File { .. }) => Ok(Metadata { is_file: true }),
"MemoryBackend doesn't do anything", Some(Entry::Dir { .. }) => Ok(Metadata { is_file: false }),
)) None => not_found(path),
}
} }
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> { fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
@@ -116,16 +154,37 @@ impl VfsBackend for MemoryBackend {
} }
fn watch(&mut self, _path: &Path) -> io::Result<()> { fn watch(&mut self, _path: &Path) -> io::Result<()> {
Err(io::Error::new( Ok(())
io::ErrorKind::Other,
"MemoryBackend doesn't do anything",
))
} }
fn unwatch(&mut self, _path: &Path) -> io::Result<()> { fn unwatch(&mut self, _path: &Path) -> io::Result<()> {
Err(io::Error::new( Ok(())
io::ErrorKind::Other,
"MemoryBackend doesn't do anything",
))
} }
} }
fn must_be_file<T>(path: &Path) -> io::Result<T> {
Err(io::Error::new(
io::ErrorKind::Other,
format!(
"path {} was a directory, but must be a file",
path.display()
),
))
}
fn must_be_dir<T>(path: &Path) -> io::Result<T> {
Err(io::Error::new(
io::ErrorKind::Other,
format!(
"path {} was a file, but must be a directory",
path.display()
),
))
}
fn not_found<T>(path: &Path) -> io::Result<T> {
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("path {} not found", path.display()),
))
}