]> git.proxmox.com Git - rustc.git/blame - src/vendor/clap/src/app/validator.rs
New upstream version 1.18.0+dfsg1
[rustc.git] / src / vendor / clap / src / app / validator.rs
CommitLineData
cc61c64b
XL
1// std
2use std::fmt::Display;
3
4// Internal
5use INTERNAL_ERROR_MSG;
6use INVALID_UTF8;
7use args::{AnyArg, ArgMatcher, MatchedArg};
8use args::settings::ArgSettings;
9use errors::{Error, ErrorKind};
10use errors::Result as ClapResult;
11use osstringext::OsStrExt2;
12use app::settings::AppSettings as AS;
13use app::parser::Parser;
14use fmt::Colorizer;
15use app::usage;
16
17pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
18 where 'a: 'b,
19 'b: 'z;
20
21impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
22 pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) }
23
24 pub fn validate(&mut self,
25 needs_val_of: Option<&'a str>,
26 subcmd_name: Option<String>,
27 matcher: &mut ArgMatcher<'a>)
28 -> ClapResult<()> {
29 debugln!("Validator::validate;");
30 let mut reqs_validated = false;
31 try!(self.0.add_defaults(matcher));
32 if let Some(a) = needs_val_of {
33 debugln!("Validator::validate: needs_val_of={:?}", a);
34 if let Some(o) = find_by_name!(self.0, &a, opts, iter) {
35 try!(self.validate_required(matcher));
36 reqs_validated = true;
37 let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
38 v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
39 } else {
40 true
41 };
42 if should_err {
43 return Err(Error::empty_value(o,
44 &*usage::create_error_usage(self.0,
45 matcher,
46 None),
47 self.0.color()));
48 }
49 }
50 }
51
52 if matcher.is_empty() && matcher.subcommand_name().is_none() &&
53 self.0.is_set(AS::ArgRequiredElseHelp) {
54 let mut out = vec![];
55 try!(self.0.write_help_err(&mut out));
56 return Err(Error {
57 message: String::from_utf8_lossy(&*out).into_owned(),
58 kind: ErrorKind::MissingArgumentOrSubcommand,
59 info: None,
60 });
61 }
62 try!(self.validate_blacklist(matcher));
63 if !(self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated {
64 try!(self.validate_required(matcher));
65 }
66 try!(self.validate_matched_args(matcher));
67 matcher.usage(usage::create_usage_with_title(self.0, &[]));
68
69 Ok(())
70 }
71
72 fn validate_values<A>(&self,
73 arg: &A,
74 ma: &MatchedArg,
75 matcher: &ArgMatcher<'a>)
76 -> ClapResult<()>
77 where A: AnyArg<'a, 'b> + Display
78 {
79 debugln!("Validator::validate_values: arg={:?}", arg.name());
80 for val in &ma.vals {
81 if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
82 debugln!("Validator::validate_values: invalid UTF-8 found in val {:?}",
83 val);
84 return Err(Error::invalid_utf8(&*usage::create_error_usage(self.0, matcher, None),
85 self.0.color()));
86 }
87 if let Some(p_vals) = arg.possible_vals() {
88 debugln!("Validator::validate_values: possible_vals={:?}", p_vals);
89 let val_str = val.to_string_lossy();
90 if !p_vals.contains(&&*val_str) {
91 return Err(Error::invalid_value(val_str,
92 p_vals,
93 arg,
94 &*usage::create_error_usage(self.0,
95 matcher,
96 None),
97 self.0.color()));
98 }
99 }
100 if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() &&
101 matcher.contains(&*arg.name()) {
102 debugln!("Validator::validate_values: illegal empty val found");
103 return Err(Error::empty_value(arg,
104 &*usage::create_error_usage(self.0, matcher, None),
105 self.0.color()));
106 }
107 if let Some(vtor) = arg.validator() {
108 debug!("Validator::validate_values: checking validator...");
109 if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
110 sdebugln!("error");
111 return Err(Error::value_validation(Some(arg), e, self.0.color()));
112 } else {
113 sdebugln!("good");
114 }
115 }
116 if let Some(vtor) = arg.validator_os() {
117 debug!("Validator::validate_values: checking validator_os...");
118 if let Err(e) = vtor(val) {
119 sdebugln!("error");
120 return Err(Error::value_validation(Some(arg),
121 (*e).to_string_lossy().to_string(),
122 self.0.color()));
123 } else {
124 sdebugln!("good");
125 }
126 }
127 }
128 Ok(())
129 }
130
131 fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
132 debugln!("Validator::validate_blacklist: blacklist={:?}",
133 self.0.blacklist);
134 macro_rules! build_err {
135 ($p:expr, $name:expr, $matcher:ident) => ({
136 debugln!("build_err!: name={}", $name);
137 let mut c_with = find_from!($p, $name, blacklist, &$matcher);
138 c_with = c_with.or(
139 $p.find_any_arg($name).map_or(None, |aa| aa.blacklist())
140 .map_or(None,
141 |bl| bl.iter().find(|arg| $matcher.contains(arg)))
142 .map_or(None, |an| $p.find_any_arg(an))
143 .map_or(None, |aa| Some(format!("{}", aa)))
144 );
145 debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, $name);
146 $matcher.remove($name);
147 let usg = usage::create_error_usage($p, $matcher, None);
148 if let Some(f) = find_by_name!($p, $name, flags, iter) {
149 debugln!("build_err!: It was a flag...");
150 Error::argument_conflict(f, c_with, &*usg, self.0.color())
151 } else if let Some(o) = find_by_name!($p, $name, opts, iter) {
152 debugln!("build_err!: It was an option...");
153 Error::argument_conflict(o, c_with, &*usg, self.0.color())
154 } else {
155 match find_by_name!($p, $name, positionals, values) {
156 Some(p) => {
157 debugln!("build_err!: It was a positional...");
158 Error::argument_conflict(p, c_with, &*usg, self.0.color())
159 },
160 None => panic!(INTERNAL_ERROR_MSG)
161 }
162 }
163 });
164 }
165
166 for name in &self.0.blacklist {
167 debugln!("Validator::validate_blacklist:iter: Checking blacklisted name: {}",
168 name);
169 if self.0
170 .groups
171 .iter()
172 .any(|g| &g.name == name) {
173 debugln!("Validator::validate_blacklist:iter: groups contains it...");
174 for n in self.0.arg_names_in_group(name) {
175 debugln!("Validator::validate_blacklist:iter:iter: Checking arg '{}' in group...",
176 n);
177 if matcher.contains(n) {
178 debugln!("Validator::validate_blacklist:iter:iter: matcher contains it...");
179 return Err(build_err!(self.0, &n, matcher));
180 }
181 }
182 } else if matcher.contains(name) {
183 debugln!("Validator::validate_blacklist:iter: matcher contains it...");
184 return Err(build_err!(self.0, name, matcher));
185 }
186 }
187 Ok(())
188 }
189
190 fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
191 debugln!("Validator::validate_matched_args;");
192 for (name, ma) in matcher.iter() {
193 debugln!("Validator::validate_matched_args:iter:{}: vals={:#?}",
194 name,
195 ma.vals);
196 if let Some(opt) = find_by_name!(self.0, name, opts, iter) {
197 try!(self.validate_arg_num_vals(opt, ma, matcher));
198 try!(self.validate_values(opt, ma, matcher));
199 try!(self.validate_arg_requires(opt, ma, matcher));
200 try!(self.validate_arg_num_occurs(opt, ma, matcher));
201 } else if let Some(flag) = find_by_name!(self.0, name, flags, iter) {
202 try!(self.validate_arg_requires(flag, ma, matcher));
203 try!(self.validate_arg_num_occurs(flag, ma, matcher));
204 } else if let Some(pos) = find_by_name!(self.0, name, positionals, values) {
205 try!(self.validate_arg_num_vals(pos, ma, matcher));
206 try!(self.validate_arg_num_occurs(pos, ma, matcher));
207 try!(self.validate_values(pos, ma, matcher));
208 try!(self.validate_arg_requires(pos, ma, matcher));
209 } else {
210 let grp = self.0
211 .groups
212 .iter()
213 .find(|g| &g.name == name)
214 .expect(INTERNAL_ERROR_MSG);
215 if let Some(ref g_reqs) = grp.requires {
216 if g_reqs.iter().any(|&n| !matcher.contains(n)) {
217 return self.missing_required_error(matcher, None);
218 }
219 }
220 }
221 }
222 Ok(())
223 }
224
225 fn validate_arg_num_occurs<A>(&self,
226 a: &A,
227 ma: &MatchedArg,
228 matcher: &ArgMatcher)
229 -> ClapResult<()>
230 where A: AnyArg<'a, 'b> + Display
231 {
232 debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
233 if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
234 // Not the first time, and we don't allow multiples
235 return Err(Error::unexpected_multiple_usage(a,
236 &*usage::create_error_usage(self.0,
237 matcher,
238 None),
239 self.0.color()));
240 }
241 Ok(())
242 }
243
244 fn validate_arg_num_vals<A>(&self,
245 a: &A,
246 ma: &MatchedArg,
247 matcher: &ArgMatcher)
248 -> ClapResult<()>
249 where A: AnyArg<'a, 'b> + Display
250 {
251 debugln!("Validator::validate_arg_num_vals;");
252 if let Some(num) = a.num_vals() {
253 debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num);
254 let should_err = if a.is_set(ArgSettings::Multiple) {
255 ((ma.vals.len() as u64) % num) != 0
256 } else {
257 num != (ma.vals.len() as u64)
258 };
259 if should_err {
260 debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
261 return Err(Error::wrong_number_of_values(a,
262 num,
263 if a.is_set(ArgSettings::Multiple) {
264 (ma.vals.len() % num as usize)
265 } else {
266 ma.vals.len()
267 },
268 if ma.vals.len() == 1 ||
269 (a.is_set(ArgSettings::Multiple) &&
270 (ma.vals.len() % num as usize) ==
271 1) {
272 "as"
273 } else {
274 "ere"
275 },
276 &*usage::create_error_usage(self.0,
277 matcher,
278 None),
279 self.0.color()));
280 }
281 }
282 if let Some(num) = a.max_vals() {
283 debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
284 if (ma.vals.len() as u64) > num {
285 debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
286 return Err(Error::too_many_values(ma.vals
287 .iter()
288 .last()
289 .expect(INTERNAL_ERROR_MSG)
290 .to_str()
291 .expect(INVALID_UTF8),
292 a,
293 &*usage::create_error_usage(self.0,
294 matcher,
295 None),
296 self.0.color()));
297 }
298 }
299 if let Some(num) = a.min_vals() {
300 debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
301 if (ma.vals.len() as u64) < num {
302 debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
303 return Err(Error::too_few_values(a,
304 num,
305 ma.vals.len(),
306 &*usage::create_error_usage(self.0,
307 matcher,
308 None),
309 self.0.color()));
310 }
311 }
312 // Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
313 if a.takes_value() && !a.is_set(ArgSettings::EmptyValues) && ma.vals.is_empty() {
314 return Err(Error::empty_value(a,
315 &*usage::create_error_usage(self.0, matcher, None),
316 self.0.color()));
317 }
318 Ok(())
319 }
320
321 fn validate_arg_requires<A>(&self,
322 a: &A,
323 ma: &MatchedArg,
324 matcher: &ArgMatcher)
325 -> ClapResult<()>
326 where A: AnyArg<'a, 'b> + Display
327 {
328 debugln!("Validator::validate_arg_requires;");
329 if let Some(a_reqs) = a.requires() {
330 for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
331 let missing_req =
332 |v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name);
333 if ma.vals.iter().any(missing_req) {
334 return self.missing_required_error(matcher, None);
335 }
336 }
337 }
338 Ok(())
339 }
340
341 fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
342 debugln!("Validator::validate_required: required={:?};",
343 self.0.required);
344 'outer: for name in &self.0.required {
345 debugln!("Validator::validate_required:iter:{}:", name);
346 if matcher.contains(name) {
347 continue 'outer;
348 }
349 if let Some(a) = find_by_name!(self.0, name, flags, iter) {
350 if self.is_missing_required_ok(a, matcher) {
351 continue 'outer;
352 }
353 } else if let Some(a) = find_by_name!(self.0, name, opts, iter) {
354 if self.is_missing_required_ok(a, matcher) {
355 continue 'outer;
356 }
357 } else if let Some(a) = find_by_name!(self.0, name, positionals, values) {
358 if self.is_missing_required_ok(a, matcher) {
359 continue 'outer;
360 }
361 }
362 return self.missing_required_error(matcher, None);
363 }
364
365 // Validate the conditionally required args
366 for &(a, v, r) in &self.0.r_ifs {
367 if let Some(ma) = matcher.get(a) {
368 if matcher.get(r).is_none() && ma.vals.iter().any(|val| val == v) {
369 return self.missing_required_error(matcher, Some(r));
370 }
371 }
372 }
373 Ok(())
374 }
375
376 fn validate_conflicts<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
377 where A: AnyArg<'a, 'b>
378 {
379 debugln!("Validator::validate_conflicts: a={:?};", a.name());
380 a.blacklist().map(|bl| {
381 bl.iter().any(|conf| {
382 matcher.contains(conf) ||
383 self.0
384 .groups
385 .iter()
386 .find(|g| &g.name == conf)
387 .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
388 })
389 })
390 }
391
392 fn validate_required_unless<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
393 where A: AnyArg<'a, 'b>
394 {
395 debugln!("Validator::validate_required_unless: a={:?};", a.name());
396 macro_rules! check {
397 ($how:ident, $_self:expr, $a:ident, $m:ident) => {{
398 $a.required_unless().map(|ru| {
399 ru.iter().$how(|n| {
400 $m.contains(n) || {
401 if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) {
402 grp.args.iter().any(|arg| $m.contains(arg))
403 } else {
404 false
405 }
406 }
407 })
408 })
409 }};
410 }
411 if a.is_set(ArgSettings::RequiredUnlessAll) {
412 check!(all, self.0, a, matcher)
413 } else {
414 check!(any, self.0, a, matcher)
415 }
416 }
417
418 fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
419 debugln!("Validator::missing_required_error: extra={:?}", extra);
420 let c = Colorizer {
421 use_stderr: true,
422 when: self.0.color(),
423 };
424 let mut reqs = self.0
425 .required
426 .iter()
427 .map(|&r| &*r)
428 .collect::<Vec<_>>();
429 if let Some(r) = extra {
430 reqs.push(r);
431 }
432 reqs.retain(|n| !matcher.contains(n));
433 reqs.dedup();
434 debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
435 let req_args =
436 usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true)
437 .iter()
438 .fold(String::new(),
439 |acc, s| acc + &format!("\n {}", c.error(s))[..]);
440 debugln!("Validator::missing_required_error: req_args={:#?}", req_args);
441 Err(Error::missing_required_argument(&*req_args,
442 &*usage::create_error_usage(self.0, matcher, extra),
443 self.0.color()))
444 }
445
446 #[inline]
447 fn is_missing_required_ok<A>(&self, a: &A, matcher: &ArgMatcher) -> bool
448 where A: AnyArg<'a, 'b>
449 {
450 debugln!("Validator::is_missing_required_ok: a={}", a.name());
451 self.validate_conflicts(a, matcher).unwrap_or(false) ||
452 self.validate_required_unless(a, matcher).unwrap_or(false)
453 }
454}