Skip to content

Commit

Permalink
fix(Safe Matches): using 'safe' forms of the get_matches family no lo…
Browse files Browse the repository at this point in the history
…nger exit the process

Closes #256
  • Loading branch information
kbknapp committed Oct 28, 2015
1 parent c9a9548 commit c47025d
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 10 deletions.
82 changes: 73 additions & 9 deletions src/app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1670,7 +1670,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
// Callers still use &[""]
assert_eq!(data.len(), 1);
"Invalid unicode character in one or more arguments".to_owned()
}
},
// HelpDisplayed, VersionDisplayed
_ => unreachable!()
};

ClapError {
Expand Down Expand Up @@ -1741,6 +1743,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
/// the real parsing function for all subcommands
///
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
/// perform a `std::process::exit` yourself.
///
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
/// manually.
///
Expand All @@ -1763,6 +1770,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
/// the real parsing function for all subcommands. Invalid unicode characters are replaced with
/// `U+FFFD REPLACEMENT CHARACTER`
///
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
/// perform a `std::process::exit` yourself.
///
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
/// manually.
///
Expand Down Expand Up @@ -1809,6 +1821,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
match self.get_matches_from_safe_borrow(itr) {
Ok(m) => return m,
Err(e) => {
match e.error_type {
ClapErrorType::HelpDisplayed | ClapErrorType::VersionDisplayed => e.exit(),
_ => ()
}
wlnerr!("{}", e.error);
if self.settings.is_set(&AppSettings::WaitOnError) {
wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
Expand Down Expand Up @@ -1850,6 +1866,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
match self.get_matches_from_safe_borrow_lossy(itr) {
Ok(m) => return m,
Err(e) => {
match e.error_type {
ClapErrorType::HelpDisplayed | ClapErrorType::VersionDisplayed => e.exit(),
_ => ()
}
wlnerr!("{}", e.error);
if self.settings.is_set(&AppSettings::WaitOnError) {
wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
Expand All @@ -1865,6 +1885,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
/// the real parsing function for all subcommands
///
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
/// perform a `std::process::exit` yourself.
///
/// **NOTE:** The first argument will be parsed as the binary name.
///
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
Expand Down Expand Up @@ -1901,6 +1926,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
/// the real parsing function for all subcommands. Invalid unicode characters are replaced with
/// `U+FFFD REPLACEMENT CHARACTER`
///
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
/// perform a `std::process::exit` yourself.
///
/// **NOTE:** The first argument will be parsed as the binary name.
///
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
Expand Down Expand Up @@ -2292,7 +2322,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
error_type: ClapErrorType::MissingSubcommand
});
}
process::exit(0);
// process::exit(0);
return Err(ClapError{
error: String::new(),
error_type: ClapErrorType::HelpDisplayed
})
}
subcmd_name = Some(arg_slice.to_owned());
break;
Expand Down Expand Up @@ -2696,19 +2730,41 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{

fn check_for_help_and_version(&self,
arg: char)
-> io::Result<()> {
-> Result<(), ClapError> {
if let Some(h) = self.help_short {
if h == arg {
try!(self.print_help());
process::exit(0);
if let Err(e) = self.print_help() {
return Err(ClapError{
error: format!("{} {}\n\terror message: {}\n",
Format::Error("error:"),
INTERNAL_ERROR_MSG, e.description()),
error_type: ClapErrorType::MissingSubcommand
});
}
// process::exit(0);
return Err(ClapError{
error: String::new(),
error_type: ClapErrorType::HelpDisplayed
})
}
}
if let Some(v) = self.version_short {
if v == arg {
let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock());
try!(self.print_version(&mut buf_w));
process::exit(0);
if let Err(e) = self.print_version(&mut buf_w) {
return Err(ClapError{
error: format!("{} {}\n\terror message: {}\n",
Format::Error("error:"),
INTERNAL_ERROR_MSG, e.description()),
error_type: ClapErrorType::MissingSubcommand
});
}
// process::exit(0);
return Err(ClapError{
error: String::new(),
error_type: ClapErrorType::VersionDisplayed
})
}
}

Expand All @@ -2730,7 +2786,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
error_type: ClapErrorType::MissingSubcommand
});
}
process::exit(0);
return Err(ClapError{
error: String::new(),
error_type: ClapErrorType::HelpDisplayed
})
// process::exit(0);
} else if arg == "version" && self.settings.is_set(&AppSettings::NeedsLongVersion) {
let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock());
Expand All @@ -2742,7 +2802,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
error_type: ClapErrorType::MissingSubcommand
});
}
process::exit(0);
return Err(ClapError{
error: String::new(),
error_type: ClapErrorType::VersionDisplayed
})
// process::exit(0);
}

let mut arg_val: Option<&'av str> = None;
Expand Down
33 changes: 32 additions & 1 deletion src/app/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,38 @@ pub enum ClapErrorType {
/// OsString::from_vec(vec![0xE9])]);
/// assert!(result.is_err());
/// ```
InvalidUnicode
InvalidUnicode,
/// Not a true 'error' as it means `--help` or similar was used. The help message will be sent
/// to `stdout` unless the help is displayed due to an error (such as missing subcommands) at
/// which point it will be sent to `stderr`
///
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg};
/// # use clap::ClapErrorType;
/// let result = App::new("myprog")
/// .get_matches_from_safe(vec!["", "--help"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().error_type, ClapErrorType::HelpDisplayed);
/// ```
HelpDisplayed,
/// Not a true 'error' as it means `--version` or similar was used. The message will be sent
/// to `stdout`
///
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg};
/// # use clap::ClapErrorType;
/// let result = App::new("myprog")
/// .get_matches_from_safe(vec!["", "--version"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().error_type, ClapErrorType::VersionDisplayed);
/// ```
VersionDisplayed
}

/// Command line argument parser error
Expand Down
1 change: 1 addition & 0 deletions src/args/argmatches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use args::MatchedArg;
/// println!("Not printing testing lists...");
/// }
/// }
#[derive(Debug)]
pub struct ArgMatches<'n, 'a> {
#[doc(hidden)]
pub args: HashMap<&'a str, MatchedArg>,
Expand Down
1 change: 1 addition & 0 deletions src/args/matchedarg.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::BTreeMap;

#[doc(hidden)]
#[derive(Debug)]
pub struct MatchedArg {
// #[doc(hidden)]
// pub name: String,
Expand Down
1 change: 1 addition & 0 deletions src/args/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use ArgMatches;
/// .help("The configuration file to use")
/// .index(1))
/// # ).get_matches();
#[derive(Debug)]
pub struct SubCommand<'n, 'a> {
#[doc(hidden)]
pub name: &'n str,
Expand Down

0 comments on commit c47025d

Please sign in to comment.