Skip to content
Snippets Groups Projects
Verified Commit ecbacfd6 authored by nfontrod's avatar nfontrod
Browse files

src/prune.rs: add prune subcommand

parent f8f7c1a8
No related branches found
No related tags found
No related merge requests found
use crate::commit;
use clap::Args;
use std::{
collections::HashMap as HM,
process::{exit, Command, Stdio},
};
#[derive(Debug, Args)]
pub(crate) struct Prune {
/// Do not change the repository
#[clap(
short = 'n',
long = "dry-run",
takes_value = false,
help_heading = "Filtering options",
display_order = 1
)]
pub(crate) dry_run: bool,
/// Output verbose list of archive
#[clap(
long = "--list",
takes_value = false,
help_heading = "Filtering options",
display_order = 2
)]
pub(crate) list: bool,
/// Print statistics for the deleted archive
#[clap(
short = 's',
long = "stats",
takes_value = false,
help_heading = "Filtering options",
display_order = 3
)]
pub(crate) stats: 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 = "Filtering options",
display_order = 4
)]
pub(crate) force: usize,
/// Work slower but using less space
#[clap(
long = "save-space",
takes_value = false,
help_heading = "Filtering options",
display_order = 5
)]
pub(crate) save_space: bool,
/// Keep all archives within this time interval
///
/// The `--keep-within` option takes an argument of the form "<int><char>"", where char is "H", "d", "w", "m", "y".
///
/// For example:
/// - --keep-within 2d means to keep all archives that were created within the past 48 hours.
/// - "1m" is taken to mean "31d". The archives kept with this option do not count towards the totals specified by any other options.
#[clap(
long = "keep-within",
value_name = "INTERVAL",
help_heading = "Filtering options",
display_order = 6
)]
pub(crate) keep_within: Option<String>,
/// Number "N" of secondly archives to keep
#[clap(
long = "keep-last",
value_name = "N",
help_heading = "Filtering options",
display_order = 7
)]
pub(crate) keep_last: Option<usize>,
/// Number "N" of minutely archives to keep
#[clap(
long = "keep-minutely",
value_name = "N",
help_heading = "Filtering options",
display_order = 8
)]
pub(crate) keep_minutely: Option<usize>,
/// Number "N" of hourly archives to keep
#[clap(
short = 'H',
long = "keep-hourly",
value_name = "N",
help_heading = "Filtering options",
display_order = 9
)]
pub(crate) keep_hourly: Option<usize>,
/// Number "N" of daily archives to keep
#[clap(
short = 'd',
long = "keep-daily",
value_name = "N",
help_heading = "Filtering options",
display_order = 10
)]
pub(crate) keep_daily: Option<usize>,
/// Number "N" of weekly archives to keep
#[clap(
short = 'w',
long = "keep-weekly",
value_name = "N",
help_heading = "Filtering options",
display_order = 11
)]
pub(crate) keep_weekly: Option<usize>,
/// Number "N" of monthly archives to keep
#[clap(
short = 'm',
long = "keep-monthly",
value_name = "N",
help_heading = "Filtering options",
display_order = 12
)]
pub(crate) keep_monthly: Option<usize>,
/// Number "N" of yearly archives to keep
#[clap(
short = 'y',
long = "keep-yearly",
value_name = "N",
help_heading = "Filtering options",
display_order = 13
)]
pub(crate) keep_yearly: Option<usize>,
/// Only consider archive names starting with this prefix (regex can be usedj)
#[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>,
}
/// 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: &Prune) -> 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),
("--save-space", sd.save_space),
]);
for (name, value) in boolp {
if value {
args.push(name.to_owned());
}
}
args
}
/// Convert an unsigned integer into a string
/// # Arguments
/// - val The value to convert
/// # Return
/// The value in string form
fn string_convert(val: Option<usize>) -> String {
match val {
Some(n) => n.to_string(),
None => String::from(""),
}
}
/// Convert an Option<String> into a string
/// # Arguments
/// - val The string to convert
/// # Return
/// The value in string form
fn get_str(val: &Option<String>) -> String {
match val {
Some(n) => n.to_owned(),
None => String::from(""),
}
}
/// 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
/// Nothing but Update `margs` parameter
fn handle_arguments_value(margs: &mut Vec<String>, sd: &Prune) {
let va: HM<&str, String> = HM::from([
("--prefix", get_str(&sd.prefix)),
("--glob-archives", get_str(&sd.glob_archives)),
("--keep-within", get_str(&sd.keep_within)),
("--keep-last", string_convert(sd.keep_last)),
("--keep-minutely", string_convert(sd.keep_minutely)),
("--keep-hourly", string_convert(sd.keep_hourly)),
("--keep-daily", string_convert(sd.keep_daily)),
("--keep-weekly", string_convert(sd.keep_weekly)),
("--keep-monthly", string_convert(sd.keep_monthly)),
("--keep-yearly", string_convert(sd.keep_yearly)),
]);
for (name, value) in va {
if value != String::from("") {
margs.push(name.to_owned());
margs.push(value);
}
}
}
/// 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: &Prune) {
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);
}
}
}
/// 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 prune_launcher(sd: Prune) {
let (borg_path, _) = commit::check_path();
let mut margs = handle_boolean_options(&sd);
handle_force_arguments(&mut margs, &sd);
handle_arguments_value(&mut margs, &sd);
margs.push(borg_path.to_str().unwrap().to_owned());
let mut output = Command::new("borg")
.arg("prune")
.args(margs)
.stdout(Stdio::piped())
.spawn()
.unwrap_or_else(|e| {
eprintln!("An error occured during borg prune ! {}", e);
exit(803);
});
let ecode = output.wait().expect("error");
match ecode.code().unwrap() {
0 => (),
num => {
eprintln!("{}", ecode.to_string());
exit(num);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment