mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 06:12:40 +00:00
Merge pull request #3438 from epage/flatten
refactor: Flatten directory heirarcy
This commit is contained in:
commit
c422ed24df
15 changed files with 183 additions and 183 deletions
|
@ -1,11 +1,3 @@
|
|||
#[cfg(debug_assertions)]
|
||||
mod debug_asserts;
|
||||
mod settings;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use self::settings::{AppFlags, AppSettings};
|
||||
|
||||
// Std
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
|
@ -23,6 +15,7 @@ use os_str_bytes::RawOsStr;
|
|||
use yaml_rust::Yaml;
|
||||
|
||||
// Internal
|
||||
use crate::build::app_settings::{AppFlags, AppSettings};
|
||||
use crate::build::{arg::ArgProvider, Arg, ArgGroup, ArgPredicate};
|
||||
use crate::error::ErrorKind;
|
||||
use crate::error::Result as ClapResult;
|
||||
|
@ -32,6 +25,9 @@ use crate::parse::{ArgMatcher, ArgMatches, Input, Parser};
|
|||
use crate::util::{color::ColorChoice, Id, Key};
|
||||
use crate::{Error, INTERNAL_ERROR_MSG};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use crate::build::debug_asserts::assert_app;
|
||||
|
||||
/// Build a command-line interface.
|
||||
///
|
||||
/// This includes defining arguments, subcommands, parser behavior, and help output.
|
||||
|
@ -2802,14 +2798,14 @@ impl<'help> App<'help> {
|
|||
self.args._build();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self::debug_asserts::assert_app(self);
|
||||
assert_app(self);
|
||||
self.settings.set(AppSettings::Built);
|
||||
} else {
|
||||
debug!("App::_build: already built");
|
||||
}
|
||||
}
|
||||
|
||||
fn _panic_on_missing_help(&self, help_required_globally: bool) {
|
||||
pub(crate) fn _panic_on_missing_help(&self, help_required_globally: bool) {
|
||||
if self.is_set(AppSettings::HelpExpected) || help_required_globally {
|
||||
let args_missing_help: Vec<String> = self
|
||||
.args
|
||||
|
@ -2831,7 +2827,7 @@ impl<'help> App<'help> {
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn two_args_of<F>(&self, condition: F) -> Option<(&Arg<'help>, &Arg<'help>)>
|
||||
pub(crate) fn two_args_of<F>(&self, condition: F) -> Option<(&Arg<'help>, &Arg<'help>)>
|
||||
where
|
||||
F: Fn(&Arg) -> bool,
|
||||
{
|
|
@ -1,17 +1,3 @@
|
|||
mod arg_predicate;
|
||||
#[cfg(debug_assertions)]
|
||||
pub mod debug_asserts;
|
||||
mod possible_value;
|
||||
mod settings;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod value_hint;
|
||||
|
||||
pub use self::possible_value::PossibleValue;
|
||||
pub use self::settings::{ArgFlags, ArgSettings};
|
||||
pub use self::value_hint::ValueHint;
|
||||
pub(crate) use arg_predicate::ArgPredicate;
|
||||
|
||||
// Std
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
|
@ -29,17 +15,16 @@ use std::{env, ffi::OsString};
|
|||
use yaml_rust::Yaml;
|
||||
|
||||
// Internal
|
||||
use crate::{
|
||||
build::usage_parser::UsageParser,
|
||||
util::{Id, Key},
|
||||
INTERNAL_ERROR_MSG,
|
||||
};
|
||||
use crate::build::usage_parser::UsageParser;
|
||||
use crate::build::ArgPredicate;
|
||||
use crate::util::{Id, Key};
|
||||
use crate::PossibleValue;
|
||||
use crate::ValueHint;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::{ArgFlags, ArgSettings};
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
mod regex;
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
pub use self::regex::RegexRef;
|
||||
use crate::build::RegexRef;
|
||||
|
||||
/// The abstract representation of a command line argument. Used to set all the options and
|
||||
/// relationships that define a valid argument for the program.
|
|
@ -1,135 +0,0 @@
|
|||
use crate::{Arg, ValueHint};
|
||||
|
||||
pub(crate) fn assert_arg(arg: &Arg) {
|
||||
debug!("Arg::_debug_asserts:{}", arg.name);
|
||||
|
||||
// Self conflict
|
||||
// TODO: this check should be recursive
|
||||
assert!(
|
||||
!arg.blacklist.iter().any(|x| *x == arg.id),
|
||||
"Argument '{}' cannot conflict with itself",
|
||||
arg.name,
|
||||
);
|
||||
|
||||
if arg.value_hint != ValueHint::Unknown {
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"Argument '{}' has value hint but takes no value",
|
||||
arg.name
|
||||
);
|
||||
|
||||
if arg.value_hint == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
|
||||
arg.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if arg.index.is_some() {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Argument '{}' is a positional argument and can't have short or long name versions",
|
||||
arg.name
|
||||
);
|
||||
}
|
||||
|
||||
if arg.is_required_set() {
|
||||
assert!(
|
||||
arg.default_vals.is_empty(),
|
||||
"Argument '{}' is required and can't have a default value",
|
||||
arg.name
|
||||
);
|
||||
}
|
||||
|
||||
assert_arg_flags(arg);
|
||||
|
||||
assert_defaults(arg, "default_value", arg.default_vals.iter().copied());
|
||||
assert_defaults(
|
||||
arg,
|
||||
"default_missing_value",
|
||||
arg.default_missing_vals.iter().copied(),
|
||||
);
|
||||
assert_defaults(
|
||||
arg,
|
||||
"default_value_if",
|
||||
arg.default_vals_ifs
|
||||
.iter()
|
||||
.filter_map(|(_, _, default)| *default),
|
||||
);
|
||||
}
|
||||
|
||||
fn assert_arg_flags(arg: &Arg) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if arg.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !arg.$b() {
|
||||
s.push_str(&format!(" Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)));
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("Argument {:?}\n{}", arg.get_name(), s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checker!(is_forbid_empty_values_set requires is_takes_value_set);
|
||||
checker!(is_require_value_delimiter_set requires is_takes_value_set);
|
||||
checker!(is_require_value_delimiter_set requires is_use_value_delimiter_set);
|
||||
checker!(is_hide_possible_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_hyphen_values_set requires is_takes_value_set);
|
||||
checker!(is_require_equals_set requires is_takes_value_set);
|
||||
checker!(is_last_set requires is_takes_value_set);
|
||||
checker!(is_hide_default_value_set requires is_takes_value_set);
|
||||
checker!(is_multiple_values_set requires is_takes_value_set);
|
||||
checker!(is_ignore_case_set requires is_takes_value_set);
|
||||
checker!(is_allow_invalid_utf8_set requires is_takes_value_set);
|
||||
}
|
||||
|
||||
fn assert_defaults<'d>(
|
||||
arg: &Arg,
|
||||
field: &'static str,
|
||||
defaults: impl IntoIterator<Item = &'d std::ffi::OsStr>,
|
||||
) {
|
||||
for default_os in defaults {
|
||||
if let Some(default_s) = default_os.to_str() {
|
||||
if !arg.possible_vals.is_empty() {
|
||||
assert!(
|
||||
arg.possible_vals.iter().any(|possible_val| {
|
||||
possible_val.matches(default_s, arg.is_ignore_case_set())
|
||||
}),
|
||||
"Argument `{}`'s {}={} doesn't match possible values",
|
||||
arg.name,
|
||||
field,
|
||||
default_s
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(validator) = arg.validator.as_ref() {
|
||||
let mut validator = validator.lock().unwrap();
|
||||
if let Err(err) = validator(default_s) {
|
||||
panic!(
|
||||
"Argument `{}`'s {}={} failed validation: {}",
|
||||
arg.name, field, default_s, err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(validator) = arg.validator_os.as_ref() {
|
||||
let mut validator = validator.lock().unwrap();
|
||||
if let Err(err) = validator(default_os) {
|
||||
panic!(
|
||||
"Argument `{}`'s {}={:?} failed validation: {}",
|
||||
arg.name, field, default_os, err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
use crate::{
|
||||
build::arg::{debug_asserts::assert_arg, ArgProvider},
|
||||
mkeymap::KeyType,
|
||||
util::Id,
|
||||
App, AppSettings, Arg, ValueHint,
|
||||
};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::build::arg::ArgProvider;
|
||||
use crate::mkeymap::KeyType;
|
||||
use crate::util::Id;
|
||||
use crate::{App, AppSettings, Arg, ValueHint};
|
||||
|
||||
pub(crate) fn assert_app(app: &App) {
|
||||
debug!("App::_debug_asserts");
|
||||
|
||||
|
@ -577,3 +576,137 @@ fn _verify_positionals(app: &App) -> bool {
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
fn assert_arg(arg: &Arg) {
|
||||
debug!("Arg::_debug_asserts:{}", arg.name);
|
||||
|
||||
// Self conflict
|
||||
// TODO: this check should be recursive
|
||||
assert!(
|
||||
!arg.blacklist.iter().any(|x| *x == arg.id),
|
||||
"Argument '{}' cannot conflict with itself",
|
||||
arg.name,
|
||||
);
|
||||
|
||||
if arg.value_hint != ValueHint::Unknown {
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"Argument '{}' has value hint but takes no value",
|
||||
arg.name
|
||||
);
|
||||
|
||||
if arg.value_hint == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
|
||||
arg.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if arg.index.is_some() {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Argument '{}' is a positional argument and can't have short or long name versions",
|
||||
arg.name
|
||||
);
|
||||
}
|
||||
|
||||
if arg.is_required_set() {
|
||||
assert!(
|
||||
arg.default_vals.is_empty(),
|
||||
"Argument '{}' is required and can't have a default value",
|
||||
arg.name
|
||||
);
|
||||
}
|
||||
|
||||
assert_arg_flags(arg);
|
||||
|
||||
assert_defaults(arg, "default_value", arg.default_vals.iter().copied());
|
||||
assert_defaults(
|
||||
arg,
|
||||
"default_missing_value",
|
||||
arg.default_missing_vals.iter().copied(),
|
||||
);
|
||||
assert_defaults(
|
||||
arg,
|
||||
"default_value_if",
|
||||
arg.default_vals_ifs
|
||||
.iter()
|
||||
.filter_map(|(_, _, default)| *default),
|
||||
);
|
||||
}
|
||||
|
||||
fn assert_arg_flags(arg: &Arg) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if arg.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !arg.$b() {
|
||||
s.push_str(&format!(" Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)));
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("Argument {:?}\n{}", arg.get_name(), s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checker!(is_forbid_empty_values_set requires is_takes_value_set);
|
||||
checker!(is_require_value_delimiter_set requires is_takes_value_set);
|
||||
checker!(is_require_value_delimiter_set requires is_use_value_delimiter_set);
|
||||
checker!(is_hide_possible_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_hyphen_values_set requires is_takes_value_set);
|
||||
checker!(is_require_equals_set requires is_takes_value_set);
|
||||
checker!(is_last_set requires is_takes_value_set);
|
||||
checker!(is_hide_default_value_set requires is_takes_value_set);
|
||||
checker!(is_multiple_values_set requires is_takes_value_set);
|
||||
checker!(is_ignore_case_set requires is_takes_value_set);
|
||||
checker!(is_allow_invalid_utf8_set requires is_takes_value_set);
|
||||
}
|
||||
|
||||
fn assert_defaults<'d>(
|
||||
arg: &Arg,
|
||||
field: &'static str,
|
||||
defaults: impl IntoIterator<Item = &'d std::ffi::OsStr>,
|
||||
) {
|
||||
for default_os in defaults {
|
||||
if let Some(default_s) = default_os.to_str() {
|
||||
if !arg.possible_vals.is_empty() {
|
||||
assert!(
|
||||
arg.possible_vals.iter().any(|possible_val| {
|
||||
possible_val.matches(default_s, arg.is_ignore_case_set())
|
||||
}),
|
||||
"Argument `{}`'s {}={} doesn't match possible values",
|
||||
arg.name,
|
||||
field,
|
||||
default_s
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(validator) = arg.validator.as_ref() {
|
||||
let mut validator = validator.lock().unwrap();
|
||||
if let Err(err) = validator(default_s) {
|
||||
panic!(
|
||||
"Argument `{}`'s {}={} failed validation: {}",
|
||||
arg.name, field, default_s, err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(validator) = arg.validator_os.as_ref() {
|
||||
let mut validator = validator.lock().unwrap();
|
||||
if let Err(err) = validator(default_os) {
|
||||
panic!(
|
||||
"Argument `{}`'s {}={:?} failed validation: {}",
|
||||
arg.name, field, default_os, err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,33 @@ mod macros;
|
|||
pub mod app;
|
||||
pub mod arg;
|
||||
|
||||
mod app_settings;
|
||||
mod arg_group;
|
||||
mod arg_predicate;
|
||||
mod arg_settings;
|
||||
mod possible_value;
|
||||
mod usage_parser;
|
||||
mod value_hint;
|
||||
|
||||
pub use self::{
|
||||
app::{App, AppFlags, AppSettings},
|
||||
arg::{Arg, ArgFlags, ArgSettings, PossibleValue, ValueHint},
|
||||
arg_group::ArgGroup,
|
||||
};
|
||||
pub(crate) use arg::ArgPredicate;
|
||||
#[cfg(feature = "regex")]
|
||||
mod regex;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
mod debug_asserts;
|
||||
|
||||
#[cfg(test)]
|
||||
mod app_tests;
|
||||
#[cfg(test)]
|
||||
mod arg_tests;
|
||||
|
||||
pub use app::App;
|
||||
pub use app_settings::{AppFlags, AppSettings};
|
||||
pub use arg::Arg;
|
||||
pub use arg_group::ArgGroup;
|
||||
pub(crate) use arg_predicate::ArgPredicate;
|
||||
pub use arg_settings::{ArgFlags, ArgSettings};
|
||||
pub use possible_value::PossibleValue;
|
||||
pub use value_hint::ValueHint;
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
pub use self::regex::RegexRef;
|
||||
|
|
|
@ -65,7 +65,7 @@ mod macros;
|
|||
mod derive;
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
pub use crate::build::arg::RegexRef;
|
||||
pub use crate::build::RegexRef;
|
||||
|
||||
pub mod error;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Internal
|
||||
use crate::build::{arg::PossibleValue, App, AppSettings as AS, Arg, ArgPredicate};
|
||||
use crate::build::{App, AppSettings as AS, Arg, ArgPredicate, PossibleValue};
|
||||
use crate::error::{Error, Result as ClapResult};
|
||||
use crate::output::Usage;
|
||||
use crate::parse::{ArgMatcher, MatchedArg, ParseState, Parser};
|
||||
|
|
Loading…
Reference in a new issue