git_global/
cli.rs

1//! The command line interface for git-global.
2
3use std::io::{stderr, stdout, Write};
4
5use clap::{command, Arg, ArgAction, ArgMatches, Command};
6use serde_json::json;
7
8use crate::config::Config;
9use crate::subcommands;
10
11/// Returns the definitive clap::Command instance for git-global.
12pub fn get_clap_app() -> Command {
13    command!()
14        .arg(
15            Arg::new("verbose")
16                .short('v')
17                .long("verbose")
18                .action(ArgAction::SetTrue)
19                .global(true)
20                .help("Enable verbose mode."),
21        )
22        .arg(
23            Arg::new("json")
24                .short('j')
25                .long("json")
26                .action(ArgAction::SetTrue)
27                .global(true)
28                .help("Output subcommand results in JSON."),
29        )
30        .arg(
31            Arg::new("untracked")
32                .short('u')
33                .long("untracked")
34                .action(ArgAction::SetTrue)
35                .conflicts_with("nountracked")
36                .global(true)
37                .help("Show untracked files in output."),
38        )
39        .arg(
40            Arg::new("nountracked")
41                .short('t')
42                .long("nountracked")
43                .action(ArgAction::SetTrue)
44                .conflicts_with("untracked")
45                .global(true)
46                .help("Don't show untracked files in output."),
47        )
48        .subcommands(
49            subcommands::get_subcommands()
50                .iter()
51                .map(|(cmd, desc)| Command::new(*cmd).about(*desc)),
52        )
53}
54
55/// Merge command-line arguments from an ArgMatches object with a Config.
56fn merge_args_with_config(config: &mut Config, matches: &ArgMatches) {
57    if matches.get_flag("verbose") {
58        config.verbose = true;
59    }
60    if matches.get_flag("untracked") {
61        config.show_untracked = true;
62    }
63    if matches.get_flag("nountracked") {
64        config.show_untracked = false;
65    }
66}
67
68/// Runs the appropriate git-global subcommand based on command line arguments.
69///
70/// As the effective binary entry point for `git-global`, prints results to
71/// `STDOUT` (or errors to `STDERR`) and returns an exit code.
72pub fn run_from_command_line() -> i32 {
73    let clap_app = get_clap_app();
74    let matches = clap_app.get_matches();
75    let mut config = Config::new();
76    merge_args_with_config(&mut config, &matches);
77    let report = subcommands::run(matches.subcommand_name(), config);
78    let use_json = matches.get_flag("json");
79    match report {
80        Ok(rep) => {
81            if use_json {
82                rep.print_json(&mut stdout());
83            } else {
84                rep.print(&mut stdout());
85            }
86            0
87        }
88        Err(err) => {
89            if use_json {
90                let out = json!({
91                    "error": true,
92                    "message": format!("{}", err)
93                });
94                writeln!(&mut stderr(), "{:#}", out).unwrap();
95            } else {
96                writeln!(&mut stderr(), "{}", err).unwrap();
97            }
98            1
99        }
100    }
101}