pub struct ArgGroup { /* private fields */ }
Expand description
Family of related arguments.
By placing arguments in a logical group, you can create easier requirement and exclusion rules instead of having to list each argument individually, or when you want a rule to apply “any but not all” arguments.
For instance, you can make an entire ArgGroup
required. If ArgGroup::multiple(true)
is
set, this means that at least one argument from that group must be present. If
ArgGroup::multiple(false)
is set (the default), one and only one must be present.
You can also do things such as name an entire ArgGroup
as a conflict or requirement for
another argument, meaning any of the arguments that belong to that group will cause a failure
if present, or must be present respectively.
Perhaps the most common use of ArgGroup
s is to require one and only one argument to be
present out of a given set. Imagine that you had multiple arguments, and you want one of them
to be required, but making all of them required isn’t feasible because perhaps they conflict
with each other. For example, lets say that you were building an application where one could
set a given version number by supplying a string with an option argument, i.e.
--set-ver v1.2.3
, you also wanted to support automatically using a previous version number
and simply incrementing one of the three numbers. So you create three flags --major
,
--minor
, and --patch
. All of these arguments shouldn’t be used at one time but you want to
specify that at least one of them is used. For this, you can create a group.
Finally, you may use ArgGroup
s to pull a value from a group of arguments when you don’t care
exactly which argument was actually used at runtime.
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.
let result = Command::new("cmd")
.arg(arg!(--"set-ver" <ver> "set the version manually"))
.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))
.try_get_matches_from(vec!["cmd", "--major", "--patch"]);
// Because we used two args in the group it's an error
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
This next example shows a passing parse of the same scenario
let result = Command::new("cmd")
.arg(arg!(--"set-ver" <ver> "set the version manually"))
.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))
.try_get_matches_from(vec!["cmd", "--major"]);
assert!(result.is_ok());
let matches = result.unwrap();
// We may not know which of the args was used, so we can test for the group...
assert!(matches.contains_id("vers"));
// We can also ask the group which arg was used
assert_eq!(matches
.get_one::<Id>("vers")
.expect("`vers` is required")
.as_str(),
"major"
);
// we could also alternatively check each arg individually (not shown here)
Implementations§
source§impl ArgGroup
impl ArgGroup
sourcepub fn new(id: impl Into<Id>) -> Self
pub fn new(id: impl Into<Id>) -> Self
Create a ArgGroup
using a unique name.
The name will be used to get values from the group or refer to the group inside of conflict and requirement rules.
Examples
ArgGroup::new("config")
Examples found in repository?
3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925
pub(crate) fn _build_self(&mut self, expand_help_tree: bool) {
debug!("Command::_build: name={:?}", self.get_name());
if !self.settings.is_set(AppSettings::Built) {
// Make sure all the globally set flags apply to us as well
self.settings = self.settings | self.g_settings;
if self.is_multicall_set() {
self.settings.insert(AppSettings::SubcommandRequired.into());
self.settings.insert(AppSettings::DisableHelpFlag.into());
self.settings.insert(AppSettings::DisableVersionFlag.into());
}
if !cfg!(feature = "help") && self.get_override_help().is_none() {
self.settings.insert(AppSettings::DisableHelpFlag.into());
self.settings
.insert(AppSettings::DisableHelpSubcommand.into());
}
if self.is_set(AppSettings::ArgsNegateSubcommands) {
self.settings
.insert(AppSettings::SubcommandsNegateReqs.into());
}
if self.external_value_parser.is_some() {
self.settings
.insert(AppSettings::AllowExternalSubcommands.into());
}
if !self.has_subcommands() {
self.settings
.insert(AppSettings::DisableHelpSubcommand.into());
}
self._propagate();
self._check_help_and_version(expand_help_tree);
self._propagate_global_args();
let mut pos_counter = 1;
let hide_pv = self.is_set(AppSettings::HidePossibleValues);
for a in self.args.args_mut() {
// Fill in the groups
for g in &a.groups {
if let Some(ag) = self.groups.iter_mut().find(|grp| grp.id == *g) {
ag.args.push(a.get_id().clone());
} else {
let mut ag = ArgGroup::new(g);
ag.args.push(a.get_id().clone());
self.groups.push(ag);
}
}
// Figure out implied settings
a._build();
if hide_pv && a.is_takes_value_set() {
a.settings.set(ArgSettings::HidePossibleValues);
}
if a.is_positional() && a.index.is_none() {
a.index = Some(pos_counter);
pos_counter += 1;
}
}
self.args._build();
#[allow(deprecated)]
{
let highest_idx = self
.get_keymap()
.keys()
.filter_map(|x| {
if let crate::mkeymap::KeyType::Position(n) = x {
Some(*n)
} else {
None
}
})
.max()
.unwrap_or(0);
let is_trailing_var_arg_set = self.is_trailing_var_arg_set();
let is_allow_hyphen_values_set = self.is_allow_hyphen_values_set();
let is_allow_negative_numbers_set = self.is_allow_negative_numbers_set();
for arg in self.args.args_mut() {
if is_allow_hyphen_values_set && arg.is_takes_value_set() {
arg.settings.insert(ArgSettings::AllowHyphenValues.into());
}
if is_allow_negative_numbers_set && arg.is_takes_value_set() {
arg.settings
.insert(ArgSettings::AllowNegativeNumbers.into());
}
if is_trailing_var_arg_set && arg.get_index() == Some(highest_idx) {
arg.settings.insert(ArgSettings::TrailingVarArg.into());
}
}
}
#[cfg(debug_assertions)]
assert_app(self);
self.settings.set(AppSettings::Built);
} else {
debug!("Command::_build: already built");
}
}
sourcepub fn arg(self, arg_id: impl IntoResettable<Id>) -> Self
pub fn arg(self, arg_id: impl IntoResettable<Id>) -> Self
Adds an argument to this group by name
Examples
let m = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.arg("flag")
.arg("color"))
.get_matches_from(vec!["myprog", "-f"]);
// maybe we don't know which of the two flags was used...
assert!(m.contains_id("req_flags"));
// but we can also check individually if needed
assert!(m.contains_id("flag"));
sourcepub fn args(self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self
pub fn args(self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self
Adds multiple arguments to this group by name
Examples
let m = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"]))
.get_matches_from(vec!["myprog", "-f"]);
// maybe we don't know which of the two flags was used...
assert!(m.contains_id("req_flags"));
// but we can also check individually if needed
assert!(m.contains_id("flag"));
sourcepub fn get_args(&self) -> impl Iterator<Item = &Id>
pub fn get_args(&self) -> impl Iterator<Item = &Id>
Getters for all args. It will return a vector of Id
Example
let args: Vec<&str> = vec!["a1".into(), "a4".into()];
let grp = ArgGroup::new("program").args(&args);
for (pos, arg) in grp.get_args().enumerate() {
assert_eq!(*arg, args[pos]);
}
sourcepub fn multiple(self, yes: bool) -> Self
pub fn multiple(self, yes: bool) -> Self
Allows more than one of the Arg
s in this group to be used. (Default: false
)
Examples
Notice in this example we use both the -f
and -c
flags which are both part of the
group
let m = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"])
.multiple(true))
.get_matches_from(vec!["myprog", "-f", "-c"]);
// maybe we don't know which of the two flags was used...
assert!(m.contains_id("req_flags"));
In this next example, we show the default behavior (i.e. `multiple(false)) which will throw an error if more than one of the args in the group was used.
let result = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"]))
.try_get_matches_from(vec!["myprog", "-f", "-c"]);
// Because we used both args in the group it's an error
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
sourcepub fn is_multiple(&mut self) -> bool
pub fn is_multiple(&mut self) -> bool
Return true if the group allows more than one of the arguments
in this group to be used. (Default: false
)
Example
let mut group = ArgGroup::new("myprog")
.args(["f", "c"])
.multiple(true);
assert!(group.is_multiple());
sourcepub fn required(self, yes: bool) -> Self
pub fn required(self, yes: bool) -> Self
Require an argument from the group to be present when parsing.
This is unless conflicting with another argument. A required group will be displayed in
the usage string of the application in the format <arg|arg2|arg3>
.
NOTE: This setting only applies to the current Command
/ Subcommand
s, and not
globally.
NOTE: By default, ArgGroup::multiple
is set to false
which when combined with
ArgGroup::required(true)
states, “One and only one arg must be used from this group.
Use of more than one arg is an error.” Vice setting ArgGroup::multiple(true)
which
states, ’At least one arg from this group must be used. Using multiple is OK.“
Examples
let result = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"])
.required(true))
.try_get_matches_from(vec!["myprog"]);
// Because we didn't use any of the args in the group, it's an error
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
sourcepub fn requires(self, id: impl IntoResettable<Id>) -> Self
pub fn requires(self, id: impl IntoResettable<Id>) -> Self
Specify an argument or group that must be present when this group is.
This is not to be confused with a required group. Requirement rules function just like argument requirement rules, you can name other arguments or groups that must be present when any one of the arguments from this group is used.
NOTE: The name provided may be an argument or group name
Examples
let result = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.arg(Arg::new("debug")
.short('d')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"])
.requires("debug"))
.try_get_matches_from(vec!["myprog", "-c"]);
// because we used an arg from the group, and the group requires "-d" to be used, it's an
// error
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
sourcepub fn requires_all(self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self
pub fn requires_all(self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self
Specify arguments or groups that must be present when this group is.
This is not to be confused with a required group. Requirement rules function just like argument requirement rules, you can name other arguments or groups that must be present when one of the arguments from this group is used.
NOTE: The names provided may be an argument or group name
Examples
let result = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.arg(Arg::new("debug")
.short('d')
.action(ArgAction::SetTrue))
.arg(Arg::new("verb")
.short('v')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"])
.requires_all(["debug", "verb"]))
.try_get_matches_from(vec!["myprog", "-c", "-d"]);
// because we used an arg from the group, and the group requires "-d" and "-v" to be used,
// yet we only used "-d" it's an error
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
sourcepub fn conflicts_with(self, id: impl IntoResettable<Id>) -> Self
pub fn conflicts_with(self, id: impl IntoResettable<Id>) -> Self
Specify an argument or group that must not be present when this group is.
Exclusion (aka conflict) rules function just like argument exclusion rules, you can name other arguments or groups that must not be present when one of the arguments from this group are used.
NOTE: The name provided may be an argument, or group name
Examples
let result = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.arg(Arg::new("debug")
.short('d')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"])
.conflicts_with("debug"))
.try_get_matches_from(vec!["myprog", "-c", "-d"]);
// because we used an arg from the group, and the group conflicts with "-d", it's an error
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
sourcepub fn conflicts_with_all(
self,
ns: impl IntoIterator<Item = impl Into<Id>>
) -> Self
pub fn conflicts_with_all(
self,
ns: impl IntoIterator<Item = impl Into<Id>>
) -> Self
Specify arguments or groups that must not be present when this group is.
Exclusion rules function just like argument exclusion rules, you can name other arguments or groups that must not be present when one of the arguments from this group are used.
NOTE: The names provided may be an argument, or group name
Examples
let result = Command::new("myprog")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("color")
.short('c')
.action(ArgAction::SetTrue))
.arg(Arg::new("debug")
.short('d')
.action(ArgAction::SetTrue))
.arg(Arg::new("verb")
.short('v')
.action(ArgAction::SetTrue))
.group(ArgGroup::new("req_flags")
.args(["flag", "color"])
.conflicts_with_all(["debug", "verb"]))
.try_get_matches_from(vec!["myprog", "-c", "-v"]);
// because we used an arg from the group, and the group conflicts with either "-v" or "-d"
// it's an error
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
source§impl ArgGroup
impl ArgGroup
sourcepub fn get_id(&self) -> &Id
pub fn get_id(&self) -> &Id
Get the name of the group
Examples found in repository?
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
pub(crate) fn new(_cmd: &Command) -> Self {
ArgMatcher {
matches: ArgMatches {
#[cfg(debug_assertions)]
valid_args: {
let args = _cmd.get_arguments().map(|a| a.get_id().clone());
let groups = _cmd.get_groups().map(|g| g.get_id().clone());
args.chain(groups).collect()
},
#[cfg(debug_assertions)]
valid_subcommands: _cmd
.get_subcommands()
.map(|sc| sc.get_name_str().clone())
.collect(),
..Default::default()
},
pending: None,
}
}
More examples
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
fn validate_required(&mut self, matcher: &ArgMatcher, conflicts: &Conflicts) -> ClapResult<()> {
debug!("Validator::validate_required: required={:?}", self.required);
self.gather_requires(matcher);
let mut missing_required = Vec::new();
let mut highest_index = 0;
let is_exclusive_present = matcher
.args()
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
.any(|(id, _)| {
self.cmd
.find(id)
.map(|arg| arg.is_exclusive_set())
.unwrap_or_default()
});
debug!(
"Validator::validate_required: is_exclusive_present={}",
is_exclusive_present
);
for arg_or_group in self
.required
.iter()
.filter(|r| !matcher.check_explicit(r, &ArgPredicate::IsPresent))
{
debug!("Validator::validate_required:iter:aog={:?}", arg_or_group);
if let Some(arg) = self.cmd.find(arg_or_group) {
debug!("Validator::validate_required:iter: This is an arg");
if !is_exclusive_present && !self.is_missing_required_ok(arg, conflicts) {
debug!(
"Validator::validate_required:iter: Missing {:?}",
arg.get_id()
);
missing_required.push(arg.get_id().clone());
if !arg.is_last_set() {
highest_index = highest_index.max(arg.get_index().unwrap_or(0));
}
}
} else if let Some(group) = self.cmd.find_group(arg_or_group) {
debug!("Validator::validate_required:iter: This is a group");
if !self
.cmd
.unroll_args_in_group(&group.id)
.iter()
.any(|a| matcher.check_explicit(a, &ArgPredicate::IsPresent))
{
debug!(
"Validator::validate_required:iter: Missing {:?}",
group.get_id()
);
missing_required.push(group.get_id().clone());
}
}
}
// Validate the conditionally required args
for a in self
.cmd
.get_arguments()
.filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
{
let mut required = false;
for (other, val) in &a.r_ifs {
if matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) {
debug!(
"Validator::validate_required:iter: Missing {:?}",
a.get_id()
);
required = true;
}
}
let match_all = a.r_ifs_all.iter().all(|(other, val)| {
matcher.check_explicit(other, &ArgPredicate::Equals(val.into()))
});
if match_all && !a.r_ifs_all.is_empty() {
debug!(
"Validator::validate_required:iter: Missing {:?}",
a.get_id()
);
required = true;
}
if (!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
&& self.fails_arg_required_unless(a, matcher)
{
debug!(
"Validator::validate_required:iter: Missing {:?}",
a.get_id()
);
required = true;
}
if required {
missing_required.push(a.get_id().clone());
if !a.is_last_set() {
highest_index = highest_index.max(a.get_index().unwrap_or(0));
}
}
}
// For display purposes, include all of the preceding positional arguments
if !self.cmd.is_allow_missing_positional_set() {
for pos in self
.cmd
.get_positionals()
.filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
{
if pos.get_index() < Some(highest_index) {
debug!(
"Validator::validate_required:iter: Missing {:?}",
pos.get_id()
);
missing_required.push(pos.get_id().clone());
}
}
}
if !missing_required.is_empty() {
ok!(self.missing_required_error(matcher, missing_required));
}
Ok(())
}
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
pub(crate) fn assert_app(cmd: &Command) {
debug!("Command::_debug_asserts");
let mut short_flags = vec![];
let mut long_flags = vec![];
// Invalid version flag settings
if cmd.get_version().is_none() && cmd.get_long_version().is_none() {
// PropagateVersion is meaningless if there is no version
assert!(
!cmd.is_propagate_version_set(),
"Command {}: No version information via Command::version or Command::long_version to propagate",
cmd.get_name(),
);
// Used `Command::mut_arg("version", ..) but did not provide any version information to display
let version_needed = cmd
.get_arguments()
.filter(|x| matches!(x.get_action(), ArgAction::Version))
.map(|x| x.get_id())
.collect::<Vec<_>>();
assert_eq!(version_needed, Vec::<&str>::new(), "Command {}: `ArgAction::Version` used without providing Command::version or Command::long_version"
,cmd.get_name()
);
}
for sc in cmd.get_subcommands() {
if let Some(s) = sc.get_short_flag().as_ref() {
short_flags.push(Flag::Command(format!("-{}", s), sc.get_name()));
}
for short_alias in sc.get_all_short_flag_aliases() {
short_flags.push(Flag::Command(format!("-{}", short_alias), sc.get_name()));
}
if let Some(l) = sc.get_long_flag().as_ref() {
assert!(!l.starts_with('-'), "Command {}: long_flag {:?} must not start with a `-`, that will be handled by the parser", sc.get_name(), l);
long_flags.push(Flag::Command(format!("--{}", l), sc.get_name()));
}
for long_alias in sc.get_all_long_flag_aliases() {
long_flags.push(Flag::Command(format!("--{}", long_alias), sc.get_name()));
}
}
for arg in cmd.get_arguments() {
assert_arg(arg);
assert!(
!cmd.is_multicall_set(),
"Command {}: Arguments like {} cannot be set on a multicall command",
cmd.get_name(),
arg.get_id()
);
if let Some(s) = arg.get_short() {
short_flags.push(Flag::Arg(format!("-{}", s), arg.get_id().as_str()));
}
for (short_alias, _) in &arg.short_aliases {
short_flags.push(Flag::Arg(
format!("-{}", short_alias),
arg.get_id().as_str(),
));
}
if let Some(l) = arg.get_long() {
assert!(!l.starts_with('-'), "Argument {}: long {:?} must not start with a `-`, that will be handled by the parser", arg.get_id(), l);
long_flags.push(Flag::Arg(format!("--{}", l), arg.get_id().as_str()));
}
for (long_alias, _) in &arg.aliases {
long_flags.push(Flag::Arg(
format!("--{}", long_alias),
arg.get_id().as_str(),
));
}
// Name conflicts
if let Some((first, second)) = cmd.two_args_of(|x| x.get_id() == arg.get_id()) {
panic!(
"Command {}: Argument names must be unique, but '{}' is in use by more than one argument or group{}",
cmd.get_name(),
arg.get_id(),
duplicate_tip(cmd, first, second),
);
}
// Long conflicts
if let Some(l) = arg.get_long() {
if let Some((first, second)) = cmd.two_args_of(|x| x.get_long() == Some(l)) {
panic!(
"Command {}: Long option names must be unique for each argument, \
but '--{}' is in use by both '{}' and '{}'{}",
cmd.get_name(),
l,
first.get_id(),
second.get_id(),
duplicate_tip(cmd, first, second)
)
}
}
// Short conflicts
if let Some(s) = arg.get_short() {
if let Some((first, second)) = cmd.two_args_of(|x| x.get_short() == Some(s)) {
panic!(
"Command {}: Short option names must be unique for each argument, \
but '-{}' is in use by both '{}' and '{}'{}",
cmd.get_name(),
s,
first.get_id(),
second.get_id(),
duplicate_tip(cmd, first, second),
)
}
}
// Index conflicts
if let Some(idx) = arg.index {
if let Some((first, second)) =
cmd.two_args_of(|x| x.is_positional() && x.get_index() == Some(idx))
{
panic!(
"Command {}: Argument '{}' has the same index as '{}' \
and they are both positional arguments\n\n\t \
Use `Arg::num_args(1..)` to allow one \
positional argument to take multiple values",
cmd.get_name(),
first.get_id(),
second.get_id()
)
}
}
// requires, r_if, r_unless
for req in &arg.requires {
assert!(
cmd.id_exists(&req.1),
"Command {}: Argument or group '{}' specified in 'requires*' for '{}' does not exist",
cmd.get_name(),
req.1,
arg.get_id(),
);
}
for req in &arg.r_ifs {
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_if_eq*`",
arg.get_id()
);
assert!(
cmd.id_exists(&req.0),
"Command {}: Argument or group '{}' specified in 'required_if_eq*' for '{}' does not exist",
cmd.get_name(),
req.0,
arg.get_id()
);
}
for req in &arg.r_ifs_all {
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_if_eq_all`",
arg.get_id()
);
assert!(
cmd.id_exists(&req.0),
"Command {}: Argument or group '{}' specified in 'required_if_eq_all' for '{}' does not exist",
cmd.get_name(),
req.0,
arg.get_id()
);
}
for req in &arg.r_unless {
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_unless*`",
arg.get_id()
);
assert!(
cmd.id_exists(req),
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
cmd.get_name(),
req,
arg.get_id(),
);
}
for req in &arg.r_unless_all {
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_unless*`",
arg.get_id()
);
assert!(
cmd.id_exists(req),
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
cmd.get_name(),
req,
arg.get_id(),
);
}
// blacklist
for req in &arg.blacklist {
assert!(
cmd.id_exists(req),
"Command {}: Argument or group '{}' specified in 'conflicts_with*' for '{}' does not exist",
cmd.get_name(),
req,
arg.get_id(),
);
}
// overrides
for req in &arg.overrides {
assert!(
cmd.id_exists(req),
"Command {}: Argument or group '{}' specified in 'overrides_with*' for '{}' does not exist",
cmd.get_name(),
req,
arg.get_id(),
);
}
if arg.is_last_set() {
assert!(
arg.get_long().is_none(),
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
cmd.get_name(),
arg.get_id()
);
assert!(
arg.get_short().is_none(),
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
cmd.get_name(),
arg.get_id()
);
}
assert!(
!(arg.is_required_set() && arg.is_global_set()),
"Command {}: Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
cmd.get_name(),
arg.get_id()
);
if arg.get_value_hint() == ValueHint::CommandWithArguments {
assert!(
arg.is_positional(),
"Command {}: Argument '{}' has hint CommandWithArguments and must be positional.",
cmd.get_name(),
arg.get_id()
);
assert!(
arg.is_trailing_var_arg_set() || arg.is_last_set(),
"Command {}: Positional argument '{}' has hint CommandWithArguments, so Command must have `trailing_var_arg(true)` or `last(true)` set.",
cmd.get_name(),
arg.get_id()
);
}
}
for group in cmd.get_groups() {
let derive_hint = if cfg!(feature = "derive") {
" (note: `Args` implicitly creates `ArgGroup`s; disable with `#[group(skip)]`"
} else {
""
};
// Name conflicts
assert!(
cmd.get_groups().filter(|x| x.id == group.id).count() < 2,
"Command {}: Argument group name must be unique\n\n\t'{}' is already in use{}",
cmd.get_name(),
group.get_id(),
derive_hint
);
// Groups should not have naming conflicts with Args
assert!(
!cmd.get_arguments().any(|x| x.get_id() == group.get_id()),
"Command {}: Argument group name '{}' must not conflict with argument name{}",
cmd.get_name(),
group.get_id(),
derive_hint
);
for arg in &group.args {
// Args listed inside groups should exist
assert!(
cmd.get_arguments().any(|x| x.get_id() == arg),
"Command {}: Argument group '{}' contains non-existent argument '{}'",
cmd.get_name(),
group.get_id(),
arg
);
}
}
// Conflicts between flags and subcommands
long_flags.sort_unstable();
short_flags.sort_unstable();
detect_duplicate_flags(&long_flags, "long");
detect_duplicate_flags(&short_flags, "short");
let mut subs = FlatSet::new();
for sc in cmd.get_subcommands() {
assert!(
subs.insert(sc.get_name()),
"Command {}: command name `{}` is duplicated",
cmd.get_name(),
sc.get_name()
);
for alias in sc.get_all_aliases() {
assert!(
subs.insert(alias),
"Command {}: command `{}` alias `{}` is duplicated",
cmd.get_name(),
sc.get_name(),
alias
);
}
}
_verify_positionals(cmd);
#[cfg(feature = "help")]
if let Some(help_template) = cmd.get_help_template() {
assert!(
!help_template.to_string().contains("{flags}"),
"Command {}: {}",
cmd.get_name(),
"`{flags}` template variable was removed in clap3, they are now included in `{options}`",
);
assert!(
!help_template.to_string().contains("{unified}"),
"Command {}: {}",
cmd.get_name(),
"`{unified}` template variable was removed in clap3, use `{options}` instead"
);
#[cfg(feature = "unstable-v5")]
assert!(
!help_template.to_string().contains("{bin}"),
"Command {}: {}",
cmd.get_name(),
"`{bin}` template variable was removed in clap5, use `{name}` instead"
)
}
cmd._panic_on_missing_help(cmd.is_help_expected_set());
assert_app_flags(cmd);
}
sourcepub fn is_required_set(&self) -> bool
pub fn is_required_set(&self) -> bool
Reports whether ArgGroup::required
is set