diff options
author | Matthias Beyer <matthias.beyer@atos.net> | 2021-08-23 09:32:37 +0200 |
---|---|---|
committer | Matthias Beyer <matthias.beyer@atos.net> | 2021-08-26 12:30:20 +0200 |
commit | de7b61ba93d62ef295f127d0d318281179d04961 (patch) | |
tree | e379dc503e898de5525ec2285148f6d4050b7a6a /src/repository | |
parent | 5226132f7e43d0b12d8f58aabef7f5785d5f03fe (diff) |
Add Filesystem layer for loading files from FS without parsing
Signed-off-by: Matthias Beyer <matthias.beyer@atos.net>
Diffstat (limited to 'src/repository')
-rw-r--r-- | src/repository/fs.rs | 117 | ||||
-rw-r--r-- | src/repository/mod.rs | 3 |
2 files changed, 120 insertions, 0 deletions
diff --git a/src/repository/fs.rs b/src/repository/fs.rs new file mode 100644 index 0000000..6cfd2ff --- /dev/null +++ b/src/repository/fs.rs @@ -0,0 +1,117 @@ +use std::path::Path; +use std::path::PathBuf; +use std::collections::HashMap; +use std::path::Component; +use std::convert::TryFrom; + +use walkdir::DirEntry; +use walkdir::WalkDir; +use anyhow::anyhow; +use anyhow::Context; +use anyhow::Result; +use anyhow::Error; +use resiter::Map; +use resiter::AndThen; + +pub struct FileSystemRepresentation { + root: PathBuf, + elements: HashMap<PathComponent, Element>, +} + +enum Element { + File(String), + Dir(HashMap<PathComponent, Element>) +} + +impl Element { + fn get_map_mut(&mut self) -> Option<&mut HashMap<PathComponent, Element>> { + match self { + Element::File(_) => None, + Element::Dir(ref mut hm) => Some(hm), + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +enum PathComponent { + PkgToml, + DirName(String), +} + +impl TryFrom<&std::path::Component<'_>> for PathComponent { + type Error = anyhow::Error; + + fn try_from(c: &std::path::Component) -> Result<Self> { + match *c { + Component::Prefix(_) => anyhow::bail!("Unexpected path component: Prefix"), + Component::RootDir => anyhow::bail!("Unexpected path component: RootDir"), + Component::CurDir => anyhow::bail!("Unexpected path component: CurDir"), + Component::ParentDir => anyhow::bail!("Unexpected path component: ParentDir"), + Component::Normal(filename) => { + let filename = filename.to_str().ok_or_else(|| anyhow!("UTF8-error"))?; + if filename == "pkg.toml" { + Ok(PathComponent::PkgToml) + } else { + Ok(PathComponent::DirName(filename.to_string())) + } + }, + } + } +} + + +impl FileSystemRepresentation { + pub fn load(root: PathBuf) -> Result<Self> { + let mut fsr = FileSystemRepresentation { + root: root.clone(), + elements: HashMap::new(), + }; + + WalkDir::new(root) + .follow_links(false) + .max_open(100) + .same_file_system(true) + .into_iter() + .filter_entry(|e| is_pkgtoml(e)) + .inspect(|el| log::trace!("Loading: {:?}", el)) + .map_err(Error::from) + .and_then_ok(|de| { + let mut curr_hm = &mut fsr.elements; + + // traverse the HashMap tree + for cmp in de.path().components() { + match PathComponent::try_from(&cmp)? { + PathComponent::PkgToml => { + curr_hm.entry(PathComponent::PkgToml) + .or_insert(Element::File(load_file(de.path())?)); + }, + dir @ PathComponent::DirName(_) => { + curr_hm.entry(dir.clone()) + .or_insert(Element::Dir(HashMap::new())); + + curr_hm = curr_hm.get_mut(&dir) + .unwrap() // safe, because we just inserted it + .get_map_mut() + .unwrap(); // safe, because we inserted Element::Dir + }, + } + } + + Ok(()) + }) + .collect::<Result<Vec<_>>>()?; + + Ok(fsr) + } +} + +fn is_pkgtoml(entry: &DirEntry) -> bool { + entry.file_name().to_str().map(|s| s == "pkg.toml").unwrap_or(false) +} + +fn load_file(path: &Path) -> Result<String> { + std::fs::read_to_string(path) + .with_context(|| anyhow!("Reading file from filesystem: {}", path.display())) + .map_err(Error::from) +} + diff --git a/src/repository/mod.rs b/src/repository/mod.rs index ca24117..63276e4 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -11,3 +11,6 @@ #![allow(clippy::module_inception)] mod repository; pub use repository::*; + +mod fs; + |