From 4689949cff96e99fe8ea2d60841fea07676739b9 Mon Sep 17 00:00:00 2001 From: Shupeng Xue Date: Tue, 25 Jun 2024 13:17:40 +1000 Subject: [PATCH 1/2] apply smart guess to `rustup update/uninstall self` Use original error instead of rewriting avoid duplicate `.to_string()` remove unnecessary `.as_str()` --- src/cli/rustup_mode.rs | 11 ++++++++++- src/toolchain.rs | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 5de45f0760..34baeae19b 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -3,6 +3,7 @@ use std::fmt; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::ExitStatus; +use std::str::FromStr; use anyhow::{anyhow, Error, Result}; use clap::{builder::PossibleValue, Args, CommandFactory, Parser, Subcommand, ValueEnum}; @@ -135,7 +136,7 @@ enum RustupSubcmd { )] Update { /// Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more information see `rustup help toolchain` - #[arg(num_args = 1..)] + #[arg(num_args = 1.., value_parser = update_toolchain_value_parser)] toolchain: Vec, /// Don't perform self update when running the `rustup update` command @@ -258,6 +259,14 @@ enum RustupSubcmd { }, } +fn update_toolchain_value_parser(s: &str) -> Result { + PartialToolchainDesc::from_str(s).inspect_err(|_| { + if s == "self" { + info!("if you meant to update rustup itself, use `rustup self update`"); + } + }) +} + #[derive(Debug, Subcommand)] enum ShowSubcmd { /// Show the active toolchain diff --git a/src/toolchain.rs b/src/toolchain.rs index 6d3c8cb2fd..6c995cba7c 100644 --- a/src/toolchain.rs +++ b/src/toolchain.rs @@ -457,7 +457,13 @@ impl<'a> Toolchain<'a> { fs::remove_dir_all(&path)?; true } else { + let name = name.to_string(); info!("no toolchain installed for '{name}'"); + if name == "self" { + info!( + "if you meant to uninstall rustup itself, use `rustup self uninstall`" + ); + } false } } From 1f9f1daf848a5260074233fe56948eaff23a4260 Mon Sep 17 00:00:00 2001 From: Xerxes-2 Date: Wed, 26 Jun 2024 17:51:49 +1000 Subject: [PATCH 2/2] add regression tests for smart guess --- tests/suite/cli_misc.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/suite/cli_misc.rs b/tests/suite/cli_misc.rs index 5359e6afbd..3dee46f337 100644 --- a/tests/suite/cli_misc.rs +++ b/tests/suite/cli_misc.rs @@ -1180,3 +1180,27 @@ async fn toolchain_link_then_list_verbose() { .expect_stdout_ok(&["rustup", "toolchain", "list", "-v"], "/custom-1") .await; } + +#[tokio::test] +async fn update_self_smart_guess() { + let cx = CliTestContext::new(Scenario::SimpleV2).await; + let out = cx.config.run("rustup", &["update", "self"], &[]).await; + let invalid_toolchain = out.stderr.contains("invalid toolchain name"); + if !out.ok && invalid_toolchain { + assert!(out + .stderr + .contains("if you meant to update rustup itself, use `rustup self update`")) + } +} + +#[tokio::test] +async fn uninstall_self_smart_guess() { + let cx = CliTestContext::new(Scenario::SimpleV2).await; + let out = cx.config.run("rustup", &["uninstall", "self"], &[]).await; + let no_toolchain_installed = out.stdout.contains("no toolchain installed"); + if out.ok && no_toolchain_installed { + assert!(out + .stdout + .contains("if you meant to uninstall rustup itself, use `rustup self uninstall`")) + } +}