mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
refactor: moves validation code into it's own module
This commit is contained in:
parent
642db9b042
commit
44ed8b663c
4 changed files with 446 additions and 422 deletions
|
@ -4,6 +4,7 @@ mod macros;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
mod meta;
|
mod meta;
|
||||||
mod help;
|
mod help;
|
||||||
|
mod validator;
|
||||||
|
|
||||||
// Std
|
// Std
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
|
@ -21,17 +21,17 @@ use app::App;
|
||||||
use app::help::Help;
|
use app::help::Help;
|
||||||
use app::meta::AppMeta;
|
use app::meta::AppMeta;
|
||||||
use app::settings::AppFlags;
|
use app::settings::AppFlags;
|
||||||
use args::{AnyArg, ArgMatcher, Base, Switched, Arg, ArgGroup, FlagBuilder, OptBuilder, PosBuilder,
|
use args::{AnyArg, ArgMatcher, Base, Switched, Arg, ArgGroup, FlagBuilder, OptBuilder, PosBuilder};
|
||||||
MatchedArg};
|
|
||||||
use args::settings::ArgSettings;
|
use args::settings::ArgSettings;
|
||||||
use completions::ComplGen;
|
use completions::ComplGen;
|
||||||
use errors::{Error, ErrorKind};
|
use errors::{Error, ErrorKind};
|
||||||
use errors::Result as ClapResult;
|
use errors::Result as ClapResult;
|
||||||
use fmt::{Colorizer, ColorWhen};
|
use fmt::ColorWhen;
|
||||||
use osstringext::OsStrExt2;
|
use osstringext::OsStrExt2;
|
||||||
use completions::Shell;
|
use completions::Shell;
|
||||||
use suggestions;
|
use suggestions;
|
||||||
use app::settings::AppSettings as AS;
|
use app::settings::AppSettings as AS;
|
||||||
|
use app::validator::Validator;
|
||||||
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -46,12 +46,12 @@ pub struct Parser<'a, 'b>
|
||||||
pub opts: Vec<OptBuilder<'a, 'b>>,
|
pub opts: Vec<OptBuilder<'a, 'b>>,
|
||||||
pub positionals: VecMap<PosBuilder<'a, 'b>>,
|
pub positionals: VecMap<PosBuilder<'a, 'b>>,
|
||||||
pub subcommands: Vec<App<'a, 'b>>,
|
pub subcommands: Vec<App<'a, 'b>>,
|
||||||
groups: Vec<ArgGroup<'a>>,
|
pub groups: Vec<ArgGroup<'a>>,
|
||||||
pub global_args: Vec<Arg<'a, 'b>>,
|
pub global_args: Vec<Arg<'a, 'b>>,
|
||||||
required: Vec<&'a str>,
|
pub required: Vec<&'a str>,
|
||||||
r_ifs: Vec<(&'a str, &'b str, &'a str)>,
|
pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
|
||||||
blacklist: Vec<&'b str>,
|
pub blacklist: Vec<&'b str>,
|
||||||
overrides: Vec<&'b str>,
|
pub overrides: Vec<&'b str>,
|
||||||
help_short: Option<char>,
|
help_short: Option<char>,
|
||||||
version_short: Option<char>,
|
version_short: Option<char>,
|
||||||
cache: Option<&'a str>,
|
cache: Option<&'a str>,
|
||||||
|
@ -1097,54 +1097,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.validate(needs_val_of, subcmd_name, matcher)
|
Validator::new(self).validate(needs_val_of, subcmd_name, matcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&mut self,
|
|
||||||
needs_val_of: Option<&'a str>,
|
|
||||||
subcmd_name: Option<String>,
|
|
||||||
matcher: &mut ArgMatcher<'a>)
|
|
||||||
-> ClapResult<()> {
|
|
||||||
debugln!("Parser::validate;");
|
|
||||||
let mut reqs_validated = false;
|
|
||||||
try!(self.add_defaults(matcher));
|
|
||||||
if let Some(a) = needs_val_of {
|
|
||||||
debugln!("Parser::validate: needs_val_of={:?}", a);
|
|
||||||
if let Some(o) = find_by_name!(self, &a, opts, iter) {
|
|
||||||
try!(self.validate_required(matcher));
|
|
||||||
reqs_validated = true;
|
|
||||||
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
|
|
||||||
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
if should_err {
|
|
||||||
return Err(Error::empty_value(o,
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try!(self.validate_blacklist(matcher));
|
|
||||||
if !(self.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated {
|
|
||||||
try!(self.validate_required(matcher));
|
|
||||||
}
|
|
||||||
try!(self.validate_matched_args(matcher));
|
|
||||||
matcher.usage(self.create_usage(&[]));
|
|
||||||
|
|
||||||
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
|
|
||||||
self.is_set(AS::ArgRequiredElseHelp) {
|
|
||||||
let mut out = vec![];
|
|
||||||
try!(self.write_help_err(&mut out));
|
|
||||||
return Err(Error {
|
|
||||||
message: String::from_utf8_lossy(&*out).into_owned(),
|
|
||||||
kind: ErrorKind::MissingArgumentOrSubcommand,
|
|
||||||
info: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn propogate_help_version(&mut self) {
|
fn propogate_help_version(&mut self) {
|
||||||
debugln!("Parser::propogate_help_version;");
|
debugln!("Parser::propogate_help_version;");
|
||||||
|
@ -1294,7 +1249,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
args.iter().map(ToOwned::to_owned).collect()
|
args.iter().map(ToOwned::to_owned).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> {
|
pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> {
|
||||||
let mut g_vec = vec![];
|
let mut g_vec = vec![];
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
|
|
||||||
|
@ -1697,62 +1652,6 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_values<A>(&self,
|
|
||||||
arg: &A,
|
|
||||||
ma: &MatchedArg,
|
|
||||||
matcher: &ArgMatcher<'a>)
|
|
||||||
-> ClapResult<()>
|
|
||||||
where A: AnyArg<'a, 'b> + Display
|
|
||||||
{
|
|
||||||
debugln!("Parser::validate_values: arg={:?}", arg.name());
|
|
||||||
for val in &ma.vals {
|
|
||||||
if self.is_set(AS::StrictUtf8) && val.to_str().is_none() {
|
|
||||||
debugln!("Parser::validate_values: invalid UTF-8 found in val {:?}",
|
|
||||||
val);
|
|
||||||
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
if let Some(p_vals) = arg.possible_vals() {
|
|
||||||
debugln!("Parser::validate_values: possible_vals={:?}", p_vals);
|
|
||||||
let val_str = val.to_string_lossy();
|
|
||||||
if !p_vals.contains(&&*val_str) {
|
|
||||||
return Err(Error::invalid_value(val_str,
|
|
||||||
p_vals,
|
|
||||||
arg,
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() &&
|
|
||||||
matcher.contains(&*arg.name()) {
|
|
||||||
debugln!("Parser::validate_values: illegal empty val found");
|
|
||||||
return Err(Error::empty_value(arg,
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
if let Some(vtor) = arg.validator() {
|
|
||||||
debug!("Parser::validate_values: checking validator...");
|
|
||||||
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
|
|
||||||
sdebugln!("error");
|
|
||||||
return Err(Error::value_validation(Some(arg), e, self.color()));
|
|
||||||
} else {
|
|
||||||
sdebugln!("good");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(vtor) = arg.validator_os() {
|
|
||||||
debug!("Parser::validate_values: checking validator_os...");
|
|
||||||
if let Err(e) = vtor(&val) {
|
|
||||||
sdebugln!("error");
|
|
||||||
return Err(Error::value_validation(Some(arg),
|
|
||||||
(*e).to_string_lossy().to_string(),
|
|
||||||
self.color()));
|
|
||||||
} else {
|
|
||||||
sdebugln!("good");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_flag(&self,
|
fn parse_flag(&self,
|
||||||
flag: &FlagBuilder<'a, 'b>,
|
flag: &FlagBuilder<'a, 'b>,
|
||||||
|
@ -1767,311 +1666,6 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
|
||||||
debugln!("Parser::validate_blacklist: blacklist={:?}", self.blacklist);
|
|
||||||
macro_rules! build_err {
|
|
||||||
($me:ident, $name:expr, $matcher:ident) => ({
|
|
||||||
debugln!("build_err!: name={}", $name);
|
|
||||||
let mut c_with = find_from!($me, $name, blacklist, &$matcher);
|
|
||||||
c_with = c_with.or(
|
|
||||||
$me.find_any_arg($name).map_or(None, |aa| aa.blacklist())
|
|
||||||
.map_or(None,
|
|
||||||
|bl| bl.iter().find(|arg| $matcher.contains(arg)))
|
|
||||||
.map_or(None, |an| $me.find_any_arg(an))
|
|
||||||
.map_or(None, |aa| Some(format!("{}", aa)))
|
|
||||||
);
|
|
||||||
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, $name);
|
|
||||||
$matcher.remove($name);
|
|
||||||
let usg = $me.create_current_usage($matcher, None);
|
|
||||||
if let Some(f) = find_by_name!($me, $name, flags, iter) {
|
|
||||||
debugln!("build_err!: It was a flag...");
|
|
||||||
Error::argument_conflict(f, c_with, &*usg, self.color())
|
|
||||||
} else if let Some(o) = find_by_name!($me, $name, opts, iter) {
|
|
||||||
debugln!("build_err!: It was an option...");
|
|
||||||
Error::argument_conflict(o, c_with, &*usg, self.color())
|
|
||||||
} else {
|
|
||||||
match find_by_name!($me, $name, positionals, values) {
|
|
||||||
Some(p) => {
|
|
||||||
debugln!("build_err!: It was a positional...");
|
|
||||||
Error::argument_conflict(p, c_with, &*usg, self.color())
|
|
||||||
},
|
|
||||||
None => panic!(INTERNAL_ERROR_MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for name in &self.blacklist {
|
|
||||||
debugln!("Parser::validate_blacklist:iter: Checking blacklisted name: {}",
|
|
||||||
name);
|
|
||||||
if self.groups.iter().any(|g| &g.name == name) {
|
|
||||||
debugln!("Parser::validate_blacklist:iter: groups contains it...");
|
|
||||||
for n in self.arg_names_in_group(name) {
|
|
||||||
debugln!("Parser::validate_blacklist:iter:iter: Checking arg '{}' in group...",
|
|
||||||
n);
|
|
||||||
if matcher.contains(n) {
|
|
||||||
debugln!("Parser::validate_blacklist:iter:iter: matcher contains it...");
|
|
||||||
return Err(build_err!(self, &n, matcher));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if matcher.contains(name) {
|
|
||||||
debugln!("Parser::validate_blacklist:iter: matcher contains it...");
|
|
||||||
return Err(build_err!(self, name, matcher));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_matched_args(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
|
||||||
debugln!("Parser::validate_matched_args;");
|
|
||||||
for (name, ma) in matcher.iter() {
|
|
||||||
debugln!("Parser::validate_matched_args:iter:{}: vals={:#?}",
|
|
||||||
name,
|
|
||||||
ma.vals);
|
|
||||||
if let Some(opt) = find_by_name!(self, name, opts, iter) {
|
|
||||||
try!(self.validate_arg_num_vals(opt, ma, matcher));
|
|
||||||
try!(self.validate_values(opt, ma, matcher));
|
|
||||||
try!(self.validate_arg_requires(opt, ma, matcher));
|
|
||||||
try!(self.validate_arg_num_occurs(opt, ma, matcher));
|
|
||||||
} else if let Some(flag) = find_by_name!(self, name, flags, iter) {
|
|
||||||
try!(self.validate_arg_requires(flag, ma, matcher));
|
|
||||||
try!(self.validate_arg_num_occurs(flag, ma, matcher));
|
|
||||||
} else if let Some(pos) = find_by_name!(self, name, positionals, values) {
|
|
||||||
try!(self.validate_arg_num_vals(pos, ma, matcher));
|
|
||||||
try!(self.validate_arg_num_occurs(pos, ma, matcher));
|
|
||||||
try!(self.validate_values(pos, ma, matcher));
|
|
||||||
try!(self.validate_arg_requires(pos, ma, matcher));
|
|
||||||
} else {
|
|
||||||
let grp = self.groups.iter().find(|g| &g.name == name).expect(INTERNAL_ERROR_MSG);
|
|
||||||
if let Some(ref g_reqs) = grp.requires {
|
|
||||||
if g_reqs.iter().any(|&n| !matcher.contains(n)) {
|
|
||||||
return self.missing_required_error(matcher, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_arg_num_occurs<A>(&self,
|
|
||||||
a: &A,
|
|
||||||
ma: &MatchedArg,
|
|
||||||
matcher: &ArgMatcher)
|
|
||||||
-> ClapResult<()>
|
|
||||||
where A: AnyArg<'a, 'b> + Display
|
|
||||||
{
|
|
||||||
debugln!("Parser::validate_arg_num_occurs: a={};", a.name());
|
|
||||||
if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
|
|
||||||
// Not the first time, and we don't allow multiples
|
|
||||||
return Err(Error::unexpected_multiple_usage(a,
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_arg_num_vals<A>(&self,
|
|
||||||
a: &A,
|
|
||||||
ma: &MatchedArg,
|
|
||||||
matcher: &ArgMatcher)
|
|
||||||
-> ClapResult<()>
|
|
||||||
where A: AnyArg<'a, 'b> + Display
|
|
||||||
{
|
|
||||||
debugln!("Parser::validate_arg_num_vals;");
|
|
||||||
if let Some(num) = a.num_vals() {
|
|
||||||
debugln!("Parser::validate_arg_num_vals: num_vals set...{}", num);
|
|
||||||
let should_err = if a.is_set(ArgSettings::Multiple) {
|
|
||||||
((ma.vals.len() as u64) % num) != 0
|
|
||||||
} else {
|
|
||||||
num != (ma.vals.len() as u64)
|
|
||||||
};
|
|
||||||
if should_err {
|
|
||||||
debugln!("Parser::validate_arg_num_vals: Sending error WrongNumberOfValues");
|
|
||||||
return Err(Error::wrong_number_of_values(a,
|
|
||||||
num,
|
|
||||||
if a.is_set(ArgSettings::Multiple) {
|
|
||||||
(ma.vals.len() % num as usize)
|
|
||||||
} else {
|
|
||||||
ma.vals.len()
|
|
||||||
},
|
|
||||||
if ma.vals.len() == 1 ||
|
|
||||||
(a.is_set(ArgSettings::Multiple) &&
|
|
||||||
(ma.vals.len() % num as usize) ==
|
|
||||||
1) {
|
|
||||||
"as"
|
|
||||||
} else {
|
|
||||||
"ere"
|
|
||||||
},
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(num) = a.max_vals() {
|
|
||||||
debugln!("Parser::validate_arg_num_vals: max_vals set...{}", num);
|
|
||||||
if (ma.vals.len() as u64) > num {
|
|
||||||
debugln!("Parser::validate_arg_num_vals: Sending error TooManyValues");
|
|
||||||
return Err(Error::too_many_values(ma.vals
|
|
||||||
.iter()
|
|
||||||
.last()
|
|
||||||
.expect(INTERNAL_ERROR_MSG)
|
|
||||||
.to_str()
|
|
||||||
.expect(INVALID_UTF8),
|
|
||||||
a,
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(num) = a.min_vals() {
|
|
||||||
debugln!("Parser::validate_arg_num_vals: min_vals set: {}", num);
|
|
||||||
if (ma.vals.len() as u64) < num {
|
|
||||||
debugln!("Parser::validate_arg_num_vals: Sending error TooFewValues");
|
|
||||||
return Err(Error::too_few_values(a,
|
|
||||||
num,
|
|
||||||
ma.vals.len(),
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
|
|
||||||
if a.takes_value() && !a.is_set(ArgSettings::EmptyValues) && ma.vals.is_empty() {
|
|
||||||
return Err(Error::empty_value(a,
|
|
||||||
&*self.create_current_usage(matcher, None),
|
|
||||||
self.color()));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_arg_requires<A>(&self,
|
|
||||||
a: &A,
|
|
||||||
ma: &MatchedArg,
|
|
||||||
matcher: &ArgMatcher)
|
|
||||||
-> ClapResult<()>
|
|
||||||
where A: AnyArg<'a, 'b> + Display
|
|
||||||
{
|
|
||||||
debugln!("Parser::validate_arg_requires;");
|
|
||||||
if let Some(a_reqs) = a.requires() {
|
|
||||||
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
|
|
||||||
if ma.vals
|
|
||||||
.iter()
|
|
||||||
.any(|v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name)) {
|
|
||||||
return self.missing_required_error(matcher, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
|
|
||||||
debugln!("Parser::missing_required_error: extra={:?}", extra);
|
|
||||||
let c = Colorizer {
|
|
||||||
use_stderr: true,
|
|
||||||
when: self.color(),
|
|
||||||
};
|
|
||||||
let mut reqs = self.required.iter().map(|&r| &*r).collect::<Vec<_>>();
|
|
||||||
if let Some(r) = extra {
|
|
||||||
reqs.push(r);
|
|
||||||
}
|
|
||||||
reqs.retain(|n| !matcher.contains(n));
|
|
||||||
reqs.dedup();
|
|
||||||
debugln!("Parser::missing_required_error: reqs={:#?}", reqs);
|
|
||||||
Err(Error::missing_required_argument(&*self.get_required_from(&reqs[..],
|
|
||||||
Some(matcher),
|
|
||||||
extra)
|
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |acc, s| {
|
|
||||||
acc + &format!("\n {}", c.error(s))[..]
|
|
||||||
}),
|
|
||||||
&*self.create_current_usage(matcher, extra),
|
|
||||||
self.color()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
|
|
||||||
debugln!("Parser::validate_required: required={:?};", self.required);
|
|
||||||
'outer: for name in &self.required {
|
|
||||||
debugln!("Parser::validate_required:iter:{}:", name);
|
|
||||||
if matcher.contains(name) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
if let Some(a) = find_by_name!(self, name, flags, iter) {
|
|
||||||
if self.is_missing_required_ok(a, matcher) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
} else if let Some(a) = find_by_name!(self, name, opts, iter) {
|
|
||||||
if self.is_missing_required_ok(a, matcher) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
} else if let Some(a) = find_by_name!(self, name, positionals, values) {
|
|
||||||
if self.is_missing_required_ok(a, matcher) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return self.missing_required_error(matcher, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the conditionally required args
|
|
||||||
for &(a, v, r) in &self.r_ifs {
|
|
||||||
if let Some(ma) = matcher.get(a) {
|
|
||||||
if matcher.get(r).is_none() {
|
|
||||||
if ma.vals.iter().any(|val| val == v) {
|
|
||||||
return self.missing_required_error(matcher, Some(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_conflicts<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
|
|
||||||
where A: AnyArg<'a, 'b>
|
|
||||||
{
|
|
||||||
debugln!("Parser::check_conflicts: a={:?};", a.name());
|
|
||||||
a.blacklist().map(|bl| {
|
|
||||||
bl.iter().any(|conf| {
|
|
||||||
matcher.contains(conf) ||
|
|
||||||
self.groups
|
|
||||||
.iter()
|
|
||||||
.find(|g| &g.name == conf)
|
|
||||||
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_required_unless<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
|
|
||||||
where A: AnyArg<'a, 'b>
|
|
||||||
{
|
|
||||||
debugln!("Parser::check_required_unless: a={:?};", a.name());
|
|
||||||
macro_rules! check {
|
|
||||||
($how:ident, $_self:ident, $a:ident, $m:ident) => {{
|
|
||||||
$a.required_unless().map(|ru| {
|
|
||||||
ru.iter().$how(|n| {
|
|
||||||
$m.contains(n) || {
|
|
||||||
if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) {
|
|
||||||
grp.args.iter().any(|arg| $m.contains(arg))
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
if a.is_set(ArgSettings::RequiredUnlessAll) {
|
|
||||||
check!(all, self, a, matcher)
|
|
||||||
} else {
|
|
||||||
check!(any, self, a, matcher)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_missing_required_ok<A>(&self, a: &A, matcher: &ArgMatcher) -> bool
|
|
||||||
where A: AnyArg<'a, 'b>
|
|
||||||
{
|
|
||||||
debugln!("Parser::is_missing_required_ok: a={}", a.name());
|
|
||||||
self.check_conflicts(a, matcher).unwrap_or(false) ||
|
|
||||||
self.check_required_unless(a, matcher).unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||||
// Didn't match a flag or option...maybe it was a typo and close to one
|
// Didn't match a flag or option...maybe it was a typo and close to one
|
||||||
let suffix =
|
let suffix =
|
||||||
|
@ -2261,7 +1855,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
Help::write_parser_help_to_stderr(w, self)
|
Help::write_parser_help_to_stderr(w, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||||
macro_rules! add_val {
|
macro_rules! add_val {
|
||||||
(@default $_self:ident, $a:ident, $m:ident) => {
|
(@default $_self:ident, $a:ident, $m:ident) => {
|
||||||
if let Some(ref val) = $a.v.default_val {
|
if let Some(ref val) = $a.v.default_val {
|
||||||
|
|
430
src/app/validator.rs
Normal file
430
src/app/validator.rs
Normal file
|
@ -0,0 +1,430 @@
|
||||||
|
// std
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
use INTERNAL_ERROR_MSG;
|
||||||
|
use INVALID_UTF8;
|
||||||
|
use args::{AnyArg, ArgMatcher, MatchedArg};
|
||||||
|
use args::settings::ArgSettings;
|
||||||
|
use errors::{Error, ErrorKind};
|
||||||
|
use errors::Result as ClapResult;
|
||||||
|
use osstringext::OsStrExt2;
|
||||||
|
use app::settings::AppSettings as AS;
|
||||||
|
use app::parser::Parser;
|
||||||
|
use fmt::Colorizer;
|
||||||
|
|
||||||
|
pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>) where 'a: 'b, 'b: 'z;
|
||||||
|
|
||||||
|
impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
|
pub fn new(p: &'z mut Parser<'a, 'b>) -> Self {
|
||||||
|
Validator(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate(&mut self,
|
||||||
|
needs_val_of: Option<&'a str>,
|
||||||
|
subcmd_name: Option<String>,
|
||||||
|
matcher: &mut ArgMatcher<'a>)
|
||||||
|
-> ClapResult<()> {
|
||||||
|
debugln!("Validator::validate;");
|
||||||
|
let mut reqs_validated = false;
|
||||||
|
try!(self.0.add_defaults(matcher));
|
||||||
|
if let Some(a) = needs_val_of {
|
||||||
|
debugln!("Validator::validate: needs_val_of={:?}", a);
|
||||||
|
if let Some(o) = find_by_name!(self.0, &a, opts, iter) {
|
||||||
|
try!(self.validate_required(matcher));
|
||||||
|
reqs_validated = true;
|
||||||
|
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
|
||||||
|
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
if should_err {
|
||||||
|
return Err(Error::empty_value(o,
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(self.validate_blacklist(matcher));
|
||||||
|
if !(self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated {
|
||||||
|
try!(self.validate_required(matcher));
|
||||||
|
}
|
||||||
|
try!(self.validate_matched_args(matcher));
|
||||||
|
matcher.usage(self.0.create_usage(&[]));
|
||||||
|
|
||||||
|
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
|
||||||
|
self.0.is_set(AS::ArgRequiredElseHelp) {
|
||||||
|
let mut out = vec![];
|
||||||
|
try!(self.0.write_help_err(&mut out));
|
||||||
|
return Err(Error {
|
||||||
|
message: String::from_utf8_lossy(&*out).into_owned(),
|
||||||
|
kind: ErrorKind::MissingArgumentOrSubcommand,
|
||||||
|
info: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_values<A>(&self,
|
||||||
|
arg: &A,
|
||||||
|
ma: &MatchedArg,
|
||||||
|
matcher: &ArgMatcher<'a>)
|
||||||
|
-> ClapResult<()>
|
||||||
|
where A: AnyArg<'a, 'b> + Display
|
||||||
|
{
|
||||||
|
debugln!("Validator::validate_values: arg={:?}", arg.name());
|
||||||
|
for val in &ma.vals {
|
||||||
|
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
|
||||||
|
debugln!("Validator::validate_values: invalid UTF-8 found in val {:?}",
|
||||||
|
val);
|
||||||
|
return Err(Error::invalid_utf8(&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
if let Some(p_vals) = arg.possible_vals() {
|
||||||
|
debugln!("Validator::validate_values: possible_vals={:?}", p_vals);
|
||||||
|
let val_str = val.to_string_lossy();
|
||||||
|
if !p_vals.contains(&&*val_str) {
|
||||||
|
return Err(Error::invalid_value(val_str,
|
||||||
|
p_vals,
|
||||||
|
arg,
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() &&
|
||||||
|
matcher.contains(&*arg.name()) {
|
||||||
|
debugln!("Validator::validate_values: illegal empty val found");
|
||||||
|
return Err(Error::empty_value(arg,
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
if let Some(vtor) = arg.validator() {
|
||||||
|
debug!("Validator::validate_values: checking validator...");
|
||||||
|
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
|
||||||
|
sdebugln!("error");
|
||||||
|
return Err(Error::value_validation(Some(arg), e, self.0.color()));
|
||||||
|
} else {
|
||||||
|
sdebugln!("good");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(vtor) = arg.validator_os() {
|
||||||
|
debug!("Validator::validate_values: checking validator_os...");
|
||||||
|
if let Err(e) = vtor(&val) {
|
||||||
|
sdebugln!("error");
|
||||||
|
return Err(Error::value_validation(Some(arg),
|
||||||
|
(*e).to_string_lossy().to_string(),
|
||||||
|
self.0.color()));
|
||||||
|
} else {
|
||||||
|
sdebugln!("good");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
||||||
|
debugln!("Validator::validate_blacklist: blacklist={:?}", self.0.blacklist);
|
||||||
|
macro_rules! build_err {
|
||||||
|
($p:expr, $name:expr, $matcher:ident) => ({
|
||||||
|
debugln!("build_err!: name={}", $name);
|
||||||
|
let mut c_with = find_from!($p, $name, blacklist, &$matcher);
|
||||||
|
c_with = c_with.or(
|
||||||
|
$p.find_any_arg($name).map_or(None, |aa| aa.blacklist())
|
||||||
|
.map_or(None,
|
||||||
|
|bl| bl.iter().find(|arg| $matcher.contains(arg)))
|
||||||
|
.map_or(None, |an| $p.find_any_arg(an))
|
||||||
|
.map_or(None, |aa| Some(format!("{}", aa)))
|
||||||
|
);
|
||||||
|
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, $name);
|
||||||
|
$matcher.remove($name);
|
||||||
|
let usg = $p.create_current_usage($matcher, None);
|
||||||
|
if let Some(f) = find_by_name!($p, $name, flags, iter) {
|
||||||
|
debugln!("build_err!: It was a flag...");
|
||||||
|
Error::argument_conflict(f, c_with, &*usg, self.0.color())
|
||||||
|
} else if let Some(o) = find_by_name!($p, $name, opts, iter) {
|
||||||
|
debugln!("build_err!: It was an option...");
|
||||||
|
Error::argument_conflict(o, c_with, &*usg, self.0.color())
|
||||||
|
} else {
|
||||||
|
match find_by_name!($p, $name, positionals, values) {
|
||||||
|
Some(p) => {
|
||||||
|
debugln!("build_err!: It was a positional...");
|
||||||
|
Error::argument_conflict(p, c_with, &*usg, self.0.color())
|
||||||
|
},
|
||||||
|
None => panic!(INTERNAL_ERROR_MSG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for name in &self.0.blacklist {
|
||||||
|
debugln!("Validator::validate_blacklist:iter: Checking blacklisted name: {}",
|
||||||
|
name);
|
||||||
|
if self.0.groups.iter().any(|g| &g.name == name) {
|
||||||
|
debugln!("Validator::validate_blacklist:iter: groups contains it...");
|
||||||
|
for n in self.0.arg_names_in_group(name) {
|
||||||
|
debugln!("Validator::validate_blacklist:iter:iter: Checking arg '{}' in group...",
|
||||||
|
n);
|
||||||
|
if matcher.contains(n) {
|
||||||
|
debugln!("Validator::validate_blacklist:iter:iter: matcher contains it...");
|
||||||
|
return Err(build_err!(self.0, &n, matcher));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if matcher.contains(name) {
|
||||||
|
debugln!("Validator::validate_blacklist:iter: matcher contains it...");
|
||||||
|
return Err(build_err!(self.0, name, matcher));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||||
|
debugln!("Validator::validate_matched_args;");
|
||||||
|
for (name, ma) in matcher.iter() {
|
||||||
|
debugln!("Validator::validate_matched_args:iter:{}: vals={:#?}",
|
||||||
|
name,
|
||||||
|
ma.vals);
|
||||||
|
if let Some(opt) = find_by_name!(self.0, name, opts, iter) {
|
||||||
|
try!(self.validate_arg_num_vals(opt, ma, matcher));
|
||||||
|
try!(self.validate_values(opt, ma, matcher));
|
||||||
|
try!(self.validate_arg_requires(opt, ma, matcher));
|
||||||
|
try!(self.validate_arg_num_occurs(opt, ma, matcher));
|
||||||
|
} else if let Some(flag) = find_by_name!(self.0, name, flags, iter) {
|
||||||
|
try!(self.validate_arg_requires(flag, ma, matcher));
|
||||||
|
try!(self.validate_arg_num_occurs(flag, ma, matcher));
|
||||||
|
} else if let Some(pos) = find_by_name!(self.0, name, positionals, values) {
|
||||||
|
try!(self.validate_arg_num_vals(pos, ma, matcher));
|
||||||
|
try!(self.validate_arg_num_occurs(pos, ma, matcher));
|
||||||
|
try!(self.validate_values(pos, ma, matcher));
|
||||||
|
try!(self.validate_arg_requires(pos, ma, matcher));
|
||||||
|
} else {
|
||||||
|
let grp = self.0.groups.iter().find(|g| &g.name == name).expect(INTERNAL_ERROR_MSG);
|
||||||
|
if let Some(ref g_reqs) = grp.requires {
|
||||||
|
if g_reqs.iter().any(|&n| !matcher.contains(n)) {
|
||||||
|
return self.missing_required_error(matcher, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_arg_num_occurs<A>(&self,
|
||||||
|
a: &A,
|
||||||
|
ma: &MatchedArg,
|
||||||
|
matcher: &ArgMatcher)
|
||||||
|
-> ClapResult<()>
|
||||||
|
where A: AnyArg<'a, 'b> + Display
|
||||||
|
{
|
||||||
|
debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
|
||||||
|
if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
|
||||||
|
// Not the first time, and we don't allow multiples
|
||||||
|
return Err(Error::unexpected_multiple_usage(a,
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_arg_num_vals<A>(&self,
|
||||||
|
a: &A,
|
||||||
|
ma: &MatchedArg,
|
||||||
|
matcher: &ArgMatcher)
|
||||||
|
-> ClapResult<()>
|
||||||
|
where A: AnyArg<'a, 'b> + Display
|
||||||
|
{
|
||||||
|
debugln!("Validator::validate_arg_num_vals;");
|
||||||
|
if let Some(num) = a.num_vals() {
|
||||||
|
debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num);
|
||||||
|
let should_err = if a.is_set(ArgSettings::Multiple) {
|
||||||
|
((ma.vals.len() as u64) % num) != 0
|
||||||
|
} else {
|
||||||
|
num != (ma.vals.len() as u64)
|
||||||
|
};
|
||||||
|
if should_err {
|
||||||
|
debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
|
||||||
|
return Err(Error::wrong_number_of_values(a,
|
||||||
|
num,
|
||||||
|
if a.is_set(ArgSettings::Multiple) {
|
||||||
|
(ma.vals.len() % num as usize)
|
||||||
|
} else {
|
||||||
|
ma.vals.len()
|
||||||
|
},
|
||||||
|
if ma.vals.len() == 1 ||
|
||||||
|
(a.is_set(ArgSettings::Multiple) &&
|
||||||
|
(ma.vals.len() % num as usize) ==
|
||||||
|
1) {
|
||||||
|
"as"
|
||||||
|
} else {
|
||||||
|
"ere"
|
||||||
|
},
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(num) = a.max_vals() {
|
||||||
|
debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
|
||||||
|
if (ma.vals.len() as u64) > num {
|
||||||
|
debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
|
||||||
|
return Err(Error::too_many_values(ma.vals
|
||||||
|
.iter()
|
||||||
|
.last()
|
||||||
|
.expect(INTERNAL_ERROR_MSG)
|
||||||
|
.to_str()
|
||||||
|
.expect(INVALID_UTF8),
|
||||||
|
a,
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(num) = a.min_vals() {
|
||||||
|
debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
|
||||||
|
if (ma.vals.len() as u64) < num {
|
||||||
|
debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
|
||||||
|
return Err(Error::too_few_values(a,
|
||||||
|
num,
|
||||||
|
ma.vals.len(),
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
|
||||||
|
if a.takes_value() && !a.is_set(ArgSettings::EmptyValues) && ma.vals.is_empty() {
|
||||||
|
return Err(Error::empty_value(a,
|
||||||
|
&*self.0.create_current_usage(matcher, None),
|
||||||
|
self.0.color()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_arg_requires<A>(&self,
|
||||||
|
a: &A,
|
||||||
|
ma: &MatchedArg,
|
||||||
|
matcher: &ArgMatcher)
|
||||||
|
-> ClapResult<()>
|
||||||
|
where A: AnyArg<'a, 'b> + Display
|
||||||
|
{
|
||||||
|
debugln!("Validator::validate_arg_requires;");
|
||||||
|
if let Some(a_reqs) = a.requires() {
|
||||||
|
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
|
||||||
|
if ma.vals
|
||||||
|
.iter()
|
||||||
|
.any(|v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name)) {
|
||||||
|
return self.missing_required_error(matcher, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
|
||||||
|
debugln!("Validator::validate_required: required={:?};", self.0.required);
|
||||||
|
'outer: for name in &self.0.required {
|
||||||
|
debugln!("Validator::validate_required:iter:{}:", name);
|
||||||
|
if matcher.contains(name) {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
if let Some(a) = find_by_name!(self.0, name, flags, iter) {
|
||||||
|
if self.is_missing_required_ok(a, matcher) {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
} else if let Some(a) = find_by_name!(self.0, name, opts, iter) {
|
||||||
|
if self.is_missing_required_ok(a, matcher) {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
} else if let Some(a) = find_by_name!(self.0, name, positionals, values) {
|
||||||
|
if self.is_missing_required_ok(a, matcher) {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.missing_required_error(matcher, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the conditionally required args
|
||||||
|
for &(a, v, r) in &self.0.r_ifs {
|
||||||
|
if let Some(ma) = matcher.get(a) {
|
||||||
|
if matcher.get(r).is_none() {
|
||||||
|
if ma.vals.iter().any(|val| val == v) {
|
||||||
|
return self.missing_required_error(matcher, Some(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_conflicts<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
|
||||||
|
where A: AnyArg<'a, 'b>
|
||||||
|
{
|
||||||
|
debugln!("Validator::validate_conflicts: a={:?};", a.name());
|
||||||
|
a.blacklist().map(|bl| {
|
||||||
|
bl.iter().any(|conf| {
|
||||||
|
matcher.contains(conf) ||
|
||||||
|
self.0.groups
|
||||||
|
.iter()
|
||||||
|
.find(|g| &g.name == conf)
|
||||||
|
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_required_unless<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
|
||||||
|
where A: AnyArg<'a, 'b>
|
||||||
|
{
|
||||||
|
debugln!("Validator::validate_required_unless: a={:?};", a.name());
|
||||||
|
macro_rules! check {
|
||||||
|
($how:ident, $_self:expr, $a:ident, $m:ident) => {{
|
||||||
|
$a.required_unless().map(|ru| {
|
||||||
|
ru.iter().$how(|n| {
|
||||||
|
$m.contains(n) || {
|
||||||
|
if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) {
|
||||||
|
grp.args.iter().any(|arg| $m.contains(arg))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
if a.is_set(ArgSettings::RequiredUnlessAll) {
|
||||||
|
check!(all, self.0, a, matcher)
|
||||||
|
} else {
|
||||||
|
check!(any, self.0, a, matcher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
|
||||||
|
debugln!("Validator::missing_required_error: extra={:?}", extra);
|
||||||
|
let c = Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: self.0.color(),
|
||||||
|
};
|
||||||
|
let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
|
||||||
|
if let Some(r) = extra {
|
||||||
|
reqs.push(r);
|
||||||
|
}
|
||||||
|
reqs.retain(|n| !matcher.contains(n));
|
||||||
|
reqs.dedup();
|
||||||
|
debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
|
||||||
|
Err(Error::missing_required_argument(&*self.0.get_required_from(&reqs[..],
|
||||||
|
Some(matcher),
|
||||||
|
extra)
|
||||||
|
.iter()
|
||||||
|
.fold(String::new(), |acc, s| {
|
||||||
|
acc + &format!("\n {}", c.error(s))[..]
|
||||||
|
}),
|
||||||
|
&*self.0.create_current_usage(matcher, extra),
|
||||||
|
self.0.color()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_missing_required_ok<A>(&self, a: &A, matcher: &ArgMatcher) -> bool
|
||||||
|
where A: AnyArg<'a, 'b>
|
||||||
|
{
|
||||||
|
debugln!("Validator::is_missing_required_ok: a={}", a.name());
|
||||||
|
self.validate_conflicts(a, matcher).unwrap_or(false) ||
|
||||||
|
self.validate_required_unless(a, matcher).unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
|
@ -847,7 +847,7 @@ macro_rules! vec_remove_all {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
macro_rules! find_from {
|
macro_rules! find_from {
|
||||||
($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
for k in $matcher.arg_names() {
|
for k in $matcher.arg_names() {
|
||||||
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
|
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
|
||||||
|
@ -877,7 +877,7 @@ macro_rules! find_from {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! find_name_from {
|
macro_rules! find_name_from {
|
||||||
($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
for k in $matcher.arg_names() {
|
for k in $matcher.arg_names() {
|
||||||
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
|
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
|
||||||
|
@ -908,8 +908,8 @@ macro_rules! find_name_from {
|
||||||
|
|
||||||
// Finds an arg by name
|
// Finds an arg by name
|
||||||
macro_rules! find_by_name {
|
macro_rules! find_by_name {
|
||||||
($_self:ident, $name:expr, $what:ident, $how:ident) => {
|
($p:expr, $name:expr, $what:ident, $how:ident) => {
|
||||||
$_self.$what.$how().find(|o| &o.b.name == $name)
|
$p.$what.$how().find(|o| &o.b.name == $name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1057,7 +1057,6 @@ macro_rules! _names {
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|s| s.p.meta.aliases.is_some())
|
.filter(|s| s.p.meta.aliases.is_some())
|
||||||
.flat_map(|s| s.p.meta.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)))
|
.flat_map(|s| s.p.meta.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)))
|
||||||
// .map(|n| &n)
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue