pub struct Command { /* private fields */ }Expand description
Build a command-line interface.
This includes defining arguments, subcommands, parser behavior, and help output.
Once all configuration is complete,
the Command::get_matches family of methods starts the runtime-parsing
process. These methods then return information about the user supplied
arguments (or lack thereof).
When deriving a Parser, you can use
CommandFactory::command to access the
Command.
- Basic API
- Application-wide Settings
- Command-specific Settings
- Subcommand-specific Settings
- Reflection
§Examples
let m = Command::new("My Program")
.author("Me, [email protected]")
.version("1.0.2")
.about("Explains in brief what the program does")
.arg(
Arg::new("in_file")
)
.after_help("Longer explanation to appear after the options when \
displaying the help information from --help or -h")
.get_matches();
// Your program logic starts here...Implementations§
Source§impl Command
§Basic API
impl Command
§Basic API
Sourcepub fn new(name: impl Into<Str>) -> Command
pub fn new(name: impl Into<Str>) -> Command
Creates a new instance of an Command.
It is common, but not required, to use binary name as the name. This
name will only be displayed to the user when they request to print
version or help and usage information.
See also command! and crate_name!.
§Examples
Command::new("My Program")Examples found in repository?
6fn applet_commands() -> [Command; 2] {
7 [
8 Command::new("true").about("does nothing successfully"),
9 Command::new("false").about("does nothing unsuccessfully"),
10 ]
11}
12
13fn main() {
14 let cmd = Command::new(env!("CARGO_CRATE_NAME"))
15 .multicall(true)
16 .subcommand(
17 Command::new("busybox")
18 .arg_required_else_help(true)
19 .subcommand_value_name("APPLET")
20 .subcommand_help_heading("APPLETS")
21 .arg(
22 Arg::new("install")
23 .long("install")
24 .help("Install hardlinks for all subcommands in path")
25 .exclusive(true)
26 .action(ArgAction::Set)
27 .default_missing_value("/usr/local/bin")
28 .value_parser(value_parser!(PathBuf)),
29 )
30 .subcommands(applet_commands()),
31 )
32 .subcommands(applet_commands());
33
34 let matches = cmd.get_matches();
35 let mut subcommand = matches.subcommand();
36 if let Some(("busybox", cmd)) = subcommand {
37 if cmd.contains_id("install") {
38 unimplemented!("Make hardlinks to the executable here");
39 }
40 subcommand = cmd.subcommand();
41 }
42 match subcommand {
43 Some(("false", _)) => exit(1),
44 Some(("true", _)) => exit(0),
45 _ => unreachable!("parser should ensure only valid subcommand names are used"),
46 }
47}More examples
3fn main() {
4 let matches = Command::new("MyApp")
5 .version("1.0")
6 .about("Does awesome things")
7 .arg(arg!(--two <VALUE>).required(true))
8 .arg(arg!(--one <VALUE>).required(true))
9 .get_matches();
10
11 println!(
12 "two: {:?}",
13 matches.get_one::<String>("two").expect("required")
14 );
15 println!(
16 "one: {:?}",
17 matches.get_one::<String>("one").expect("required")
18 );
19}3fn main() {
4 let cmd = Command::new(env!("CARGO_CRATE_NAME"))
5 .multicall(true)
6 .arg_required_else_help(true)
7 .subcommand_value_name("APPLET")
8 .subcommand_help_heading("APPLETS")
9 .subcommand(Command::new("hostname").about("show hostname part of FQDN"))
10 .subcommand(Command::new("dnsdomainname").about("show domain name part of FQDN"));
11
12 match cmd.get_matches().subcommand_name() {
13 Some("hostname") => println!("www"),
14 Some("dnsdomainname") => println!("example.com"),
15 _ => unreachable!("parser should ensure only valid subcommand names are used"),
16 }
17}9fn main() {
10 let cli = Command::new("CLI").arg(arg!(-b - -built).action(clap::ArgAction::SetTrue));
11 // Augment built args with derived args
12 let cli = DerivedArgs::augment_args(cli);
13
14 let matches = cli.get_matches();
15 println!("Value of built: {:?}", matches.get_flag("built"));
16 println!(
17 "Value of derived via ArgMatches: {:?}",
18 matches.get_flag("derived")
19 );
20
21 // Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
22 // This is the main benefit of using derived arguments.
23 let derived_matches = DerivedArgs::from_arg_matches(&matches)
24 .map_err(|err| err.exit())
25 .unwrap();
26 println!("Value of derived: {derived_matches:#?}");
27}Sourcepub fn arg(self, a: impl Into<Arg>) -> Command
pub fn arg(self, a: impl Into<Arg>) -> Command
Adds an argument to the list of valid possibilities.
§Examples
Command::new("myprog")
// Adding a single "flag" argument with a short and help text, using Arg::new()
.arg(
Arg::new("debug")
.short('d')
.help("turns on debugging mode")
)
// Adding a single "option" argument with a short, a long, and help text using the less
// verbose Arg::from()
.arg(
arg!(-c --config <CONFIG> "Optionally sets a config file to use")
)Examples found in repository?
3fn main() {
4 let matches = Command::new("MyApp")
5 .version("1.0")
6 .about("Does awesome things")
7 .arg(arg!(--two <VALUE>).required(true))
8 .arg(arg!(--one <VALUE>).required(true))
9 .get_matches();
10
11 println!(
12 "two: {:?}",
13 matches.get_one::<String>("two").expect("required")
14 );
15 println!(
16 "one: {:?}",
17 matches.get_one::<String>("one").expect("required")
18 );
19}More examples
38 fn augment_args(cmd: Command) -> Command {
39 cmd.arg(
40 Arg::new("foo")
41 .short('f')
42 .long("foo")
43 .action(ArgAction::SetTrue),
44 )
45 .arg(
46 Arg::new("bar")
47 .short('b')
48 .long("bar")
49 .action(ArgAction::SetTrue),
50 )
51 .arg(
52 Arg::new("quuz")
53 .short('q')
54 .long("quuz")
55 .action(ArgAction::Set),
56 )
57 }
58 fn augment_args_for_update(cmd: Command) -> Command {
59 cmd.arg(
60 Arg::new("foo")
61 .short('f')
62 .long("foo")
63 .action(ArgAction::SetTrue),
64 )
65 .arg(
66 Arg::new("bar")
67 .short('b')
68 .long("bar")
69 .action(ArgAction::SetTrue),
70 )
71 .arg(
72 Arg::new("quuz")
73 .short('q')
74 .long("quuz")
75 .action(ArgAction::Set),
76 )
77 }9fn main() {
10 let cli = Command::new("CLI").arg(arg!(-b - -built).action(clap::ArgAction::SetTrue));
11 // Augment built args with derived args
12 let cli = DerivedArgs::augment_args(cli);
13
14 let matches = cli.get_matches();
15 println!("Value of built: {:?}", matches.get_flag("built"));
16 println!(
17 "Value of derived via ArgMatches: {:?}",
18 matches.get_flag("derived")
19 );
20
21 // Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
22 // This is the main benefit of using derived arguments.
23 let derived_matches = DerivedArgs::from_arg_matches(&matches)
24 .map_err(|err| err.exit())
25 .unwrap();
26 println!("Value of derived: {derived_matches:#?}");
27}13fn main() {
14 let cmd = Command::new(env!("CARGO_CRATE_NAME"))
15 .multicall(true)
16 .subcommand(
17 Command::new("busybox")
18 .arg_required_else_help(true)
19 .subcommand_value_name("APPLET")
20 .subcommand_help_heading("APPLETS")
21 .arg(
22 Arg::new("install")
23 .long("install")
24 .help("Install hardlinks for all subcommands in path")
25 .exclusive(true)
26 .action(ArgAction::Set)
27 .default_missing_value("/usr/local/bin")
28 .value_parser(value_parser!(PathBuf)),
29 )
30 .subcommands(applet_commands()),
31 )
32 .subcommands(applet_commands());
33
34 let matches = cmd.get_matches();
35 let mut subcommand = matches.subcommand();
36 if let Some(("busybox", cmd)) = subcommand {
37 if cmd.contains_id("install") {
38 unimplemented!("Make hardlinks to the executable here");
39 }
40 subcommand = cmd.subcommand();
41 }
42 match subcommand {
43 Some(("false", _)) => exit(1),
44 Some(("true", _)) => exit(0),
45 _ => unreachable!("parser should ensure only valid subcommand names are used"),
46 }
47}6fn 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 .flatten_help(true)
49 .args(push_args())
50 .subcommand(Command::new("push").args(push_args()))
51 .subcommand(Command::new("pop").arg(arg!([STASH])))
52 .subcommand(Command::new("apply").arg(arg!([STASH]))),
53 )
54}3fn main() {
4 let matches = Command::new("pacman")
5 .about("package manager utility")
6 .version("5.2.1")
7 .subcommand_required(true)
8 .arg_required_else_help(true)
9 // Query subcommand
10 //
11 // Only a few of its arguments are implemented below.
12 .subcommand(
13 Command::new("query")
14 .short_flag('Q')
15 .long_flag("query")
16 .about("Query the package database.")
17 .arg(
18 Arg::new("search")
19 .short('s')
20 .long("search")
21 .help("search locally installed packages for matching strings")
22 .conflicts_with("info")
23 .action(ArgAction::Set)
24 .num_args(1..),
25 )
26 .arg(
27 Arg::new("info")
28 .long("info")
29 .short('i')
30 .conflicts_with("search")
31 .help("view package information")
32 .action(ArgAction::Set)
33 .num_args(1..),
34 ),
35 )
36 // Sync subcommand
37 //
38 // Only a few of its arguments are implemented below.
39 .subcommand(
40 Command::new("sync")
41 .short_flag('S')
42 .long_flag("sync")
43 .about("Synchronize packages.")
44 .arg(
45 Arg::new("search")
46 .short('s')
47 .long("search")
48 .conflicts_with("info")
49 .action(ArgAction::Set)
50 .num_args(1..)
51 .help("search remote repositories for matching strings"),
52 )
53 .arg(
54 Arg::new("info")
55 .long("info")
56 .conflicts_with("search")
57 .short('i')
58 .action(ArgAction::SetTrue)
59 .help("view package information"),
60 )
61 .arg(
62 Arg::new("package")
63 .help("packages")
64 .required_unless_present("search")
65 .action(ArgAction::Set)
66 .num_args(1..),
67 ),
68 )
69 .get_matches();
70
71 match matches.subcommand() {
72 Some(("sync", sync_matches)) => {
73 if sync_matches.contains_id("search") {
74 let packages: Vec<_> = sync_matches
75 .get_many::<String>("search")
76 .expect("contains_id")
77 .map(|s| s.as_str())
78 .collect();
79 let values = packages.join(", ");
80 println!("Searching for {values}...");
81 return;
82 }
83
84 let packages: Vec<_> = sync_matches
85 .get_many::<String>("package")
86 .expect("is present")
87 .map(|s| s.as_str())
88 .collect();
89 let values = packages.join(", ");
90
91 if sync_matches.get_flag("info") {
92 println!("Retrieving info for {values}...");
93 } else {
94 println!("Installing {values}...");
95 }
96 }
97 Some(("query", query_matches)) => {
98 if let Some(packages) = query_matches.get_many::<String>("info") {
99 let comma_sep = packages.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
100 println!("Retrieving info for {comma_sep}...");
101 } else if let Some(queries) = query_matches.get_many::<String>("search") {
102 let comma_sep = queries.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
103 println!("Searching Locally for {comma_sep}...");
104 } else {
105 println!("Displaying all locally installed packages...");
106 }
107 }
108 _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable
109 }
110}Sourcepub fn args(self, args: impl IntoIterator<Item = impl Into<Arg>>) -> Command
pub fn args(self, args: impl IntoIterator<Item = impl Into<Arg>>) -> Command
Adds multiple arguments to the list of valid possibilities.
§Examples
Command::new("myprog")
.args([
arg!(-d --debug "turns on debugging info"),
Arg::new("input").help("the input file to use")
])Examples found in repository?
6fn 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 .flatten_help(true)
49 .args(push_args())
50 .subcommand(Command::new("push").args(push_args()))
51 .subcommand(Command::new("pop").arg(arg!([STASH])))
52 .subcommand(Command::new("apply").arg(arg!([STASH]))),
53 )
54}Sourcepub fn mut_arg<F>(self, arg_id: impl AsRef<str>, f: F) -> Command
pub fn mut_arg<F>(self, arg_id: impl AsRef<str>, f: F) -> Command
Allows one to mutate an Arg after it’s been added to a Command.
§Panics
If the argument is undefined
§Examples
let mut cmd = Command::new("foo")
.arg(Arg::new("bar")
.short('b')
.action(ArgAction::SetTrue))
.mut_arg("bar", |a| a.short('B'));
let res = cmd.try_get_matches_from_mut(vec!["foo", "-b"]);
// Since we changed `bar`'s short to "B" this should err as there
// is no `-b` anymore, only `-B`
assert!(res.is_err());
let res = cmd.try_get_matches_from_mut(vec!["foo", "-B"]);
assert!(res.is_ok());Sourcepub fn mut_args<F>(self, f: F) -> Command
pub fn mut_args<F>(self, f: F) -> Command
Allows one to mutate all Args after they’ve been added to a Command.
This does not affect the built-in --help or --version arguments.
§Examples
let mut cmd = Command::new("foo")
.arg(Arg::new("bar")
.long("bar")
.action(ArgAction::SetTrue))
.arg(Arg::new("baz")
.long("baz")
.action(ArgAction::SetTrue))
.mut_args(|a| {
if let Some(l) = a.get_long().map(|l| format!("prefix-{l}")) {
a.long(l)
} else {
a
}
});
let res = cmd.try_get_matches_from_mut(vec!["foo", "--bar"]);
// Since we changed `bar`'s long to "prefix-bar" this should err as there
// is no `--bar` anymore, only `--prefix-bar`.
assert!(res.is_err());
let res = cmd.try_get_matches_from_mut(vec!["foo", "--prefix-bar"]);
assert!(res.is_ok());Sourcepub fn mut_group<F>(self, arg_id: impl AsRef<str>, f: F) -> Command
pub fn mut_group<F>(self, arg_id: impl AsRef<str>, f: F) -> Command
Allows one to mutate an ArgGroup after it’s been added to a Command.
§Panics
If the argument is undefined
§Examples
Command::new("foo")
.arg(arg!(--"set-ver" <ver> "set the version manually").required(false))
.arg(arg!(--major "auto increase major"))
.arg(arg!(--minor "auto increase minor"))
.arg(arg!(--patch "auto increase patch"))
.group(ArgGroup::new("vers")
.args(["set-ver", "major", "minor","patch"])
.required(true))
.mut_group("vers", |a| a.required(false));Sourcepub fn mut_subcommand<F>(self, name: impl AsRef<str>, f: F) -> Command
pub fn mut_subcommand<F>(self, name: impl AsRef<str>, f: F) -> Command
Allows one to mutate a Command after it’s been added as a subcommand.
This can be useful for modifying auto-generated arguments of nested subcommands with
Command::mut_arg.
§Panics
If the subcommand is undefined
§Examples
let mut cmd = Command::new("foo")
.subcommand(Command::new("bar"))
.mut_subcommand("bar", |subcmd| subcmd.disable_help_flag(true));
let res = cmd.try_get_matches_from_mut(vec!["foo", "bar", "--help"]);
// Since we disabled the help flag on the "bar" subcommand, this should err.
assert!(res.is_err());
let res = cmd.try_get_matches_from_mut(vec!["foo", "bar"]);
assert!(res.is_ok());Sourcepub fn mut_subcommands<F>(self, f: F) -> Command
pub fn mut_subcommands<F>(self, f: F) -> Command
Allows one to mutate all Commands after they’ve been added as subcommands.
This does not affect the built-in --help or --version arguments.
§Examples
let mut cmd = Command::new("foo")
.subcommands([
Command::new("fetch"),
Command::new("push"),
])
// Allow title-case subcommands
.mut_subcommands(|sub| {
let name = sub.get_name();
let alias = name.chars().enumerate().map(|(i, c)| {
if i == 0 {
c.to_ascii_uppercase()
} else {
c
}
}).collect::<String>();
sub.alias(alias)
});
let res = cmd.try_get_matches_from_mut(vec!["foo", "fetch"]);
assert!(res.is_ok());
let res = cmd.try_get_matches_from_mut(vec!["foo", "Fetch"]);
assert!(res.is_ok());Sourcepub fn group(self, group: impl Into<ArgGroup>) -> Command
pub fn group(self, group: impl Into<ArgGroup>) -> Command
Adds an ArgGroup to the application.
ArgGroups are a family of related arguments.
By placing them in a logical group, you can build easier requirement and exclusion rules.
Example use cases:
- Make an entire
ArgGrouprequired, meaning that one (and only one) argument from that group must be present at runtime. - Name an
ArgGroupas a conflict to another argument. Meaning any of the arguments that belong to that group will cause a failure if present with the conflicting argument. - Ensure exclusion between arguments.
- Extract a value from a group instead of determining exactly which argument was used.
§Examples
The following example demonstrates using an ArgGroup to ensure that one, and only one,
of the arguments from the specified group is present at runtime.
Command::new("cmd")
.arg(arg!(--"set-ver" <ver> "set the version manually").required(false))
.arg(arg!(--major "auto increase major"))
.arg(arg!(--minor "auto increase minor"))
.arg(arg!(--patch "auto increase patch"))
.group(ArgGroup::new("vers")
.args(["set-ver", "major", "minor","patch"])
.required(true))Sourcepub fn groups(
self,
groups: impl IntoIterator<Item = impl Into<ArgGroup>>,
) -> Command
pub fn groups( self, groups: impl IntoIterator<Item = impl Into<ArgGroup>>, ) -> Command
Adds multiple ArgGroups to the Command at once.
§Examples
Command::new("cmd")
.arg(arg!(--"set-ver" <ver> "set the version manually").required(false))
.arg(arg!(--major "auto increase major"))
.arg(arg!(--minor "auto increase minor"))
.arg(arg!(--patch "auto increase patch"))
.arg(arg!(-c <FILE> "a config file").required(false))
.arg(arg!(-i <IFACE> "an interface").required(false))
.groups([
ArgGroup::new("vers")
.args(["set-ver", "major", "minor","patch"])
.required(true),
ArgGroup::new("input")
.args(["c", "i"])
])Sourcepub fn subcommand(self, subcmd: impl Into<Command>) -> Command
pub fn subcommand(self, subcmd: impl Into<Command>) -> Command
Adds a subcommand to the list of valid possibilities.
Subcommands are effectively sub-Commands, because they can contain their own arguments,
subcommands, version, usage, etc. They also function just like Commands, in that they get
their own auto generated help, version, and usage.
A subcommand’s Command::name will be used for:
- The argument the user passes in
- Programmatically looking up the subcommand
§Examples
Command::new("myprog")
.subcommand(Command::new("config")
.about("Controls configuration features")
.arg(arg!(<config> "Required configuration file to use")))Examples found in repository?
More examples
3fn main() {
4 let cmd = Command::new(env!("CARGO_CRATE_NAME"))
5 .multicall(true)
6 .arg_required_else_help(true)
7 .subcommand_value_name("APPLET")
8 .subcommand_help_heading("APPLETS")
9 .subcommand(Command::new("hostname").about("show hostname part of FQDN"))
10 .subcommand(Command::new("dnsdomainname").about("show domain name part of FQDN"));
11
12 match cmd.get_matches().subcommand_name() {
13 Some("hostname") => println!("www"),
14 Some("dnsdomainname") => println!("example.com"),
15 _ => unreachable!("parser should ensure only valid subcommand names are used"),
16 }
17}51fn cli() -> Command {
52 // strip out usage
53 const PARSER_TEMPLATE: &str = "\
54 {all-args}
55 ";
56 // strip out name/version
57 const APPLET_TEMPLATE: &str = "\
58 {about-with-newline}\n\
59 {usage-heading}\n {usage}\n\
60 \n\
61 {all-args}{after-help}\
62 ";
63
64 Command::new("repl")
65 .multicall(true)
66 .arg_required_else_help(true)
67 .subcommand_required(true)
68 .subcommand_value_name("APPLET")
69 .subcommand_help_heading("APPLETS")
70 .help_template(PARSER_TEMPLATE)
71 .subcommand(
72 Command::new("ping")
73 .about("Get a response")
74 .help_template(APPLET_TEMPLATE),
75 )
76 .subcommand(
77 Command::new("quit")
78 .alias("exit")
79 .about("Quit the REPL")
80 .help_template(APPLET_TEMPLATE),
81 )
82}13fn main() {
14 let cmd = Command::new(env!("CARGO_CRATE_NAME"))
15 .multicall(true)
16 .subcommand(
17 Command::new("busybox")
18 .arg_required_else_help(true)
19 .subcommand_value_name("APPLET")
20 .subcommand_help_heading("APPLETS")
21 .arg(
22 Arg::new("install")
23 .long("install")
24 .help("Install hardlinks for all subcommands in path")
25 .exclusive(true)
26 .action(ArgAction::Set)
27 .default_missing_value("/usr/local/bin")
28 .value_parser(value_parser!(PathBuf)),
29 )
30 .subcommands(applet_commands()),
31 )
32 .subcommands(applet_commands());
33
34 let matches = cmd.get_matches();
35 let mut subcommand = matches.subcommand();
36 if let Some(("busybox", cmd)) = subcommand {
37 if cmd.contains_id("install") {
38 unimplemented!("Make hardlinks to the executable here");
39 }
40 subcommand = cmd.subcommand();
41 }
42 match subcommand {
43 Some(("false", _)) => exit(1),
44 Some(("true", _)) => exit(0),
45 _ => unreachable!("parser should ensure only valid subcommand names are used"),
46 }
47}6fn 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 .flatten_help(true)
49 .args(push_args())
50 .subcommand(Command::new("push").args(push_args()))
51 .subcommand(Command::new("pop").arg(arg!([STASH])))
52 .subcommand(Command::new("apply").arg(arg!([STASH]))),
53 )
54}3fn main() {
4 let matches = Command::new("pacman")
5 .about("package manager utility")
6 .version("5.2.1")
7 .subcommand_required(true)
8 .arg_required_else_help(true)
9 // Query subcommand
10 //
11 // Only a few of its arguments are implemented below.
12 .subcommand(
13 Command::new("query")
14 .short_flag('Q')
15 .long_flag("query")
16 .about("Query the package database.")
17 .arg(
18 Arg::new("search")
19 .short('s')
20 .long("search")
21 .help("search locally installed packages for matching strings")
22 .conflicts_with("info")
23 .action(ArgAction::Set)
24 .num_args(1..),
25 )
26 .arg(
27 Arg::new("info")
28 .long("info")
29 .short('i')
30 .conflicts_with("search")
31 .help("view package information")
32 .action(ArgAction::Set)
33 .num_args(1..),
34 ),
35 )
36 // Sync subcommand
37 //
38 // Only a few of its arguments are implemented below.
39 .subcommand(
40 Command::new("sync")
41 .short_flag('S')
42 .long_flag("sync")
43 .about("Synchronize packages.")
44 .arg(
45 Arg::new("search")
46 .short('s')
47 .long("search")
48 .conflicts_with("info")
49 .action(ArgAction::Set)
50 .num_args(1..)
51 .help("search remote repositories for matching strings"),
52 )
53 .arg(
54 Arg::new("info")
55 .long("info")
56 .conflicts_with("search")
57 .short('i')
58 .action(ArgAction::SetTrue)
59 .help("view package information"),
60 )
61 .arg(
62 Arg::new("package")
63 .help("packages")
64 .required_unless_present("search")
65 .action(ArgAction::Set)
66 .num_args(1..),
67 ),
68 )
69 .get_matches();
70
71 match matches.subcommand() {
72 Some(("sync", sync_matches)) => {
73 if sync_matches.contains_id("search") {
74 let packages: Vec<_> = sync_matches
75 .get_many::<String>("search")
76 .expect("contains_id")
77 .map(|s| s.as_str())
78 .collect();
79 let values = packages.join(", ");
80 println!("Searching for {values}...");
81 return;
82 }
83
84 let packages: Vec<_> = sync_matches
85 .get_many::<String>("package")
86 .expect("is present")
87 .map(|s| s.as_str())
88 .collect();
89 let values = packages.join(", ");
90
91 if sync_matches.get_flag("info") {
92 println!("Retrieving info for {values}...");
93 } else {
94 println!("Installing {values}...");
95 }
96 }
97 Some(("query", query_matches)) => {
98 if let Some(packages) = query_matches.get_many::<String>("info") {
99 let comma_sep = packages.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
100 println!("Retrieving info for {comma_sep}...");
101 } else if let Some(queries) = query_matches.get_many::<String>("search") {
102 let comma_sep = queries.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
103 println!("Searching Locally for {comma_sep}...");
104 } else {
105 println!("Displaying all locally installed packages...");
106 }
107 }
108 _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable
109 }
110}Sourcepub fn subcommands(
self,
subcmds: impl IntoIterator<Item = impl Into<Command>>,
) -> Command
pub fn subcommands( self, subcmds: impl IntoIterator<Item = impl Into<Command>>, ) -> Command
Adds multiple subcommands to the list of valid possibilities.
§Examples
.subcommands( [
Command::new("config").about("Controls configuration functionality")
.arg(Arg::new("config_file")),
Command::new("debug").about("Controls debug functionality")])Examples found in repository?
13fn main() {
14 let cmd = Command::new(env!("CARGO_CRATE_NAME"))
15 .multicall(true)
16 .subcommand(
17 Command::new("busybox")
18 .arg_required_else_help(true)
19 .subcommand_value_name("APPLET")
20 .subcommand_help_heading("APPLETS")
21 .arg(
22 Arg::new("install")
23 .long("install")
24 .help("Install hardlinks for all subcommands in path")
25 .exclusive(true)
26 .action(ArgAction::Set)
27 .default_missing_value("/usr/local/bin")
28 .value_parser(value_parser!(PathBuf)),
29 )
30 .subcommands(applet_commands()),
31 )
32 .subcommands(applet_commands());
33
34 let matches = cmd.get_matches();
35 let mut subcommand = matches.subcommand();
36 if let Some(("busybox", cmd)) = subcommand {
37 if cmd.contains_id("install") {
38 unimplemented!("Make hardlinks to the executable here");
39 }
40 subcommand = cmd.subcommand();
41 }
42 match subcommand {
43 Some(("false", _)) => exit(1),
44 Some(("true", _)) => exit(0),
45 _ => unreachable!("parser should ensure only valid subcommand names are used"),
46 }
47}Sourcepub fn defer(self, deferred: fn(Command) -> Command) -> Command
pub fn defer(self, deferred: fn(Command) -> Command) -> Command
Delay initialization for parts of the Command
This is useful for large applications to delay definitions of subcommands until they are being invoked.
§Examples
Command::new("myprog")
.subcommand(Command::new("config")
.about("Controls configuration features")
.defer(|cmd| {
cmd.arg(arg!(<config> "Required configuration file to use"))
})
)Sourcepub fn debug_assert(self)
pub fn debug_assert(self)
Catch problems earlier in the development cycle.
Most error states are handled as asserts under the assumption they are programming mistake and not something to handle at runtime. Rather than relying on tests (manual or automated) that exhaustively test your CLI to ensure the asserts are evaluated, this will run those asserts in a way convenient for running as a test.
Note: This will not help with asserts in ArgMatches, those will need exhaustive
testing of your CLI.
§Examples
fn cmd() -> Command {
Command::new("foo")
.arg(
Arg::new("bar").short('b').action(ArgAction::SetTrue)
)
}
#[test]
fn verify_app() {
cmd().debug_assert();
}
fn main() {
let m = cmd().get_matches_from(vec!["foo", "-b"]);
println!("{}", m.get_flag("bar"));
}Sourcepub fn error(&mut self, kind: ErrorKind, message: impl Display) -> Error
pub fn error(&mut self, kind: ErrorKind, message: impl Display) -> Error
Custom error message for post-parsing validation
Note: this will ensure the Command has been sufficiently built for any
relevant context, including usage.
§Panics
If contradictory arguments or settings exist (debug builds).
§Examples
let mut cmd = Command::new("myprog");
let err = cmd.error(ErrorKind::InvalidValue, "Some failure case");Examples found in repository?
34fn main() {
35 let cli = Cli::parse();
36
37 // Let's assume the old version 1.2.3
38 let mut major = 1;
39 let mut minor = 2;
40 let mut patch = 3;
41
42 // See if --set-ver was used to set the version manually
43 let version = if let Some(ver) = cli.set_ver.as_deref() {
44 if cli.major || cli.minor || cli.patch {
45 let mut cmd = Cli::command();
46 cmd.error(
47 ErrorKind::ArgumentConflict,
48 "Can't do relative and absolute version change",
49 )
50 .exit();
51 }
52 ver.to_string()
53 } else {
54 // Increment the one requested (in a real program, we'd reset the lower numbers)
55 let (maj, min, pat) = (cli.major, cli.minor, cli.patch);
56 match (maj, min, pat) {
57 (true, false, false) => major += 1,
58 (false, true, false) => minor += 1,
59 (false, false, true) => patch += 1,
60 _ => {
61 let mut cmd = Cli::command();
62 cmd.error(
63 ErrorKind::ArgumentConflict,
64 "Can only modify one version field",
65 )
66 .exit();
67 }
68 };
69 format!("{major}.{minor}.{patch}")
70 };
71
72 println!("Version: {version}");
73
74 // Check for usage of -c
75 if let Some(config) = cli.config.as_deref() {
76 let input = cli
77 .input_file
78 .as_deref()
79 // 'or' is preferred to 'or_else' here since `Option::as_deref` is 'const'
80 .or(cli.spec_in.as_deref())
81 .unwrap_or_else(|| {
82 let mut cmd = Cli::command();
83 cmd.error(
84 ErrorKind::MissingRequiredArgument,
85 "INPUT_FILE or --spec-in is required when using --config",
86 )
87 .exit()
88 });
89 println!("Doing work using input {input} and config {config}");
90 }
91}Sourcepub fn get_matches(self) -> ArgMatches
pub fn get_matches(self) -> ArgMatches
Parse env::args_os, exiting on failure.
§Panics
If contradictory arguments or settings exist (debug builds).
§Examples
let matches = Command::new("myprog")
// Args and options go here...
.get_matches();