use anyhow::{Context, Result};
use ghee_lang::{Assignment, Xattr};
use std::{fmt::Formatter, path::PathBuf};
use crate::{list_xattrs, xattr_value};
use super::{rm, set};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CopyOrMove {
Copy,
Move,
}
impl CopyOrMove {
pub fn name(&self) -> &str {
match self {
Self::Copy => "copy",
Self::Move => "move",
}
}
}
impl std::fmt::Display for CopyOrMove {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.name())
}
}
pub(crate) fn cp_or_mv(
src: &PathBuf,
dest: &PathBuf,
fields: &Vec<Xattr>,
verbose: bool,
kind: CopyOrMove,
) -> Result<()> {
let fields: Vec<Xattr> = if fields.is_empty() {
list_xattrs(src)
} else {
fields.clone()
};
if verbose {
let attrs: Vec<String> = fields.iter().map(|f| f.to_string()).collect();
println!(
"{} {} from {} to {}",
kind,
attrs.join(", "),
src.display(),
dest.display()
);
}
let assignments = {
let mut assignments: Vec<Assignment> = Vec::with_capacity(fields.len());
for field in &fields {
let value = xattr_value(src, field)
.with_context(|| format!("Could not retrieve xattr {} value", field))?;
assignments.push(Assignment::new(field.clone(), value));
}
assignments
};
set(&vec![dest.clone()], &assignments, false, verbose)
.context("Could not set the field values on the destination")?;
if kind == CopyOrMove::Move {
rm(&vec![src.clone()], &fields, false, false, verbose)
.context("Could not remove the field values from the source")?;
}
Ok(())
}
#[cfg(test)]
mod test {
use ghee_lang::Value;
use crate::{test_support::Scenario, xattr_values};
use super::{cp_or_mv, CopyOrMove};
#[test]
fn test_cp() {
test_cp_or_mv(CopyOrMove::Copy);
}
#[test]
fn test_mv() {
test_cp_or_mv(CopyOrMove::Move);
}
fn test_cp_or_mv(kind: CopyOrMove) {
let s = Scenario::new(kind.name());
{
let values = xattr_values(&s.dir1path1).unwrap();
assert_eq!(values.len(), 4);
assert_eq!(values[&s.xattr1], Value::Number(0f64));
assert_eq!(values[&s.xattr2], Value::Number(1f64));
assert_eq!(values[&s.xattr3], Value::Number(2f64));
assert_eq!(values[&s.xattr4], Value::Number(3f64));
}
{
let values = xattr_values(&s.dir1path2).unwrap();
assert_eq!(values.len(), 4);
assert_eq!(values[&s.xattr1], Value::Number(10f64));
assert_eq!(values[&s.xattr2], Value::Number(11f64));
assert_eq!(values[&s.xattr3], Value::Number(12f64));
assert_eq!(values[&s.xattr4], Value::Number(13f64));
}
cp_or_mv(
&s.dir1path1,
&s.dir1path2,
&vec![s.xattr4.clone()],
false,
kind,
)
.unwrap();
{
let values = xattr_values(&s.dir1path1).unwrap();
assert_eq!(
values.len(),
match kind {
CopyOrMove::Copy => 4,
CopyOrMove::Move => 3,
}
);
assert_eq!(values[&s.xattr1], Value::Number(0f64));
assert_eq!(values[&s.xattr2], Value::Number(1f64));
assert_eq!(values[&s.xattr3], Value::Number(2f64));
if kind == CopyOrMove::Copy {
assert_eq!(values[&s.xattr4], Value::Number(3f64));
}
}
{
let values = xattr_values(&s.dir1path2).unwrap();
assert_eq!(values.len(), 4);
assert_eq!(values[&s.xattr1], Value::Number(10f64));
assert_eq!(values[&s.xattr2], Value::Number(11f64));
assert_eq!(values[&s.xattr3], Value::Number(12f64));
assert_eq!(values[&s.xattr4], Value::Number(3f64));
}
}
}