1 // Internal 2 use crate::{ 3 build::{arg::PossibleValue, App, AppSettings as AS, Arg, ArgSettings}, 4 output::Usage, 5 parse::{ 6 errors::{Error, ErrorKind, Result as ClapResult}, 7 ArgMatcher, MatchedArg, ParseState, Parser, 8 }, 9 util::Id, 10 INTERNAL_ERROR_MSG, INVALID_UTF8, 11 }; 12 13 pub(crate) struct Validator<'help, 'app, 'parser> { 14 p: &'parser mut Parser<'help, 'app>, 15 } 16 17 impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> { new(p: &'parser mut Parser<'help, 'app>) -> Self18 pub(crate) fn new(p: &'parser mut Parser<'help, 'app>) -> Self { 19 Validator { p } 20 } 21 validate( &mut self, parse_state: ParseState, is_subcmd: bool, matcher: &mut ArgMatcher, trailing_values: bool, ) -> ClapResult<()>22 pub(crate) fn validate( 23 &mut self, 24 parse_state: ParseState, 25 is_subcmd: bool, 26 matcher: &mut ArgMatcher, 27 trailing_values: bool, 28 ) -> ClapResult<()> { 29 debug!("Validator::validate"); 30 let mut reqs_validated = false; 31 32 #[cfg(feature = "env")] 33 self.p.add_env(matcher, trailing_values)?; 34 35 self.p.add_defaults(matcher, trailing_values); 36 37 if let ParseState::Opt(a) = parse_state { 38 debug!("Validator::validate: needs_val_of={:?}", a); 39 self.validate_required(matcher)?; 40 self.validate_required_unless(matcher)?; 41 42 let o = &self.p.app[&a]; 43 reqs_validated = true; 44 let should_err = if let Some(v) = matcher.args.get(&o.id) { 45 v.all_val_groups_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0) 46 } else { 47 true 48 }; 49 if should_err { 50 return Err(Error::empty_value( 51 self.p.app, 52 o, 53 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 54 )); 55 } 56 } 57 58 if matcher.is_empty() 59 && matcher.subcommand_name().is_none() 60 && self.p.is_set(AS::ArgRequiredElseHelp) 61 { 62 let message = self.p.write_help_err()?; 63 return Err(Error::new( 64 message, 65 ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand, 66 self.p.is_set(AS::WaitOnError), 67 )); 68 } 69 self.validate_conflicts(matcher)?; 70 if !(self.p.is_set(AS::SubcommandsNegateReqs) && is_subcmd || reqs_validated) { 71 self.validate_required(matcher)?; 72 self.validate_required_unless(matcher)?; 73 } 74 self.validate_matched_args(matcher)?; 75 76 Ok(()) 77 } 78 validate_arg_values( &self, arg: &Arg, ma: &MatchedArg, matcher: &ArgMatcher, ) -> ClapResult<()>79 fn validate_arg_values( 80 &self, 81 arg: &Arg, 82 ma: &MatchedArg, 83 matcher: &ArgMatcher, 84 ) -> ClapResult<()> { 85 debug!("Validator::validate_arg_values: arg={:?}", arg.name); 86 for val in ma.vals_flatten() { 87 if !arg.is_set(ArgSettings::AllowInvalidUtf8) && val.to_str().is_none() { 88 debug!( 89 "Validator::validate_arg_values: invalid UTF-8 found in val {:?}", 90 val 91 ); 92 return Err(Error::invalid_utf8( 93 self.p.app, 94 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 95 )); 96 } 97 if !arg.possible_vals.is_empty() { 98 debug!( 99 "Validator::validate_arg_values: possible_vals={:?}", 100 arg.possible_vals 101 ); 102 let val_str = val.to_string_lossy(); 103 let ok = arg 104 .possible_vals 105 .iter() 106 .any(|pv| pv.matches(&val_str, arg.is_set(ArgSettings::IgnoreCase))); 107 if !ok { 108 let used: Vec<Id> = matcher 109 .arg_names() 110 .filter(|&n| { 111 self.p.app.find(n).map_or(true, |a| { 112 !(a.is_set(ArgSettings::Hidden) || self.p.required.contains(&a.id)) 113 }) 114 }) 115 .cloned() 116 .collect(); 117 return Err(Error::invalid_value( 118 self.p.app, 119 val_str.into_owned(), 120 &arg.possible_vals 121 .iter() 122 .filter_map(PossibleValue::get_visible_name) 123 .collect::<Vec<_>>(), 124 arg, 125 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&used), 126 )); 127 } 128 } 129 if arg.is_set(ArgSettings::ForbidEmptyValues) 130 && val.is_empty() 131 && matcher.contains(&arg.id) 132 { 133 debug!("Validator::validate_arg_values: illegal empty val found"); 134 return Err(Error::empty_value( 135 self.p.app, 136 arg, 137 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 138 )); 139 } 140 141 if let Some(ref vtor) = arg.validator { 142 debug!("Validator::validate_arg_values: checking validator..."); 143 let mut vtor = vtor.lock().unwrap(); 144 if let Err(e) = vtor(&*val.to_string_lossy()) { 145 debug!("error"); 146 return Err(Error::value_validation( 147 self.p.app, 148 arg.to_string(), 149 val.to_string_lossy().into_owned(), 150 e, 151 )); 152 } else { 153 debug!("good"); 154 } 155 } 156 if let Some(ref vtor) = arg.validator_os { 157 debug!("Validator::validate_arg_values: checking validator_os..."); 158 let mut vtor = vtor.lock().unwrap(); 159 if let Err(e) = vtor(val) { 160 debug!("error"); 161 return Err(Error::value_validation( 162 self.p.app, 163 arg.to_string(), 164 val.to_string_lossy().into(), 165 e, 166 )); 167 } else { 168 debug!("good"); 169 } 170 } 171 } 172 Ok(()) 173 } 174 validate_conflicts(&self, matcher: &ArgMatcher) -> ClapResult<()>175 fn validate_conflicts(&self, matcher: &ArgMatcher) -> ClapResult<()> { 176 debug!("Validator::validate_conflicts"); 177 178 self.validate_exclusive(matcher)?; 179 180 let mut conflicts = Conflicts::new(); 181 for arg_id in matcher 182 .arg_names() 183 .filter(|arg_id| matcher.contains_explicit(arg_id) && self.p.app.find(arg_id).is_some()) 184 { 185 debug!("Validator::validate_conflicts::iter: id={:?}", arg_id); 186 let conflicts = conflicts.gather_conflicts(self.p.app, matcher, arg_id); 187 self.build_conflict_err(arg_id, &conflicts, matcher)?; 188 } 189 190 Ok(()) 191 } 192 validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()>193 fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> { 194 debug!("Validator::validate_exclusive"); 195 let args_count = matcher.arg_names().count(); 196 matcher 197 .arg_names() 198 .filter_map(|name| { 199 debug!("Validator::validate_exclusive:iter:{:?}", name); 200 self.p 201 .app 202 .find(name) 203 // Find `arg`s which are exclusive but also appear with other args. 204 .filter(|&arg| arg.is_set(ArgSettings::Exclusive) && args_count > 1) 205 }) 206 // Throw an error for the first conflict found. 207 .try_for_each(|arg| { 208 Err(Error::argument_conflict( 209 self.p.app, 210 arg, 211 Vec::new(), 212 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 213 )) 214 }) 215 } 216 build_conflict_err( &self, name: &Id, conflict_ids: &[Id], matcher: &ArgMatcher, ) -> ClapResult<()>217 fn build_conflict_err( 218 &self, 219 name: &Id, 220 conflict_ids: &[Id], 221 matcher: &ArgMatcher, 222 ) -> ClapResult<()> { 223 if conflict_ids.is_empty() { 224 return Ok(()); 225 } 226 227 debug!("Validator::build_conflict_err: name={:?}", name); 228 let mut seen = std::collections::HashSet::new(); 229 let conflicts = conflict_ids 230 .iter() 231 .flat_map(|c_id| { 232 if self.p.app.find_group(c_id).is_some() { 233 self.p.app.unroll_args_in_group(c_id) 234 } else { 235 vec![c_id.clone()] 236 } 237 }) 238 .filter_map(|c_id| { 239 seen.insert(c_id.clone()).then(|| { 240 let c_arg = self.p.app.find(&c_id).expect(INTERNAL_ERROR_MSG); 241 c_arg.to_string() 242 }) 243 }) 244 .collect(); 245 246 let former_arg = self.p.app.find(name).expect(INTERNAL_ERROR_MSG); 247 let usg = self.build_conflict_err_usage(matcher, conflict_ids); 248 Err(Error::argument_conflict( 249 self.p.app, former_arg, conflicts, usg, 250 )) 251 } 252 build_conflict_err_usage(&self, matcher: &ArgMatcher, conflicting_keys: &[Id]) -> String253 fn build_conflict_err_usage(&self, matcher: &ArgMatcher, conflicting_keys: &[Id]) -> String { 254 let used_filtered: Vec<Id> = matcher 255 .arg_names() 256 .filter(|key| !conflicting_keys.contains(key)) 257 .cloned() 258 .collect(); 259 let required: Vec<Id> = used_filtered 260 .iter() 261 .filter_map(|key| self.p.app.find(key)) 262 .flat_map(|arg| arg.requires.iter().map(|item| &item.1)) 263 .filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key)) 264 .chain(used_filtered.iter()) 265 .cloned() 266 .collect(); 267 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&required) 268 } 269 gather_requirements(&mut self, matcher: &ArgMatcher)270 fn gather_requirements(&mut self, matcher: &ArgMatcher) { 271 debug!("Validator::gather_requirements"); 272 for name in matcher.arg_names() { 273 debug!("Validator::gather_requirements:iter:{:?}", name); 274 if let Some(arg) = self.p.app.find(name) { 275 for req in self.p.app.unroll_requirements_for_arg(&arg.id, matcher) { 276 self.p.required.insert(req); 277 } 278 } else if let Some(g) = self.p.app.find_group(name) { 279 debug!("Validator::gather_requirements:iter:{:?}:group", name); 280 for r in &g.requires { 281 self.p.required.insert(r.clone()); 282 } 283 } 284 } 285 } 286 validate_matched_args(&self, matcher: &ArgMatcher) -> ClapResult<()>287 fn validate_matched_args(&self, matcher: &ArgMatcher) -> ClapResult<()> { 288 debug!("Validator::validate_matched_args"); 289 matcher.iter().try_for_each(|(name, ma)| { 290 debug!( 291 "Validator::validate_matched_args:iter:{:?}: vals={:#?}", 292 name, 293 ma.vals_flatten() 294 ); 295 if let Some(arg) = self.p.app.find(name) { 296 self.validate_arg_num_vals(arg, ma)?; 297 self.validate_arg_values(arg, ma, matcher)?; 298 self.validate_arg_num_occurs(arg, ma)?; 299 } 300 Ok(()) 301 }) 302 } 303 validate_arg_num_occurs(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()>304 fn validate_arg_num_occurs(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> { 305 debug!( 306 "Validator::validate_arg_num_occurs: {:?}={}", 307 a.name, 308 ma.get_occurrences() 309 ); 310 // Occurrence of positional argument equals to number of values rather 311 // than number of grouped values. 312 if ma.get_occurrences() > 1 313 && !a.is_set(ArgSettings::MultipleOccurrences) 314 && !a.is_positional() 315 { 316 // Not the first time, and we don't allow multiples 317 return Err(Error::unexpected_multiple_usage( 318 self.p.app, 319 a, 320 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 321 )); 322 } 323 if let Some(max_occurs) = a.max_occurs { 324 debug!( 325 "Validator::validate_arg_num_occurs: max_occurs set...{}", 326 max_occurs 327 ); 328 let occurs = ma.get_occurrences() as usize; 329 if occurs > max_occurs { 330 return Err(Error::too_many_occurrences( 331 self.p.app, 332 a, 333 max_occurs, 334 occurs, 335 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 336 )); 337 } 338 } 339 340 Ok(()) 341 } 342 validate_arg_num_vals(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()>343 fn validate_arg_num_vals(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> { 344 debug!("Validator::validate_arg_num_vals"); 345 if let Some(num) = a.num_vals { 346 let total_num = ma.num_vals(); 347 debug!("Validator::validate_arg_num_vals: num_vals set...{}", num); 348 let should_err = if a.is_set(ArgSettings::MultipleOccurrences) { 349 total_num % num != 0 350 } else { 351 num != total_num 352 }; 353 if should_err { 354 debug!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues"); 355 return Err(Error::wrong_number_of_values( 356 self.p.app, 357 a, 358 num, 359 if a.is_set(ArgSettings::MultipleOccurrences) { 360 total_num % num 361 } else { 362 total_num 363 }, 364 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 365 )); 366 } 367 } 368 if let Some(num) = a.max_vals { 369 debug!("Validator::validate_arg_num_vals: max_vals set...{}", num); 370 if ma.num_vals() > num { 371 debug!("Validator::validate_arg_num_vals: Sending error TooManyValues"); 372 return Err(Error::too_many_values( 373 self.p.app, 374 ma.vals_flatten() 375 .last() 376 .expect(INTERNAL_ERROR_MSG) 377 .to_str() 378 .expect(INVALID_UTF8) 379 .to_string(), 380 a.to_string(), 381 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 382 )); 383 } 384 } 385 let min_vals_zero = if let Some(num) = a.min_vals { 386 debug!("Validator::validate_arg_num_vals: min_vals set: {}", num); 387 if ma.num_vals() < num && num != 0 { 388 debug!("Validator::validate_arg_num_vals: Sending error TooFewValues"); 389 return Err(Error::too_few_values( 390 self.p.app, 391 a, 392 num, 393 ma.num_vals(), 394 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 395 )); 396 } 397 num == 0 398 } else { 399 false 400 }; 401 // Issue 665 (https://github.com/clap-rs/clap/issues/665) 402 // Issue 1105 (https://github.com/clap-rs/clap/issues/1105) 403 if a.is_set(ArgSettings::TakesValue) && !min_vals_zero && ma.all_val_groups_empty() { 404 return Err(Error::empty_value( 405 self.p.app, 406 a, 407 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]), 408 )); 409 } 410 Ok(()) 411 } 412 validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()>413 fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> { 414 debug!( 415 "Validator::validate_required: required={:?}", 416 self.p.required 417 ); 418 self.gather_requirements(matcher); 419 420 for arg_or_group in self.p.required.iter().filter(|r| !matcher.contains(r)) { 421 debug!("Validator::validate_required:iter:aog={:?}", arg_or_group); 422 if let Some(arg) = self.p.app.find(arg_or_group) { 423 debug!("Validator::validate_required:iter: This is an arg"); 424 if !self.is_missing_required_ok(arg, matcher) { 425 return self.missing_required_error(matcher, vec![]); 426 } 427 } else if let Some(group) = self.p.app.find_group(arg_or_group) { 428 debug!("Validator::validate_required:iter: This is a group"); 429 if !self 430 .p 431 .app 432 .unroll_args_in_group(&group.id) 433 .iter() 434 .any(|a| matcher.contains(a)) 435 { 436 return self.missing_required_error(matcher, vec![]); 437 } 438 } 439 } 440 441 // Validate the conditionally required args 442 for a in self.p.app.args.args() { 443 for (other, val) in &a.r_ifs { 444 if let Some(ma) = matcher.get(other) { 445 if ma.contains_val(val) && !matcher.contains(&a.id) { 446 return self.missing_required_error(matcher, vec![a.id.clone()]); 447 } 448 } 449 } 450 451 let match_all = a 452 .r_ifs_all 453 .iter() 454 .all(|(other, val)| matcher.get(other).map_or(false, |ma| ma.contains_val(val))); 455 if match_all && !a.r_ifs_all.is_empty() && !matcher.contains(&a.id) { 456 return self.missing_required_error(matcher, vec![a.id.clone()]); 457 } 458 } 459 Ok(()) 460 } 461 is_missing_required_ok(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool462 fn is_missing_required_ok(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool { 463 debug!("Validator::is_missing_required_ok: {}", a.name); 464 self.validate_arg_conflicts(a, matcher) || self.p.overridden.borrow().contains(&a.id) 465 } 466 validate_arg_conflicts(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool467 fn validate_arg_conflicts(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool { 468 debug!("Validator::validate_arg_conflicts: a={:?}", a.name); 469 a.blacklist.iter().any(|conf| { 470 matcher.contains(conf) 471 || self 472 .p 473 .app 474 .find_group(conf) 475 .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg))) 476 }) 477 } 478 validate_required_unless(&self, matcher: &ArgMatcher) -> ClapResult<()>479 fn validate_required_unless(&self, matcher: &ArgMatcher) -> ClapResult<()> { 480 debug!("Validator::validate_required_unless"); 481 let failed_args: Vec<_> = self 482 .p 483 .app 484 .args 485 .args() 486 .filter(|&a| { 487 (!a.r_unless.is_empty() || !a.r_unless_all.is_empty()) 488 && !matcher.contains(&a.id) 489 && self.fails_arg_required_unless(a, matcher) 490 }) 491 .map(|a| a.id.clone()) 492 .collect(); 493 if failed_args.is_empty() { 494 Ok(()) 495 } else { 496 self.missing_required_error(matcher, failed_args) 497 } 498 } 499 500 // Failing a required unless means, the arg's "unless" wasn't present, and neither were they fails_arg_required_unless(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool501 fn fails_arg_required_unless(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool { 502 debug!("Validator::fails_arg_required_unless: a={:?}", a.name); 503 let exists = |id| matcher.contains(id); 504 505 (a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists)) 506 && !a.r_unless.iter().any(exists) 507 } 508 509 // `incl`: an arg to include in the error even if not used missing_required_error(&self, matcher: &ArgMatcher, incl: Vec<Id>) -> ClapResult<()>510 fn missing_required_error(&self, matcher: &ArgMatcher, incl: Vec<Id>) -> ClapResult<()> { 511 debug!("Validator::missing_required_error; incl={:?}", incl); 512 debug!( 513 "Validator::missing_required_error: reqs={:?}", 514 self.p.required 515 ); 516 517 let usg = Usage::new(self.p.app, &self.p.required); 518 519 let req_args = usg.get_required_usage_from(&incl, Some(matcher), true); 520 521 debug!( 522 "Validator::missing_required_error: req_args={:#?}", 523 req_args 524 ); 525 526 let used: Vec<Id> = matcher 527 .arg_names() 528 .filter(|n| { 529 // Filter out the args we don't want to specify. 530 self.p.app.find(n).map_or(true, |a| { 531 !a.is_set(ArgSettings::Hidden) 532 && a.default_vals.is_empty() 533 && !self.p.required.contains(&a.id) 534 }) 535 }) 536 .cloned() 537 .chain(incl) 538 .collect(); 539 540 Err(Error::missing_required_argument( 541 self.p.app, 542 req_args, 543 usg.create_usage_with_title(&used), 544 )) 545 } 546 } 547 548 #[derive(Default, Clone, Debug)] 549 struct Conflicts { 550 potential: std::collections::HashMap<Id, Vec<Id>>, 551 } 552 553 impl Conflicts { new() -> Self554 fn new() -> Self { 555 Self::default() 556 } 557 gather_conflicts(&mut self, app: &App, matcher: &ArgMatcher, arg_id: &Id) -> Vec<Id>558 fn gather_conflicts(&mut self, app: &App, matcher: &ArgMatcher, arg_id: &Id) -> Vec<Id> { 559 debug!("Conflicts::gather_conflicts"); 560 let mut conflicts = Vec::new(); 561 for other_arg_id in matcher 562 .arg_names() 563 .filter(|arg_id| matcher.contains_explicit(arg_id)) 564 { 565 if arg_id == other_arg_id { 566 continue; 567 } 568 569 if self 570 .gather_direct_conflicts(app, arg_id) 571 .contains(other_arg_id) 572 { 573 conflicts.push(other_arg_id.clone()); 574 } 575 if self 576 .gather_direct_conflicts(app, other_arg_id) 577 .contains(arg_id) 578 { 579 conflicts.push(other_arg_id.clone()); 580 } 581 } 582 conflicts 583 } 584 gather_direct_conflicts(&mut self, app: &App, arg_id: &Id) -> &[Id]585 fn gather_direct_conflicts(&mut self, app: &App, arg_id: &Id) -> &[Id] { 586 self.potential.entry(arg_id.clone()).or_insert_with(|| { 587 let conf = if let Some(arg) = app.find(arg_id) { 588 let mut conf = arg.blacklist.clone(); 589 for group_id in app.groups_for_arg(arg_id) { 590 let group = app.find_group(&group_id).expect(INTERNAL_ERROR_MSG); 591 conf.extend(group.conflicts.iter().cloned()); 592 if !group.multiple { 593 for member_id in &group.args { 594 if member_id != arg_id { 595 conf.push(member_id.clone()); 596 } 597 } 598 } 599 } 600 conf 601 } else if let Some(group) = app.find_group(arg_id) { 602 group.conflicts.clone() 603 } else { 604 debug_assert!(false, "id={:?} is unknown", arg_id); 605 Vec::new() 606 }; 607 debug!( 608 "Conflicts::gather_direct_conflicts id={:?}, conflicts={:?}", 609 arg_id, conf 610 ); 611 conf 612 }) 613 } 614 } 615