From 686b0379ce3baaebaa073ac027002ad82833bc51 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 3 May 2022 16:51:36 -0500 Subject: [PATCH] feat(multicall): Stablize multicall `multicall` allows you to have one binary expose itself as multiple programs, like busybox does. This also works well for user clap for parsing REPLs. Fixes #2861 --- Cargo.toml | 6 +----- Makefile | 4 ++-- README.md | 1 - examples/multicall-busybox.rs | 2 -- examples/multicall-hostname.rs | 2 -- examples/repl.rs | 2 -- src/builder/app_settings.rs | 3 --- src/builder/command.rs | 23 ++++++----------------- src/builder/debug_asserts.rs | 16 ++++++---------- tests/builder/subcommands.rs | 7 ------- tests/examples.rs | 2 -- tests/ui.rs | 2 -- 12 files changed, 15 insertions(+), 55 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 74ef6dadd1e..c53b04a8aeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,7 @@ default = [ "suggestions", ] debug = ["clap_derive/debug", "backtrace"] # Enables debug messages -unstable-doc = ["derive", "cargo", "wrap_help", "yaml", "env", "unicode", "regex", "unstable-replace", "unstable-multicall", "unstable-grouped"] # for docs.rs +unstable-doc = ["derive", "cargo", "wrap_help", "yaml", "env", "unicode", "regex", "unstable-replace", "unstable-grouped"] # for docs.rs # Used in default std = ["indexmap/std"] # support for no_std in a backwards-compatible way @@ -81,7 +81,6 @@ unicode = ["textwrap/unicode-width", "unicase"] # Support for unicode character # In-work features unstable-replace = [] -unstable-multicall = [] unstable-grouped = [] # note: this will always enable clap_derive, change this to `clap_derive?/unstable-v4` when MSRV is bigger than 1.60 unstable-v4 = ["clap_derive/unstable-v4"] @@ -178,17 +177,14 @@ required-features = ["derive"] [[example]] name = "busybox" path = "examples/multicall-busybox.rs" -required-features = ["unstable-multicall"] [[example]] name = "hostname" path = "examples/multicall-hostname.rs" -required-features = ["unstable-multicall"] [[example]] name = "repl" path = "examples/repl.rs" -required-features = ["unstable-multicall"] [[example]] name = "01_quick" diff --git a/Makefile b/Makefile index 19e9b8c757a..1f3db6eeb4b 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,8 @@ MSRV?=1.56.0 _FEATURES = minimal default wasm full debug release _FEATURES_minimal = --no-default-features --features "std" _FEATURES_default = -_FEATURES_wasm = --features "derive cargo env unicode yaml regex unstable-replace unstable-multicall unstable-grouped" -_FEATURES_full = --features "derive cargo env unicode yaml regex unstable-replace unstable-multicall unstable-grouped wrap_help" +_FEATURES_wasm = --features "derive cargo env unicode yaml regex unstable-replace unstable-grouped" +_FEATURES_full = --features "derive cargo env unicode yaml regex unstable-replace unstable-grouped wrap_help" _FEATURES_next = ${_FEATURES_full} --features unstable-v4 _FEATURES_debug = ${_FEATURES_full} --features debug _FEATURES_release = ${_FEATURES_full} --release diff --git a/README.md b/README.md index 8d9d4398012..94b9bb9ea9f 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,6 @@ Why use the procedural [Builder API](https://github.com/clap-rs/clap/blob/v3.1.1 **Warning:** These may contain breaking changes between minor releases. * **unstable-replace**: Enable [`Command::replace`](https://github.com/clap-rs/clap/issues/2836) -* **unstable-multicall**: Enable [`Command::multicall`](https://github.com/clap-rs/clap/issues/2861) * **unstable-grouped**: Enable [`ArgMatches::grouped_values_of`](https://github.com/clap-rs/clap/issues/2924) * **unstable-v4**: Preview features which will be stable on the v4.0 release diff --git a/examples/multicall-busybox.rs b/examples/multicall-busybox.rs index 30865a8303f..f9d678679e8 100644 --- a/examples/multicall-busybox.rs +++ b/examples/multicall-busybox.rs @@ -1,5 +1,3 @@ -// Note: this requires the `unstable-multicall` feature - use std::process::exit; use clap::{Arg, Command}; diff --git a/examples/multicall-hostname.rs b/examples/multicall-hostname.rs index 2c89a14484a..b57680a5c11 100644 --- a/examples/multicall-hostname.rs +++ b/examples/multicall-hostname.rs @@ -1,5 +1,3 @@ -// Note: this requires the `unstable-multicall` feature - use clap::Command; fn main() { diff --git a/examples/repl.rs b/examples/repl.rs index f1b65c3090f..c509adee641 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -1,5 +1,3 @@ -// Note: this requires the `unstable-multicall` feature - use std::io::Write; use clap::Command; diff --git a/src/builder/app_settings.rs b/src/builder/app_settings.rs index 65d69ef825b..d16ffc336df 100644 --- a/src/builder/app_settings.rs +++ b/src/builder/app_settings.rs @@ -153,7 +153,6 @@ pub enum AppSettings { since = "3.1.0", note = "Replaced with `Command::multicall` and `Command::is_multicall_set`" )] - #[cfg(feature = "unstable-multicall")] Multicall, /// Deprecated, replaced with [`Command::allow_invalid_utf8_for_external_subcommands`] and [`Command::is_allow_invalid_utf8_for_external_subcommands_set`] @@ -466,7 +465,6 @@ bitflags! { const USE_LONG_FORMAT_FOR_HELP_SC = 1 << 42; const INFER_LONG_ARGS = 1 << 43; const IGNORE_ERRORS = 1 << 44; - #[cfg(feature = "unstable-multicall")] const MULTICALL = 1 << 45; const NO_OP = 0; } @@ -533,7 +531,6 @@ impl_settings! { AppSettings, AppFlags, => Flags::HELP_REQUIRED, Hidden => Flags::HIDDEN, - #[cfg(feature = "unstable-multicall")] Multicall => Flags::MULTICALL, NoAutoHelp diff --git a/src/builder/command.rs b/src/builder/command.rs index 36b160aff15..3864b549d83 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -637,7 +637,6 @@ impl<'help> App<'help> { let mut raw_args = clap_lex::RawArgs::new(itr.into_iter()); let mut cursor = raw_args.cursor(); - #[cfg(feature = "unstable-multicall")] if self.settings.is_set(AppSettings::Multicall) { if let Some(argv0) = raw_args.next_os(&mut cursor) { let argv0 = Path::new(&argv0); @@ -3062,7 +3061,6 @@ impl<'help> App<'help> { /// [`App::subcommand_value_name`]: crate::Command::subcommand_value_name /// [`App::subcommand_help_heading`]: crate::Command::subcommand_help_heading #[inline] - #[cfg(feature = "unstable-multicall")] pub fn multicall(self, yes: bool) -> Self { if yes { self.setting(AppSettings::Multicall) @@ -3715,15 +3713,9 @@ impl<'help> App<'help> { } /// Report whether [`Command::multicall`] is set - #[cfg(feature = "unstable-multicall")] pub fn is_multicall_set(&self) -> bool { self.is_set(AppSettings::Multicall) } - - #[cfg(not(feature = "unstable-multicall"))] - fn is_multicall_set(&self) -> bool { - false - } } /// Deprecated @@ -4109,13 +4101,10 @@ impl<'help> App<'help> { // Make sure all the globally set flags apply to us as well self.settings = self.settings | self.g_settings; - #[cfg(feature = "unstable-multicall")] - { - if self.is_multicall_set() { - self.settings.insert(AppSettings::SubcommandRequired.into()); - self.settings.insert(AppSettings::DisableHelpFlag.into()); - self.settings.insert(AppSettings::DisableVersionFlag.into()); - } + if self.is_multicall_set() { + self.settings.insert(AppSettings::SubcommandRequired.into()); + self.settings.insert(AppSettings::DisableHelpFlag.into()); + self.settings.insert(AppSettings::DisableVersionFlag.into()); } self._propagate(); @@ -4180,7 +4169,7 @@ impl<'help> App<'help> { mid_string.push(' '); } } - let is_multicall_set = cfg!(feature = "unstable-multicall") && self.is_multicall_set(); + let is_multicall_set = self.is_multicall_set(); let sc = self.subcommands.iter_mut().find(|s| s.name == name)?; @@ -4263,7 +4252,7 @@ impl<'help> App<'help> { mid_string.push(' '); } } - let is_multicall_set = cfg!(feature = "unstable-multicall") && self.is_multicall_set(); + let is_multicall_set = self.is_multicall_set(); let self_bin_name = if is_multicall_set { self.bin_name.as_deref().unwrap_or("") diff --git a/src/builder/debug_asserts.rs b/src/builder/debug_asserts.rs index ae656471774..ccfa2f8c682 100644 --- a/src/builder/debug_asserts.rs +++ b/src/builder/debug_asserts.rs @@ -60,15 +60,12 @@ pub(crate) fn assert_app(cmd: &Command) { for arg in cmd.get_arguments() { assert_arg(arg); - #[cfg(feature = "unstable-multicall")] - { - assert!( - !cmd.is_multicall_set(), - "Command {}: Arguments like {} cannot be set on a multicall command", - cmd.get_name(), - arg.name - ); - } + assert!( + !cmd.is_multicall_set(), + "Command {}: Arguments like {} cannot be set on a multicall command", + cmd.get_name(), + arg.name + ); if let Some(s) = arg.short.as_ref() { short_flags.push(Flag::Arg(format!("-{}", s), &*arg.name)); @@ -467,7 +464,6 @@ fn assert_app_flags(cmd: &Command) { } checker!(is_allow_invalid_utf8_for_external_subcommands_set requires is_allow_external_subcommands_set); - #[cfg(feature = "unstable-multicall")] checker!(is_multicall_set conflicts is_no_binary_name_set); } diff --git a/tests/builder/subcommands.rs b/tests/builder/subcommands.rs index c3114238558..8e047de642a 100644 --- a/tests/builder/subcommands.rs +++ b/tests/builder/subcommands.rs @@ -494,7 +494,6 @@ For more information try --help ); } -#[cfg(feature = "unstable-multicall")] #[test] fn busybox_like_multicall() { fn applet_commands() -> [Command<'static>; 2] { @@ -520,7 +519,6 @@ fn busybox_like_multicall() { assert_eq!(m.unwrap_err().kind(), ErrorKind::UnrecognizedSubcommand); } -#[cfg(feature = "unstable-multicall")] #[test] fn hostname_like_multicall() { let mut cmd = Command::new("hostname") @@ -550,7 +548,6 @@ fn hostname_like_multicall() { assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument); } -#[cfg(feature = "unstable-multicall")] #[test] fn bad_multicall_command_error() { let cmd = Command::new("repl") @@ -606,7 +603,6 @@ For more information try help assert_eq!(err.kind(), ErrorKind::DisplayVersion); } -#[cfg(feature = "unstable-multicall")] #[test] #[should_panic = "Command repl: Arguments like oh-no cannot be set on a multicall command"] fn cant_have_args_with_multicall() { @@ -620,7 +616,6 @@ fn cant_have_args_with_multicall() { cmd.build(); } -#[cfg(feature = "unstable-multicall")] #[test] fn multicall_help_flag() { static EXPECTED: &str = "\ @@ -644,7 +639,6 @@ OPTIONS: utils::assert_output(cmd, "foo bar --help", EXPECTED, false); } -#[cfg(feature = "unstable-multicall")] #[test] fn multicall_help_subcommand() { static EXPECTED: &str = "\ @@ -668,7 +662,6 @@ OPTIONS: utils::assert_output(cmd, "help foo bar", EXPECTED, false); } -#[cfg(feature = "unstable-multicall")] #[test] fn multicall_render_help() { static EXPECTED: &str = "\ diff --git a/tests/examples.rs b/tests/examples.rs index 4f0f1e946d2..b3fb1d15bb1 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -22,8 +22,6 @@ fn example_tests() { "wrap_help", #[cfg(feature = "unstable-replace")] "unstable-replace", - #[cfg(feature = "unstable-multicall")] - "unstable-multicall", #[cfg(feature = "unstable-grouped")] "unstable-grouped", ] diff --git a/tests/ui.rs b/tests/ui.rs index c7cab689f01..77bcac71c5c 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -22,8 +22,6 @@ fn ui_tests() { "wrap_help", #[cfg(feature = "unstable-replace")] "unstable-replace", - #[cfg(feature = "unstable-multicall")] - "unstable-multicall", #[cfg(feature = "unstable-grouped")] "unstable-grouped", ]