use std::cmp;
use std::env;
use env_logger::Env;
use log::{debug, error, info};
use clap::{ArgAction, Parser, ValueEnum};
use clap::{crate_name, crate_version};
use std::path::PathBuf;
use git_mirror::MirrorOptions;
use git_mirror::do_mirror;
use git_mirror::provider::{GitHub, GitLab, Provider};
use std::process::exit;
#[derive(ValueEnum, Clone, Debug)]
#[value(rename_all = "verbatim")]
enum Providers {
GitLab,
GitHub,
}
#[derive(Parser, Debug)]
#[command(name = "git-mirror", version, about)]
struct Opt {
#[arg(
long = "provider",
short = 'p',
default_value = "GitLab",
ignore_case = true,
value_enum
)]
provider: Providers,
#[arg(
long = "url",
short = 'u',
default_value_ifs([
("provider", "GitLab", Some("https://gitlab.com")),
("provider", "GitHub", Some("https://api.github.com")),
])
)]
url: String,
#[arg(long = "group", short = 'g')]
group: String,
#[arg(long = "mirror-dir", short = 'm', default_value = "./mirror-dir")]
mirror_dir: PathBuf,
#[arg(short, long, action = ArgAction::Count)]
verbose: u8,
#[arg(long)]
http: bool,
#[arg(long)]
dry_run: bool,
#[arg(short = 'c', long, default_value = "1")]
worker_count: usize,
#[arg(long)]
metric_file: Option<PathBuf>,
#[arg(long)]
junit_report: Option<PathBuf>,
#[arg(long, default_value = "git")]
git_executable: String,
#[arg(long, env = "PRIVATE_TOKEN")]
private_token: Option<String>,
#[arg(long)]
refspec: Option<Vec<String>>,
#[arg(long)]
remove_workrepo: bool,
#[arg(long)]
fail_on_sync_error: bool,
#[arg(long, default_value = "false")]
lfs: bool,
}
impl From<Opt> for MirrorOptions {
fn from(opt: Opt) -> MirrorOptions {
MirrorOptions {
mirror_dir: opt.mirror_dir,
dry_run: opt.dry_run,
worker_count: opt.worker_count,
metrics_file: opt.metric_file,
junit_file: opt.junit_report,
git_executable: opt.git_executable,
refspec: opt.refspec,
remove_workrepo: opt.remove_workrepo,
fail_on_sync_error: opt.fail_on_sync_error,
mirror_lfs: opt.lfs,
}
}
}
fn main() {
let opt = Opt::parse();
debug!("{opt:#?}");
let env_log_level = match cmp::min(opt.verbose, 4) {
4 => "git_mirror=trace",
3 => "git_mirror=debug",
2 => "git_mirror=info",
1 => "git_mirror=warn",
_ => "git_mirror=error",
};
env_logger::Builder::from_env(Env::default().default_filter_or(env_log_level)).init();
unsafe {
openssl_probe::init_openssl_env_vars();
};
let provider: Box<dyn Provider> = match opt.provider {
Providers::GitLab => Box::new(GitLab {
url: opt.url.to_owned(),
group: opt.group.to_owned(),
use_http: opt.http,
private_token: opt.private_token.to_owned(),
recursive: true,
}),
Providers::GitHub => Box::new(GitHub {
url: opt.url.to_owned(),
org: opt.group.to_owned(),
use_http: opt.http,
private_token: opt.private_token.to_owned(),
useragent: format!("{}/{}", crate_name!(), crate_version!()),
}),
};
let opts: MirrorOptions = opt.into();
match do_mirror(provider, &opts) {
Ok(_) => {
info!("All done");
}
Err(e) => {
error!("Error occured: {e}");
exit(e.into());
}
};
}
#[cfg(test)]
mod tests {
use super::Opt;
#[test]
fn verify_app() {
use clap::CommandFactory;
Opt::command().debug_assert()
}
}