delete.rs 7.36 KiB
use clap::Args;
use colored::Colorize;
use std::{
collections::HashMap as HM,
process::{exit, Command, Stdio},
};
use crate::{commit, prune};
#[derive(Debug, Args)]
pub(crate) struct Delete {
/// Do not change the repository
#[clap(
short = 'n',
long = "dry-run",
takes_value = false,
help_heading = "General options"
)]
pub(crate) dry_run: bool,
/// Output verbose list of archive
#[clap(long = "--list", takes_value = false, help_heading = "General options")]
pub(crate) list: bool,
/// Print statistics for the deleted archive
#[clap(
short = 's',
long = "stats",
takes_value = false,
help_heading = "General options"
)]
pub(crate) stats: bool,
/// Delete only the local cache for the given repository
#[clap(
long = "cache-only",
takes_value = false,
help_heading = "General options"
)]
pub(crate) cache_only: bool,
/// Force deletion of corrupted archives, use `--force --force` in case `--force` does not work.
#[clap(
long,
parse(from_occurrences),
takes_value = false,
help_heading = "General options"
)]
pub(crate) force: usize,
/// Keep the local security info when deleting a repository
#[clap(
long = "keep-security-info",
takes_value = false,
help_heading = "General options"
)]
pub(crate) keep_security_info: bool,
/// Work slower but using less space
#[clap(
long = "save-space",
takes_value = false,
help_heading = "General options"
)]
pub(crate) save_space: bool,
/// Only consider archive names starting with this prefix
#[clap(
short = 'P',
long = "prefix",
group = "pref",
value_name = "PREFIX",
help_heading = "Archive filters",
display_order = 1
)]
pub(crate) prefix: Option<String>,
/// only consider archive names matching the glob. sh: rules apply, see "borg help patterns".
/// `--prefix` and `--glob-archives` are mutually exclusive.
#[clap(
short = 'a',
long = "glob-archives",
group = "pref",
value_name = "GLOB",
help_heading = "Archive filters",
display_order = 2
)]
pub(crate) glob_archives: Option<String>,
/// Comma-separated list of sorting keys; valid keys are: timestamp, name, id; default is: timestamp
#[clap(long = "sort-by", help_heading = "Archive filters", display_order = 3)]
pub(crate) sort_by: Option<String>,
/// consider first N archives after other filters were applied
#[clap(
long,
value_name = "N",
help_heading = "Archive filters",
display_order = 4
)]
pub(crate) first: Option<usize>,
/// consider last N archives after other filters were applied
#[clap(
long,
value_name = "N",
help_heading = "Archive filters",
display_order = 5
)]
pub(crate) last: Option<usize>,
/// Name of archives to delete
#[clap(
help_heading = "Positional Arguments",
multiple_occurrences = true,
multiple_values = true,
required = false
)]
pub(crate) archive: Vec<String>,
}
/// Function that add flags arguments in the delete commands
/// # Arguments
/// * `sd`: Struct containing all the data that can be used to build the delete command
/// # Returns
/// A vector containing boolean options
fn handle_boolean_options(sd: &Delete) -> Vec<String> {
let mut args: Vec<String> = Vec::new();
let boolp: HM<&str, bool> = HM::from([
("--list", sd.list),
("--stats", sd.stats),
("--dry-run", sd.dry_run),
("--cache-only", sd.cache_only),
("--keep-security-info", sd.keep_security_info),
("--save-space", sd.save_space),
]);
for (name, value) in boolp {
if value {
args.push(name.to_owned());
}
}
args
}
/// Handle the number of time --force is given to borg delete
/// # Arguments
/// * margs A vector the arguments to pass to borg delete
/// * sd: A struct containing all arguments passed to gblk delete
/// # Return
/// Nothing, but will update `margs` parameter
fn handle_force_arguments(margs: &mut Vec<String>, sd: &Delete) {
match sd.force {
1 | 2 => {
margs.push("--force".to_string());
if sd.force == 2 {
margs.push("--force".to_owned());
}
}
0 => (),
_ => {
eprintln!("error: --force can only be used once or twice !");
exit(99);
}
}
}
/// Function to handle optional arguments with an associated value
/// # Arguments
/// * margs A vector the arguments to pass to borg delete
/// * sd: A struct containing all arguments passed to gblk delete
/// Return
/// A boolean indicating if Archive filters are used. Also Update `margs` parameter
fn handle_arguments_value(margs: &mut Vec<String>, sd: &Delete) -> bool {
let va: HM<&str, String> = HM::from([
("--prefix", prune::get_str(&sd.prefix)),
("--glob-archives", prune::get_str(&sd.glob_archives)),
("--sort-by", prune::get_str(&sd.sort_by)),
("--first", prune::string_convert(sd.first)),
("--last", prune::string_convert(sd.last)),
]);
let mut count = 0;
for (name, value) in va {
if value != String::from("") {
count += 1;
margs.push(name.to_owned());
margs.push(value);
}
}
count == 0
}
/// Function handling positional arguments
/// # Arguments
/// * margs A vector the arguments to pass to borg delete
/// * sd: A struct containing all arguments passed to gblk delete
/// Return
/// A boolean indicating if Archive filters are used. Also Update `margs` parameter
fn handle_positional_arguments(margs: &mut Vec<String>, sd: &Delete) -> bool {
for p in sd.archive.to_owned().into_iter() {
margs.push(p);
}
sd.archive.len() == 0
}
/// Fonction that will launch borg delete
/// # Arguments
/// * `sd`: Struct containing all the data that can be used to build the delete command
pub(crate) fn deletion_launcher(sd: Delete) {
let (borg_path, _) = commit::check_path();
let mut margs = handle_boolean_options(&sd);
handle_force_arguments(&mut margs, &sd);
let no_filter = handle_arguments_value(&mut margs, &sd);
margs.push(borg_path.to_str().unwrap().to_owned());
let no_pos = handle_positional_arguments(&mut margs, &sd);
if no_filter && no_pos {
let sargs = margs.join(" ");
let cmd = format!("borg delete {}", sargs);
eprintln!(
"{} this command `{}` will remove your `{}` repository wich may disrup the behavior of gblk !\n{}\n{}",
"Warning:".yellow(),
cmd.blue(),
borg_path.to_str().unwrap().blue(),
"Using it is not recommended".bold().yellow(),
"Terminating".italic().red()
);
exit(801);
}
let mut output = Command::new("borg")
.arg("delete")
.args(margs)
.stdout(Stdio::piped())
.spawn()
.unwrap_or_else(|e| {
eprintln!("An error occured during borg delete ! {}", e);
exit(800);
});
let ecode = output.wait().expect("error");
match ecode.code().unwrap() {
0 => (),
num => {
eprintln!("{}", ecode.to_string());
exit(num);
}
}
}