mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
Attach validation error as Error::source
This commit is contained in:
parent
5a1a209965
commit
b31df047b8
8 changed files with 63 additions and 17 deletions
|
@ -4,12 +4,12 @@ use clap::Clap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
/// Parse a single key-value pair
|
/// Parse a single key-value pair
|
||||||
fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error>>
|
fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
|
||||||
where
|
where
|
||||||
T: std::str::FromStr,
|
T: std::str::FromStr,
|
||||||
T::Err: Error + 'static,
|
T::Err: Error + Send + Sync + 'static,
|
||||||
U: std::str::FromStr,
|
U: std::str::FromStr,
|
||||||
U::Err: Error + 'static,
|
U::Err: Error + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let pos = s
|
let pos = s
|
||||||
.find('=')
|
.find('=')
|
||||||
|
|
|
@ -227,7 +227,6 @@ pub fn gen_app_augmentation(
|
||||||
.validator(|s| {
|
.validator(|s| {
|
||||||
#func(s)
|
#func(s)
|
||||||
.map(|_: #convert_type| ())
|
.map(|_: #convert_type| ())
|
||||||
.map_err(|e| e.to_string())
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
|
ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
|
||||||
|
|
|
@ -90,7 +90,15 @@ fn test_parse_hex() {
|
||||||
fn custom_parser_1(_: &str) -> &'static str {
|
fn custom_parser_1(_: &str) -> &'static str {
|
||||||
"A"
|
"A"
|
||||||
}
|
}
|
||||||
fn custom_parser_2(_: &str) -> Result<&'static str, u32> {
|
#[derive(Debug)]
|
||||||
|
struct ErrCode(u32);
|
||||||
|
impl std::error::Error for ErrCode {}
|
||||||
|
impl std::fmt::Display for ErrCode {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn custom_parser_2(_: &str) -> Result<&'static str, ErrCode> {
|
||||||
Ok("B")
|
Ok("B")
|
||||||
}
|
}
|
||||||
fn custom_parser_3(_: &OsStr) -> &'static str {
|
fn custom_parser_3(_: &OsStr) -> &'static str {
|
||||||
|
|
|
@ -11,6 +11,7 @@ use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
cmp::{Ord, Ordering},
|
cmp::{Ord, Ordering},
|
||||||
env,
|
env,
|
||||||
|
error::Error,
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
str,
|
str,
|
||||||
|
@ -38,8 +39,8 @@ use crate::{
|
||||||
#[cfg(feature = "yaml")]
|
#[cfg(feature = "yaml")]
|
||||||
use yaml_rust::Yaml;
|
use yaml_rust::Yaml;
|
||||||
|
|
||||||
type Validator<'a> = dyn FnMut(&str) -> Result<(), String> + Send + 'a;
|
type Validator<'a> = dyn FnMut(&str) -> Result<(), Box<dyn Error + Send + Sync>> + Send + 'a;
|
||||||
type ValidatorOs<'a> = dyn FnMut(&OsStr) -> Result<(), String> + Send + 'a;
|
type ValidatorOs<'a> = dyn FnMut(&OsStr) -> Result<(), Box<dyn Error + Send + Sync>> + Send + 'a;
|
||||||
|
|
||||||
/// The abstract representation of a command line argument. Used to set all the options and
|
/// The abstract representation of a command line argument. Used to set all the options and
|
||||||
/// relationships that define a valid argument for the program.
|
/// relationships that define a valid argument for the program.
|
||||||
|
@ -1879,10 +1880,10 @@ impl<'help> Arg<'help> {
|
||||||
pub fn validator<F, O, E>(mut self, mut f: F) -> Self
|
pub fn validator<F, O, E>(mut self, mut f: F) -> Self
|
||||||
where
|
where
|
||||||
F: FnMut(&str) -> Result<O, E> + Send + 'help,
|
F: FnMut(&str) -> Result<O, E> + Send + 'help,
|
||||||
E: ToString,
|
E: Into<Box<dyn Error + Send + Sync + 'static>>,
|
||||||
{
|
{
|
||||||
self.validator = Some(Arc::new(Mutex::new(move |s: &str| {
|
self.validator = Some(Arc::new(Mutex::new(move |s: &str| {
|
||||||
f(s).map(|_| ()).map_err(|e| e.to_string())
|
f(s).map(|_| ()).map_err(|e| e.into())
|
||||||
})));
|
})));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -1917,11 +1918,14 @@ impl<'help> Arg<'help> {
|
||||||
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
|
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
|
||||||
/// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
|
/// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
|
||||||
/// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
|
/// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
|
||||||
pub fn validator_os<F, O>(mut self, mut f: F) -> Self
|
pub fn validator_os<F, O, E>(mut self, mut f: F) -> Self
|
||||||
where
|
where
|
||||||
F: FnMut(&OsStr) -> Result<O, String> + Send + 'help,
|
F: FnMut(&OsStr) -> Result<O, E> + Send + 'help,
|
||||||
|
E: Into<Box<dyn Error + Send + Sync + 'static>>,
|
||||||
{
|
{
|
||||||
self.validator_os = Some(Arc::new(Mutex::new(move |s: &OsStr| f(s).map(|_| ()))));
|
self.validator_os = Some(Arc::new(Mutex::new(move |s: &OsStr| {
|
||||||
|
f(s).map(|_| ()).map_err(|e| e.into())
|
||||||
|
})));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -385,6 +385,7 @@ pub struct Error {
|
||||||
/// Additional information depending on the error kind, like values and argument names.
|
/// Additional information depending on the error kind, like values and argument names.
|
||||||
/// Useful when you want to render an error of your own.
|
/// Useful when you want to render an error of your own.
|
||||||
pub info: Vec<String>,
|
pub info: Vec<String>,
|
||||||
|
pub(crate) source: Option<Box<dyn error::Error + Send + Sync>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
|
@ -478,6 +479,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::ArgumentConflict,
|
kind: ErrorKind::ArgumentConflict,
|
||||||
info,
|
info,
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,6 +497,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::EmptyValue,
|
kind: ErrorKind::EmptyValue,
|
||||||
info: vec![arg],
|
info: vec![arg],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,6 +560,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::InvalidValue,
|
kind: ErrorKind::InvalidValue,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,6 +591,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::InvalidSubcommand,
|
kind: ErrorKind::InvalidSubcommand,
|
||||||
info: vec![subcmd],
|
info: vec![subcmd],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,6 +613,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::UnrecognizedSubcommand,
|
kind: ErrorKind::UnrecognizedSubcommand,
|
||||||
info: vec![subcmd],
|
info: vec![subcmd],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,6 +643,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::MissingRequiredArgument,
|
kind: ErrorKind::MissingRequiredArgument,
|
||||||
info,
|
info,
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,6 +660,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::MissingSubcommand,
|
kind: ErrorKind::MissingSubcommand,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,6 +678,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::InvalidUtf8,
|
kind: ErrorKind::InvalidUtf8,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,6 +702,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::TooManyValues,
|
kind: ErrorKind::TooManyValues,
|
||||||
info: vec![arg.to_string(), val],
|
info: vec![arg.to_string(), val],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,13 +730,14 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::TooFewValues,
|
kind: ErrorKind::TooFewValues,
|
||||||
info: vec![arg.to_string(), curr_vals.to_string(), min_vals.to_string()],
|
info: vec![arg.to_string(), curr_vals.to_string(), min_vals.to_string()],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn value_validation(
|
pub(crate) fn value_validation(
|
||||||
arg: String,
|
arg: String,
|
||||||
val: String,
|
val: String,
|
||||||
err: String,
|
err: Box<dyn error::Error + Send + Sync>,
|
||||||
color: ColorChoice,
|
color: ColorChoice,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut c = Colorizer::new(true, color);
|
let mut c = Colorizer::new(true, color);
|
||||||
|
@ -743,7 +754,8 @@ impl Error {
|
||||||
Error {
|
Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::ValueValidation,
|
kind: ErrorKind::ValueValidation,
|
||||||
info: vec![arg, val, err],
|
info: vec![arg, val, err.to_string()],
|
||||||
|
source: Some(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,6 +783,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::WrongNumberOfValues,
|
kind: ErrorKind::WrongNumberOfValues,
|
||||||
info: vec![arg.to_string(), curr_vals.to_string(), num_vals.to_string()],
|
info: vec![arg.to_string(), curr_vals.to_string(), num_vals.to_string()],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,6 +801,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::UnexpectedMultipleUsage,
|
kind: ErrorKind::UnexpectedMultipleUsage,
|
||||||
info: vec![arg],
|
info: vec![arg],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,6 +850,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::UnknownArgument,
|
kind: ErrorKind::UnknownArgument,
|
||||||
info: vec![arg],
|
info: vec![arg],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,6 +872,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::UnknownArgument,
|
kind: ErrorKind::UnknownArgument,
|
||||||
info: vec![arg],
|
info: vec![arg],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,6 +888,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::ArgumentNotFound,
|
kind: ErrorKind::ArgumentNotFound,
|
||||||
info: vec![arg],
|
info: vec![arg],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,6 +905,7 @@ impl Error {
|
||||||
message: c,
|
message: c,
|
||||||
kind,
|
kind,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -904,4 +922,12 @@ impl From<fmt::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {}
|
impl error::Error for Error {
|
||||||
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||||
|
if let Some(source) = self.source.as_deref() {
|
||||||
|
Some(source)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -351,7 +351,12 @@ impl ArgMatches {
|
||||||
v, name, e
|
v, name, e
|
||||||
);
|
);
|
||||||
|
|
||||||
Error::value_validation(name.to_string(), v.to_string(), message, ColorChoice::Auto)
|
Error::value_validation(
|
||||||
|
name.to_string(),
|
||||||
|
v.to_string(),
|
||||||
|
message.into(),
|
||||||
|
ColorChoice::Auto,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::argument_not_found_auto(name.to_string()))
|
Err(Error::argument_not_found_auto(name.to_string()))
|
||||||
|
@ -439,7 +444,7 @@ impl ArgMatches {
|
||||||
Error::value_validation(
|
Error::value_validation(
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
v.to_string(),
|
v.to_string(),
|
||||||
message,
|
message.into(),
|
||||||
ColorChoice::Auto,
|
ColorChoice::Auto,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -752,6 +752,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
message,
|
message,
|
||||||
kind: ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
kind: ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1747,6 +1748,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::DisplayHelp,
|
kind: ErrorKind::DisplayHelp,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1761,6 +1763,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
message: c,
|
message: c,
|
||||||
kind: ErrorKind::DisplayVersion,
|
kind: ErrorKind::DisplayVersion,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
message,
|
message,
|
||||||
kind: ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
kind: ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
||||||
info: vec![],
|
info: vec![],
|
||||||
|
source: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.validate_conflicts(matcher)?;
|
self.validate_conflicts(matcher)?;
|
||||||
|
|
Loading…
Reference in a new issue