]>
git.proxmox.com Git - rustc.git/blob - vendor/clap_builder/src/builder/arg_group.rs
2 use crate::builder
::IntoResettable
;
5 /// Family of related [arguments].
7 /// By placing arguments in a logical group, you can create easier requirement and
8 /// exclusion rules instead of having to list each argument individually, or when you want a rule
9 /// to apply "any but not all" arguments.
11 /// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is
12 /// set, this means that at least one argument from that group must be present. If
13 /// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present.
15 /// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for
16 /// another argument, meaning any of the arguments that belong to that group will cause a failure
17 /// if present, or must be present respectively.
19 /// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
20 /// present out of a given set. Imagine that you had multiple arguments, and you want one of them
21 /// to be required, but making all of them required isn't feasible because perhaps they conflict
22 /// with each other. For example, lets say that you were building an application where one could
23 /// set a given version number by supplying a string with an option argument, i.e.
24 /// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number
25 /// and simply incrementing one of the three numbers. So you create three flags `--major`,
26 /// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to
27 /// specify that *at least one* of them is used. For this, you can create a group.
29 /// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care
30 /// exactly which argument was actually used at runtime.
34 /// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of
35 /// the arguments from the specified group is present at runtime.
38 /// # use clap_builder as clap;
39 /// # use clap::{Command, arg, ArgGroup, error::ErrorKind};
40 /// let result = Command::new("cmd")
41 /// .arg(arg!(--"set-ver" <ver> "set the version manually"))
42 /// .arg(arg!(--major "auto increase major"))
43 /// .arg(arg!(--minor "auto increase minor"))
44 /// .arg(arg!(--patch "auto increase patch"))
45 /// .group(ArgGroup::new("vers")
46 /// .args(["set-ver", "major", "minor", "patch"])
48 /// .try_get_matches_from(vec!["cmd", "--major", "--patch"]);
49 /// // Because we used two args in the group it's an error
50 /// assert!(result.is_err());
51 /// let err = result.unwrap_err();
52 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
55 /// This next example shows a passing parse of the same scenario
57 /// # use clap_builder as clap;
58 /// # use clap::{Command, arg, ArgGroup, Id};
59 /// let result = Command::new("cmd")
60 /// .arg(arg!(--"set-ver" <ver> "set the version manually"))
61 /// .arg(arg!(--major "auto increase major"))
62 /// .arg(arg!(--minor "auto increase minor"))
63 /// .arg(arg!(--patch "auto increase patch"))
64 /// .group(ArgGroup::new("vers")
65 /// .args(["set-ver", "major", "minor","patch"])
67 /// .try_get_matches_from(vec!["cmd", "--major"]);
68 /// assert!(result.is_ok());
69 /// let matches = result.unwrap();
70 /// // We may not know which of the args was used, so we can test for the group...
71 /// assert!(matches.contains_id("vers"));
72 /// // We can also ask the group which arg was used
73 /// assert_eq!(matches
74 /// .get_one::<Id>("vers")
75 /// .expect("`vers` is required")
79 /// // we could also alternatively check each arg individually (not shown here)
81 /// [`ArgGroup::multiple(true)`]: ArgGroup::multiple()
83 /// [`ArgGroup::multiple(false)`]: ArgGroup::multiple()
84 /// [arguments]: crate::Arg
85 /// [conflict]: crate::Arg::conflicts_with()
86 /// [requirement]: crate::Arg::requires()
87 #[derive(Default, Clone, Debug, PartialEq, Eq)]
90 pub(crate) args
: Vec
<Id
>,
91 pub(crate) required
: bool
,
92 pub(crate) requires
: Vec
<Id
>,
93 pub(crate) conflicts
: Vec
<Id
>,
94 pub(crate) multiple
: bool
,
99 /// Create a `ArgGroup` using a unique name.
101 /// The name will be used to get values from the group or refer to the group inside of conflict
102 /// and requirement rules.
107 /// # use clap_builder as clap;
108 /// # use clap::{Command, ArgGroup};
109 /// ArgGroup::new("config")
112 pub fn new(id
: impl Into
<Id
>) -> Self {
113 ArgGroup
::default().id(id
)
116 /// Sets the group name.
121 /// # use clap_builder as clap;
122 /// # use clap::{Command, ArgGroup};
123 /// ArgGroup::default().id("config")
127 pub fn id(mut self, id
: impl Into
<Id
>) -> Self {
132 /// Adds an [argument] to this group by name
137 /// # use clap_builder as clap;
138 /// # use clap::{Command, Arg, ArgGroup, ArgAction};
139 /// let m = Command::new("myprog")
140 /// .arg(Arg::new("flag")
142 /// .action(ArgAction::SetTrue))
143 /// .arg(Arg::new("color")
145 /// .action(ArgAction::SetTrue))
146 /// .group(ArgGroup::new("req_flags")
149 /// .get_matches_from(vec!["myprog", "-f"]);
150 /// // maybe we don't know which of the two flags was used...
151 /// assert!(m.contains_id("req_flags"));
152 /// // but we can also check individually if needed
153 /// assert!(m.contains_id("flag"));
155 /// [argument]: crate::Arg
157 pub fn arg(mut self, arg_id
: impl IntoResettable
<Id
>) -> Self {
158 if let Some(arg_id
) = arg_id
.into_resettable().into_option() {
159 self.args
.push(arg_id
);
166 /// Adds multiple [arguments] to this group by name
171 /// # use clap_builder as clap;
172 /// # use clap::{Command, Arg, ArgGroup, ArgAction};
173 /// let m = Command::new("myprog")
174 /// .arg(Arg::new("flag")
176 /// .action(ArgAction::SetTrue))
177 /// .arg(Arg::new("color")
179 /// .action(ArgAction::SetTrue))
180 /// .group(ArgGroup::new("req_flags")
181 /// .args(["flag", "color"]))
182 /// .get_matches_from(vec!["myprog", "-f"]);
183 /// // maybe we don't know which of the two flags was used...
184 /// assert!(m.contains_id("req_flags"));
185 /// // but we can also check individually if needed
186 /// assert!(m.contains_id("flag"));
188 /// [arguments]: crate::Arg
190 pub fn args(mut self, ns
: impl IntoIterator
<Item
= impl Into
<Id
>>) -> Self {
197 /// Getters for all args. It will return a vector of `Id`
202 /// # use clap_builder as clap;
203 /// # use clap::{ArgGroup};
204 /// let args: Vec<&str> = vec!["a1".into(), "a4".into()];
205 /// let grp = ArgGroup::new("program").args(&args);
207 /// for (pos, arg) in grp.get_args().enumerate() {
208 /// assert_eq!(*arg, args[pos]);
211 pub fn get_args(&self) -> impl Iterator
<Item
= &Id
> {
215 /// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`)
219 /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the
223 /// # use clap_builder as clap;
224 /// # use clap::{Command, Arg, ArgGroup, ArgAction};
225 /// let m = Command::new("myprog")
226 /// .arg(Arg::new("flag")
228 /// .action(ArgAction::SetTrue))
229 /// .arg(Arg::new("color")
231 /// .action(ArgAction::SetTrue))
232 /// .group(ArgGroup::new("req_flags")
233 /// .args(["flag", "color"])
235 /// .get_matches_from(vec!["myprog", "-f", "-c"]);
236 /// // maybe we don't know which of the two flags was used...
237 /// assert!(m.contains_id("req_flags"));
239 /// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw
240 /// an error if more than one of the args in the group was used.
243 /// # use clap_builder as clap;
244 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
245 /// let result = Command::new("myprog")
246 /// .arg(Arg::new("flag")
248 /// .action(ArgAction::SetTrue))
249 /// .arg(Arg::new("color")
251 /// .action(ArgAction::SetTrue))
252 /// .group(ArgGroup::new("req_flags")
253 /// .args(["flag", "color"]))
254 /// .try_get_matches_from(vec!["myprog", "-f", "-c"]);
255 /// // Because we used both args in the group it's an error
256 /// assert!(result.is_err());
257 /// let err = result.unwrap_err();
258 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
261 /// [`Arg`]: crate::Arg
264 pub fn multiple(mut self, yes
: bool
) -> Self {
269 /// Return true if the group allows more than one of the arguments
270 /// in this group to be used. (Default: `false`)
275 /// # use clap_builder as clap;
276 /// # use clap::{ArgGroup};
277 /// let mut group = ArgGroup::new("myprog")
278 /// .args(["f", "c"])
281 /// assert!(group.is_multiple());
283 pub fn is_multiple(&mut self) -> bool
{
287 /// Require an argument from the group to be present when parsing.
289 /// This is unless conflicting with another argument. A required group will be displayed in
290 /// the usage string of the application in the format `<arg|arg2|arg3>`.
292 /// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not
295 /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
296 /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group.
297 /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which
298 /// states, '*At least* one arg from this group must be used. Using multiple is OK."
303 /// # use clap_builder as clap;
304 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
305 /// let result = Command::new("myprog")
306 /// .arg(Arg::new("flag")
308 /// .action(ArgAction::SetTrue))
309 /// .arg(Arg::new("color")
311 /// .action(ArgAction::SetTrue))
312 /// .group(ArgGroup::new("req_flags")
313 /// .args(["flag", "color"])
315 /// .try_get_matches_from(vec!["myprog"]);
316 /// // Because we didn't use any of the args in the group, it's an error
317 /// assert!(result.is_err());
318 /// let err = result.unwrap_err();
319 /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
322 /// [`Subcommand`]: crate::Subcommand
323 /// [`ArgGroup::multiple`]: ArgGroup::multiple()
324 /// [`Command`]: crate::Command
327 pub fn required(mut self, yes
: bool
) -> Self {
332 /// Specify an argument or group that must be present when this group is.
334 /// This is not to be confused with a [required group]. Requirement rules function just like
335 /// [argument requirement rules], you can name other arguments or groups that must be present
336 /// when any one of the arguments from this group is used.
338 /// **NOTE:** The name provided may be an argument or group name
343 /// # use clap_builder as clap;
344 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
345 /// let result = Command::new("myprog")
346 /// .arg(Arg::new("flag")
348 /// .action(ArgAction::SetTrue))
349 /// .arg(Arg::new("color")
351 /// .action(ArgAction::SetTrue))
352 /// .arg(Arg::new("debug")
354 /// .action(ArgAction::SetTrue))
355 /// .group(ArgGroup::new("req_flags")
356 /// .args(["flag", "color"])
357 /// .requires("debug"))
358 /// .try_get_matches_from(vec!["myprog", "-c"]);
359 /// // because we used an arg from the group, and the group requires "-d" to be used, it's an
361 /// assert!(result.is_err());
362 /// let err = result.unwrap_err();
363 /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
365 /// [required group]: ArgGroup::required()
366 /// [argument requirement rules]: crate::Arg::requires()
368 pub fn requires(mut self, id
: impl IntoResettable
<Id
>) -> Self {
369 if let Some(id
) = id
.into_resettable().into_option() {
370 self.requires
.push(id
);
372 self.requires
.clear();
377 /// Specify arguments or groups that must be present when this group is.
379 /// This is not to be confused with a [required group]. Requirement rules function just like
380 /// [argument requirement rules], you can name other arguments or groups that must be present
381 /// when one of the arguments from this group is used.
383 /// **NOTE:** The names provided may be an argument or group name
388 /// # use clap_builder as clap;
389 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
390 /// let result = Command::new("myprog")
391 /// .arg(Arg::new("flag")
393 /// .action(ArgAction::SetTrue))
394 /// .arg(Arg::new("color")
396 /// .action(ArgAction::SetTrue))
397 /// .arg(Arg::new("debug")
399 /// .action(ArgAction::SetTrue))
400 /// .arg(Arg::new("verb")
402 /// .action(ArgAction::SetTrue))
403 /// .group(ArgGroup::new("req_flags")
404 /// .args(["flag", "color"])
405 /// .requires_all(["debug", "verb"]))
406 /// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
407 /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used,
408 /// // yet we only used "-d" it's an error
409 /// assert!(result.is_err());
410 /// let err = result.unwrap_err();
411 /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
413 /// [required group]: ArgGroup::required()
414 /// [argument requirement rules]: crate::Arg::requires_ifs()
416 pub fn requires_all(mut self, ns
: impl IntoIterator
<Item
= impl Into
<Id
>>) -> Self {
418 self = self.requires(n
);
423 /// Specify an argument or group that must **not** be present when this group is.
425 /// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name
426 /// other arguments or groups that must *not* be present when one of the arguments from this
429 /// **NOTE:** The name provided may be an argument, or group name
434 /// # use clap_builder as clap;
435 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
436 /// let result = Command::new("myprog")
437 /// .arg(Arg::new("flag")
439 /// .action(ArgAction::SetTrue))
440 /// .arg(Arg::new("color")
442 /// .action(ArgAction::SetTrue))
443 /// .arg(Arg::new("debug")
445 /// .action(ArgAction::SetTrue))
446 /// .group(ArgGroup::new("req_flags")
447 /// .args(["flag", "color"])
448 /// .conflicts_with("debug"))
449 /// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
450 /// // because we used an arg from the group, and the group conflicts with "-d", it's an error
451 /// assert!(result.is_err());
452 /// let err = result.unwrap_err();
453 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
455 /// [argument exclusion rules]: crate::Arg::conflicts_with()
457 pub fn conflicts_with(mut self, id
: impl IntoResettable
<Id
>) -> Self {
458 if let Some(id
) = id
.into_resettable().into_option() {
459 self.conflicts
.push(id
);
461 self.conflicts
.clear();
466 /// Specify arguments or groups that must **not** be present when this group is.
468 /// Exclusion rules function just like [argument exclusion rules], you can name other arguments
469 /// or groups that must *not* be present when one of the arguments from this group are used.
471 /// **NOTE:** The names provided may be an argument, or group name
476 /// # use clap_builder as clap;
477 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
478 /// let result = Command::new("myprog")
479 /// .arg(Arg::new("flag")
481 /// .action(ArgAction::SetTrue))
482 /// .arg(Arg::new("color")
484 /// .action(ArgAction::SetTrue))
485 /// .arg(Arg::new("debug")
487 /// .action(ArgAction::SetTrue))
488 /// .arg(Arg::new("verb")
490 /// .action(ArgAction::SetTrue))
491 /// .group(ArgGroup::new("req_flags")
492 /// .args(["flag", "color"])
493 /// .conflicts_with_all(["debug", "verb"]))
494 /// .try_get_matches_from(vec!["myprog", "-c", "-v"]);
495 /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d"
497 /// assert!(result.is_err());
498 /// let err = result.unwrap_err();
499 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
502 /// [argument exclusion rules]: crate::Arg::conflicts_with_all()
504 pub fn conflicts_with_all(mut self, ns
: impl IntoIterator
<Item
= impl Into
<Id
>>) -> Self {
506 self = self.conflicts_with(n
);
514 /// Get the name of the group
516 pub fn get_id(&self) -> &Id
{
520 /// Reports whether [`ArgGroup::required`] is set
522 pub fn is_required_set(&self) -> bool
{
527 impl From
<&'_ ArgGroup
> for ArgGroup
{
528 fn from(g
: &ArgGroup
) -> Self {
539 let g
= ArgGroup
::new("test")
544 .conflicts_with("c1")
545 .conflicts_with_all(["c2", "c3"])
546 .conflicts_with("c4")
548 .requires_all(["r2", "r3"])
551 let args
: Vec
<Id
> = vec
!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
552 let reqs
: Vec
<Id
> = vec
!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
553 let confs
: Vec
<Id
> = vec
!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
555 assert_eq
!(g
.args
, args
);
556 assert_eq
!(g
.requires
, reqs
);
557 assert_eq
!(g
.conflicts
, confs
);
562 let g
= ArgGroup
::new("test")
567 .conflicts_with("c1")
568 .conflicts_with_all(["c2", "c3"])
569 .conflicts_with("c4")
571 .requires_all(["r2", "r3"])
574 let args
: Vec
<Id
> = vec
!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
575 let reqs
: Vec
<Id
> = vec
!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
576 let confs
: Vec
<Id
> = vec
!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
578 let g2
= ArgGroup
::from(&g
);
579 assert_eq
!(g2
.args
, args
);
580 assert_eq
!(g2
.requires
, reqs
);
581 assert_eq
!(g2
.conflicts
, confs
);
584 // This test will *fail to compile* if ArgGroup is not Send + Sync
586 fn arg_group_send_sync() {
587 fn foo
<T
: Send
+ Sync
>(_
: T
) {}
588 foo(ArgGroup
::new("test"))
592 fn arg_group_expose_is_multiple_helper() {
593 let args
: Vec
<Id
> = vec
!["a1".into(), "a4".into()];
595 let mut grp_multiple
= ArgGroup
::new("test_multiple").args(&args
).multiple(true);
596 assert
!(grp_multiple
.is_multiple());
598 let mut grp_not_multiple
= ArgGroup
::new("test_multiple").args(&args
).multiple(false);
599 assert
!(!grp_not_multiple
.is_multiple());
603 fn arg_group_expose_get_args_helper() {
604 let args
: Vec
<Id
> = vec
!["a1".into(), "a4".into()];
605 let grp
= ArgGroup
::new("program").args(&args
);
607 for (pos
, arg
) in grp
.get_args().enumerate() {
608 assert_eq
!(*arg
, args
[pos
]);