1// Internal 2use crate::builder::StyledStr; 3use crate::builder::{Arg, ArgGroup, ArgPredicate, Command, PossibleValue}; 4use crate::error::{Error, Result as ClapResult}; 5use crate::output::Usage; 6use crate::parser::{ArgMatcher, ParseState}; 7use crate::util::ChildGraph; 8use crate::util::FlatMap; 9use crate::util::FlatSet; 10use crate::util::Id; 11use crate::INTERNAL_ERROR_MSG; 12 13pub(crate) struct Validator<'cmd> { 14 cmd: &'cmd Command, 15 required: ChildGraph<Id>, 16} 17 18impl<'cmd> Validator<'cmd> { 19 pub(crate) fn new(cmd: &'cmd Command) -> Self { 20 let required = cmd.required_graph(); 21 Validator { cmd, required } 22 } 23 24 pub(crate) fn validate( 25 &mut self, 26 parse_state: ParseState, 27 matcher: &mut ArgMatcher, 28 ) -> ClapResult<()> { 29 debug!("Validator::validate"); 30 let conflicts = Conflicts::with_args(self.cmd, matcher); 31 let has_subcmd = matcher.subcommand_name().is_some(); 32 33 if let ParseState::Opt(a) = parse_state { 34 debug!("Validator::validate: needs_val_of={:?}", a); 35 36 let o = &self.cmd[&a]; 37 let should_err = if let Some(v) = matcher.args.get(o.get_id()) { 38 v.all_val_groups_empty() && o.get_min_vals() != 0 39 } else { 40 true 41 }; 42 if should_err { 43 return Err(Error::empty_value( 44 self.cmd, 45 &get_possible_values_cli(o) 46 .iter() 47 .filter(|pv| !pv.is_hide_set()) 48 .map(|n| n.get_name().to_owned()) 49 .collect::<Vec<_>>(), 50 o.to_string(), 51 )); 52 } 53 } 54 55 if !has_subcmd && self.cmd.is_arg_required_else_help_set() { 56 let num_user_values = matcher 57 .args() 58 .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 59 .count(); 60 if num_user_values == 0 { 61 let message = self.cmd.write_help_err(false); 62 return Err(Error::display_help_error(self.cmd, message)); 63 } 64 } 65 if !has_subcmd && self.cmd.is_subcommand_required_set() { 66 let bn = self 67 .cmd 68 .get_bin_name() 69 .unwrap_or_else(|| self.cmd.get_name()); 70 return Err(Error::missing_subcommand( 71 self.cmd, 72 bn.to_string(), 73 self.cmd 74 .all_subcommand_names() 75 .map(|s| s.to_owned()) 76 .collect::<Vec<_>>(), 77 Usage::new(self.cmd) 78 .required(&self.required) 79 .create_usage_with_title(&[]), 80 )); 81 } 82 83 ok!(self.validate_conflicts(matcher, &conflicts)); 84 if !(self.cmd.is_subcommand_negates_reqs_set() && has_subcmd) { 85 ok!(self.validate_required(matcher, &conflicts)); 86 } 87 88 Ok(()) 89 } 90 91 fn validate_conflicts( 92 &mut self, 93 matcher: &ArgMatcher, 94 conflicts: &Conflicts, 95 ) -> ClapResult<()> { 96 debug!("Validator::validate_conflicts"); 97 98 ok!(self.validate_exclusive(matcher)); 99 100 for (arg_id, _) in matcher 101 .args() 102 .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 103 .filter(|(arg_id, _)| self.cmd.find(arg_id).is_some()) 104 { 105 debug!("Validator::validate_conflicts::iter: id={:?}", arg_id); 106 let conflicts = conflicts.gather_conflicts(self.cmd, arg_id); 107 ok!(self.build_conflict_err(arg_id, &conflicts, matcher)); 108 } 109 110 Ok(()) 111 } 112 113 fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> { 114 debug!("Validator::validate_exclusive"); 115 let args_count = matcher 116 .args() 117 .filter(|(arg_id, matched)| { 118 matched.check_explicit(&crate::builder::ArgPredicate::IsPresent) 119 // Avoid including our own groups by checking none of them. If a group is present, the 120 // args for the group will be. 121 && self.cmd.find(arg_id).is_some() 122 }) 123 .count(); 124 if args_count <= 1 { 125 // Nothing present to conflict with 126 return Ok(()); 127 } 128 129 matcher 130 .args() 131 .filter(|(_, matched)| matched.check_explicit(&crate::builder::ArgPredicate::IsPresent)) 132 .filter_map(|(id, _)| { 133 debug!("Validator::validate_exclusive:iter:{:?}", id); 134 self.cmd 135 .find(id) 136 // Find `arg`s which are exclusive but also appear with other args. 137 .filter(|&arg| arg.is_exclusive_set() && args_count > 1) 138 }) 139 // Throw an error for the first conflict found. 140 .try_for_each(|arg| { 141 Err(Error::argument_conflict( 142 self.cmd, 143 arg.to_string(), 144 Vec::new(), 145 Usage::new(self.cmd) 146 .required(&self.required) 147 .create_usage_with_title(&[]), 148 )) 149 }) 150 } 151 152 fn build_conflict_err( 153 &self, 154 name: &Id, 155 conflict_ids: &[Id], 156 matcher: &ArgMatcher, 157 ) -> ClapResult<()> { 158 if conflict_ids.is_empty() { 159 return Ok(()); 160 } 161 162 debug!("Validator::build_conflict_err: name={:?}", name); 163 let mut seen = FlatSet::new(); 164 let conflicts = conflict_ids 165 .iter() 166 .flat_map(|c_id| { 167 if self.cmd.find_group(c_id).is_some() { 168 self.cmd.unroll_args_in_group(c_id) 169 } else { 170 vec![c_id.clone()] 171 } 172 }) 173 .filter_map(|c_id| { 174 seen.insert(c_id.clone()).then(|| { 175 let c_arg = self.cmd.find(&c_id).expect(INTERNAL_ERROR_MSG); 176 c_arg.to_string() 177 }) 178 }) 179 .collect(); 180 181 let former_arg = self.cmd.find(name).expect(INTERNAL_ERROR_MSG); 182 let usg = self.build_conflict_err_usage(matcher, conflict_ids); 183 Err(Error::argument_conflict( 184 self.cmd, 185 former_arg.to_string(), 186 conflicts, 187 usg, 188 )) 189 } 190 191 fn build_conflict_err_usage( 192 &self, 193 matcher: &ArgMatcher, 194 conflicting_keys: &[Id], 195 ) -> Option<StyledStr> { 196 let used_filtered: Vec<Id> = matcher 197 .args() 198 .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 199 .map(|(n, _)| n) 200 .filter(|n| { 201 // Filter out the args we don't want to specify. 202 self.cmd.find(n).map_or(false, |a| !a.is_hide_set()) 203 }) 204 .filter(|key| !conflicting_keys.contains(key)) 205 .cloned() 206 .collect(); 207 let required: Vec<Id> = used_filtered 208 .iter() 209 .filter_map(|key| self.cmd.find(key)) 210 .flat_map(|arg| arg.requires.iter().map(|item| &item.1)) 211 .filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key)) 212 .chain(used_filtered.iter()) 213 .cloned() 214 .collect(); 215 Usage::new(self.cmd) 216 .required(&self.required) 217 .create_usage_with_title(&required) 218 } 219 220 fn gather_requires(&mut self, matcher: &ArgMatcher) { 221 debug!("Validator::gather_requires"); 222 for (name, matched) in matcher 223 .args() 224 .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 225 { 226 debug!("Validator::gather_requires:iter:{:?}", name); 227 if let Some(arg) = self.cmd.find(name) { 228 let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> { 229 let required = matched.check_explicit(val); 230 required.then(|| req_arg.clone()) 231 }; 232 233 for req in self.cmd.unroll_arg_requires(is_relevant, arg.get_id()) { 234 self.required.insert(req); 235 } 236 } else if let Some(g) = self.cmd.find_group(name) { 237 debug!("Validator::gather_requires:iter:{:?}:group", name); 238 for r in &g.requires { 239 self.required.insert(r.clone()); 240 } 241 } 242 } 243 } 244 245 fn validate_required(&mut self, matcher: &ArgMatcher, conflicts: &Conflicts) -> ClapResult<()> { 246 debug!("Validator::validate_required: required={:?}", self.required); 247 self.gather_requires(matcher); 248 249 let mut missing_required = Vec::new(); 250 let mut highest_index = 0; 251 252 let is_exclusive_present = matcher 253 .args() 254 .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 255 .any(|(id, _)| { 256 self.cmd 257 .find(id) 258 .map(|arg| arg.is_exclusive_set()) 259 .unwrap_or_default() 260 }); 261 debug!( 262 "Validator::validate_required: is_exclusive_present={}", 263 is_exclusive_present 264 ); 265 266 for arg_or_group in self 267 .required 268 .iter() 269 .filter(|r| !matcher.check_explicit(r, &ArgPredicate::IsPresent)) 270 { 271 debug!("Validator::validate_required:iter:aog={:?}", arg_or_group); 272 if let Some(arg) = self.cmd.find(arg_or_group) { 273 debug!("Validator::validate_required:iter: This is an arg"); 274 if !is_exclusive_present && !self.is_missing_required_ok(arg, conflicts) { 275 debug!( 276 "Validator::validate_required:iter: Missing {:?}", 277 arg.get_id() 278 ); 279 missing_required.push(arg.get_id().clone()); 280 if !arg.is_last_set() { 281 highest_index = highest_index.max(arg.get_index().unwrap_or(0)); 282 } 283 } 284 } else if let Some(group) = self.cmd.find_group(arg_or_group) { 285 debug!("Validator::validate_required:iter: This is a group"); 286 if !self 287 .cmd 288 .unroll_args_in_group(&group.id) 289 .iter() 290 .any(|a| matcher.check_explicit(a, &ArgPredicate::IsPresent)) 291 { 292 debug!( 293 "Validator::validate_required:iter: Missing {:?}", 294 group.get_id() 295 ); 296 missing_required.push(group.get_id().clone()); 297 } 298 } 299 } 300 301 // Validate the conditionally required args 302 for a in self 303 .cmd 304 .get_arguments() 305 .filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent)) 306 { 307 let mut required = false; 308 309 for (other, val) in &a.r_ifs { 310 if matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) { 311 debug!( 312 "Validator::validate_required:iter: Missing {:?}", 313 a.get_id() 314 ); 315 required = true; 316 } 317 } 318 319 let match_all = a.r_ifs_all.iter().all(|(other, val)| { 320 matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) 321 }); 322 if match_all && !a.r_ifs_all.is_empty() { 323 debug!( 324 "Validator::validate_required:iter: Missing {:?}", 325 a.get_id() 326 ); 327 required = true; 328 } 329 330 if (!a.r_unless.is_empty() || !a.r_unless_all.is_empty()) 331 && self.fails_arg_required_unless(a, matcher) 332 { 333 debug!( 334 "Validator::validate_required:iter: Missing {:?}", 335 a.get_id() 336 ); 337 required = true; 338 } 339 340 if required { 341 missing_required.push(a.get_id().clone()); 342 if !a.is_last_set() { 343 highest_index = highest_index.max(a.get_index().unwrap_or(0)); 344 } 345 } 346 } 347 348 // For display purposes, include all of the preceding positional arguments 349 if !self.cmd.is_allow_missing_positional_set() { 350 for pos in self 351 .cmd 352 .get_positionals() 353 .filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent)) 354 { 355 if pos.get_index() < Some(highest_index) { 356 debug!( 357 "Validator::validate_required:iter: Missing {:?}", 358 pos.get_id() 359 ); 360 missing_required.push(pos.get_id().clone()); 361 } 362 } 363 } 364 365 if !missing_required.is_empty() { 366 ok!(self.missing_required_error(matcher, missing_required)); 367 } 368 369 Ok(()) 370 } 371 372 fn is_missing_required_ok(&self, a: &Arg, conflicts: &Conflicts) -> bool { 373 debug!("Validator::is_missing_required_ok: {}", a.get_id()); 374 if !conflicts.gather_conflicts(self.cmd, a.get_id()).is_empty() { 375 debug!("Validator::is_missing_required_ok: true (self)"); 376 return true; 377 } 378 for group_id in self.cmd.groups_for_arg(a.get_id()) { 379 if !conflicts.gather_conflicts(self.cmd, &group_id).is_empty() { 380 debug!("Validator::is_missing_required_ok: true ({})", group_id); 381 return true; 382 } 383 } 384 false 385 } 386 387 // Failing a required unless means, the arg's "unless" wasn't present, and neither were they 388 fn fails_arg_required_unless(&self, a: &Arg, matcher: &ArgMatcher) -> bool { 389 debug!("Validator::fails_arg_required_unless: a={:?}", a.get_id()); 390 let exists = |id| matcher.check_explicit(id, &ArgPredicate::IsPresent); 391 392 (a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists)) 393 && !a.r_unless.iter().any(exists) 394 } 395 396 // `req_args`: an arg to include in the error even if not used 397 fn missing_required_error( 398 &self, 399 matcher: &ArgMatcher, 400 raw_req_args: Vec<Id>, 401 ) -> ClapResult<()> { 402 debug!("Validator::missing_required_error; incl={:?}", raw_req_args); 403 debug!( 404 "Validator::missing_required_error: reqs={:?}", 405 self.required 406 ); 407 408 let usg = Usage::new(self.cmd).required(&self.required); 409 410 let req_args = { 411 #[cfg(feature = "usage")] 412 { 413 usg.get_required_usage_from(&raw_req_args, Some(matcher), true) 414 .into_iter() 415 .map(|s| s.to_string()) 416 .collect::<Vec<_>>() 417 } 418 419 #[cfg(not(feature = "usage"))] 420 { 421 raw_req_args 422 .iter() 423 .map(|id| { 424 if let Some(arg) = self.cmd.find(id) { 425 arg.to_string() 426 } else if let Some(_group) = self.cmd.find_group(id) { 427 self.cmd.format_group(id).to_string() 428 } else { 429 debug_assert!(false, "id={:?} is unknown", id); 430 "".to_owned() 431 } 432 }) 433 .collect::<Vec<_>>() 434 } 435 }; 436 437 debug!( 438 "Validator::missing_required_error: req_args={:#?}", 439 req_args 440 ); 441 442 let used: Vec<Id> = matcher 443 .args() 444 .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 445 .map(|(n, _)| n) 446 .filter(|n| { 447 // Filter out the args we don't want to specify. 448 self.cmd.find(n).map_or(false, |a| !a.is_hide_set()) 449 }) 450 .cloned() 451 .chain(raw_req_args) 452 .collect(); 453 454 Err(Error::missing_required_argument( 455 self.cmd, 456 req_args, 457 usg.create_usage_with_title(&used), 458 )) 459 } 460} 461 462#[derive(Default, Clone, Debug)] 463struct Conflicts { 464 potential: FlatMap<Id, Vec<Id>>, 465} 466 467impl Conflicts { 468 fn with_args(cmd: &Command, matcher: &ArgMatcher) -> Self { 469 let mut potential = FlatMap::new(); 470 potential.extend_unchecked( 471 matcher 472 .args() 473 .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 474 .map(|(id, _)| { 475 let conf = gather_direct_conflicts(cmd, id); 476 (id.clone(), conf) 477 }), 478 ); 479 Self { potential } 480 } 481 482 fn gather_conflicts(&self, cmd: &Command, arg_id: &Id) -> Vec<Id> { 483 debug!("Conflicts::gather_conflicts: arg={:?}", arg_id); 484 let mut conflicts = Vec::new(); 485 486 let arg_id_conflicts_storage; 487 let arg_id_conflicts = if let Some(arg_id_conflicts) = self.get_direct_conflicts(arg_id) { 488 arg_id_conflicts 489 } else { 490 // `is_missing_required_ok` is a case where we check not-present args for conflicts 491 arg_id_conflicts_storage = gather_direct_conflicts(cmd, arg_id); 492 &arg_id_conflicts_storage 493 }; 494 for (other_arg_id, other_arg_id_conflicts) in self.potential.iter() { 495 if arg_id == other_arg_id { 496 continue; 497 } 498 499 if arg_id_conflicts.contains(other_arg_id) { 500 conflicts.push(other_arg_id.clone()); 501 } 502 if other_arg_id_conflicts.contains(arg_id) { 503 conflicts.push(other_arg_id.clone()); 504 } 505 } 506 507 debug!("Conflicts::gather_conflicts: conflicts={:?}", conflicts); 508 conflicts 509 } 510 511 fn get_direct_conflicts(&self, arg_id: &Id) -> Option<&[Id]> { 512 self.potential.get(arg_id).map(Vec::as_slice) 513 } 514} 515 516fn gather_direct_conflicts(cmd: &Command, id: &Id) -> Vec<Id> { 517 let conf = if let Some(arg) = cmd.find(id) { 518 gather_arg_direct_conflicts(cmd, arg) 519 } else if let Some(group) = cmd.find_group(id) { 520 gather_group_direct_conflicts(group) 521 } else { 522 debug_assert!(false, "id={id:?} is unknown"); 523 Vec::new() 524 }; 525 debug!("Conflicts::gather_direct_conflicts id={id:?}, conflicts={conf:?}",); 526 conf 527} 528 529fn gather_arg_direct_conflicts(cmd: &Command, arg: &Arg) -> Vec<Id> { 530 let mut conf = arg.blacklist.clone(); 531 for group_id in cmd.groups_for_arg(arg.get_id()) { 532 let group = cmd.find_group(&group_id).expect(INTERNAL_ERROR_MSG); 533 conf.extend(group.conflicts.iter().cloned()); 534 if !group.multiple { 535 for member_id in &group.args { 536 if member_id != arg.get_id() { 537 conf.push(member_id.clone()); 538 } 539 } 540 } 541 } 542 543 // Overrides are implicitly conflicts 544 conf.extend(arg.overrides.iter().cloned()); 545 546 conf 547} 548 549fn gather_group_direct_conflicts(group: &ArgGroup) -> Vec<Id> { 550 group.conflicts.clone() 551} 552 553pub(crate) fn get_possible_values_cli(a: &Arg) -> Vec<PossibleValue> { 554 if !a.is_takes_value_set() { 555 vec![] 556 } else { 557 a.get_value_parser() 558 .possible_values() 559 .map(|pvs| pvs.collect()) 560 .unwrap_or_default() 561 } 562} 563