Work toward recursive set
and rm
; failing tests
This commit is contained in:
parent
6e5f4345d4
commit
b9ef10bf6e
6 changed files with 173 additions and 27 deletions
|
@ -62,6 +62,8 @@ enum Commands {
|
|||
paths: Vec<PathBuf>,
|
||||
#[arg(name = "field", short, long, help = "xattrs to remove")]
|
||||
fields: Vec<Xattr>,
|
||||
#[arg(long, help = "Process paths nonrecursively; defaults to false")]
|
||||
flat: bool,
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
},
|
||||
|
@ -94,6 +96,8 @@ enum Commands {
|
|||
paths: Vec<PathBuf>,
|
||||
#[arg(name = "set", short, long, help = "k=v pairs to set", value_parser = ValueParser::new(AssignmentParser{}))]
|
||||
field_assignments: Vec<Assignment>,
|
||||
#[arg(long, help = "Process paths nonrecursively; defaults to false")]
|
||||
flat: bool,
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
},
|
||||
|
@ -271,9 +275,10 @@ fn run_command(cmd: &Commands) {
|
|||
Commands::Rm {
|
||||
paths,
|
||||
fields,
|
||||
flat,
|
||||
verbose,
|
||||
} => {
|
||||
rm(paths, fields, *verbose)
|
||||
rm(paths, fields, !*flat, *verbose)
|
||||
.unwrap_or_else(|e| panic!("Error removing xattr(s): {}", e));
|
||||
}
|
||||
Commands::Get {
|
||||
|
@ -290,8 +295,9 @@ fn run_command(cmd: &Commands) {
|
|||
Commands::Set {
|
||||
paths,
|
||||
field_assignments,
|
||||
flat,
|
||||
verbose,
|
||||
} => set(paths, field_assignments, *verbose)
|
||||
} => set(paths, field_assignments, !*flat, *verbose)
|
||||
.unwrap_or_else(|e| panic!("Error setting xattrs: {}", e)),
|
||||
|
||||
Commands::Ins {
|
||||
|
|
|
@ -113,6 +113,6 @@ mod test {
|
|||
|
||||
create(&dir, &key, false).unwrap();
|
||||
|
||||
get(&vec![dir], &vec![], false, &vec![], true, true).unwrap();
|
||||
get(&vec![dir], &vec![], false, &vec![], true, true, false).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
148
src/cmd/rm.rs
148
src/cmd/rm.rs
|
@ -1,5 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use thiserror::Error;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -15,27 +16,150 @@ pub enum RmErr {
|
|||
*
|
||||
* Not to be mistaken for `del` which removes records from tables.
|
||||
*/
|
||||
pub fn rm(paths: &Vec<PathBuf>, fields: &Vec<Xattr>, verbose: bool) -> Result<()> {
|
||||
pub fn rm(paths: &Vec<PathBuf>, fields: &Vec<Xattr>, recursive: bool, verbose: bool) -> Result<()> {
|
||||
let max_depth = if recursive { usize::MAX } else { 0 };
|
||||
|
||||
if verbose {
|
||||
let fields: Vec<String> = fields.iter().map(|f| f.to_string()).collect();
|
||||
eprintln!("Removing {} from:", fields.join(", "));
|
||||
}
|
||||
|
||||
for path in paths {
|
||||
let fields: Vec<Xattr> = if fields.is_empty() {
|
||||
list_xattrs(path)
|
||||
} else {
|
||||
fields.clone()
|
||||
};
|
||||
for entry in WalkDir::new(path).max_depth(max_depth).into_iter() {
|
||||
let entry = entry?;
|
||||
|
||||
for field in fields.iter() {
|
||||
let field_osstring = field.to_osstring();
|
||||
xattr::remove(path, field_osstring).map_err(RmErr::IoError)?;
|
||||
}
|
||||
if verbose {
|
||||
eprintln!("\t{}", path.display());
|
||||
let fields: Vec<Xattr> = if fields.is_empty() {
|
||||
list_xattrs(path)
|
||||
} else {
|
||||
fields.clone()
|
||||
};
|
||||
|
||||
for field in fields.iter() {
|
||||
let field_osstring = field.to_osstring();
|
||||
xattr::remove(entry.path(), field_osstring).map_err(RmErr::IoError)?;
|
||||
}
|
||||
if verbose {
|
||||
eprintln!("\t{}", entry.path().display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{cmd::rm, test_support::Scenario, xattr_values};
|
||||
|
||||
#[test]
|
||||
fn test_rm() {
|
||||
let s: Scenario = Default::default();
|
||||
|
||||
// The path in dir1
|
||||
let path1 = {
|
||||
let mut path = s.dir1.clone();
|
||||
path.push("0");
|
||||
path
|
||||
};
|
||||
|
||||
let path2 = {
|
||||
let mut path = s.dir2.clone();
|
||||
path.push("1");
|
||||
path.push("2");
|
||||
path
|
||||
};
|
||||
|
||||
assert!(path1.exists());
|
||||
assert!(path2.exists());
|
||||
|
||||
{
|
||||
let values1 = xattr_values(&path1).unwrap();
|
||||
|
||||
assert!(values1.contains_key(&s.xattr1));
|
||||
assert!(values1.contains_key(&s.xattr2));
|
||||
assert!(values1.contains_key(&s.xattr3));
|
||||
}
|
||||
{
|
||||
let values2 = xattr_values(&path2).unwrap();
|
||||
|
||||
assert!(values2.contains_key(&s.xattr1));
|
||||
assert!(values2.contains_key(&s.xattr2));
|
||||
assert!(values2.contains_key(&s.xattr3));
|
||||
}
|
||||
|
||||
// Remove
|
||||
rm(&vec![path1.clone()], &vec![s.xattr1.clone()], false, false).unwrap();
|
||||
|
||||
assert!(
|
||||
!path1.exists(),
|
||||
"Record not removed from index even though it no longer has relevant xattr"
|
||||
);
|
||||
assert!(path2.exists());
|
||||
|
||||
{
|
||||
let values2 = xattr_values(path2).unwrap();
|
||||
|
||||
assert!(!values2.contains_key(&s.xattr1));
|
||||
assert!(values2.contains_key(&s.xattr2));
|
||||
assert!(values2.contains_key(&s.xattr3));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rm_recursive() {
|
||||
let s: Scenario = Default::default();
|
||||
|
||||
let path1 = {
|
||||
let mut path = s.dir1.clone();
|
||||
path.push("0");
|
||||
path
|
||||
};
|
||||
|
||||
let path2 = {
|
||||
let mut path = s.dir2.clone();
|
||||
path.push("1");
|
||||
path.push("2");
|
||||
path
|
||||
};
|
||||
|
||||
let path3 = {
|
||||
let mut path = s.dir1.clone();
|
||||
path.push("10");
|
||||
path
|
||||
};
|
||||
|
||||
let path4 = {
|
||||
let mut path = s.dir2.clone();
|
||||
path.push("11");
|
||||
path.push("12");
|
||||
path
|
||||
};
|
||||
|
||||
assert!(path1.exists());
|
||||
assert!(path2.exists());
|
||||
assert!(path3.exists());
|
||||
assert!(path4.exists());
|
||||
|
||||
for path in vec![&path1, &path2, &path3, &path4] {
|
||||
let values = xattr_values(&path).unwrap();
|
||||
|
||||
assert!(values.contains_key(&s.xattr1));
|
||||
assert!(values.contains_key(&s.xattr2));
|
||||
assert!(values.contains_key(&s.xattr3));
|
||||
}
|
||||
|
||||
// Remove
|
||||
rm(&vec![s.dir1.clone()], &vec![s.xattr1.clone()], true, false).unwrap();
|
||||
|
||||
assert!(
|
||||
!path1.exists(),
|
||||
"Record not removed from index even though it no longer has relevant xattr"
|
||||
);
|
||||
assert!(path2.exists());
|
||||
assert!(
|
||||
!path3.exists(),
|
||||
"Record not removed from index even though it no longer has relevant xattr"
|
||||
);
|
||||
assert!(path4.exists());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use thiserror::Error;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::parser::value::Value;
|
||||
|
||||
|
@ -19,21 +20,28 @@ pub enum SetErr {
|
|||
pub fn set<P: AsRef<Path>>(
|
||||
paths: &Vec<P>,
|
||||
field_assignments: &Vec<Assignment>,
|
||||
recursive: bool,
|
||||
verbose: bool,
|
||||
) -> Result<()> {
|
||||
let max_depth = if recursive { usize::MAX } else { 0 };
|
||||
|
||||
let field_assignments: Vec<(Xattr, Value)> = field_assignments
|
||||
.iter()
|
||||
.map(|fa| (fa.xattr.clone(), fa.value.clone()))
|
||||
.collect();
|
||||
|
||||
for path in paths {
|
||||
for (field, value) in field_assignments.iter() {
|
||||
let field_osstring = field.to_osstring();
|
||||
xattr::set(path, field_osstring, value.as_bytes().as_slice())
|
||||
.map_err(SetErr::IoError)?;
|
||||
for entry in WalkDir::new(&path).max_depth(max_depth).into_iter() {
|
||||
let entry = entry?;
|
||||
|
||||
if verbose {
|
||||
eprintln!("Set {} to {} on {}", field, value, path.as_ref().display());
|
||||
for (field, value) in field_assignments.iter() {
|
||||
let field_osstring = field.to_osstring();
|
||||
xattr::set(entry.path(), field_osstring, value.as_bytes().as_slice())
|
||||
.map_err(SetErr::IoError)?;
|
||||
|
||||
if verbose {
|
||||
eprintln!("Set {} to {} on {}", field, value, path.as_ref().display());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
src/lib.rs
15
src/lib.rs
|
@ -601,7 +601,7 @@ mod test {
|
|||
assert_eq!(get_key(&dir).unwrap().unwrap(), key);
|
||||
}
|
||||
|
||||
fn visited(path: &PathBuf, recursive: bool, all: bool) -> Vec<PathBuf> {
|
||||
fn visited(path: &PathBuf, recursive: bool, all: bool, nosort: bool) -> Vec<PathBuf> {
|
||||
let visited: Rc<RefCell<Vec<PathBuf>>> = Rc::new(RefCell::new(Vec::new()));
|
||||
|
||||
walk(
|
||||
|
@ -609,6 +609,7 @@ mod test {
|
|||
&Vec::new(),
|
||||
recursive,
|
||||
all,
|
||||
nosort,
|
||||
&|path| {
|
||||
visited.borrow_mut().push(path.path.clone());
|
||||
Ok(())
|
||||
|
@ -624,7 +625,7 @@ mod test {
|
|||
fn test_walk_bare_dir() {
|
||||
let dir = TempDir::new("ghee-test-walk").unwrap().into_path();
|
||||
|
||||
assert!(visited(&dir, true, true).is_empty());
|
||||
assert!(visited(&dir, true, true, false).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -633,7 +634,7 @@ mod test {
|
|||
|
||||
init(&dir, &Key::from_string("test"), false).unwrap();
|
||||
|
||||
let visited = visited(&dir, true, true);
|
||||
let visited = visited(&dir, true, true, false);
|
||||
|
||||
assert_eq!(
|
||||
visited.len(),
|
||||
|
@ -650,7 +651,7 @@ mod test {
|
|||
|
||||
init(&dir, &Key::from_string("test"), false).unwrap();
|
||||
|
||||
let visited = visited(&dir, true, false);
|
||||
let visited = visited(&dir, true, false, true);
|
||||
|
||||
assert!(visited.is_empty());
|
||||
}
|
||||
|
@ -663,6 +664,7 @@ mod test {
|
|||
&vec![&dir1],
|
||||
&vec![parse_assignment(b"a=1").unwrap().1],
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -675,15 +677,16 @@ mod test {
|
|||
&vec![&dir2],
|
||||
&vec![parse_assignment(b"a=2").unwrap().1],
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let visited_flat = visited(&dir1, false, false);
|
||||
let visited_flat = visited(&dir1, false, false, true);
|
||||
|
||||
assert_eq!(visited_flat.len(), 1);
|
||||
assert!(visited_flat.contains(&dir1));
|
||||
|
||||
let visited_recursive = visited(&dir1, true, false);
|
||||
let visited_recursive = visited(&dir1, true, false, false);
|
||||
|
||||
assert_eq!(visited_recursive.len(), 2);
|
||||
assert!(visited_recursive.contains(&dir1));
|
||||
|
|
|
@ -7,6 +7,11 @@ use crate::{
|
|||
parser::{key::Key, xattr::Xattr},
|
||||
};
|
||||
|
||||
/** A test scenario
|
||||
*
|
||||
* dir1 is indexed by ['test1'] (xattr1)
|
||||
* dir2 is indexed by ['test2', 'test3'] (xattr2, xattr3)
|
||||
*/
|
||||
pub struct Scenario {
|
||||
/// Table indexed by xattr1
|
||||
pub dir1: PathBuf,
|
||||
|
|
Loading…
Reference in a new issue