pub mod strategy;
use std::env;
use std::path::PathBuf;
use anyhow::Result;
use clap::ValueHint;
use garbage_fs::Filesystem;
use crate::ops::put::strategy::DeletionStrategy;
use crate::utils;
use crate::TrashDir;
#[derive(Parser)]
pub struct PutOptions {
#[clap(value_parser, value_hint(ValueHint::AnyPath))]
paths: Vec<PathBuf>,
#[clap(long = "dry")]
dry: bool,
#[clap(long = "prompt", short = 'i')]
prompt: bool,
#[clap(long = "recursive", short = 'r')]
_recursive: bool,
#[clap(long = "force", short = 'f')]
force: bool,
#[clap(long = "trash-dir", value_parser, value_hint(ValueHint::DirPath))]
trash_dir: Option<PathBuf>,
}
pub fn put(options: PutOptions, fs: &impl Filesystem) -> Result<()> {
let mut errors = vec![];
for path in options.paths.iter() {
let abs_path = utils::into_absolute(&path)?;
if !options.force && !fs.symlink_exists(&abs_path)? {
errors.push(anyhow!("Path {:?} doesn't exist.", path));
continue;
}
let current_directory = env::current_dir()?;
let parent_directory = current_directory.parent();
trace!(
?current_directory,
?parent_directory,
"Checking if we are trying to delete current or parent",
);
if abs_path == current_directory.as_path()
|| (current_directory.parent().is_some()
&& abs_path == current_directory.parent().unwrap())
{
errors.push(anyhow!("Refusing to delete . or .., skipping..."));
continue;
}
let strategy = if let Some(ref trash_dir) = options.trash_dir {
DeletionStrategy::Fixed(TrashDir::from(trash_dir))
} else {
DeletionStrategy::pick_strategy(&abs_path, fs)?
};
debug!(?path, ?strategy, "Chosen strategy.");
if options.dry {
eprintln!("Dry-deleting {:?} with strategy {:?}", path, strategy);
} else if let Err(err) = strategy.delete(abs_path, &options, fs) {
eprintln!("{}", err);
}
}
if !errors.is_empty() {
if errors.len() == 1 {
bail!("{}", errors[0]);
}
for error in errors {
error!("{}", error);
}
bail!("Multiple errors occurred.");
}
Ok(())
}