use anyhow::Result;
use ghee_lang::{Predicate, Value, Xattr};
use path_absolutize::Absolutize;
use serde::Serialize;
use thiserror::Error;
use crate::{paths::PathBufExt, walk::walk_records};
use std::{collections::BTreeMap, io::Write, path::PathBuf};
#[derive(Serialize)]
struct FileXattrs<'a, 'b> {
path: String,
xattrs: BTreeMap<&'a Xattr, &'b Value>,
}
#[derive(Error, Debug)]
pub enum GetErr {
#[error("Error serializing JSON: {0}")]
JsonSerializationError(serde_json::Error),
#[error("IO error writing xattr(s) to stdin: {0}")]
IoError(std::io::Error),
}
pub fn get(
paths: &Vec<PathBuf>,
fields: &Vec<Xattr>,
json: bool,
where_: &Vec<Predicate>,
recursive: bool,
all: bool,
sort: bool,
visit_empty: bool,
) -> Result<()> {
for path in paths {
let abs_path = path.absolutize().unwrap().to_path_buf();
walk_records(
&abs_path,
where_,
recursive,
all,
sort,
visit_empty,
&|record| {
let output_path = record
.original_path_abs()
.map(|p| p.relative_to_curdir_if_possible())
.unwrap_or_default();
let projected_fields: Vec<Xattr> = if fields.is_empty() {
record.xattr_values.keys().cloned().collect()
} else {
fields.clone()
};
if json {
let mut xattrs: BTreeMap<&Xattr, &Value> = BTreeMap::new();
for field in projected_fields.iter() {
let value = &record.xattr_values[field];
xattrs.insert(field, value);
}
if !xattrs.is_empty() {
let file_xattrs = FileXattrs {
path: output_path.display().to_string(),
xattrs,
};
println!(
"{}",
serde_json::to_string(&file_xattrs)
.map_err(GetErr::JsonSerializationError)?
);
}
} else {
for field in projected_fields.iter() {
if let Some(value) = record.xattr_values.get(field) {
print!("{}\t{}\t", output_path.display(), field);
{
let mut stdout = std::io::stdout();
stdout
.write(value.as_bytes().as_slice())
.map_err(GetErr::IoError)?;
}
println!();
}
}
}
Ok(())
},
)?;
}
Ok(())
}
#[cfg(test)]
mod test {
use ghee_lang::Key;
use crate::{cmd::create, test_support::TempDirAuto};
use super::get;
#[test]
fn test_get_all_after_create() {
let dir = TempDirAuto::new("ghee-test-get-all");
let nonexisting = dir.push("nonexisting");
let key = Key::from_string("a");
create(&nonexisting, &key, false).unwrap();
get(
&vec![nonexisting.clone()],
&vec![],
false,
&vec![],
true,
true,
false,
true,
)
.unwrap();
assert!(dir.exists());
}
}