|
|
|
@ -15,14 +15,14 @@ |
|
|
|
|
|
|
|
|
|
|
|
use std::iter::Peekable; |
|
|
|
use std::fs::{DirEntry, Metadata, ReadDir, read_dir}; |
|
|
|
use std::fs::read_dir; |
|
|
|
use std::vec::IntoIter; |
|
|
|
|
|
|
|
use camino::{Utf8Path, Utf8PathBuf}; |
|
|
|
use camino::Utf8Path; |
|
|
|
|
|
|
|
use cas_core::{err, Error, ObjectId, Result}; |
|
|
|
use cas_core::{Error, ObjectId, Result}; |
|
|
|
|
|
|
|
use crate::{PathPair, Repository, TreeItem}; |
|
|
|
use crate::TreeItem; |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
|
|
|
@ -87,13 +87,15 @@ impl Iterator for TreeWalker { |
|
|
|
(Some(Ok(curr_item)), Some(prev_item)) => { |
|
|
|
if curr_item.name == prev_item.name { |
|
|
|
let action = |
|
|
|
if curr_item.modified != prev_item.modified { |
|
|
|
if curr_item.modified != prev_item.modified |
|
|
|
|| curr_item.otype != prev_item.otype |
|
|
|
|| curr_item.size != prev_item.size { |
|
|
|
Action::Update |
|
|
|
} |
|
|
|
else { |
|
|
|
Action::Skip |
|
|
|
}; |
|
|
|
self.prev_tree_it.next(); |
|
|
|
self.prev_tree_it.next().unwrap(); |
|
|
|
Some(Ok((action, self.dir_it.next().unwrap().unwrap()))) |
|
|
|
} |
|
|
|
else if curr_item.name < prev_item.name { |
|
|
|
@ -117,15 +119,107 @@ impl Iterator for TreeWalker { |
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
mod tests { |
|
|
|
use std::fs::{create_dir, remove_file as fs_remove_file, write}; |
|
|
|
|
|
|
|
use tempfile::tempdir; |
|
|
|
|
|
|
|
use cas_core::ObjectType; |
|
|
|
use crate::Permissions; |
|
|
|
use super::*; |
|
|
|
|
|
|
|
fn mkdir(root: &Utf8Path, path: &str) -> Result<()> { |
|
|
|
let mut full_path = root.to_path_buf(); |
|
|
|
full_path.push(path); |
|
|
|
create_dir(full_path).map_err(|err| err.into()) |
|
|
|
} |
|
|
|
|
|
|
|
fn write_file(root: &Utf8Path, path: &str, content: &[u8]) -> Result<()> { |
|
|
|
let mut full_path = root.to_path_buf(); |
|
|
|
full_path.push(path); |
|
|
|
write(full_path, content).map_err(|err| err.into()) |
|
|
|
} |
|
|
|
|
|
|
|
fn remove_file(root: &Utf8Path, path: &str) -> Result<()> { |
|
|
|
let mut full_path = root.to_path_buf(); |
|
|
|
full_path.push(path); |
|
|
|
fs_remove_file(full_path).map_err(|err| err.into()) |
|
|
|
} |
|
|
|
|
|
|
|
fn to_tree_items(items: Vec<Result<(Action, TreeItem)>>) -> Vec<TreeItem> { |
|
|
|
items.into_iter() |
|
|
|
.filter(|ref item| item.as_ref().unwrap().0 != Action::Remove) |
|
|
|
.map(|item| item.unwrap().1) |
|
|
|
.collect() |
|
|
|
} |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_tree_walker() { |
|
|
|
for item in TreeWalker::new("/home/draklaw/tmp", vec![]).unwrap() { |
|
|
|
match item { |
|
|
|
Ok((action, tree_item)) => println!("{:?} {:?}", action, tree_item.name), |
|
|
|
Err(err) => println!("error while iterating directory: {}", err), |
|
|
|
} |
|
|
|
} |
|
|
|
fn test_tree_walker() -> Result<()>{ |
|
|
|
let root_dir = tempdir()?; |
|
|
|
let root = Utf8Path::from_path(root_dir.path()).unwrap(); |
|
|
|
|
|
|
|
mkdir(root, "test")?; |
|
|
|
write_file(root, "test/foobar.txt", b"baz")?; |
|
|
|
write_file(root, "readme", b"hello world!")?; |
|
|
|
|
|
|
|
let items: Vec<_> = TreeWalker::new(root, vec![]).unwrap().collect(); |
|
|
|
assert_eq!(items.len(), 2); |
|
|
|
let (action, item) = items[0].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Add); |
|
|
|
assert_eq!(item.name, "readme"); |
|
|
|
assert_eq!(item.otype, ObjectType::new(b"blob").unwrap()); |
|
|
|
assert_eq!(item.size, 12); |
|
|
|
assert_eq!(item.permissions, Permissions{read: true, write: true, execute: false}); |
|
|
|
let (action, item) = items[1].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Add); |
|
|
|
assert_eq!(item.name, "test"); |
|
|
|
assert_eq!(item.otype, ObjectType::new(b"tree").unwrap()); |
|
|
|
assert_eq!(item.size, 0); |
|
|
|
assert_eq!(item.permissions, Permissions{read: true, write: true, execute: true}); |
|
|
|
|
|
|
|
write_file(root, "abc", b"xxxx")?; |
|
|
|
|
|
|
|
let items: Vec<_> = TreeWalker::new(root, to_tree_items(items)).unwrap().collect(); |
|
|
|
assert_eq!(items.len(), 3); |
|
|
|
let (action, item) = items[0].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Add); |
|
|
|
assert_eq!(item.name, "abc"); |
|
|
|
assert_eq!(item.otype, ObjectType::new(b"blob").unwrap()); |
|
|
|
assert_eq!(item.size, 4); |
|
|
|
assert_eq!(item.permissions, Permissions{read: true, write: true, execute: false}); |
|
|
|
let (action, item) = items[1].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Skip); |
|
|
|
assert_eq!(item.name, "readme"); |
|
|
|
let (action, item) = items[2].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Skip); |
|
|
|
assert_eq!(item.name, "test"); |
|
|
|
|
|
|
|
remove_file(root, "readme")?; |
|
|
|
|
|
|
|
let items: Vec<_> = TreeWalker::new(root, to_tree_items(items)).unwrap().collect(); |
|
|
|
assert_eq!(items.len(), 3); |
|
|
|
let (action, item) = items[0].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Skip); |
|
|
|
assert_eq!(item.name, "abc"); |
|
|
|
let (action, item) = items[1].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Remove); |
|
|
|
assert_eq!(item.name, "readme"); |
|
|
|
let (action, item) = items[2].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Skip); |
|
|
|
assert_eq!(item.name, "test"); |
|
|
|
|
|
|
|
write_file(root, "abc", b"ab")?; |
|
|
|
write_file(root, "test/foobar.txt", b"redacted")?; |
|
|
|
|
|
|
|
let items: Vec<_> = TreeWalker::new(root, to_tree_items(items)).unwrap().collect(); |
|
|
|
assert_eq!(items.len(), 2); |
|
|
|
let (action, item) = items[0].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Update); |
|
|
|
assert_eq!(item.name, "abc"); |
|
|
|
assert_eq!(item.size, 2); |
|
|
|
let (action, item) = items[1].as_ref().unwrap(); |
|
|
|
assert_eq!(action, &Action::Skip); |
|
|
|
assert_eq!(item.name, "test"); |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|