Test TreeWalker + some fixes.
This commit is contained in:
@@ -10,4 +10,7 @@ toml = "0.5.8"
|
||||
camino = "1.0.7"
|
||||
regex = "1.6.0"
|
||||
cas-core = { path = "../cas-core" }
|
||||
cas-simple = { path = "../cas-simple" }
|
||||
cas-simple = { path = "../cas-simple" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.7.1"
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
// along with bsv. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use camino::Utf8Path;
|
||||
use regex::RegexSet;
|
||||
|
||||
use cas_core::{err, Error, Result};
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Action {
|
||||
pub enum IgnoreAction {
|
||||
Ignore,
|
||||
Accept,
|
||||
}
|
||||
@@ -30,7 +30,7 @@ pub enum Action {
|
||||
#[derive(Debug)]
|
||||
pub struct IgnoreRules {
|
||||
patterns: RegexSet,
|
||||
actions: Vec<Action>,
|
||||
actions: Vec<IgnoreAction>,
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ impl IgnoreRules {
|
||||
};
|
||||
|
||||
let mut patterns = Vec::<String>::default();
|
||||
let mut actions = Vec::<Action>::default();
|
||||
let mut actions = Vec::<IgnoreAction>::default();
|
||||
|
||||
for line in source.lines() {
|
||||
let rule = line.trim();
|
||||
@@ -65,10 +65,10 @@ impl IgnoreRules {
|
||||
|
||||
if rule_it.peek() == Some(&'!') {
|
||||
rule_it.next();
|
||||
actions.push(Action::Accept);
|
||||
actions.push(IgnoreAction::Accept);
|
||||
}
|
||||
else {
|
||||
actions.push(Action::Ignore);
|
||||
actions.push(IgnoreAction::Ignore);
|
||||
}
|
||||
|
||||
let mut pat = String::new();
|
||||
@@ -125,13 +125,13 @@ impl IgnoreRules {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn action_for<P: AsRef<Utf8Path>>(&self, path: P) -> Action {
|
||||
pub fn action_for<P: AsRef<Utf8Path>>(&self, path: P) -> IgnoreAction {
|
||||
assert!(path.as_ref().is_absolute());
|
||||
let index = self.patterns.matches(path.as_ref().as_str())
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap_or(self.actions.len());
|
||||
*self.actions.get(index).unwrap_or(&Action::Accept)
|
||||
*self.actions.get(index).unwrap_or(&IgnoreAction::Accept)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ impl IgnoreRules {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use camino::Utf8PathBuf;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@@ -147,17 +149,17 @@ mod tests {
|
||||
let patterns = "!hello/world\nhello\n/world/\n\\!\\*\n*.bak";
|
||||
let ignore = IgnoreRules::from_source(patterns, root).unwrap();
|
||||
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test")), Action::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/aoeu")), Action::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello_world/aoeu")), Action::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/world/aoeu")), Action::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/world/aoeu")), Action::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world/aoeu")), Action::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world")), Action::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/fooXdir/bar/world")), Action::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/!*/aoeu")), Action::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/file.bak")), Action::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/fileXbak")), Action::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test.bak/file")), Action::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test")), IgnoreAction::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/aoeu")), IgnoreAction::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello_world/aoeu")), IgnoreAction::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/world/aoeu")), IgnoreAction::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/world/aoeu")), IgnoreAction::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world/aoeu")), IgnoreAction::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world")), IgnoreAction::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/fooXdir/bar/world")), IgnoreAction::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/!*/aoeu")), IgnoreAction::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/file.bak")), IgnoreAction::Ignore);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/fileXbak")), IgnoreAction::Accept);
|
||||
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test.bak/file")), IgnoreAction::Ignore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,24 @@ extern crate toml;
|
||||
extern crate camino;
|
||||
extern crate regex;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate tempfile;
|
||||
|
||||
extern crate cas_core;
|
||||
|
||||
|
||||
// mod config;
|
||||
mod ignore;
|
||||
mod path_map;
|
||||
mod permissions;
|
||||
mod repository;
|
||||
mod tree_item;
|
||||
mod tree_walker;
|
||||
// mod config;
|
||||
mod path_map;
|
||||
mod ignore;
|
||||
mod repository;
|
||||
|
||||
|
||||
pub use crate::permissions::Permissions;
|
||||
pub use crate::tree_item::{Serialize, TreeItem};
|
||||
pub use crate::ignore::{IgnoreAction, IgnoreRules};
|
||||
pub use crate::path_map::{PathMap, PathPair};
|
||||
pub use crate::repository::{Repository};
|
||||
pub use crate::permissions::Permissions;
|
||||
pub use crate::repository::Repository;
|
||||
pub use crate::tree_item::{Serialize, TreeItem};
|
||||
pub use crate::tree_walker::{Action, TreeWalker};
|
||||
|
||||
@@ -40,9 +40,9 @@ impl Permissions {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
let mode = metadata.mode();
|
||||
Ok(Self {
|
||||
read: mode & 0o100 != 0,
|
||||
read: mode & 0o400 != 0,
|
||||
write: mode & 0o200 != 0,
|
||||
execute: mode & 0o400 != 0,
|
||||
execute: mode & 0o100 != 0,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use camino::{Utf8Path, Utf8PathBuf};
|
||||
use toml::Value;
|
||||
|
||||
use cas_core::{Cas, err, Error, ObjectId, Result};
|
||||
use cas_simple::{SimpleCas};
|
||||
use cas_simple::SimpleCas;
|
||||
|
||||
pub use crate::permissions::Permissions;
|
||||
pub use crate::tree_item::{Serialize, TreeItem};
|
||||
|
||||
@@ -58,7 +58,7 @@ impl TreeItem {
|
||||
Ok(Self {
|
||||
name: name,
|
||||
otype,
|
||||
size: metadata.len(),
|
||||
size: if metadata.is_file() { metadata.len() } else { 0 },
|
||||
created: metadata.created().unwrap_or(UNIX_EPOCH),
|
||||
modified: metadata.modified().unwrap_or(UNIX_EPOCH),
|
||||
permissions,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user