use std::io::{Write, stderr, stdout};
use clap::{Arg, ArgAction, ArgMatches, Command, command};
use serde_json::json;
use crate::config::Config;
use crate::subcommands;
pub fn get_clap_app() -> Command {
command!()
.arg(
Arg::new("config")
.short('c')
.long("config")
.value_name("FILE")
.global(true)
.help("Read configuration from FILE instead of the default gitconfig."),
)
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.action(ArgAction::SetTrue)
.global(true)
.help("Enable verbose mode."),
)
.arg(
Arg::new("json")
.short('j')
.long("json")
.action(ArgAction::SetTrue)
.global(true)
.help("Output subcommand results in JSON."),
)
.arg(
Arg::new("untracked")
.short('u')
.long("untracked")
.action(ArgAction::SetTrue)
.conflicts_with("nountracked")
.global(true)
.help("Show untracked files in output."),
)
.arg(
Arg::new("nountracked")
.short('t')
.long("nountracked")
.action(ArgAction::SetTrue)
.conflicts_with("untracked")
.global(true)
.help("Don't show untracked files in output."),
)
.subcommands(
subcommands::get_subcommands()
.iter()
.map(|(cmd, desc)| {
let mut subcmd = Command::new(*cmd).about(*desc);
if *cmd == "ignore" {
subcmd = subcmd.arg(
Arg::new("pattern")
.help("Pattern to add to global.ignore (matches paths containing this string)")
.required(true)
.index(1),
);
}
if *cmd == "scan" {
subcmd = subcmd.arg(
Arg::new("paths")
.help("Additional directories to scan for git repos")
.num_args(0..)
.value_name("PATH"),
);
}
subcmd
}),
)
}
fn merge_args_with_config(config: &mut Config, matches: &ArgMatches) {
if matches.get_flag("verbose") {
config.verbose = true;
}
if matches.get_flag("untracked") {
config.show_untracked = true;
}
if matches.get_flag("nountracked") {
config.show_untracked = false;
}
}
pub fn run_from_command_line() -> i32 {
let clap_app = get_clap_app();
let matches = clap_app.get_matches();
let mut config = match matches.get_one::<String>("config") {
Some(path) => Config::from_gitconfig(path),
None => Config::new(),
};
merge_args_with_config(&mut config, &matches);
let args: Vec<String> = matches
.subcommand()
.map(|(name, sub_matches)| match name {
"ignore" => sub_matches
.get_one::<String>("pattern")
.cloned()
.into_iter()
.collect(),
"scan" => sub_matches
.get_many::<String>("paths")
.map(|v| v.cloned().collect())
.unwrap_or_default(),
_ => vec![],
})
.unwrap_or_default();
let report = subcommands::run(matches.subcommand_name(), config, args);
let use_json = matches.get_flag("json");
match report {
Ok(rep) => {
if use_json {
rep.print_json(&mut stdout());
} else {
rep.print(&mut stdout());
}
0
}
Err(err) => {
if use_json {
let out = json!({
"error": true,
"message": format!("{}", err)
});
writeln!(&mut stderr(), "{:#}", out).unwrap();
} else {
writeln!(&mut stderr(), "{}", err).unwrap();
}
1
}
}
}