use clap::{AppSettings, Clap};
use std::ffi::OsString;
use std::path::PathBuf;
#[derive(Debug, Clap)]
#[clap(about = "The rusty git", version = clap::crate_version!())]
#[clap(setting = AppSettings::SubcommandRequired)]
#[clap(setting = AppSettings::ColoredHelp)]
pub struct Args {
#[clap(long, short = 'q')]
pub quiet: bool,
#[clap(long, conflicts_with("quiet"))]
pub progress: bool,
#[clap(long, conflicts_with("quiet"), requires("progress"))]
pub progress_keep_open: bool,
#[clap(subcommand)]
pub cmd: Subcommands,
}
#[derive(Debug, Clap)]
pub enum Subcommands {
#[clap(visible_alias = "initialize")]
#[clap(setting = AppSettings::ColoredHelp, setting = AppSettings::DisableVersion)]
Init {
directory: Option<PathBuf>,
},
#[clap(setting = AppSettings::ColoredHelp, setting = AppSettings::DisableVersion, setting = AppSettings::SubcommandRequired)]
#[clap(visible_alias = "t")]
Tools(ToolCommands),
}
#[derive(Debug, Clap)]
pub enum ToolCommands {
#[clap(setting = AppSettings::ColoredHelp, setting = AppSettings::DisableVersion)]
Find {
root: Option<PathBuf>,
},
#[clap(setting = AppSettings::ColoredHelp, setting = AppSettings::DisableVersion)]
Organize {
#[clap(long)]
execute: bool,
#[clap(long, short = 'f')]
repository_source: Option<PathBuf>,
#[clap(long, short = 't')]
destination_directory: Option<PathBuf>,
},
EstimateHours(EstimateHours),
}
#[derive(Debug, Clap)]
#[clap(
about = "Estimate hours worked basted on a commit history",
long_about = "See https://github.com/kimmobrunfeldt/git-hours#how-it-works for details",
version = clap::crate_version!(),
visible_alias = "h")
]
#[clap(setting = clap::AppSettings::ColoredHelp)]
pub struct EstimateHours {
#[clap(parse(from_os_str))]
#[clap(validator_os = validator::is_repo)]
#[clap(default_value = ".")]
pub working_dir: PathBuf,
#[clap(default_value("main"))]
pub refname: OsString,
#[clap(short = 'p', long)]
pub show_pii: bool,
#[clap(short = 'i', long)]
pub omit_unify_identities: bool,
}
mod validator {
use anyhow::Context;
use std::{ffi::OsStr, path::PathBuf};
fn is_repo_inner(dir: &OsStr) -> anyhow::Result<()> {
let git_dir = PathBuf::from(dir).join(".git");
let p = git_dir
.canonicalize()
.with_context(|| format!("Could not canonicalize git repository at '{}'", git_dir.display()))?;
if p.extension().unwrap_or_default() == "git"
|| p.file_name().unwrap_or_default() == ".git"
|| p.join("HEAD").is_file()
{
Ok(())
} else {
Err(anyhow::anyhow!(
"Path '{}' needs to be a directory containing '.git/'",
p.display()
))
}
}
pub fn is_repo(dir: &OsStr) -> Result<(), String> {
is_repo_inner(dir).map_err(|err| format!("{:#}", err))
}
}