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

src/configt.rs src/prune.rs src/main.rs: add configuration to ease pruning

parent c9c161e2
Branches
No related tags found
No related merge requests found
use crate::commit;
use crate::prune::{new_prune, prune_launcher};
use clap::Args;
use colored::Colorize;
use regex::Regex;
use serde_derive::{Deserialize, Serialize};
use std::{path::PathBuf, process::exit};
use toml::{self, Value};
#[derive(Debug, Args)]
pub(crate) struct PartialPrune {
/// 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,
}
// ================================ toml structure of borg config
/// Structure containing the global definition of the borg config file
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Config {
repository: Repository,
gblk_prune: Option<GblkConfig>,
}
/// Structure that store the current borg configuration for the project
#[derive(Debug, Deserialize, Serialize, Clone)]
struct Repository {
version: Value,
segments_per_dir: usize,
max_segment_size: usize,
append_only: usize,
storage_quota: usize,
additional_free_space: usize,
id: String,
}
/// Structure corresponding to the gblk prune config to automatically use
/// inside a project
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct GblkConfig {
pub save_space: Option<bool>,
pub keep_within: Option<String>,
pub keep_last: Option<usize>,
pub keep_minutely: Option<usize>,
pub keep_hourly: Option<usize>,
pub keep_daily: Option<usize>,
pub keep_weekly: Option<usize>,
pub keep_monthly: Option<usize>,
pub keep_yearly: Option<usize>,
pub prefix: Option<String>,
pub glob_archives: Option<String>,
}
impl GblkConfig {
fn empty(&self) -> bool {
if self.save_space != None {
return false;
};
if self.keep_within != None {
return false;
};
if self.keep_last != None {
return false;
};
if self.keep_minutely != None {
return false;
};
if self.keep_hourly != None {
return false;
};
if self.keep_daily != None {
return false;
};
if self.keep_weekly != None {
return false;
};
if self.keep_monthly != None {
return false;
};
if self.keep_yearly != None {
return false;
};
if self.prefix != None {
return false;
};
if self.glob_archives != None {
return false;
};
true
}
}
// =================== Functions
/// Get the config file inside borg folder
/// # Return
/// A pathbuf variable containing the location of borg config file for the
/// current project
fn get_borgconfig() -> PathBuf {
let (mut config_path, _) = commit::check_path();
config_path.push("config");
if !config_path.is_file() {
eprintln!("{} not found !", config_path.to_str().unwrap());
exit(1);
}
config_path
}
fn parse_toml() -> Config {
let config_file = get_borgconfig();
let rcontent = std::fs::read_to_string(&config_file);
let content = match rcontent {
Err(e) => {
eprintln!("Unable to read {} - {}", &config_file.to_str().unwrap(), e);
exit(101);
}
Ok(s) => s,
};
let re = Regex::new("id = (?P<first>[0-9a-z]+)\\W").unwrap();
let nc = re.replace(&content, "id = '$first'");
let config_str: Config = toml::from_str(&nc).unwrap();
config_str
}
/// Function that show the current gblk config of the borg folder
pub fn show() -> () {
let config = parse_toml();
let gblk_config: GblkConfig = match config.gblk_prune {
Some(data) => data,
None => {
println!("{}", "No configuration defined for this project".yellow());
exit(0)
}
};
let gblk_str = toml::to_string_pretty(&gblk_config).unwrap();
println!("{}", gblk_str);
}
/// Function that update the current gblk config file for the project folder
/// # Arguments
/// - `key` : The key to update
/// - `value`: The value of the key to update
/// # Return
/// The updated prune keys
fn update_val(input: &mut GblkConfig, key: &str, value: &str) -> () {
match key {
"save_space" | "save-space" => {
input.save_space = Some(str::parse::<bool>(value).unwrap());
}
"keep_within" | "keep-within" => {
input.keep_within = Some(value.to_owned());
}
"keep_last" | "keep-last" => {
input.keep_last = Some(str::parse::<usize>(value).unwrap());
}
"keep_minutely" | "keep-minutely" => {
input.keep_minutely = Some(str::parse::<usize>(value).unwrap());
}
"keep_hourly" | "keep-hourly" => {
input.keep_hourly = Some(str::parse::<usize>(value).unwrap());
}
"keep_daily" | "keep-daily" => {
input.keep_daily = Some(str::parse::<usize>(value).unwrap());
}
"keep_weekly" | "keep-weekly" => {
input.keep_weekly = Some(str::parse::<usize>(value).unwrap());
}
"keep_monthly" | "keep-monthly" => {
input.keep_monthly = Some(str::parse::<usize>(value).unwrap());
}
"keep_yearly" | "keep-yearly" => {
input.keep_yearly = Some(str::parse::<usize>(value).unwrap());
}
"prefix" => {
input.prefix = Some(value.to_owned());
}
"glob_archives" | "glob-archives" => {
input.glob_archives = Some(value.to_owned());
}
&_ => {
eprintln!(
"{} {} '{}' {}\n{}\n- {}\n- {}",
"error:".red(),
"The key",
key,
"doesn't exist !",
"choose from:",
"keep_within, keep_last, keep_minutely, keep_hourly, keep_daily".blue(),
"keep_weekly, keep_monthly, keep_yearly, prefix, glob_archives, save_space".blue()
);
exit(1);
}
}
}
/// Function that checks if the parameter input param is already defined
/// # Description:
/// If input_param is already defined, returns None but if not, return an error
/// # Arguments:
/// - input_param: A parameter of the gblk config structure
/// - key: The key to remove
/// # Return
/// None if input_param is defined, error else
fn check_and_warn<T>(input_param: &Option<T>, key: &str) -> Option<T> {
match input_param {
None => {
eprintln!(
"{} {} {} {}",
"error:".red(),
"The key",
key,
"is not defined !"
);
exit(103);
}
Some(_) => None,
}
}
/// Function that remove a key from the current gblk config file for the project folder
/// # Arguments
/// - `key` : The key to remove
/// # Return
/// The updated prune keys
fn remove_val(input: &mut GblkConfig, key: &str) -> () {
match key {
"save_space" | "save-space" => {
input.save_space = check_and_warn(&input.save_space, &key);
}
"keep_within" | "keep-within" => {
input.keep_within = check_and_warn(&input.keep_within, &key);
}
"keep_last" | "keep-last" => {
input.keep_last = check_and_warn(&input.keep_last, &key);
}
"keep_minutely" | "keep-minutely" => {
input.keep_minutely = check_and_warn(&input.keep_minutely, &key);
}
"keep_hourly" | "keep-hourly" => {
input.keep_hourly = check_and_warn(&input.keep_hourly, &key);
}
"keep_daily" | "keep-daily" => {
input.keep_daily = check_and_warn(&input.keep_daily, &key);
}
"keep_weekly" | "keep-weekly" => {
input.keep_weekly = check_and_warn(&input.keep_weekly, &key);
}
"keep_monthly" | "keep-monthly" => {
input.keep_monthly = check_and_warn(&input.keep_monthly, &key);
}
"keep_yearly" | "keep-yearly" => {
input.keep_yearly = check_and_warn(&input.keep_yearly, &key);
}
"prefix" => {
input.prefix = check_and_warn(&input.prefix, &key);
}
"glob_archives" | "glob-archives" => {
input.glob_archives = check_and_warn(&input.glob_archives, &key);
}
&_ => {
eprintln!(
"{} {} '{}' {}\n{}\n- {}\n- {}",
"error:".red(),
"The key",
key,
"doesn't exist !",
"choose from:",
"keep_within, keep_last, keep_minutely, keep_hourly, keep_daily".blue(),
"keep_weekly, keep_monthly, keep_yearly, prefix, glob_archives, save_space".blue()
);
exit(1);
}
}
}
/// Get the object conrresponding to gblk prune config
/// # Arguments
/// - full_config: The entire configuration file
/// # Return
/// The configuration for gblk prune object
fn get_gblkconfig(full_config: &Config) -> GblkConfig {
let gblk_config: GblkConfig = match &full_config.gblk_prune {
Some(data) => data.clone(),
None => GblkConfig {
save_space: None,
keep_within: None,
keep_last: None,
keep_minutely: None,
keep_hourly: None,
keep_daily: None,
keep_weekly: None,
keep_monthly: None,
keep_yearly: None,
prefix: None,
glob_archives: None,
},
};
gblk_config
}
/// Function that turn toml into string
/// # Argument
/// - config: The full toml file parsed
/// # Return
/// The string corresponding to toml file
fn toml_to_string(config: &Config) -> String {
let gblk_str = toml::to_string_pretty(&config).unwrap();
let re = Regex::new("id = '(?P<first>[0-9a-z]+)'").unwrap();
let nc = re.replace(&gblk_str, "id = $first").to_string();
nc
}
/// Function that update the current gblk config file for the project folder
/// # Arguments
/// - `key` : The key to update
/// - `value`: The value of the key to update
pub fn update_config(key: &str, value: &str) -> () {
let mut config = parse_toml();
let mut gblk_config: GblkConfig = get_gblkconfig(&config);
update_val(&mut gblk_config, key, value);
config.gblk_prune = Some(gblk_config);
let gblk_str = toml_to_string(&config);
let config_file = get_borgconfig();
match std::fs::write(&config_file, gblk_str) {
Err(_) => {
eprintln!(
"{} {} {} {}",
"error:".red(),
"Unable to write the config file",
config_file.to_str().unwrap(),
"!"
);
exit(102);
}
Ok(_) => (),
};
}
/// Function that remove the current gblk config file for the project folder
/// for a given arguments
/// # Arguments
/// - `key` : The key to update
pub fn remove_config(key: &str) -> () {
let mut config = parse_toml();
let mut gblk_config: GblkConfig = get_gblkconfig(&config);
remove_val(&mut gblk_config, key);
config.gblk_prune = if gblk_config.empty() {
None
} else {
Some(gblk_config)
};
let gblk_str = toml_to_string(&config);
let config_file = get_borgconfig();
match std::fs::write(&config_file, gblk_str) {
Err(_) => {
eprintln!(
"{} {} {} {}",
"error:".red(),
"Unable to write the config file",
config_file.to_str().unwrap(),
"!"
);
exit(102);
}
Ok(_) => (),
};
}
/// Execute a prune based on gblk configuration
/// # Arguments
/// - config_prune: contains partial configuration for prune that cannot be
/// used in the configuration file
pub(crate) fn launch_config_prune(config_prune: PartialPrune) {
let config = parse_toml();
let gblk_config: GblkConfig = get_gblkconfig(&config);
if gblk_config.empty() {
eprintln!(
"{} No configuration defined for pruning!",
"error:".red()
);
exit(104);
}
let prune_obj = new_prune(gblk_config, config_prune);
prune_launcher(prune_obj);
}
...@@ -3,9 +3,11 @@ use crate::delete::Delete; ...@@ -3,9 +3,11 @@ use crate::delete::Delete;
use crate::prune::Prune; use crate::prune::Prune;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use colored::Colorize; use colored::Colorize;
use configt::PartialPrune;
mod checkout; mod checkout;
mod commit; mod commit;
mod compact; mod compact;
mod configt;
mod create_hooks; mod create_hooks;
mod delete; mod delete;
mod diff; mod diff;
...@@ -58,7 +60,7 @@ enum Commands { ...@@ -58,7 +60,7 @@ enum Commands {
DeleteHooks, DeleteHooks,
/// Show differences between two commits of the `results` folder /// Show differences between two commits of the `results` folder
Diff(Diff), Diff(Diff),
/// Mount an old file/directory from one or multiple archive named afert /// Mount an old file/directory from one or multiple archive named after
/// git commits into the .mount folder inside de project directory. /// git commits into the .mount folder inside de project directory.
Mount(Mount), Mount(Mount),
/// Unmount everything in the folder .mount /// Unmount everything in the folder .mount
...@@ -68,7 +70,7 @@ enum Commands { ...@@ -68,7 +70,7 @@ enum Commands {
/// This is basically a wrapper of the borg delete command /// This is basically a wrapper of the borg delete command
/// ///
/// You can visit: /// You can visit:
/// https://borgbackup.readthedocs.io/en/stable/usage/delete.html for more details /// <https://borgbackup.readthedocs.io/en/stable/usage/prune.html> for more details
/// ///
/// This function don't free disk space until gblk compact is used /// This function don't free disk space until gblk compact is used
Delete(Delete), Delete(Delete),
...@@ -78,7 +80,7 @@ enum Commands { ...@@ -78,7 +80,7 @@ enum Commands {
/// This is basically a wrapper of the borg prune command /// This is basically a wrapper of the borg prune command
/// ///
/// You can visit: /// You can visit:
/// https://borgbackup.readthedocs.io/en/stable/usage/prune.html for more details /// <https://borgbackup.readthedocs.io/en/stable/usage/prune.html> for more details
/// ///
/// This function don't free disk space until gblk compact is used /// This function don't free disk space until gblk compact is used
Prune(Prune), Prune(Prune),
...@@ -87,6 +89,12 @@ enum Commands { ...@@ -87,6 +89,12 @@ enum Commands {
/// It is especially useful after deleting archives because compaction will /// It is especially useful after deleting archives because compaction will
/// free repository space /// free repository space
Compact(Compact), Compact(Compact),
/// This command can bed used to add gblk configuration
///
/// It's useful when you want to defined to always keep archive in given
/// time interval without typing always the same prune command
#[clap(subcommand)]
Config(Config),
} }
#[derive(Debug, Args)] #[derive(Debug, Args)]
...@@ -206,6 +214,33 @@ struct Mount { ...@@ -206,6 +214,33 @@ struct Mount {
last: Option<u8>, last: Option<u8>,
} }
#[derive(Debug, Subcommand)]
enum Config {
/// Add a new parameter in the gblk config file to be able to automatically
/// prune some commits
Add(Add),
/// Display the current gblk configuration
Show,
/// Remove the configuration of a given key in prune
Rm(Rm),
/// Prune using the project configuration
Prune(PartialPrune),
}
#[derive(Debug, Args)]
struct Add {
/// The name of the argument to add, see optional arguments of the prune subcommands
key: String,
/// The value of the argument to add in the configuration file
value: String,
}
#[derive(Debug, Args)]
struct Rm {
/// The name of the argument to remove, see optional arguments of the prune subcommands
key: String,
}
fn main() { fn main() {
let args = Cli::parse(); let args = Cli::parse();
...@@ -273,5 +308,11 @@ fn main() { ...@@ -273,5 +308,11 @@ fn main() {
Commands::Compact(my_compact) => { Commands::Compact(my_compact) => {
compact::launch_compact(my_compact); compact::launch_compact(my_compact);
} }
Commands::Config(conf) => match conf {
Config::Add(e) => configt::update_config(&e.key, &e.value),
Config::Show => configt::show(),
Config::Rm(e) => configt::remove_config(&e.key),
Config::Prune(pp) => configt::launch_config_prune(pp),
},
} }
} }
use crate::commit; use crate::commit;
use crate::configt::{GblkConfig, PartialPrune};
use clap::Args; use clap::Args;
use std::{ use std::{
collections::HashMap as HM, collections::HashMap as HM,
...@@ -148,6 +149,30 @@ pub(crate) struct Prune { ...@@ -148,6 +149,30 @@ pub(crate) struct Prune {
pub(crate) glob_archives: Option<String>, pub(crate) glob_archives: Option<String>,
} }
pub(crate) fn new_prune(gblk_config: GblkConfig, partial_prune: PartialPrune) -> Prune {
let ss = match gblk_config.save_space {
None => false,
Some(bool) => bool,
};
Prune {
dry_run: partial_prune.dry_run,
list: partial_prune.list,
stats: partial_prune.stats,
force: partial_prune.force,
save_space: ss,
keep_within: gblk_config.keep_within,
keep_last: gblk_config.keep_last,
keep_minutely: gblk_config.keep_minutely,
keep_hourly: gblk_config.keep_hourly,
keep_daily: gblk_config.keep_daily,
keep_weekly: gblk_config.keep_weekly,
keep_monthly: gblk_config.keep_monthly,
keep_yearly: gblk_config.keep_yearly,
prefix: gblk_config.prefix,
glob_archives: gblk_config.glob_archives,
}
}
/// Function that add flags arguments in the delete commands /// Function that add flags arguments in the delete commands
/// # Arguments /// # Arguments
/// * `sd`: Struct containing all the data that can be used to build the delete command /// * `sd`: Struct containing all the data that can be used to build the delete command
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment