]>
Commit | Line | Data |
---|---|---|
6522a427 EL |
1 | use std::ffi::OsString; |
2 | use std::path::PathBuf; | |
3 | ||
4 | use clap::{arg, Command}; | |
5 | ||
6 | fn cli() -> Command { | |
7 | Command::new("git") | |
8 | .about("A fictional versioning CLI") | |
9 | .subcommand_required(true) | |
10 | .arg_required_else_help(true) | |
11 | .allow_external_subcommands(true) | |
12 | .subcommand( | |
13 | Command::new("clone") | |
14 | .about("Clones repos") | |
15 | .arg(arg!(<REMOTE> "The remote to clone")) | |
16 | .arg_required_else_help(true), | |
17 | ) | |
18 | .subcommand( | |
19 | Command::new("diff") | |
20 | .about("Compare two commits") | |
21 | .arg(arg!(base: [COMMIT])) | |
22 | .arg(arg!(head: [COMMIT])) | |
23 | .arg(arg!(path: [PATH]).last(true)) | |
24 | .arg( | |
25 | arg!(--color <WHEN>) | |
26 | .value_parser(["always", "auto", "never"]) | |
27 | .num_args(0..=1) | |
28 | .require_equals(true) | |
29 | .default_value("auto") | |
30 | .default_missing_value("always"), | |
31 | ), | |
32 | ) | |
33 | .subcommand( | |
34 | Command::new("push") | |
35 | .about("pushes things") | |
36 | .arg(arg!(<REMOTE> "The remote to target")) | |
37 | .arg_required_else_help(true), | |
38 | ) | |
39 | .subcommand( | |
40 | Command::new("add") | |
41 | .about("adds things") | |
42 | .arg_required_else_help(true) | |
43 | .arg(arg!(<PATH> ... "Stuff to add").value_parser(clap::value_parser!(PathBuf))), | |
44 | ) | |
45 | .subcommand( | |
46 | Command::new("stash") | |
47 | .args_conflicts_with_subcommands(true) | |
48 | .args(push_args()) | |
49 | .subcommand(Command::new("push").args(push_args())) | |
50 | .subcommand(Command::new("pop").arg(arg!([STASH]))) | |
51 | .subcommand(Command::new("apply").arg(arg!([STASH]))), | |
52 | ) | |
53 | } | |
54 | ||
55 | fn push_args() -> Vec<clap::Arg> { | |
56 | vec![arg!(-m --message <MESSAGE>)] | |
57 | } | |
58 | ||
59 | fn main() { | |
60 | let matches = cli().get_matches(); | |
61 | ||
62 | match matches.subcommand() { | |
63 | Some(("clone", sub_matches)) => { | |
64 | println!( | |
65 | "Cloning {}", | |
66 | sub_matches.get_one::<String>("REMOTE").expect("required") | |
67 | ); | |
68 | } | |
69 | Some(("diff", sub_matches)) => { | |
70 | let color = sub_matches | |
71 | .get_one::<String>("color") | |
72 | .map(|s| s.as_str()) | |
73 | .expect("defaulted in clap"); | |
74 | ||
75 | let mut base = sub_matches.get_one::<String>("base").map(|s| s.as_str()); | |
76 | let mut head = sub_matches.get_one::<String>("head").map(|s| s.as_str()); | |
77 | let mut path = sub_matches.get_one::<String>("path").map(|s| s.as_str()); | |
78 | if path.is_none() { | |
79 | path = head; | |
80 | head = None; | |
81 | if path.is_none() { | |
82 | path = base; | |
83 | base = None; | |
84 | } | |
85 | } | |
86 | let base = base.unwrap_or("stage"); | |
87 | let head = head.unwrap_or("worktree"); | |
88 | let path = path.unwrap_or(""); | |
89 | println!("Diffing {}..{} {} (color={})", base, head, path, color); | |
90 | } | |
91 | Some(("push", sub_matches)) => { | |
92 | println!( | |
93 | "Pushing to {}", | |
94 | sub_matches.get_one::<String>("REMOTE").expect("required") | |
95 | ); | |
96 | } | |
97 | Some(("add", sub_matches)) => { | |
98 | let paths = sub_matches | |
99 | .get_many::<PathBuf>("PATH") | |
100 | .into_iter() | |
101 | .flatten() | |
102 | .collect::<Vec<_>>(); | |
103 | println!("Adding {:?}", paths); | |
104 | } | |
105 | Some(("stash", sub_matches)) => { | |
106 | let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches)); | |
107 | match stash_command { | |
108 | ("apply", sub_matches) => { | |
109 | let stash = sub_matches.get_one::<String>("STASH"); | |
110 | println!("Applying {:?}", stash); | |
111 | } | |
112 | ("pop", sub_matches) => { | |
113 | let stash = sub_matches.get_one::<String>("STASH"); | |
114 | println!("Popping {:?}", stash); | |
115 | } | |
116 | ("push", sub_matches) => { | |
117 | let message = sub_matches.get_one::<String>("message"); | |
118 | println!("Pushing {:?}", message); | |
119 | } | |
120 | (name, _) => { | |
121 | unreachable!("Unsupported subcommand `{}`", name) | |
122 | } | |
123 | } | |
124 | } | |
125 | Some((ext, sub_matches)) => { | |
126 | let args = sub_matches | |
127 | .get_many::<OsString>("") | |
128 | .into_iter() | |
129 | .flatten() | |
130 | .collect::<Vec<_>>(); | |
131 | println!("Calling out to {:?} with {:?}", ext, args); | |
132 | } | |
133 | _ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!() | |
134 | } | |
135 | ||
136 | // Continued program logic goes here... | |
137 | } |