fix: fixes group tests on v3-master

This commit is contained in:
Kevin K 2018-08-01 21:04:11 -04:00
parent 5a06a8270a
commit a2cd63cc9e
No known key found for this signature in database
GPG key ID: 2E39D46AABC94DDD
6 changed files with 90 additions and 41 deletions

View file

@ -1720,6 +1720,23 @@ impl<'a, 'b> App<'a, 'b> {
write!(w, "{} {}", &self.name[..], ver)
}
}
pub(crate) fn format_group(&self, g: &str) -> String {
let g_string = self
.unroll_args_in_group(g)
.iter()
.filter_map(|x| self.find(x))
.map(|x| {
if x.index.is_some() {
x.name.to_owned()
} else {
x.to_string()
}
})
.collect::<Vec<_>>()
.join("|");
format!("<{}>", &*g_string)
}
}
// Internal Query Methods

View file

@ -1007,23 +1007,6 @@ macro_rules! groups_for_arg {
}}
}
macro_rules! find_from {
($app:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None;
for k in $matcher.arg_names() {
if let Some(a) = find!($app, k) {
if let Some(ref v) = a.$from {
if v.contains($arg_name) {
ret = Some(a.to_string());
}
}
}
}
ret
}};
}
// Finds an arg by name
macro_rules! find {
($app:expr, $name:expr, $what:ident) => {

View file

@ -303,8 +303,6 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
}
// Returns the required args in usage string form by fully unrolling all groups
// `used`: The args that were used
// `incl`: Args that should be displayed even if not required
// `incl_last`: should we incldue args that are Arg::Last? (i.e. `prog [foo] -- [last]). We
// can't do that for required usages being built for subcommands because it would look like:
// `prog [foo] -- [last] <subcommand>` which is totally wrong.
@ -394,8 +392,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
.iter()
.filter(|n| self.p.app.groups.iter().any(|g| &&g.name == n))
{
let g_string = self.p.app.unroll_args_in_group(g).join("|");
let elem = format!("<{}>", &g_string[..g_string.len()]);
let elem = self.p.app.format_group(g);
if !g_vec.contains(&elem) {
g_vec.push(elem);
}

View file

@ -8,7 +8,7 @@ use std::process;
use std::result::Result as StdResult;
// Internal
use build::Arg;
use build::{Arg, ArgGroup};
use output::fmt::{ColorWhen, Colorizer, ColorizerOption};
use parse::features::suggestions;
@ -405,6 +405,44 @@ impl Error {
#[doc(hidden)]
pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
#[doc(hidden)]
pub fn group_conflict<'a, 'b, O, U>(
group: &ArgGroup,
other: Option<O>,
usage: U,
color: ColorWhen,
) -> Self
where
O: Into<String>,
U: Display,
{
let mut v = vec![group.name.to_owned()];
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!(
"{} The argument '{}' cannot be used with {}\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(group.name),
match other {
Some(name) => {
let n = name.into();
v.push(n.clone());
c.warning(format!("'{}'", n))
}
None => c.none("one or more of the other specified arguments".to_owned()),
},
usage,
c.good("--help")
),
kind: ErrorKind::ArgumentConflict,
info: Some(v),
}
}
#[doc(hidden)]
pub fn argument_conflict<'a, 'b, O, U>(
arg: &Arg,

View file

@ -161,28 +161,42 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
fn build_conflict_err(&self, name: &str, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
debugln!("build_err!: name={}", name);
let mut c_with = find_from!(self.p.app, &name, blacklist, &matcher);
c_with = c_with.or(self
.p
.app
.find(&name)
.map_or(None, |ref aa| aa.blacklist.as_ref())
.map_or(None, |ref bl| bl.iter().find(|arg| matcher.contains(arg)))
.map_or(None, |an| self.p.app.find(an))
.map_or(None, |aa| Some(format!("{}", aa))));
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
let usg = Usage::new(self.p).create_usage_with_title(&[]);
if let Some(f) = self.p.app.find(&name) {
debugln!("build_err!: It was a flag...");
Err(Error::argument_conflict(
f,
if let Some(a) = self.p.app.find(name) {
for k in matcher.arg_names() {
if let Some(a) = self.p.app.find(k) {
if let Some(ref v) = a.blacklist {
if v.contains(&name) {
return Err(Error::argument_conflict(
a,
Some(a.to_string()),
&*usg,
self.p.app.color(),
));
}
}
}
}
} else if let Some(g) = self.p.app.groups.iter().find(|x| x.name == name) {
let args_in_group = self.p.app.unroll_args_in_group(g.name);
let first = matcher
.arg_names()
.find(|x| args_in_group.contains(x))
.expect(INTERNAL_ERROR_MSG);
let c_with = matcher
.arg_names()
.find(|x| x != &first && args_in_group.contains(x))
.map(|x| self.p.app.find(x).expect(INTERNAL_ERROR_MSG).to_string());
debugln!("build_err!:c_with={:?}:group", c_with);
return Err(Error::argument_conflict(
self.p.app.find(first).expect(INTERNAL_ERROR_MSG),
c_with,
&*usg,
self.p.app.color(),
))
} else {
panic!(INTERNAL_ERROR_MSG);
));
}
panic!(INTERNAL_ERROR_MSG);
}
fn validate_conflicts(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {

View file

@ -22,7 +22,7 @@ USAGE:
For more information try --help";
static REQ_GROUP_CONFLICT_REV: &'static str =
"error: The argument '--delete' cannot be used with 'base'
"error: The argument '--delete' cannot be used with '<base>'
USAGE:
clap-test <base|--delete>
@ -227,7 +227,7 @@ fn group_multiple_args_error() {
let result = App::new("group")
.args_from_usage(
"-f, --flag 'some flag'
-c, --color 'some other flag'",
-c, --color 'some other flag'",
)
.group(ArgGroup::with_name("req").args(&["flag", "color"]))
.get_matches_from_safe(vec!["group", "-f", "-c"]);