From f16bdcc821cf49db202f53675cbc0a27af525633 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Dec 2021 09:03:54 -0600 Subject: [PATCH 1/2] fix!: Limit Setting FromStrs to YAML These exist pretty much just for YAML (#3087). If anyone else is building on these, it has a limited shelf-life anyways because of #2717. BREAKING CHANGE: `FromStr` for settings requires the `yaml` feature. --- src/build/app/settings.rs | 9 ++++++--- src/build/arg/settings.rs | 9 ++++++--- src/macros.rs | 2 ++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs index 5367c5b3b53..91479831c37 100644 --- a/src/build/app/settings.rs +++ b/src/build/app/settings.rs @@ -1,5 +1,7 @@ // Std -use std::{ops::BitOr, str::FromStr}; +use std::ops::BitOr; +#[cfg(feature = "yaml")] +use std::str::FromStr; // Third party use bitflags::bitflags; @@ -1158,11 +1160,12 @@ impl_settings! { AppSettings, AppFlags, #[cfg(test)] mod test { - use super::AppSettings; - #[allow(clippy::cognitive_complexity)] #[test] + #[cfg(feature = "yaml")] fn app_settings_fromstr() { + use super::AppSettings; + assert_eq!( "disablehelpflag".parse::().unwrap(), AppSettings::DisableHelpFlag diff --git a/src/build/arg/settings.rs b/src/build/arg/settings.rs index 1dd0ecf2cd6..af6712e24e5 100644 --- a/src/build/arg/settings.rs +++ b/src/build/arg/settings.rs @@ -1,5 +1,7 @@ // Std -use std::{ops::BitOr, str::FromStr}; +use std::ops::BitOr; +#[cfg(feature = "yaml")] +use std::str::FromStr; // Third party use bitflags::bitflags; @@ -157,10 +159,11 @@ impl_settings! { ArgSettings, ArgFlags, #[cfg(test)] mod test { - use super::ArgSettings; - #[test] + #[cfg(feature = "yaml")] fn arg_settings_fromstr() { + use super::ArgSettings; + assert_eq!( "allowhyphenvalues".parse::().unwrap(), ArgSettings::AllowHyphenValues diff --git a/src/macros.rs b/src/macros.rs index 01bed5b45a9..bc3a1013be8 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -879,6 +879,8 @@ macro_rules! impl_settings { } } + /// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case? + #[cfg(feature = "yaml")] impl FromStr for $settings { type Err = String; fn from_str(s: &str) -> Result::Err> { From 8a30b01bc1644c9a79e72874d5c718dfc1822328 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Dec 2021 09:09:17 -0600 Subject: [PATCH 2/2] refactor(yaml): Freeze FromStr --- src/build/app/settings.rs | 158 ++++++++++++++++++++++++++------------ src/build/arg/settings.rs | 90 ++++++++++++++++------ src/macros.rs | 19 +---- 3 files changed, 176 insertions(+), 91 deletions(-) diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs index 91479831c37..e2fa1f5ba8d 100644 --- a/src/build/app/settings.rs +++ b/src/build/app/settings.rs @@ -1060,104 +1060,166 @@ bitflags! { } impl_settings! { AppSettings, AppFlags, - ArgRequiredElseHelp("argrequiredelsehelp") + ArgRequiredElseHelp => Flags::ARG_REQUIRED_ELSE_HELP, - SubcommandPrecedenceOverArg("subcommandprecedenceoverarg") + SubcommandPrecedenceOverArg => Flags::SUBCOMMAND_PRECEDENCE_OVER_ARG, - ArgsNegateSubcommands("argsnegatesubcommands") + ArgsNegateSubcommands => Flags::ARGS_NEGATE_SCS, - AllowExternalSubcommands("allowexternalsubcommands") + AllowExternalSubcommands => Flags::ALLOW_UNK_SC, - StrictUtf8("strictutf8") + StrictUtf8 => Flags::NO_OP, - AllowInvalidUtf8ForExternalSubcommands("allowinvalidutf8forexternalsubcommands") + AllowInvalidUtf8ForExternalSubcommands => Flags::SC_UTF8_NONE, - AllowHyphenValues("allowhyphenvalues") + AllowHyphenValues => Flags::LEADING_HYPHEN, - AllowLeadingHyphen("allowleadinghyphen") + AllowLeadingHyphen => Flags::LEADING_HYPHEN, - AllowNegativeNumbers("allownegativenumbers") + AllowNegativeNumbers => Flags::ALLOW_NEG_NUMS, - AllowMissingPositional("allowmissingpositional") + AllowMissingPositional => Flags::ALLOW_MISSING_POS, - UnifiedHelpMessage("unifiedhelpmessage") + UnifiedHelpMessage => Flags::NO_OP, - ColoredHelp("coloredhelp") + ColoredHelp => Flags::NO_OP, - ColorAlways("coloralways") + ColorAlways => Flags::COLOR_ALWAYS, - ColorAuto("colorauto") + ColorAuto => Flags::COLOR_AUTO, - ColorNever("colornever") + ColorNever => Flags::COLOR_NEVER, - DontDelimitTrailingValues("dontdelimittrailingvalues") + DontDelimitTrailingValues => Flags::DONT_DELIM_TRAIL, - DontCollapseArgsInUsage("dontcollapseargsinusage") + DontCollapseArgsInUsage => Flags::DONT_COLLAPSE_ARGS, - DeriveDisplayOrder("derivedisplayorder") + DeriveDisplayOrder => Flags::DERIVE_DISP_ORDER, - DisableColoredHelp("disablecoloredhelp") + DisableColoredHelp => Flags::DISABLE_COLORED_HELP, - DisableHelpSubcommand("disablehelpsubcommand") + DisableHelpSubcommand => Flags::DISABLE_HELP_SC, - DisableHelpFlag("disablehelpflag") + DisableHelpFlag => Flags::DISABLE_HELP_FLAG, - DisableHelpFlags("disablehelpflags") + DisableHelpFlags => Flags::DISABLE_HELP_FLAG, - DisableVersionFlag("disableversionflag") + DisableVersionFlag => Flags::DISABLE_VERSION_FLAG, - DisableVersion("disableversion") + DisableVersion => Flags::DISABLE_VERSION_FLAG, - PropagateVersion("propagateversion") + PropagateVersion => Flags::PROPAGATE_VERSION, - GlobalVersion("propagateversion") + GlobalVersion => Flags::PROPAGATE_VERSION, - HidePossibleValues("hidepossiblevalues") + HidePossibleValues => Flags::NO_POS_VALUES, - HidePossibleValuesInHelp("hidepossiblevaluesinhelp") + HidePossibleValuesInHelp => Flags::NO_POS_VALUES, - HelpExpected("helpexpected") + HelpExpected => Flags::HELP_REQUIRED, - Hidden("hidden") + Hidden => Flags::HIDDEN, #[cfg(feature = "unstable-multicall")] - Multicall("multicall") + Multicall => Flags::MULTICALL, - NoAutoHelp("noautohelp") + NoAutoHelp => Flags::NO_AUTO_HELP, - NoAutoVersion("noautoversion") + NoAutoVersion => Flags::NO_AUTO_VERSION, - NoBinaryName("nobinaryname") + NoBinaryName => Flags::NO_BIN_NAME, - SubcommandsNegateReqs("subcommandsnegatereqs") + SubcommandsNegateReqs => Flags::SC_NEGATE_REQS, - SubcommandRequired("subcommandrequired") + SubcommandRequired => Flags::SC_REQUIRED, - SubcommandRequiredElseHelp("subcommandrequiredelsehelp") + SubcommandRequiredElseHelp => Flags::SC_REQUIRED_ELSE_HELP, - UseLongFormatForHelpSubcommand("uselongformatforhelpsubcommand") + UseLongFormatForHelpSubcommand => Flags::USE_LONG_FORMAT_FOR_HELP_SC, - TrailingVarArg("trailingvararg") + TrailingVarArg => Flags::TRAILING_VARARG, - UnifiedHelp("unifiedhelp") => Flags::NO_OP, - NextLineHelp("nextlinehelp") + UnifiedHelp => Flags::NO_OP, + NextLineHelp => Flags::NEXT_LINE_HELP, - IgnoreErrors("ignoreerrors") + IgnoreErrors => Flags::IGNORE_ERRORS, - WaitOnError("waitonerror") + WaitOnError => Flags::WAIT_ON_ERROR, - Built("built") + Built => Flags::BUILT, - BinNameBuilt("binnamebuilt") + BinNameBuilt => Flags::BIN_NAME_BUILT, - InferSubcommands("infersubcommands") + InferSubcommands => Flags::INFER_SUBCOMMANDS, - AllArgsOverrideSelf("allargsoverrideself") + AllArgsOverrideSelf => Flags::ARGS_OVERRIDE_SELF, - InferLongArgs("inferlongargs") + InferLongArgs => Flags::INFER_LONG_ARGS } +/// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case? +#[cfg(feature = "yaml")] +impl FromStr for AppSettings { + type Err = String; + fn from_str(s: &str) -> Result::Err> { + #[allow(deprecated)] + #[allow(unreachable_patterns)] + match &*s.to_ascii_lowercase() { + "argrequiredelsehelp" => Ok(AppSettings::ArgRequiredElseHelp), + "subcommandprecedenceoverarg" => Ok(AppSettings::SubcommandPrecedenceOverArg), + "argsnegatesubcommands" => Ok(AppSettings::ArgsNegateSubcommands), + "allowexternalsubcommands" => Ok(AppSettings::AllowExternalSubcommands), + "strictutf8" => Ok(AppSettings::StrictUtf8), + "allowinvalidutf8forexternalsubcommands" => { + Ok(AppSettings::AllowInvalidUtf8ForExternalSubcommands) + } + "allowhyphenvalues" => Ok(AppSettings::AllowHyphenValues), + "allowleadinghyphen" => Ok(AppSettings::AllowLeadingHyphen), + "allownegativenumbers" => Ok(AppSettings::AllowNegativeNumbers), + "allowmissingpositional" => Ok(AppSettings::AllowMissingPositional), + "unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage), + "coloredhelp" => Ok(AppSettings::ColoredHelp), + "coloralways" => Ok(AppSettings::ColorAlways), + "colorauto" => Ok(AppSettings::ColorAuto), + "colornever" => Ok(AppSettings::ColorNever), + "dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues), + "dontcollapseargsinusage" => Ok(AppSettings::DontCollapseArgsInUsage), + "derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder), + "disablecoloredhelp" => Ok(AppSettings::DisableColoredHelp), + "disablehelpsubcommand" => Ok(AppSettings::DisableHelpSubcommand), + "disablehelpflag" => Ok(AppSettings::DisableHelpFlag), + "disablehelpflags" => Ok(AppSettings::DisableHelpFlags), + "disableversionflag" => Ok(AppSettings::DisableVersionFlag), + "disableversion" => Ok(AppSettings::DisableVersion), + "propagateversion" => Ok(AppSettings::PropagateVersion), + "propagateversion" => Ok(AppSettings::GlobalVersion), + "hidepossiblevalues" => Ok(AppSettings::HidePossibleValues), + "hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp), + "helpexpected" => Ok(AppSettings::HelpExpected), + "hidden" => Ok(AppSettings::Hidden), + "noautohelp" => Ok(AppSettings::NoAutoHelp), + "noautoversion" => Ok(AppSettings::NoAutoVersion), + "nobinaryname" => Ok(AppSettings::NoBinaryName), + "subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs), + "subcommandrequired" => Ok(AppSettings::SubcommandRequired), + "subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp), + "uselongformatforhelpsubcommand" => Ok(AppSettings::UseLongFormatForHelpSubcommand), + "trailingvararg" => Ok(AppSettings::TrailingVarArg), + "unifiedhelp" => Ok(AppSettings::UnifiedHelp), + "nextlinehelp" => Ok(AppSettings::NextLineHelp), + "ignoreerrors" => Ok(AppSettings::IgnoreErrors), + "waitonerror" => Ok(AppSettings::WaitOnError), + "built" => Ok(AppSettings::Built), + "binnamebuilt" => Ok(AppSettings::BinNameBuilt), + "infersubcommands" => Ok(AppSettings::InferSubcommands), + "allargsoverrideself" => Ok(AppSettings::AllArgsOverrideSelf), + "inferlongargs" => Ok(AppSettings::InferLongArgs), + _ => Err(format!("unknown AppSetting: `{}`", s)), + } + } +} + #[cfg(test)] mod test { #[allow(clippy::cognitive_complexity)] diff --git a/src/build/arg/settings.rs b/src/build/arg/settings.rs index af6712e24e5..f6d45859095 100644 --- a/src/build/arg/settings.rs +++ b/src/build/arg/settings.rs @@ -128,33 +128,73 @@ bitflags! { // @TODO @p6 @internal: Reorder alphabetically impl_settings! { ArgSettings, ArgFlags, - Required("required") => Flags::REQUIRED, - MultipleOccurrences("multipleoccurrences") => Flags::MULTIPLE_OCC, - MultipleValues("multiplevalues") => Flags::MULTIPLE_VALS, - Multiple("multiple") => Flags::MULTIPLE, - ForbidEmptyValues("forbidemptyvalues") => Flags::NO_EMPTY_VALS, - Global("global") => Flags::GLOBAL, - Hidden("hidden") => Flags::HIDDEN, - TakesValue("takesvalue") => Flags::TAKES_VAL, - UseValueDelimiter("usevaluedelimiter") => Flags::USE_DELIM, - NextLineHelp("nextlinehelp") => Flags::NEXT_LINE_HELP, - RequireDelimiter("requiredelimiter") => Flags::REQ_DELIM, - HidePossibleValues("hidepossiblevalues") => Flags::HIDE_POS_VALS, - AllowHyphenValues("allowhyphenvalues") => Flags::ALLOW_TAC_VALS, - AllowLeadingHyphen("allowleadinghypyhen") => Flags::ALLOW_TAC_VALS, - RequireEquals("requireequals") => Flags::REQUIRE_EQUALS, - Last("last") => Flags::LAST, - IgnoreCase("ignorecase") => Flags::CASE_INSENSITIVE, - CaseInsensitive("caseinsensitive") => Flags::CASE_INSENSITIVE, + Required => Flags::REQUIRED, + MultipleOccurrences => Flags::MULTIPLE_OCC, + MultipleValues => Flags::MULTIPLE_VALS, + Multiple => Flags::MULTIPLE, + ForbidEmptyValues => Flags::NO_EMPTY_VALS, + Global => Flags::GLOBAL, + Hidden => Flags::HIDDEN, + TakesValue => Flags::TAKES_VAL, + UseValueDelimiter => Flags::USE_DELIM, + NextLineHelp => Flags::NEXT_LINE_HELP, + RequireDelimiter => Flags::REQ_DELIM, + HidePossibleValues => Flags::HIDE_POS_VALS, + AllowHyphenValues => Flags::ALLOW_TAC_VALS, + AllowLeadingHyphen => Flags::ALLOW_TAC_VALS, + RequireEquals => Flags::REQUIRE_EQUALS, + Last => Flags::LAST, + IgnoreCase => Flags::CASE_INSENSITIVE, + CaseInsensitive => Flags::CASE_INSENSITIVE, #[cfg(feature = "env")] - HideEnv("hideenv") => Flags::HIDE_ENV, + HideEnv => Flags::HIDE_ENV, #[cfg(feature = "env")] - HideEnvValues("hideenvvalues") => Flags::HIDE_ENV_VALS, - HideDefaultValue("hidedefaultvalue") => Flags::HIDE_DEFAULT_VAL, - HiddenShortHelp("hiddenshorthelp") => Flags::HIDDEN_SHORT_H, - HiddenLongHelp("hiddenlonghelp") => Flags::HIDDEN_LONG_H, - AllowInvalidUtf8("allowinvalidutf8") => Flags::UTF8_NONE, - Exclusive("exclusive") => Flags::EXCLUSIVE + HideEnvValues => Flags::HIDE_ENV_VALS, + HideDefaultValue => Flags::HIDE_DEFAULT_VAL, + HiddenShortHelp => Flags::HIDDEN_SHORT_H, + HiddenLongHelp => Flags::HIDDEN_LONG_H, + AllowInvalidUtf8 => Flags::UTF8_NONE, + Exclusive => Flags::EXCLUSIVE +} + +/// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case? +#[cfg(feature = "yaml")] +impl FromStr for ArgSettings { + type Err = String; + fn from_str(s: &str) -> Result::Err> { + #[allow(deprecated)] + #[allow(unreachable_patterns)] + match &*s.to_ascii_lowercase() { + "required" => Ok(ArgSettings::Required), + "multipleoccurrences" => Ok(ArgSettings::MultipleOccurrences), + "multiplevalues" => Ok(ArgSettings::MultipleValues), + "multiple" => Ok(ArgSettings::Multiple), + "forbidemptyvalues" => Ok(ArgSettings::ForbidEmptyValues), + "global" => Ok(ArgSettings::Global), + "hidden" => Ok(ArgSettings::Hidden), + "takesvalue" => Ok(ArgSettings::TakesValue), + "usevaluedelimiter" => Ok(ArgSettings::UseValueDelimiter), + "nextlinehelp" => Ok(ArgSettings::NextLineHelp), + "requiredelimiter" => Ok(ArgSettings::RequireDelimiter), + "hidepossiblevalues" => Ok(ArgSettings::HidePossibleValues), + "allowhyphenvalues" => Ok(ArgSettings::AllowHyphenValues), + "allowleadinghypyhen" => Ok(ArgSettings::AllowLeadingHyphen), + "requireequals" => Ok(ArgSettings::RequireEquals), + "last" => Ok(ArgSettings::Last), + "ignorecase" => Ok(ArgSettings::IgnoreCase), + "caseinsensitive" => Ok(ArgSettings::CaseInsensitive), + #[cfg(feature = "env")] + "hideenv" => Ok(ArgSettings::HideEnv), + #[cfg(feature = "env")] + "hideenvvalues" => Ok(ArgSettings::HideEnvValues), + "hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue), + "hiddenshorthelp" => Ok(ArgSettings::HiddenShortHelp), + "hiddenlonghelp" => Ok(ArgSettings::HiddenLongHelp), + "allowinvalidutf8" => Ok(ArgSettings::AllowInvalidUtf8), + "exclusive" => Ok(ArgSettings::Exclusive), + _ => Err(format!("unknown AppSetting: `{}`", s)), + } + } } #[cfg(test)] diff --git a/src/macros.rs b/src/macros.rs index bc3a1013be8..a706c28cb02 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -789,7 +789,7 @@ macro_rules! impl_settings { ($settings:ident, $flags:ident, $( $(#[$inner:ident $($args:tt)*])* - $setting:ident($str:expr) => $flag:path + $setting:ident => $flag:path ),+ ) => { impl $flags { @@ -878,23 +878,6 @@ macro_rules! impl_settings { flags } } - - /// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case? - #[cfg(feature = "yaml")] - impl FromStr for $settings { - type Err = String; - fn from_str(s: &str) -> Result::Err> { - #[allow(deprecated)] // some Settings might be deprecated - #[allow(unreachable_patterns)] // some Settings might be deprecated - match &*s.to_ascii_lowercase() { - $( - $(#[$inner $($args)*])* - $str => Ok($settings::$setting), - )* - _ => Err(format!("unknown AppSetting: `{}`", s)), - } - } - } } }