From 38547fdd3a9270ea3132f6e5ad767e8603f4163f Mon Sep 17 00:00:00 2001 From: rami3l Date: Mon, 22 Jan 2024 10:52:13 +0800 Subject: [PATCH] refactor(cli): rewrite `rustup component` with `clap-derive` --- src/cli/rustup_mode.rs | 164 ++++++++++-------- ...omponent_cmd_add_cmd_help_flag_stdout.toml | 8 +- ...mponent_cmd_list_cmd_help_flag_stdout.toml | 4 +- ...onent_cmd_remove_cmd_help_flag_stdout.toml | 8 +- .../cli-ui/rustup/rustup_help_cmd_stdout.toml | 2 +- .../rustup/rustup_help_flag_stdout.toml | 2 +- .../rustup/rustup_only_options_stdout.toml | 2 +- 7 files changed, 104 insertions(+), 86 deletions(-) diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 3cd67b84c02..b91a6965f5c 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -150,6 +150,12 @@ enum RustupSubcmd { #[command(subcommand)] subcmd: TargetSubcmd, }, + + /// Modify a toolchain's installed components + Component { + #[command(subcommand)] + subcmd: ComponentSubcmd, + }, } #[derive(Debug, Subcommand)] @@ -293,6 +299,44 @@ enum TargetSubcmd { }, } +#[derive(Debug, Subcommand)] +#[command(arg_required_else_help = true, subcommand_required = true)] +enum ComponentSubcmd { + /// List installed and available components + List { + #[arg(long, help = OFFICIAL_TOOLCHAIN_ARG_HELP)] + toolchain: Option, + + /// List only installed components + #[arg(long)] + installed: bool, + }, + + /// Add a component to a Rust toolchain + Add { + #[arg(required = true, num_args = 1..)] + component: Vec, + + #[arg(long, help = OFFICIAL_TOOLCHAIN_ARG_HELP)] + toolchain: Option, + + #[arg(long)] + target: Option, + }, + + /// Remove a component from a Rust toolchain + Remove { + #[arg(required = true, num_args = 1..)] + component: Vec, + + #[arg(long, help = OFFICIAL_TOOLCHAIN_ARG_HELP)] + toolchain: Option, + + #[arg(long)] + target: Option, + }, +} + impl Rustup { fn dispatch(self, cfg: &mut Cfg) -> Result { match self.subcmd { @@ -337,6 +381,22 @@ impl Rustup { TargetSubcmd::Add { target, toolchain } => target_add(cfg, target, toolchain), TargetSubcmd::Remove { target, toolchain } => target_remove(cfg, target, toolchain), }, + RustupSubcmd::Component { subcmd } => match subcmd { + ComponentSubcmd::List { + toolchain, + installed, + } => handle_epipe(component_list(cfg, toolchain, installed)), + ComponentSubcmd::Add { + component, + toolchain, + target, + } => component_add(cfg, component, toolchain, target.as_deref()), + ComponentSubcmd::Remove { + component, + toolchain, + target, + } => component_remove(cfg, component, toolchain, target.as_deref()), + }, } } } @@ -415,18 +475,9 @@ pub fn main() -> Result { ("dump-testament", _) => common::dump_testament()?, ( "show" | "update" | "install" | "uninstall" | "toolchain" | "check" | "default" - | "target", + | "target" | "component", _, ) => Rustup::from_arg_matches(&matches)?.dispatch(cfg)?, - ("component", c) => match c.subcommand() { - Some(s) => match s { - ("list", m) => handle_epipe(component_list(cfg, m))?, - ("add", m) => component_add(cfg, m)?, - ("remove", m) => component_remove(cfg, m)?, - _ => unreachable!(), - }, - None => unreachable!(), - }, ("override", c) => match c.subcommand() { Some(s) => match s { ("list", _) => handle_epipe(common::list_overrides(cfg))?, @@ -513,55 +564,6 @@ pub(crate) fn cli() -> Command { .about("Dump information about the build") .hide(true), // Not for users, only CI ) - .subcommand( - Command::new("component") - .about("Modify a toolchain's installed components") - .subcommand_required(true) - .arg_required_else_help(true) - .subcommand( - Command::new("list") - .about("List installed and available components") - .arg( - Arg::new("toolchain") - .help(OFFICIAL_TOOLCHAIN_ARG_HELP) - .long("toolchain") - .num_args(1) - .value_parser(partial_toolchain_desc_parser), - ) - .arg( - Arg::new("installed") - .long("installed") - .help("List only installed components") - .action(ArgAction::SetTrue), - ), - ) - .subcommand( - Command::new("add") - .about("Add a component to a Rust toolchain") - .arg(Arg::new("component").required(true).num_args(1..)) - .arg( - Arg::new("toolchain") - .help(OFFICIAL_TOOLCHAIN_ARG_HELP) - .long("toolchain") - .num_args(1) - .value_parser(partial_toolchain_desc_parser), - ) - .arg(Arg::new("target").long("target").num_args(1)), - ) - .subcommand( - Command::new("remove") - .about("Remove a component from a Rust toolchain") - .arg(Arg::new("component").required(true).num_args(1..)) - .arg( - Arg::new("toolchain") - .help(OFFICIAL_TOOLCHAIN_ARG_HELP) - .long("toolchain") - .num_args(1) - .value_parser(partial_toolchain_desc_parser), - ) - .arg(Arg::new("target").long("target").num_args(1)), - ), - ) .subcommand( Command::new("override") .about("Modify toolchain overrides for directories") @@ -1298,12 +1300,16 @@ fn target_remove( Ok(utils::ExitCode(0)) } -fn component_list(cfg: &Cfg, m: &ArgMatches) -> Result { - let toolchain = explicit_desc_or_dir_toolchain_old(cfg, m)?; +fn component_list( + cfg: &Cfg, + toolchain: Option, + installed_only: bool, +) -> Result { + let toolchain = explicit_desc_or_dir_toolchain(cfg, toolchain)?; // downcasting required because the toolchain files can name any toolchain let distributable = (&toolchain).try_into()?; - if m.get_flag("installed") { + if installed_only { common::list_installed_components(distributable)?; } else { common::list_components(distributable)?; @@ -1311,12 +1317,17 @@ fn component_list(cfg: &Cfg, m: &ArgMatches) -> Result { Ok(utils::ExitCode(0)) } -fn component_add(cfg: &Cfg, m: &ArgMatches) -> Result { - let toolchain = explicit_desc_or_dir_toolchain_old(cfg, m)?; +fn component_add( + cfg: &Cfg, + components: Vec, + toolchain: Option, + target: Option<&str>, +) -> Result { + let toolchain = explicit_desc_or_dir_toolchain(cfg, toolchain)?; let distributable = DistributableToolchain::try_from(&toolchain)?; - let target = get_target(m, &distributable); + let target = get_target(target, &distributable); - for component in m.get_many::("component").unwrap() { + for component in &components { let new_component = Component::new_with_target(component, false) .unwrap_or_else(|| Component::new(component.to_string(), target.clone(), true)); distributable.add_component(new_component)?; @@ -1325,19 +1336,26 @@ fn component_add(cfg: &Cfg, m: &ArgMatches) -> Result { Ok(utils::ExitCode(0)) } -fn get_target(m: &ArgMatches, distributable: &DistributableToolchain<'_>) -> Option { - m.get_one::("target") - .map(|s| &**s) +fn get_target( + target: Option<&str>, + distributable: &DistributableToolchain<'_>, +) -> Option { + target .map(TargetTriple::new) .or_else(|| Some(distributable.desc().target.clone())) } -fn component_remove(cfg: &Cfg, m: &ArgMatches) -> Result { - let toolchain = explicit_desc_or_dir_toolchain_old(cfg, m)?; +fn component_remove( + cfg: &Cfg, + components: Vec, + toolchain: Option, + target: Option<&str>, +) -> Result { + let toolchain = explicit_desc_or_dir_toolchain(cfg, toolchain)?; let distributable = DistributableToolchain::try_from(&toolchain)?; - let target = get_target(m, &distributable); + let target = get_target(target, &distributable); - for component in m.get_many::("component").unwrap() { + for component in &components { let new_component = Component::new_with_target(component, false) .unwrap_or_else(|| Component::new(component.to_string(), target.clone(), true)); distributable.remove_component(new_component)?; diff --git a/tests/suite/cli-ui/rustup/rustup_component_cmd_add_cmd_help_flag_stdout.toml b/tests/suite/cli-ui/rustup/rustup_component_cmd_add_cmd_help_flag_stdout.toml index 10643c06031..e40c683361a 100644 --- a/tests/suite/cli-ui/rustup/rustup_component_cmd_add_cmd_help_flag_stdout.toml +++ b/tests/suite/cli-ui/rustup/rustup_component_cmd_add_cmd_help_flag_stdout.toml @@ -4,15 +4,15 @@ stdout = """ ... Add a component to a Rust toolchain -Usage: rustup[EXE] component add [OPTIONS] ... +Usage: rustup[EXE] component add [OPTIONS] ... Arguments: - ... + ... Options: - --toolchain Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more + --toolchain Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more information see `rustup help toolchain` - --target + --target -h, --help Print help """ stderr = "" diff --git a/tests/suite/cli-ui/rustup/rustup_component_cmd_list_cmd_help_flag_stdout.toml b/tests/suite/cli-ui/rustup/rustup_component_cmd_list_cmd_help_flag_stdout.toml index b4f5d20398d..26e8628e5eb 100644 --- a/tests/suite/cli-ui/rustup/rustup_component_cmd_list_cmd_help_flag_stdout.toml +++ b/tests/suite/cli-ui/rustup/rustup_component_cmd_list_cmd_help_flag_stdout.toml @@ -1,5 +1,5 @@ bin.name = "rustup" -args = ["component","list","--help"] +args = ["component", "list", "--help"] stdout = """ ... List installed and available components @@ -7,7 +7,7 @@ List installed and available components Usage: rustup[EXE] component list [OPTIONS] Options: - --toolchain Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more + --toolchain Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more information see `rustup help toolchain` --installed List only installed components -h, --help Print help diff --git a/tests/suite/cli-ui/rustup/rustup_component_cmd_remove_cmd_help_flag_stdout.toml b/tests/suite/cli-ui/rustup/rustup_component_cmd_remove_cmd_help_flag_stdout.toml index 1bb7c4042f2..a2f5a2980d3 100644 --- a/tests/suite/cli-ui/rustup/rustup_component_cmd_remove_cmd_help_flag_stdout.toml +++ b/tests/suite/cli-ui/rustup/rustup_component_cmd_remove_cmd_help_flag_stdout.toml @@ -4,15 +4,15 @@ stdout = """ ... Remove a component from a Rust toolchain -Usage: rustup[EXE] component remove [OPTIONS] ... +Usage: rustup[EXE] component remove [OPTIONS] ... Arguments: - ... + ... Options: - --toolchain Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more + --toolchain Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more information see `rustup help toolchain` - --target + --target -h, --help Print help """ stderr = "" diff --git a/tests/suite/cli-ui/rustup/rustup_help_cmd_stdout.toml b/tests/suite/cli-ui/rustup/rustup_help_cmd_stdout.toml index 61b18dd2f58..c6f199d7a7d 100644 --- a/tests/suite/cli-ui/rustup/rustup_help_cmd_stdout.toml +++ b/tests/suite/cli-ui/rustup/rustup_help_cmd_stdout.toml @@ -9,7 +9,6 @@ The Rust toolchain installer Usage: rustup[EXE] [OPTIONS] [+toolchain] [COMMAND] Commands: - component Modify a toolchain's installed components override Modify toolchain overrides for directories run Run a command with an environment configured for a given toolchain which Display which binary will be run for a given command @@ -24,6 +23,7 @@ Commands: default Set the default toolchain toolchain Modify or query the installed toolchains target Modify a toolchain's supported targets + component Modify a toolchain's installed components help Print this message or the help of the given subcommand(s) Arguments: diff --git a/tests/suite/cli-ui/rustup/rustup_help_flag_stdout.toml b/tests/suite/cli-ui/rustup/rustup_help_flag_stdout.toml index 84fc97041ca..9c25c1aa0e9 100644 --- a/tests/suite/cli-ui/rustup/rustup_help_flag_stdout.toml +++ b/tests/suite/cli-ui/rustup/rustup_help_flag_stdout.toml @@ -9,7 +9,6 @@ The Rust toolchain installer Usage: rustup[EXE] [OPTIONS] [+toolchain] [COMMAND] Commands: - component Modify a toolchain's installed components override Modify toolchain overrides for directories run Run a command with an environment configured for a given toolchain which Display which binary will be run for a given command @@ -24,6 +23,7 @@ Commands: default Set the default toolchain toolchain Modify or query the installed toolchains target Modify a toolchain's supported targets + component Modify a toolchain's installed components help Print this message or the help of the given subcommand(s) Arguments: diff --git a/tests/suite/cli-ui/rustup/rustup_only_options_stdout.toml b/tests/suite/cli-ui/rustup/rustup_only_options_stdout.toml index 1ea90490487..a1409ee3307 100644 --- a/tests/suite/cli-ui/rustup/rustup_only_options_stdout.toml +++ b/tests/suite/cli-ui/rustup/rustup_only_options_stdout.toml @@ -9,7 +9,6 @@ The Rust toolchain installer Usage: rustup[EXE] [OPTIONS] [+toolchain] [COMMAND] Commands: - component Modify a toolchain's installed components override Modify toolchain overrides for directories run Run a command with an environment configured for a given toolchain which Display which binary will be run for a given command @@ -24,6 +23,7 @@ Commands: default Set the default toolchain toolchain Modify or query the installed toolchains target Modify a toolchain's supported targets + component Modify a toolchain's installed components help Print this message or the help of the given subcommand(s) Arguments: