Add support for arg stability attributes (unstable/deprecated)
Please complete the following tasks
- [X] I have searched the discussions
- [X] I have searched the existing issues
Clap Version
3.0.10
Describe your use case
I had this idea while I was reviewing @sunshowers's CLI recommendations on versioning: https://rust-cli-recommendations.sunshowers.io/versioning.html. In their book they recommend having a stability flag or environment variable for gating new experimental features being exposed in your CLI. This made me think it would be nice if clap provided some support out of the box for managing the stability of various subsets of an App's CLI.
Describe the solution you'd like
I'm imagining two new methods being added to Arg
impl Arg {
/// Specifies that an argument is unstable.
///
/// **Note**: Unstable arguments cannot be used except when the `--unstable-options` flag is also enabled
fn unstable(self, yes: bool) -> Self;
/// Specifies that an argument is deprecated.
///
/// **Note**: Using a deprecated argument will produce a warning unless the `--allow-deprecated` flag is also enabled
fn deprecated(self, yes: bool) -> Self;
}
I'd expect these flags to also affect the generated help text to somehow deprioritize unstable/deprecated arguments in the generated output and to make it clear that they are not intended for general use.
Alternatives, if applicable
@epage and @sunshowers have both also suggested adding general support for custom settings / attributes so that a feature like this could be experimented with out of tree rather than needing to bake it into clap directly.
Additional Context
No response
This entails a lot of policy (flag names, whether they should be global or not, user messages, etc). This would both lock us in to specific behavior but also leave a lot of room for it not quite meeting people needs and wanting customization of it.
My proposal is we start an example that covers these cases. We then use this to explore how we could improve clap.
For example, "require an argument to be present with a value" would go a long way towards a general solution to unstable(yes) but we don't have this. We instead have "when value is set, require another argument" (as both requires_if and required_if_eq, depending on which side you want to express this relationship).
My hope is we can move clap from a closed-form API to an open-form API where we don't need to bake all of the validation options directly into clap but allow users to create their own (https://github.com/clap-rs/clap/issues/3008). This means we can add this new form of requires in a way that the compiler can trivially remove if unused, unlike the current validation logic.
As another example of this open-form API design, yaahc mentioned in a PM wanting this relationship included in a hint in the help, like defaults, envs, and possible values. I had two idea for this
- We expose a general hint mechanism (this would help with https://github.com/clap-rs/clap/issues/1695)
- Have a
hint(&self, app &App) -> Option<String>as part of the validation interface. The "require when other arg has value" struct could then have ashow(self, yes: bool) -> Selffunction which will causehintto report a "[requires --]` to be added to the help - This could still help us with #1695 if we are able to make custom defaulting logic into a trait as well
experimented with out of tree rather than needing to bake it into clap directly.
As a small clarification on my vague statements, we are looking at not having everything baked directly into clap::App::get_matches but allow passing in logic through trait objects. These trait impls can be defined in-tree or out-of-tree. General ones, like what I talked about above, could be in the clap crate. If someone wanted to customize things, like optimizing for this specific feature request, that would probably be kept out-of-tree.
Now that #[deprecated] is available to 3rd-party crates, would it be possible for for clap to pick up the presence of that attribute for displaying this kind thing?
That is an interesting idea to leverage #[deprecated]. We'd have to work out how it affects the CLI (ie what builder calls does it make or how it changes existing builder calls)
Now that
#[deprecated]is available to 3rd-party crates, would it be possible for forclapto pick up the presence of that attribute for displaying this kind thing?
I was just searching for something similar in issues: my idea was that items marked with the #[deprecated] attribute should be hidden by default, or, when using the --allow-deprecated flag, shown to the user, but have some kind of note that the item was deprecated. I recently wrote a plugin for Cargo that parses the entire source code and finds #[deprecated] attributes, looks at their versions and matches them with the version from Cargo.toml of its crate to issue a warning that the item is deprecated and can be removed, if 1+ major version(-s) has passed since its removal. In my case, specifying the "deprecated" attribute would be very useful.