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