aboutsummaryrefslogtreecommitdiff
path: root/clap/examples/20_subcommands.rs
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2020-01-07 11:18:04 +0000
committerDaniel Mueller <deso@posteo.net>2020-01-08 09:20:25 -0800
commit5e20a29b4fdc8a2d442d1093681b396dcb4b816b (patch)
tree55ab083fa8999d2ccbb5e921c1ffe52560dca152 /clap/examples/20_subcommands.rs
parent203e691f46d591a2cc8acdfd850fa9f5b0fb8a98 (diff)
downloadnitrocli-5e20a29b4fdc8a2d442d1093681b396dcb4b816b.tar.gz
nitrocli-5e20a29b4fdc8a2d442d1093681b396dcb4b816b.tar.bz2
Add structopt dependency in version 0.3.7
This patch series replaces argparse with structopt in the argument handling code. As a first step, we need structopt as a dependency. Import subrepo structopt/:structopt at efbdda4753592e27bc430fb01f7b9650b2f3174d Import subrepo bitflags/:bitflags at 30668016aca6bd3b02c766e8347e0b4080d4c296 Import subrepo clap/:clap at 784524f7eb193e35f81082cc69454c8c21b948f7 Import subrepo heck/:heck at 093d56fbf001e1506e56dbfa38631d99b1066df1 Import subrepo proc-macro-error/:proc-macro-error at 6c4cfe79a622c5de8ae68557993542be46eacae2 Import subrepo proc-macro2/:proc-macro2 at d5d48eddca4566e5438e8a2cbed4a74e049544de Import subrepo quote/:quote at 727436c6c137b20f0f34dde5d8fda2679b9747ad Import subrepo rustversion/:rustversion at 0c5663313516263059ce9059ef81fc7a1cf655ca Import subrepo syn-mid/:syn-mid at 5d3d85414a9e6674e1857ec22a87b96e04a6851a Import subrepo syn/:syn at e87c27e87f6f4ef8919d0372bdb056d53ef0d8f3 Import subrepo textwrap/:textwrap at abcd618beae3f74841032aa5b53c1086b0a57ca2 Import subrepo unicode-segmentation/:unicode-segmentation at 637c9874c4fe0c205ff27787faf150a40295c6c3 Import subrepo unicode-width/:unicode-width at 3033826f8bf05e82724140a981d5941e48fce393 Import subrepo unicode-xid/:unicode-xid at 4baae9fffb156ba229665b972a9cd5991787ceb7
Diffstat (limited to 'clap/examples/20_subcommands.rs')
-rw-r--r--clap/examples/20_subcommands.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/clap/examples/20_subcommands.rs b/clap/examples/20_subcommands.rs
new file mode 100644
index 0000000..f80f46d
--- /dev/null
+++ b/clap/examples/20_subcommands.rs
@@ -0,0 +1,143 @@
+// Working with subcommands is simple. There are a few key points to remember when working with
+// subcommands in clap. First, SubCommands are really just Apps. This means they can have their own
+// settings, version, authors, args, and even their own subcommands. The next thing to remember is
+// that subcommands are set up in a tree like hierarchy.
+//
+// An ASCII art depiction may help explain this better. Using a fictional version of git as the demo
+// subject. Imagine the following are all subcommands of git (note, the author is aware these aren't
+// actually all subcommands in the real git interface, but it makes explanation easier)
+//
+// Top Level App (git) TOP
+// |
+// -----------------------------------------
+// / | \ \
+// clone push add commit LEVEL 1
+// | / \ / \ |
+// url origin remote ref name message LEVEL 2
+// / /\
+// path remote local LEVEL 3
+//
+// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all inclusive
+// list):
+//
+// $ git clone url
+// $ git push origin path
+// $ git add ref local
+// $ git commit message
+//
+// Notice only one command per "level" may be used. You could not, for example, do:
+//
+// $ git clone url push origin path
+//
+// It's also important to know that subcommands each have their own set of matches and may have args
+// with the same name as other subcommands in a different part of the tree hierarchy (i.e. the arg
+// names aren't in a flat namespace).
+//
+// In order to use subcommands in clap, you only need to know which subcommand you're at in your
+// tree, and which args are defined on that subcommand.
+//
+// Let's make a quick program to illustrate. We'll be using the same example as above but for
+// brevity sake we won't implement all of the subcommands, only a few.
+
+extern crate clap;
+
+use clap::{App, Arg, SubCommand, AppSettings};
+
+fn main() {
+
+ let matches = App::new("git")
+ .about("A fictional versioning CLI")
+ .version("1.0")
+ .author("Me")
+ .subcommand(SubCommand::with_name("clone")
+ .about("clones repos")
+ .arg(Arg::with_name("repo")
+ .help("The repo to clone")
+ .required(true)))
+ .subcommand(SubCommand::with_name("push")
+ .about("pushes things")
+ .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("remote") // Subcommands can have their own subcommands,
+ // which in turn have their own subcommands
+ .about("pushes remote things")
+ .arg(Arg::with_name("repo")
+ .required(true)
+ .help("The remote repo to push things to")))
+ .subcommand(SubCommand::with_name("local")
+ .about("pushes local things")))
+ .subcommand(SubCommand::with_name("add")
+ .about("adds things")
+ .author("Someone Else") // Subcommands can list different authors
+ .version("v2.0 (I'm versioned differently") // or different version from their parents
+ .setting(AppSettings::ArgRequiredElseHelp) // They can even have different settings
+ .arg(Arg::with_name("stuff")
+ .long("stuff")
+ .help("Stuff to add")
+ .takes_value(true)
+ .multiple(true)))
+ .get_matches();
+
+ // At this point, the matches we have point to git. Keep this in mind...
+
+ // You can check if one of git's subcommands was used
+ if matches.is_present("clone") {
+ println!("'git clone' was run.");
+ }
+
+ // You can see which subcommand was used
+ if let Some(subcommand) = matches.subcommand_name() {
+ println!("'git {}' was used", subcommand);
+
+ // It's important to note, this *only* check's git's DIRECT children, **NOT** it's
+ // grandchildren, great grandchildren, etc.
+ //
+ // i.e. if the command `git push remove --stuff foo` was run, the above will only print out,
+ // `git push` was used. We'd need to get push's matches to see further into the tree
+ }
+
+ // An alternative to checking the name is matching on known names. Again notice that only the
+ // direct children are matched here.
+ match matches.subcommand_name() {
+ Some("clone") => println!("'git clone' was used"),
+ Some("push") => println!("'git push' was used"),
+ Some("add") => println!("'git add' was used"),
+ None => println!("No subcommand was used"),
+ _ => unreachable!(), // Assuming you've listed all direct children above, this is unreachable
+ }
+
+ // You could get the independent subcommand matches, although this is less common
+ if let Some(clone_matches) = matches.subcommand_matches("clone") {
+ // Now we have a reference to clone's matches
+ println!("Cloning repo: {}", clone_matches.value_of("repo").unwrap());
+ }
+
+ // The most common way to handle subcommands is via a combined approach using
+ // `ArgMatches::subcommand` which returns a tuple of both the name and matches
+ match matches.subcommand() {
+ ("clone", Some(clone_matches)) =>{
+ // Now we have a reference to clone's matches
+ println!("Cloning {}", clone_matches.value_of("repo").unwrap());
+ },
+ ("push", Some(push_matches)) =>{
+ // Now we have a reference to push's matches
+ match push_matches.subcommand() {
+ ("remote", Some(remote_matches)) =>{
+ // Now we have a reference to remote's matches
+ println!("Pushing to {}", remote_matches.value_of("repo").unwrap());
+ },
+ ("local", Some(_)) =>{
+ println!("'git push local' was used");
+ },
+ _ => unreachable!(),
+ }
+ },
+ ("add", Some(add_matches)) =>{
+ // Now we have a reference to add's matches
+ println!("Adding {}", add_matches.values_of("stuff").unwrap().collect::<Vec<_>>().join(", "));
+ },
+ ("", None) => println!("No subcommand was used"), // If no subcommand was used it'll match the tuple ("", None)
+ _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!()
+ }
+
+ // Continued program logic goes here...
+}