clap/app/
validator.rs

1// std
2#[allow(deprecated, unused_imports)]
3use std::{ascii::AsciiExt, fmt::Display};
4
5// Internal
6use crate::{
7    app::{
8        parser::{ParseResult, Parser},
9        settings::AppSettings as AS,
10        usage,
11    },
12    args::{settings::ArgSettings, AnyArg, ArgMatcher, MatchedArg},
13    errors::{Error, ErrorKind, Result as ClapResult},
14    fmt::{Colorizer, ColorizerOption},
15    INTERNAL_ERROR_MSG, INVALID_UTF8,
16};
17
18pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
19where
20    'a: 'b,
21    'b: 'z;
22
23impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
24    pub fn new(p: &'z mut Parser<'a, 'b>) -> Self {
25        Validator(p)
26    }
27
28    pub fn validate(
29        &mut self,
30        needs_val_of: ParseResult<'a>,
31        subcmd_name: Option<String>,
32        matcher: &mut ArgMatcher<'a>,
33    ) -> ClapResult<()> {
34        debugln!("Validator::validate;");
35        let mut reqs_validated = false;
36        self.0.add_env(matcher)?;
37        self.0.add_defaults(matcher)?;
38        if let ParseResult::Opt(a) = needs_val_of {
39            debugln!("Validator::validate: needs_val_of={:?}", a);
40            let o = {
41                self.0
42                    .opts
43                    .iter()
44                    .find(|o| o.b.name == a)
45                    .expect(INTERNAL_ERROR_MSG)
46                    .clone()
47            };
48            self.validate_required(matcher)?;
49            reqs_validated = true;
50            let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
51                v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
52            } else {
53                true
54            };
55            if should_err {
56                return Err(Error::empty_value(
57                    &o,
58                    &*usage::create_error_usage(self.0, matcher, None),
59                    self.0.color(),
60                ));
61            }
62        }
63
64        if matcher.is_empty()
65            && matcher.subcommand_name().is_none()
66            && self.0.is_set(AS::ArgRequiredElseHelp)
67        {
68            let mut out = vec![];
69            self.0.write_help_err(&mut out)?;
70            return Err(Error {
71                message: String::from_utf8_lossy(&*out).into_owned(),
72                kind: ErrorKind::MissingArgumentOrSubcommand,
73                info: None,
74            });
75        }
76        self.validate_blacklist(matcher)?;
77        if !(reqs_validated || self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) {
78            self.validate_required(matcher)?;
79        }
80        self.validate_matched_args(matcher)?;
81        matcher.usage(usage::create_usage_with_title(self.0, &[]));
82
83        Ok(())
84    }
85
86    fn validate_arg_values<A>(
87        &self,
88        arg: &A,
89        ma: &MatchedArg,
90        matcher: &ArgMatcher<'a>,
91    ) -> ClapResult<()>
92    where
93        A: AnyArg<'a, 'b> + Display,
94    {
95        debugln!("Validator::validate_arg_values: arg={:?}", arg.name());
96        for val in &ma.vals {
97            if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
98                debugln!(
99                    "Validator::validate_arg_values: invalid UTF-8 found in val {:?}",
100                    val
101                );
102                return Err(Error::invalid_utf8(
103                    &*usage::create_error_usage(self.0, matcher, None),
104                    self.0.color(),
105                ));
106            }
107            if let Some(p_vals) = arg.possible_vals() {
108                debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals);
109                let val_str = val.to_string_lossy();
110                let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
111                    p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str))
112                } else {
113                    p_vals.contains(&&*val_str)
114                };
115                if !ok {
116                    return Err(Error::invalid_value(
117                        val_str,
118                        p_vals,
119                        arg,
120                        &*usage::create_error_usage(self.0, matcher, None),
121                        self.0.color(),
122                    ));
123                }
124            }
125            if !arg.is_set(ArgSettings::EmptyValues)
126                && val.is_empty()
127                && matcher.contains(&*arg.name())
128            {
129                debugln!("Validator::validate_arg_values: illegal empty val found");
130                return Err(Error::empty_value(
131                    arg,
132                    &*usage::create_error_usage(self.0, matcher, None),
133                    self.0.color(),
134                ));
135            }
136            if let Some(vtor) = arg.validator() {
137                debug!("Validator::validate_arg_values: checking validator...");
138                if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
139                    sdebugln!("error");
140                    return Err(Error::value_validation(Some(arg), e, self.0.color()));
141                } else {
142                    sdebugln!("good");
143                }
144            }
145            if let Some(vtor) = arg.validator_os() {
146                debug!("Validator::validate_arg_values: checking validator_os...");
147                if let Err(e) = vtor(val) {
148                    sdebugln!("error");
149                    return Err(Error::value_validation(
150                        Some(arg),
151                        (*e).to_string_lossy().to_string(),
152                        self.0.color(),
153                    ));
154                } else {
155                    sdebugln!("good");
156                }
157            }
158        }
159        Ok(())
160    }
161
162    fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> {
163        debugln!("build_err!: name={}", name);
164        let mut c_with = find_from!(self.0, &name, blacklist, matcher);
165        c_with = c_with.or_else(|| {
166            self.0
167                .find_any_arg(name)
168                .and_then(|aa| aa.blacklist())
169                .and_then(|bl| bl.iter().find(|arg| matcher.contains(arg)))
170                .and_then(|an| self.0.find_any_arg(an))
171                .map(|aa| format!("{}", aa))
172        });
173        debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
174        //        matcher.remove(&name);
175        let usg = usage::create_error_usage(self.0, matcher, None);
176        if let Some(f) = find_by_name!(self.0, name, flags, iter) {
177            debugln!("build_err!: It was a flag...");
178            Err(Error::argument_conflict(f, c_with, &*usg, self.0.color()))
179        } else if let Some(o) = find_by_name!(self.0, name, opts, iter) {
180            debugln!("build_err!: It was an option...");
181            Err(Error::argument_conflict(o, c_with, &*usg, self.0.color()))
182        } else {
183            match find_by_name!(self.0, name, positionals, values) {
184                Some(p) => {
185                    debugln!("build_err!: It was a positional...");
186                    Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
187                }
188                None => panic!("{}", INTERNAL_ERROR_MSG),
189            }
190        }
191    }
192
193    fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
194        debugln!("Validator::validate_blacklist;");
195        let mut conflicts: Vec<&str> = vec![];
196        for (&name, _) in matcher.iter() {
197            debugln!("Validator::validate_blacklist:iter:{};", name);
198            if let Some(grps) = self.0.groups_for_arg(name) {
199                for grp in &grps {
200                    if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) {
201                        if !g.multiple {
202                            for arg in &g.args {
203                                if arg == &name {
204                                    continue;
205                                }
206                                conflicts.push(arg);
207                            }
208                        }
209                        if let Some(ref gc) = g.conflicts {
210                            conflicts.extend(&*gc);
211                        }
212                    }
213                }
214            }
215            if let Some(arg) = find_any_by_name!(self.0, name) {
216                if let Some(bl) = arg.blacklist() {
217                    for conf in bl {
218                        if matcher.get(conf).is_some() {
219                            conflicts.push(conf);
220                        }
221                    }
222                }
223            } else {
224                debugln!("Validator::validate_blacklist:iter:{}:group;", name);
225                let args = self.0.arg_names_in_group(name);
226                for arg in &args {
227                    debugln!(
228                        "Validator::validate_blacklist:iter:{}:group:iter:{};",
229                        name,
230                        arg
231                    );
232                    if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() {
233                        for conf in bl {
234                            if matcher.get(conf).is_some() {
235                                conflicts.push(conf);
236                            }
237                        }
238                    }
239                }
240            }
241        }
242
243        for name in &conflicts {
244            debugln!(
245                "Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
246                name
247            );
248            let mut should_err = false;
249            if self.0.groups.iter().any(|g| &g.name == name) {
250                debugln!(
251                    "Validator::validate_blacklist:iter:{}: groups contains it...",
252                    name
253                );
254                for n in self.0.arg_names_in_group(name) {
255                    debugln!(
256                        "Validator::validate_blacklist:iter:{}:iter:{}: looking in group...",
257                        name,
258                        n
259                    );
260                    if matcher.contains(n) {
261                        debugln!(
262                            "Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...",
263                            name,
264                            n
265                        );
266                        return self.build_err(n, matcher);
267                    }
268                }
269            } else if let Some(ma) = matcher.get(name) {
270                debugln!(
271                    "Validator::validate_blacklist:iter:{}: matcher contains it...",
272                    name
273                );
274                should_err = ma.occurs > 0;
275            }
276            if should_err {
277                return self.build_err(*name, matcher);
278            }
279        }
280        Ok(())
281    }
282
283    fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
284        debugln!("Validator::validate_matched_args;");
285        for (name, ma) in matcher.iter() {
286            debugln!(
287                "Validator::validate_matched_args:iter:{}: vals={:#?}",
288                name,
289                ma.vals
290            );
291            if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
292                self.validate_arg_num_vals(opt, ma, matcher)?;
293                self.validate_arg_values(opt, ma, matcher)?;
294                self.validate_arg_requires(opt, ma, matcher)?;
295                self.validate_arg_num_occurs(opt, ma, matcher)?;
296            } else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
297                self.validate_arg_requires(flag, ma, matcher)?;
298                self.validate_arg_num_occurs(flag, ma, matcher)?;
299            } else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
300                self.validate_arg_num_vals(pos, ma, matcher)?;
301                self.validate_arg_num_occurs(pos, ma, matcher)?;
302                self.validate_arg_values(pos, ma, matcher)?;
303                self.validate_arg_requires(pos, ma, matcher)?;
304            } else {
305                let grp = self
306                    .0
307                    .groups
308                    .iter()
309                    .find(|g| &g.name == name)
310                    .expect(INTERNAL_ERROR_MSG);
311                if let Some(ref g_reqs) = grp.requires {
312                    if g_reqs.iter().any(|&n| !matcher.contains(n)) {
313                        return self.missing_required_error(matcher, None);
314                    }
315                }
316            }
317        }
318        Ok(())
319    }
320
321    fn validate_arg_num_occurs<A>(
322        &self,
323        a: &A,
324        ma: &MatchedArg,
325        matcher: &ArgMatcher,
326    ) -> ClapResult<()>
327    where
328        A: AnyArg<'a, 'b> + Display,
329    {
330        debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
331        if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
332            // Not the first time, and we don't allow multiples
333            return Err(Error::unexpected_multiple_usage(
334                a,
335                &*usage::create_error_usage(self.0, matcher, None),
336                self.0.color(),
337            ));
338        }
339        Ok(())
340    }
341
342    fn validate_arg_num_vals<A>(
343        &self,
344        a: &A,
345        ma: &MatchedArg,
346        matcher: &ArgMatcher,
347    ) -> ClapResult<()>
348    where
349        A: AnyArg<'a, 'b> + Display,
350    {
351        debugln!("Validator::validate_arg_num_vals:{}", a.name());
352        if let Some(num) = a.num_vals() {
353            debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num);
354            let should_err = if a.is_set(ArgSettings::Multiple) {
355                ((ma.vals.len() as u64) % num) != 0
356            } else {
357                num != (ma.vals.len() as u64)
358            };
359            if should_err {
360                debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
361                return Err(Error::wrong_number_of_values(
362                    a,
363                    num,
364                    if a.is_set(ArgSettings::Multiple) {
365                        ma.vals.len() % num as usize
366                    } else {
367                        ma.vals.len()
368                    },
369                    if ma.vals.len() == 1
370                        || (a.is_set(ArgSettings::Multiple) && (ma.vals.len() % num as usize) == 1)
371                    {
372                        "as"
373                    } else {
374                        "ere"
375                    },
376                    &*usage::create_error_usage(self.0, matcher, None),
377                    self.0.color(),
378                ));
379            }
380        }
381        if let Some(num) = a.max_vals() {
382            debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
383            if (ma.vals.len() as u64) > num {
384                debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
385                return Err(Error::too_many_values(
386                    ma.vals
387                        .iter()
388                        .last()
389                        .expect(INTERNAL_ERROR_MSG)
390                        .to_str()
391                        .expect(INVALID_UTF8),
392                    a,
393                    &*usage::create_error_usage(self.0, matcher, None),
394                    self.0.color(),
395                ));
396            }
397        }
398        let min_vals_zero = if let Some(num) = a.min_vals() {
399            debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
400            if (ma.vals.len() as u64) < num && num != 0 {
401                debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
402                return Err(Error::too_few_values(
403                    a,
404                    num,
405                    ma.vals.len(),
406                    &*usage::create_error_usage(self.0, matcher, None),
407                    self.0.color(),
408                ));
409            }
410            num == 0
411        } else {
412            false
413        };
414        // Issue 665 (https://github.com/clap-rs/clap/issues/665)
415        // Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
416        if a.takes_value() && !min_vals_zero && ma.vals.is_empty() {
417            return Err(Error::empty_value(
418                a,
419                &*usage::create_error_usage(self.0, matcher, None),
420                self.0.color(),
421            ));
422        }
423        Ok(())
424    }
425
426    fn validate_arg_requires<A>(
427        &self,
428        a: &A,
429        ma: &MatchedArg,
430        matcher: &ArgMatcher,
431    ) -> ClapResult<()>
432    where
433        A: AnyArg<'a, 'b> + Display,
434    {
435        debugln!("Validator::validate_arg_requires:{};", a.name());
436        if let Some(a_reqs) = a.requires() {
437            for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
438                let missing_req =
439                    |v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name);
440                if ma.vals.iter().any(missing_req) {
441                    return self.missing_required_error(matcher, None);
442                }
443            }
444            for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) {
445                if !matcher.contains(name) {
446                    return self.missing_required_error(matcher, Some(name));
447                }
448            }
449        }
450        Ok(())
451    }
452
453    fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> {
454        debugln!(
455            "Validator::validate_required: required={:?};",
456            self.0.required
457        );
458
459        let mut should_err = false;
460        let mut to_rem = Vec::new();
461        for name in &self.0.required {
462            debugln!("Validator::validate_required:iter:{}:", name);
463            if matcher.contains(name) {
464                continue;
465            }
466            if to_rem.contains(name) {
467                continue;
468            } else if let Some(a) = find_any_by_name!(self.0, *name) {
469                if self.is_missing_required_ok(a, matcher) {
470                    to_rem.push(a.name());
471                    if let Some(reqs) = a.requires() {
472                        for r in reqs
473                            .iter()
474                            .filter(|&&(val, _)| val.is_none())
475                            .map(|&(_, name)| name)
476                        {
477                            to_rem.push(r);
478                        }
479                    }
480                    continue;
481                }
482            }
483            should_err = true;
484            break;
485        }
486        if should_err {
487            for r in &to_rem {
488                'inner: for i in (0..self.0.required.len()).rev() {
489                    if &self.0.required[i] == r {
490                        self.0.required.swap_remove(i);
491                        break 'inner;
492                    }
493                }
494            }
495            return self.missing_required_error(matcher, None);
496        }
497
498        // Validate the conditionally required args
499        for &(a, v, r) in &self.0.r_ifs {
500            if let Some(ma) = matcher.get(a) {
501                if matcher.get(r).is_none() && ma.vals.iter().any(|val| val == v) {
502                    return self.missing_required_error(matcher, Some(r));
503                }
504            }
505        }
506        Ok(())
507    }
508
509    fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
510        debugln!("Validator::validate_arg_conflicts: a={:?};", a.name());
511        a.blacklist().map(|bl| {
512            bl.iter().any(|conf| {
513                matcher.contains(conf)
514                    || self
515                        .0
516                        .groups
517                        .iter()
518                        .find(|g| &g.name == conf)
519                        .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
520            })
521        })
522    }
523
524    fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
525        debugln!("Validator::validate_required_unless: a={:?};", a.name());
526        macro_rules! check {
527            ($how:ident, $_self:expr, $a:ident, $m:ident) => {{
528                $a.required_unless().map(|ru| {
529                    ru.iter().$how(|n| {
530                        $m.contains(n) || {
531                            if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) {
532                                grp.args.iter().any(|arg| $m.contains(arg))
533                            } else {
534                                false
535                            }
536                        }
537                    })
538                })
539            }};
540        }
541        if a.is_set(ArgSettings::RequiredUnlessAll) {
542            check!(all, self.0, a, matcher)
543        } else {
544            check!(any, self.0, a, matcher)
545        }
546    }
547
548    fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
549        debugln!("Validator::missing_required_error: extra={:?}", extra);
550        let c = Colorizer::new(ColorizerOption {
551            use_stderr: true,
552            when: self.0.color(),
553        });
554        let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
555        if let Some(r) = extra {
556            reqs.push(r);
557        }
558        reqs.retain(|n| !matcher.contains(n));
559        reqs.dedup();
560        debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
561        let req_args =
562            usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true)
563                .iter()
564                .fold(String::new(), |acc, s| {
565                    acc + &format!("\n    {}", c.error(s))[..]
566                });
567        debugln!(
568            "Validator::missing_required_error: req_args={:#?}",
569            req_args
570        );
571        Err(Error::missing_required_argument(
572            &*req_args,
573            &*usage::create_error_usage(self.0, matcher, extra),
574            self.0.color(),
575        ))
576    }
577
578    #[inline]
579    fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
580        debugln!("Validator::is_missing_required_ok: a={}", a.name());
581        self.validate_arg_conflicts(a, matcher).unwrap_or(false)
582            || self.validate_required_unless(a, matcher).unwrap_or(false)
583    }
584}