TreeWalker WIP.
This commit is contained in:
@@ -84,6 +84,9 @@ pub enum Error {
|
|||||||
#[error("io error: {0}")]
|
#[error("io error: {0}")]
|
||||||
IoError(#[from] std::io::Error),
|
IoError(#[from] std::io::Error),
|
||||||
|
|
||||||
|
#[error("non-unicode file name: '{0}'")]
|
||||||
|
NonUnicodeFileName(String),
|
||||||
|
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
UnknownError(String),
|
UnknownError(String),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ impl FromStr for ObjectId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for ObjectId {
|
||||||
|
fn default() -> Self {
|
||||||
|
return Self {
|
||||||
|
id: Arc::new(vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for ObjectId {
|
impl fmt::Display for ObjectId {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
|
||||||
write_hex(f, self.id.as_slice())
|
write_hex(f, self.id.as_slice())
|
||||||
|
|||||||
2
libbsv/.gitignore
vendored
2
libbsv/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
/target
|
|
||||||
Cargo.lock
|
|
||||||
@@ -23,7 +23,7 @@ extern crate cas_core;
|
|||||||
|
|
||||||
mod permissions;
|
mod permissions;
|
||||||
mod tree_item;
|
mod tree_item;
|
||||||
// mod tree_walker;
|
mod tree_walker;
|
||||||
// mod config;
|
// mod config;
|
||||||
mod path_map;
|
mod path_map;
|
||||||
mod ignore;
|
mod ignore;
|
||||||
|
|||||||
@@ -51,12 +51,12 @@ pub struct TreeItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TreeItem {
|
impl TreeItem {
|
||||||
pub fn from_metadata(name: &str, metadata: &std::fs::Metadata, oid: ObjectId) -> Result<Self> {
|
pub fn from_metadata(name: String, metadata: &std::fs::Metadata, oid: ObjectId) -> Result<Self> {
|
||||||
let otype = otype_from_metadata(metadata)?;
|
let otype = otype_from_metadata(metadata)?;
|
||||||
let permissions = Permissions::from_metadata(metadata)?;
|
let permissions = Permissions::from_metadata(metadata)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: name.to_string(),
|
name: name,
|
||||||
otype,
|
otype,
|
||||||
size: metadata.len(),
|
size: metadata.len(),
|
||||||
created: metadata.created().unwrap_or(UNIX_EPOCH),
|
created: metadata.created().unwrap_or(UNIX_EPOCH),
|
||||||
|
|||||||
@@ -14,130 +14,118 @@
|
|||||||
// along with cdb. If not, see <https://www.gnu.org/licenses/>.
|
// along with cdb. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
use std::path::Utf8Path;
|
use std::iter::Peekable;
|
||||||
// use std::fs::Metadata;
|
use std::fs::{DirEntry, Metadata, ReadDir, read_dir};
|
||||||
use std::fs::{DirEntry, ReadDir, read_dir};
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
use cas_core::{err, Error, Result};
|
use camino::{Utf8Path, Utf8PathBuf};
|
||||||
|
|
||||||
// use crate::{PathPair, Repository, TreeItem};
|
use cas_core::{err, Error, ObjectId, Result};
|
||||||
|
|
||||||
|
use crate::{PathPair, Repository, TreeItem};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct RecursiveDirIterator {
|
pub enum Action {
|
||||||
dir_iterators: Vec<ReadDir>,
|
Add,
|
||||||
|
Update,
|
||||||
|
Remove,
|
||||||
|
Skip,
|
||||||
|
Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecursiveDirIterator {
|
pub struct TreeWalker {
|
||||||
pub fn new<P: AsRef<Utf8Path>>(root_dir: P) -> Result<RecursiveDirIterator> {
|
dir_it: Peekable<IntoIter<Result<TreeItem>>>,
|
||||||
Ok(RecursiveDirIterator {
|
prev_tree_it: Peekable<IntoIter<TreeItem>>,
|
||||||
dir_iterators: vec![read_dir(root_dir)?],
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl TreeWalker {
|
||||||
|
pub fn new<P: AsRef<Utf8Path>>(path: P, prev_tree: Vec<TreeItem>) -> Result<Self> {
|
||||||
|
let dir_entries = read_dir(path.as_ref().to_path_buf())?
|
||||||
|
.map(|res| res.map_err(|err| err.into()))
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
|
let mut dir_items: Vec<_> = dir_entries.into_iter()
|
||||||
|
.map(|dir_entry| {
|
||||||
|
let file_name = dir_entry
|
||||||
|
.file_name()
|
||||||
|
.into_string()
|
||||||
|
// .or_else(|os_string| err!("non-unicode file name '{}'", os_string.to_string_lossy()))?;
|
||||||
|
.or_else(|os_string| Err(Error::NonUnicodeFileName(os_string.to_string_lossy().into())))?;
|
||||||
|
let metadata = dir_entry.metadata()?;
|
||||||
|
Ok(TreeItem::from_metadata(
|
||||||
|
file_name,
|
||||||
|
&metadata,
|
||||||
|
ObjectId::default()
|
||||||
|
)?
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
dir_items.sort_unstable_by_key(|result| {
|
||||||
|
match result {
|
||||||
|
Ok(entry) => entry.name.clone(),
|
||||||
|
Err(_) => String::default(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
dir_it: dir_items.into_iter().peekable(),
|
||||||
|
prev_tree_it: prev_tree.into_iter().peekable(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_dir(&mut self) -> Result<()> {
|
|
||||||
match self.dir_iterators.pop() {
|
|
||||||
Some(_) => Ok(()),
|
|
||||||
None => err!("cannot pop directory: iterator reached the end"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for RecursiveDirIterator {
|
impl Iterator for TreeWalker {
|
||||||
type Item = Result<DirEntry>;
|
type Item = Result<(Action, TreeItem)>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(top_it) = self.dir_iterators.last_mut() {
|
match (self.dir_it.peek(), self.prev_tree_it.peek()) {
|
||||||
let next = top_it.next();
|
(Some(Err(_)), _) => {
|
||||||
if let Some(item) = next {
|
Some(Err(self.dir_it.next().unwrap().unwrap_err()))
|
||||||
let item = item.and_then(|dir_entry| {
|
}
|
||||||
if let Ok(file_type) = dir_entry.file_type() {
|
(Some(Ok(curr_item)), Some(prev_item)) => {
|
||||||
if file_type.is_dir() {
|
if curr_item.name == prev_item.name {
|
||||||
self.dir_iterators.push(read_dir(dir_entry.path())?)
|
let action =
|
||||||
|
if curr_item.modified != prev_item.modified {
|
||||||
|
Action::Update
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
Ok(dir_entry)
|
Action::Skip
|
||||||
});
|
};
|
||||||
return Some(item.map_err(Into::into));
|
self.prev_tree_it.next();
|
||||||
}
|
Some(Ok((action, self.dir_it.next().unwrap().unwrap())))
|
||||||
else {
|
}
|
||||||
self.dir_iterators.pop();
|
else if curr_item.name < prev_item.name {
|
||||||
}
|
Some(Ok((Action::Add, self.dir_it.next().unwrap().unwrap())))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some(Ok((Action::Remove, self.prev_tree_it.next().unwrap())))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Some(_), None) => {
|
||||||
|
Some(Ok((Action::Add, self.dir_it.next().unwrap().unwrap())))
|
||||||
|
},
|
||||||
|
(None, Some(_)) => {
|
||||||
|
Some(Ok((Action::Remove, self.prev_tree_it.next().unwrap())))
|
||||||
|
},
|
||||||
|
(None, None) => None,
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// pub trait FsWalker {
|
#[cfg(test)]
|
||||||
// fn visit(&self)
|
mod tests {
|
||||||
// }
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
fn test_tree_walker() {
|
||||||
// pub enum Action {
|
for item in TreeWalker::new("/home/draklaw/tmp", vec![]).unwrap() {
|
||||||
// Default,
|
match item {
|
||||||
// Add,
|
Ok((action, tree_item)) => println!("{:?} {:?}", action, tree_item.name),
|
||||||
// Update,
|
Err(err) => println!("error while iterating directory: {}", err),
|
||||||
// Remove,
|
}
|
||||||
// Skip,
|
}
|
||||||
// Ignore,
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// #[derive()]
|
|
||||||
// pub struct TreeWalker<'repo> {
|
|
||||||
// repository: &'repo Repository,
|
|
||||||
// rules: Vec<Box<dyn Fn(&Utf8Path, Option<&TreeItem>) -> Result<Action>>>,
|
|
||||||
// default_action: Action,
|
|
||||||
// reporters: Vec<Box<dyn Fn(&Utf8Path, Action, Option<&ObjectId>) -> Result<()>>>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// impl<'repo> TreeWalker<'repo> {
|
|
||||||
// pub fn process<P: AsRef<Utf8Path>>(&self, physic_path: P) -> Result<Option<ObjectId>>
|
|
||||||
// {
|
|
||||||
// let physic_path_ref = physic_path.as_ref();
|
|
||||||
|
|
||||||
// let metadata = std::fs::symlink_metadata(physic_path_ref)
|
|
||||||
// .or_else(|err| err!("failed to read {}: {}", physic_path_ref, err))?;
|
|
||||||
|
|
||||||
// let path_pair = match self.repository.path_pair_from_physic_path(physic_path)? {
|
|
||||||
// Some(path_pair) => path_pair,
|
|
||||||
// None => return Ok(None),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let maybe_tree = self.repository
|
|
||||||
// .oid_from_logic_path(&path_pair.logic)
|
|
||||||
// .ok()
|
|
||||||
// .map(|oid| self.repository.read_tree(&oid))
|
|
||||||
// .transpose()?
|
|
||||||
// .flatten();
|
|
||||||
|
|
||||||
// self.process_impl(&path_pair, &metadata, &maybe_tree)
|
|
||||||
// .map(|oid| Some(oid))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn process_impl(&self, path_pair: &PathPair, metadata: &Metadata, maybe_tree: &Option<Vec<TreeItem>>) -> Result<ObjectId> {
|
|
||||||
// err!("not implemented")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn eval_rules(&self, path: &Utf8Path, maybe_item: Option<&TreeItem>) -> Result<Action> {
|
|
||||||
// self.rules.iter()
|
|
||||||
// .map(|rule|
|
|
||||||
// rule(path, maybe_item)
|
|
||||||
// )
|
|
||||||
// .skip_while(|action_result|
|
|
||||||
// *action_result == Ok(Action::Default)
|
|
||||||
// )
|
|
||||||
// .nth(0)
|
|
||||||
// .unwrap_or(Ok(self.default_action))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn report(&self, path: &Utf8Path, action: Action, maybe_oid: Option<&ObjectId>) -> Result<()> {
|
|
||||||
// for reporter in &self.reporters {
|
|
||||||
// reporter(path, action, maybe_oid)?
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
Reference in New Issue
Block a user