Skip to main content

git_global/
cli.rs

1//! The command line interface for git-global.
2
3use std::io::{Write, stderr, stdout};
4
5use clap::{Arg, ArgAction, ArgMatches, Command, 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)| {
52                    let mut subcmd = Command::new(*cmd).about(*desc);
53                    if *cmd == "ignore" {
54                        subcmd = subcmd.arg(
55                            Arg::new("pattern")
56                                .help("Pattern to add to global.ignore (matches paths containing this string)")
57                                .required(true)
58                                .index(1),
59                        );
60                    }
61                    subcmd
62                }),
63        )
64}
65
66/// Merge command-line arguments from an ArgMatches object with a Config.
67fn merge_args_with_config(config: &mut Config, matches: &ArgMatches) {
68    if matches.get_flag("verbose") {
69        config.verbose = true;
70    }
71    if matches.get_flag("untracked") {
72        config.show_untracked = true;
73    }
74    if matches.get_flag("nountracked") {
75        config.show_untracked = false;
76    }
77}
78
79/// Runs the appropriate git-global subcommand based on command line arguments.
80///
81/// As the effective binary entry point for `git-global`, prints results to
82/// `STDOUT` (or errors to `STDERR`) and returns an exit code.
83pub fn run_from_command_line() -> i32 {
84    let clap_app = get_clap_app();
85    let matches = clap_app.get_matches();
86    let mut config = Config::new();
87    merge_args_with_config(&mut config, &matches);
88
89    // Extract additional arguments for subcommands that need them
90    let args = matches.subcommand().and_then(|(name, sub_matches)| {
91        if name == "ignore" {
92            sub_matches.get_one::<String>("pattern").map(|s| s.as_str())
93        } else {
94            None
95        }
96    });
97
98    let report = subcommands::run(matches.subcommand_name(), config, args);
99    let use_json = matches.get_flag("json");
100    match report {
101        Ok(rep) => {
102            if use_json {
103                rep.print_json(&mut stdout());
104            } else {
105                rep.print(&mut stdout());
106            }
107            0
108        }
109        Err(err) => {
110            if use_json {
111                let out = json!({
112                    "error": true,
113                    "message": format!("{}", err)
114                });
115                writeln!(&mut stderr(), "{:#}", out).unwrap();
116            } else {
117                writeln!(&mut stderr(), "{}", err).unwrap();
118            }
119            1
120        }
121    }
122}