use clap::{Args, Parser, Subcommand};
mod checkout;
mod commit;
mod create_hooks;
mod diff;
mod init;
mod list;
mod mount;
#[derive(Debug, Parser)]
#[clap(name = "gbl")]
/// A tool used to link borg and git together
///
/// This tool was created to link borg and git together and ease the management of developpment artifact versionning using git
struct Cli {
#[clap(subcommand)]
commands: Commands,
}
#[derive(Debug, Subcommand)]
enum Commands {
/// Initialize a borg repository inside a git project
Init(Init),
/// Save the results folder of a git repository in an archive
///
/// The archive will be named as the current commit in git
Commit(Commit),
/// List the content of the .borg archive
List(List),
/// Check if a checkout can be performed without losing data
#[clap(name = "pre-co")]
PreCo,
/// Checkout results to the current git commit
#[clap(alias = "co")]
Checkout(Checkout),
/// Create github hooks to use gbl automaticaly after commit, before and after checkout
#[clap(
name = "create-hooks",
alias = "ch",
long_about = "Create github hooks to use gbl automaticaly after commit, \
before and after checkout \n \n\
This command should be used after git init and glb init. \n \n\
This will create 2 hooks file: \n\
1. post-commit: `glb commit` will be launched after git commit \n\
2. post-checkout: `gbl checkout` will be launched after git checkout
"
)]
CreateHooks(CreateHooks),
/// Remove the post-checkout and the post-commit hooks
#[clap(name = "delete-hooks", alias = "dh")]
DeleteHooks,
/// Show differences between two commits of the `results` folder
Diff(Diff),
/// Mount an old file/directory from one or multiple archive named afert
/// git commits into the .mount folder inside de project directory.
Mount(Mount),
/// Unmount everything in the folder .mount
Umount,
}
#[derive(Debug, Args)]
struct Init {
/// If specified, hooks are created inside `.git/hooks repository`
#[clap(takes_value = false, short = 'H', long)]
hooks: bool,
/// The compression to use automatically at each commit if hooks are created
#[clap(short, long, default_value = "lz4")]
compression: String,
/// The checkout mode used by gblk automatically after a git checkout: soft or hard.
/// This option is only used if hooks are created.
/// The hard mode will delete every file in your results folder and extract
/// those corresponding to the commit targeted by the checkout.
///
/// The soft mode will only update files that existed in the targeted checkout
#[clap(short, long, default_value = "hard")]
mode: String,
}
#[derive(Debug, Args)]
struct Commit {
/// The compression used to save the results folder (no, lz4, zstd, zlib or lzma)
#[clap(short, long, default_value = "lz4")]
compression: String,
/// Use this flag to update the content of the current commit archive if it has changed
#[clap(takes_value = false, short, long)]
update: bool,
/// Use this flag to revert your results folder like it was before for this commit
#[clap(takes_value = false, short, long)]
revert: bool,
}
#[derive(Debug, Args)]
struct List {
/// consider first N archives
#[clap(short, long, default_value_t = 0)]
first: i32,
/// consider last N archives
#[clap(short, long, default_value_t = 0)]
last: i32,
/// If set list the files in this archive
#[clap(short, long, default_value = "")]
archive: String,
}
#[derive(Debug, Args)]
struct Checkout {
/// The checkout mode: hard or soft
///
/// The hard mode will delete every file in your results folder and extract
/// those corresponding to the commit targeted by the checkout.
///
/// The soft mode will only update files that existed in the targeted checkout
#[clap(short, long, default_value = "soft")]
mode: String,
}
#[derive(Debug, Args)]
struct CreateHooks {
/// The compression that will automatically be used after each commit
#[clap(short, long, default_value = "lz4")]
compression: String,
/// The checkout mode used by gblk automatically after a git checkout: soft or hard.
/// The hard mode will delete every file in your results folder and extract
/// those corresponding to the commit targeted by the checkout.
///
/// The soft mode will only update files that existed in the targeted checkout
#[clap(short, long, default_value = "hard")]
mode: String,
}
#[derive(Debug, Args)]
struct Diff {
/// The SHA1 of a commit
commit1: String,
/// The SHA1 of another commit.
/// If you leave this blank,
/// it will check the different between the commit1 and
/// your current result folder
commit2: Option<String>,
}
#[derive(Debug, Args)]
struct Mount {
/// Commit name, sh: Glob is supported. This is an optional parameter: if
/// not set then all commit archives will be mounted into the .mount directory
#[clap(short, long)]
commit: Option<String>,
/// The file/directory to extract. This is an optional parameter. If not set
/// then all files in the archive will be displayed
#[clap(short, long)]
path: Option<String>,
/// If set, displays the .mount directory in 'version view'.
///
/// - Normal view: The `.mount` directory contains a subfolder with the name
/// of archives.
///
/// - Version view: The `.mount` directory contains the results folder and
/// every file within it becomes a directory storing every version of
/// that file
#[clap(short, long)]
versions: bool,
/// Displays the differences between two files mounted corresponding to the
/// given path.
///
/// Note that if only one file is recovered then, the other is taken from
/// the current result folder
///
/// This option is deactivated when used with --diff
#[clap(short, long)]
diff: bool,
/// Consider last N archive after other filter were applied
#[clap(short, long)]
last: Option<u8>,
}
fn main() {
let args = Cli::parse();
match args.commands {
Commands::Init(init) => {
init::init_and_hook(init.hooks, &init.compression, &init.mode);
}
Commands::Commit(commit) => {
mount::umount_archive(true);
if commit.revert {
if commit.revert == commit.update {
eprintln!("Error: You moust choose between --revert and --update option")
}
}
if !commit.revert {
commit::commit(commit.compression, String::from(""), commit.update);
} else {
commit::revert_commit();
}
}
Commands::List(list) => {
list::borg_list(list.first, list.last, &list.archive);
}
Commands::PreCo => {
mount::umount_archive(true);
checkout::prepare_checkout();
}
Commands::Checkout(co) => {
mount::umount_archive(true);
checkout::checkout(&co.mode);
}
Commands::CreateHooks(ch) => {
create_hooks::create_hooks(&ch.compression, &ch.mode);
}
Commands::Diff(diff) => {
diff::compute_diff(&diff.commit1, &diff.commit2);
}
Commands::DeleteHooks => {
create_hooks::delete_hooks();
}
Commands::Mount(mount) => {
mount::umount_archive(true);
mount::mount_archive(
&mount.commit,
&mount.path,
mount.versions,
mount.diff,
mount.last,
);
}
Commands::Umount => {
mount::umount_archive(false);
}
}
}