Test TreeWalker + some fixes.

This commit is contained in:
Simon Boyé
2023-08-12 23:52:26 +02:00
parent 7230127f26
commit 2b27b788e5
8 changed files with 271 additions and 134 deletions

View File

@@ -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"

View File

@@ -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);
}
}

View File

@@ -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};

View File

@@ -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,
})
}

View File

@@ -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};

View File

@@ -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,

View File

@@ -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(())
}
}