Skip to content

Commit d3d34a2

Browse files
committed
fix: fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands
Closes #789
1 parent eb1d79d commit d3d34a2

File tree

2 files changed

+49
-53
lines changed

2 files changed

+49
-53
lines changed

src/app/parser.rs

+49-51
Original file line numberDiff line numberDiff line change
@@ -817,10 +817,10 @@ impl<'a, 'b> Parser<'a, 'b>
817817
subcmd_name = Some(arg_os.to_str().expect(INVALID_UTF8).to_owned());
818818
break;
819819
} else if let Some(cdate) =
820-
suggestions::did_you_mean(&*arg_os.to_string_lossy(),
821-
self.subcommands
822-
.iter()
823-
.map(|s| &s.p.meta.name)) {
820+
suggestions::did_you_mean(&*arg_os.to_string_lossy(),
821+
self.subcommands
822+
.iter()
823+
.map(|s| &s.p.meta.name)) {
824824
return Err(Error::invalid_subcommand(arg_os.to_string_lossy().into_owned(),
825825
cdate,
826826
self.meta
@@ -894,51 +894,13 @@ impl<'a, 'b> Parser<'a, 'b>
894894
}
895895
}
896896

897-
self.validate(needs_val_of, subcmd_name, matcher, it)
898-
}
899-
900-
fn validate<I, T>(&mut self,
901-
needs_val_of: Option<&'a str>,
902-
subcmd_name: Option<String>,
903-
matcher: &mut ArgMatcher<'a>,
904-
it: &mut Peekable<I>)
905-
-> ClapResult<()>
906-
where I: Iterator<Item = T>,
907-
T: Into<OsString> + Clone
908-
{
909-
let mut reqs_validated = false;
910-
if let Some(a) = needs_val_of {
911-
debugln!("needs_val_of={:?}", a);
912-
let o = find_by_name!(self, &a, opts, iter).expect(INTERNAL_ERROR_MSG);
913-
try!(self.validate_required(matcher));
914-
reqs_validated = true;
915-
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
916-
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
917-
} else {
918-
true
919-
};
920-
if should_err {
921-
return Err(Error::empty_value(o,
922-
&*self.create_current_usage(matcher),
923-
self.color()));
924-
}
925-
}
926-
927-
try!(self.add_defaults(matcher));
928-
try!(self.validate_blacklist(matcher));
929-
try!(self.validate_num_args(matcher));
930-
matcher.usage(self.create_usage(&[]));
931-
932-
if !(self.settings.is_set(AppSettings::SubcommandsNegateReqs) && subcmd_name.is_some()) &&
933-
!reqs_validated {
934-
try!(self.validate_required(matcher));
935-
}
936-
if let Some(pos_sc_name) = subcmd_name {
897+
if let Some(ref pos_sc_name) = subcmd_name {
937898
// is this is a real subcommand, or an alias
938-
let sc_name = if self.subcommands.iter().any(|sc| sc.p.meta.name == pos_sc_name) {
939-
pos_sc_name
899+
if self.subcommands.iter().any(|sc| &sc.p.meta.name == pos_sc_name) {
900+
901+
try!(self.parse_subcommand(&*pos_sc_name, matcher, it));
940902
} else {
941-
self.subcommands
903+
let sc_name = &*self.subcommands
942904
.iter()
943905
.filter(|sc| sc.p.meta.aliases.is_some())
944906
.filter_map(|sc| if sc.p
@@ -953,9 +915,9 @@ impl<'a, 'b> Parser<'a, 'b>
953915
None
954916
})
955917
.next()
956-
.expect(INTERNAL_ERROR_MSG)
918+
.expect(INTERNAL_ERROR_MSG);
919+
try!(self.parse_subcommand(sc_name, matcher, it));
957920
};
958-
try!(self.parse_subcommand(sc_name, matcher, it));
959921
} else if self.is_set(AppSettings::SubcommandRequired) {
960922
let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
961923
return Err(Error::missing_subcommand(bn,
@@ -970,6 +932,42 @@ impl<'a, 'b> Parser<'a, 'b>
970932
info: None,
971933
});
972934
}
935+
936+
self.validate(needs_val_of, subcmd_name, matcher)
937+
}
938+
939+
fn validate(&mut self,
940+
needs_val_of: Option<&'a str>,
941+
subcmd_name: Option<String>,
942+
matcher: &mut ArgMatcher<'a>)
943+
-> ClapResult<()> {
944+
let mut reqs_validated = false;
945+
if let Some(a) = needs_val_of {
946+
debugln!("needs_val_of={:?}", a);
947+
let o = find_by_name!(self, &a, opts, iter).expect(INTERNAL_ERROR_MSG);
948+
try!(self.validate_required(matcher));
949+
reqs_validated = true;
950+
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
951+
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
952+
} else {
953+
true
954+
};
955+
if should_err {
956+
return Err(Error::empty_value(o,
957+
&*self.create_current_usage(matcher),
958+
self.color()));
959+
}
960+
}
961+
962+
try!(self.add_defaults(matcher));
963+
try!(self.validate_blacklist(matcher));
964+
try!(self.validate_num_args(matcher));
965+
matcher.usage(self.create_usage(&[]));
966+
967+
if !(self.settings.is_set(AppSettings::SubcommandsNegateReqs) && subcmd_name.is_some()) &&
968+
!reqs_validated {
969+
try!(self.validate_required(matcher));
970+
}
973971
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
974972
self.is_set(AppSettings::ArgRequiredElseHelp) {
975973
let mut out = vec![];
@@ -1019,7 +1017,7 @@ impl<'a, 'b> Parser<'a, 'b>
10191017
}
10201018

10211019
fn parse_subcommand<I, T>(&mut self,
1022-
sc_name: String,
1020+
sc_name: &str,
10231021
matcher: &mut ArgMatcher<'a>,
10241022
it: &mut Peekable<I>)
10251023
-> ClapResult<()>
@@ -1750,7 +1748,7 @@ impl<'a, 'b> Parser<'a, 'b>
17501748
return true;
17511749
}
17521750
}
1753-
}
1751+
}
17541752
if let Some(ru) = a.required_unless() {
17551753
debugln!("Required unless found...{:?}", ru);
17561754
let mut found_any = false;

src/usage_parser.rs

-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ use INTERNAL_ERROR_MSG;
66
use args::Arg;
77
use args::settings::ArgSettings;
88

9-
type ParseResult = Result<(), ()>;
10-
119
#[derive(PartialEq, Debug)]
1210
enum UsageToken {
1311
Name,

0 commit comments

Comments
 (0)