diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 08ac9e0454..6a8075c91a 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -301,6 +301,36 @@ fn update_toolchain_value_parser(s: &str) -> Result { }) } +impl RustupSubcmd { + fn allow_auto_install(&self) -> bool { + match self { + // These subcommands execute or rely on the active toolchain, so auto-installing it when + // missing may be reasonable depending on the user's decision. + #[cfg(not(windows))] + RustupSubcmd::Man { .. } => true, + RustupSubcmd::Doc { .. } | RustupSubcmd::Run { .. } => true, + + // These subcommands don't require the active toolchain, so auto-installing it should be + // disabled to avoid surprises. + RustupSubcmd::Check { .. } + | RustupSubcmd::Completions { .. } + | RustupSubcmd::Component { .. } + | RustupSubcmd::Default { .. } + | RustupSubcmd::DumpTestament + | RustupSubcmd::Install { .. } + | RustupSubcmd::Override { .. } + | RustupSubcmd::Self_ { .. } + | RustupSubcmd::Set { .. } + | RustupSubcmd::Show { .. } + | RustupSubcmd::Target { .. } + | RustupSubcmd::Toolchain { .. } + | RustupSubcmd::Uninstall { .. } + | RustupSubcmd::Update { .. } + | RustupSubcmd::Which { .. } => false, + } + } +} + #[derive(Debug, Subcommand)] enum ShowSubcmd { /// Show the active toolchain @@ -631,15 +661,20 @@ pub async fn main( update_console_filter(process, &console_filter, matches.quiet, matches.verbose); - let cfg = &mut Cfg::from_env(current_dir, matches.quiet, true, process)?; - cfg.toolchain_override = matches.plus_toolchain; - let Some(subcmd) = matches.subcmd else { let help = Rustup::command().render_long_help(); writeln!(process.stderr().lock(), "{}", help.ansi())?; return Ok(ExitCode::FAILURE); }; + let cfg = &mut Cfg::from_env( + current_dir, + matches.quiet, + subcmd.allow_auto_install(), + process, + )?; + cfg.toolchain_override = matches.plus_toolchain; + match subcmd { RustupSubcmd::DumpTestament => common::dump_testament(process), RustupSubcmd::Install { opts } => update(cfg, opts, true).await, diff --git a/src/config.rs b/src/config.rs index 42da8d1983..1659468332 100644 --- a/src/config.rs +++ b/src/config.rs @@ -142,10 +142,10 @@ impl EnsureInstalled { } impl EnsureInstalled { - fn warn_auto_install(&self, process: &Process) { + fn warn_auto_install(&self, cfg: &Cfg<'_>) { // If we're already in a recursion, or we haven't just installed the active toolchain, then // don't print the warning. - let recursions = process.var("RUST_RECURSION_COUNT"); + let recursions = cfg.process.var("RUST_RECURSION_COUNT"); if recursions.is_ok_and(|it| it != "0") || !matches!(self.status, UpdateStatus::Installed) { return; } @@ -154,6 +154,16 @@ impl EnsureInstalled { "the missing active toolchain `{}` has been auto-installed", self.inner, ); + + if !cfg.allow_auto_install { + // NOTE: Special behavior for rustup v1.29 + warn!( + "this is deprecated for most `rustup` commands and may not work in a future release" + ); + warn!("see for more info"); + return; + } + warn!("this might cause rustup commands to take longer time to finish than expected"); info!("you may opt out with `RUSTUP_AUTO_INSTALL=0` or `rustup set auto-install disable`"); } @@ -423,10 +433,6 @@ impl<'a> Cfg<'a> { } pub(crate) fn should_auto_install(&self) -> Result { - if !self.allow_auto_install { - return Ok(false); - } - if let Ok(mode) = self.process.var("RUSTUP_AUTO_INSTALL") { Ok(mode != "0") } else { @@ -562,7 +568,7 @@ impl<'a> Cfg<'a> { match self.ensure_active_toolchain(true, false).await { Ok(r) => { let (tc, source) = r; - tc.warn_auto_install(self.process); + tc.warn_auto_install(self); Ok(Some((tc.inner, source))) } Err(e) => match e.downcast_ref::() { @@ -768,7 +774,7 @@ impl<'a> Cfg<'a> { let install_if_missing = self.should_auto_install()?; let EnsureInstalled { inner: tc, status } = Toolchain::from_local(tc, install_if_missing, self).await?; - EnsureInstalled::new(tc.name(), status).warn_auto_install(self.process); + EnsureInstalled::new(tc.name(), status).warn_auto_install(self); Ok((tc, source)) } None => { diff --git a/tests/suite/cli_misc.rs b/tests/suite/cli_misc.rs index b27a0834d3..8d021588a9 100644 --- a/tests/suite/cli_misc.rs +++ b/tests/suite/cli_misc.rs @@ -1795,3 +1795,27 @@ info: you may opt out with `RUSTUP_AUTO_INSTALL=0` or `rustup set auto-install d "#]]) .is_ok(); } + +#[tokio::test] +async fn warn_auto_install_on_rustup_deprecated() { + let cx = CliTestContext::new(Scenario::SimpleV2).await; + cx.config + .expect_with_env( + ["rustup", "component", "list"], + [("RUSTUP_TOOLCHAIN", "stable"), ("RUSTUP_AUTO_INSTALL", "1")], + ) + .await + .with_stdout(snapbox::str![[r#" +... +rustc-[HOST_TUPLE] (installed) +... +"#]]) + .with_stderr(snapbox::str![[r#" +... +warn: the missing active toolchain `stable-[HOST_TUPLE]` has been auto-installed +warn: this is deprecated for most `rustup` commands and may not work in a future release +warn: see for more info + +"#]]) + .is_ok(); +}