diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 672e20dea7..93557ff637 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -1023,7 +1023,7 @@ async fn run( install: bool, ) -> Result { let toolchain = toolchain.resolve(&cfg.get_default_host_triple()?)?; - let toolchain = Toolchain::from_local(toolchain, install, cfg).await?; + let toolchain = Toolchain::from_local(toolchain, || Ok(install), cfg).await?; let cmd = toolchain.command(&command[0])?; command::run_command_for_dir(cmd, &command[0], &command[1..]) } diff --git a/src/config.rs b/src/config.rs index 100eae6eb5..a5ed955765 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,7 +8,7 @@ use anyhow::{Context, Result, anyhow, bail}; use serde::Deserialize; use thiserror::Error as ThisError; use tokio_stream::StreamExt; -use tracing::trace; +use tracing::{info, trace, warn}; use crate::dist::AutoInstallMode; use crate::{ @@ -387,12 +387,26 @@ impl<'a> Cfg<'a> { } pub(crate) fn should_auto_install(&self) -> Result { - if let Ok(mode) = self.process.var("RUSTUP_AUTO_INSTALL") { - Ok(mode != "0") - } else { - self.settings_file - .with(|s| Ok(s.auto_install != Some(AutoInstallMode::Disable))) + let res = match self.process.var("RUSTUP_AUTO_INSTALL") { + Ok(mode) => mode != "0", + Err(_) => self + .settings_file + .with(|s| Ok(s.auto_install != Some(AutoInstallMode::Disable)))?, + }; + if res + // We also need to suppress this warning if we're deep inside a recursive call. + && matches!( + self.process.var("RUST_RECURSION_COUNT").as_deref(), + Err(_) | Ok("0"), + ) + { + warn!("auto-install is enabled, active toolchain will be installed if absent"); + warn!("this behavior is deprecated and will be removed in a future version"); + info!( + "you may opt out now with `RUSTUP_AUTO_INSTALL=0` or `rustup set auto-install disable`" + ); } + Ok(res) } // Returns a profile, if one exists in the settings file. @@ -746,10 +760,7 @@ impl<'a> Cfg<'a> { async fn local_toolchain(&self, name: Option) -> Result> { match name { - Some(tc) => { - let install_if_missing = self.should_auto_install()?; - Toolchain::from_local(tc, install_if_missing, self).await - } + Some(tc) => Toolchain::from_local(tc, || self.should_auto_install(), self).await, None => { let tc = self .maybe_ensure_active_toolchain(None) diff --git a/src/dist/component/components.rs b/src/dist/component/components.rs index a956f6c724..db9a7805c1 100644 --- a/src/dist/component/components.rs +++ b/src/dist/component/components.rs @@ -89,7 +89,7 @@ impl Components { } pub fn find(&self, name: &str) -> Result> { let result = self.list()?; - Ok(result.into_iter().find(|c| (c.name() == name))) + Ok(result.into_iter().find(|c| c.name() == name)) } pub(crate) fn prefix(&self) -> InstallPrefix { self.prefix.clone() diff --git a/src/test/clitools.rs b/src/test/clitools.rs index 5e9a98590e..d4fb34da4b 100644 --- a/src/test/clitools.rs +++ b/src/test/clitools.rs @@ -277,6 +277,12 @@ impl Config { "/bogus-config-file.toml", ); + // Clear current recursion count to avoid messing up related logic + cmd.env("RUST_RECURSION_COUNT", ""); + + // Disable auto installation of active toolchain unless explicitly requested + cmd.env("RUSTUP_AUTO_INSTALL", "0"); + // Pass `RUSTUP_CI` over to the test process in case it is required downstream if let Some(ci) = env::var_os("RUSTUP_CI") { cmd.env("RUSTUP_CI", ci); @@ -291,7 +297,7 @@ impl Config { /// specified by `args` under the default environment. #[must_use] pub async fn expect + Clone + Debug>(&self, args: impl AsRef<[S]>) -> Assert { - self.expect_with_env(args, &[]).await + self.expect_with_env(args, []).await } /// Returns an [`Assert`] object to check the output of running the command diff --git a/src/toolchain.rs b/src/toolchain.rs index 30ae066fd7..cfa3e3ff84 100644 --- a/src/toolchain.rs +++ b/src/toolchain.rs @@ -53,7 +53,7 @@ pub(crate) struct Toolchain<'a> { impl<'a> Toolchain<'a> { pub(crate) async fn from_local( name: LocalToolchainName, - install_if_missing: bool, + install_if_missing: impl Fn() -> anyhow::Result, cfg: &'a Cfg<'a>, ) -> anyhow::Result> { match Self::new(cfg, name) { @@ -61,7 +61,7 @@ impl<'a> Toolchain<'a> { Err(RustupError::ToolchainNotInstalled { name: ToolchainName::Official(desc), .. - }) if install_if_missing => { + }) if install_if_missing()? => { Ok( DistributableToolchain::install(cfg, &desc, &[], &[], cfg.get_profile()?, true) .await? diff --git a/tests/suite/cli_misc.rs b/tests/suite/cli_misc.rs index 286e5ff770..e036430007 100644 --- a/tests/suite/cli_misc.rs +++ b/tests/suite/cli_misc.rs @@ -64,7 +64,7 @@ async fn rustc_with_bad_rustup_toolchain_env_var() { .expect_with_env(["rustc"], [("RUSTUP_TOOLCHAIN", "bogus")]) .await .with_stderr(snapbox::str![[r#" -error: override toolchain 'bogus' is not installed[..] +error:[..] toolchain 'bogus' is not installed[..] "#]]) .is_err(); @@ -1381,7 +1381,10 @@ async fn which_asking_uninstalled_toolchain() { "#]]) .is_ok(); cx.config - .expect(["rustup", "which", "--toolchain=nightly", "rustc"]) + .expect_with_env( + ["rustup", "which", "--toolchain=nightly", "rustc"], + [("RUSTUP_AUTO_INSTALL", "1")], + ) .await .with_stdout(snapbox::str![[r#" [..]/toolchains/nightly-[HOST_TRIPLE]/bin/rustc[EXE] @@ -1512,7 +1515,7 @@ active because: overridden by +toolchain on the command line .expect(["rustup", "+foo", "which", "rustc"]) .await .with_stderr(snapbox::str![[r#" -error: override toolchain 'foo' is not installed: the +toolchain on the command line specifies an uninstalled toolchain +error:[..] toolchain 'foo' is not installed[..] "#]]) .is_err(); @@ -1746,3 +1749,26 @@ info: falling back to "[EXTERN_PATH]" "#]]) .is_ok(); } + +#[tokio::test] +async fn warn_auto_install() { + let cx = CliTestContext::new(Scenario::SimpleV2).await; + cx.config + .expect_with_env( + ["rustc", "--version"], + [("RUSTUP_TOOLCHAIN", "stable"), ("RUSTUP_AUTO_INSTALL", "1")], + ) + .await + .with_stdout(snapbox::str![[r#" +1.1.0 (hash-stable-1.1.0) + +"#]]) + .with_stderr(snapbox::str![[r#" +... +warn: auto-install is enabled, active toolchain will be installed if absent +warn: this behavior is deprecated and will be removed in a future version +info: you may opt out now with `RUSTUP_AUTO_INSTALL=0` or `rustup set auto-install disable` +... +"#]]) + .is_ok(); +} diff --git a/tests/suite/cli_rustup.rs b/tests/suite/cli_rustup.rs index 3f2f557b6a..9ea3c7f4e8 100644 --- a/tests/suite/cli_rustup.rs +++ b/tests/suite/cli_rustup.rs @@ -1238,7 +1238,7 @@ async fn show_toolchain_override_not_installed() { .await .is_ok(); cx.config - .expect(["rustup", "show"]) + .expect_with_env(["rustup", "show"], [("RUSTUP_AUTO_INSTALL", "1")]) .await .extend_redactions([("[RUSTUP_DIR]", &cx.config.rustupdir.to_string())]) .with_stdout(snapbox::str![[r#" @@ -1327,7 +1327,7 @@ async fn show_toolchain_env() { .await .is_ok(); cx.config - .expect_with_env(["rustup", "show"], &[("RUSTUP_TOOLCHAIN", "nightly")]) + .expect_with_env(["rustup", "show"], [("RUSTUP_TOOLCHAIN", "nightly")]) .await .extend_redactions([("[RUSTUP_DIR]", &cx.config.rustupdir.to_string())]) .is_ok() @@ -1353,7 +1353,13 @@ installed targets: async fn show_toolchain_env_not_installed() { let cx = CliTestContext::new(Scenario::SimpleV2).await; cx.config - .expect_with_env(["rustup", "show"], &[("RUSTUP_TOOLCHAIN", "nightly")]) + .expect_with_env( + ["rustup", "show"], + [ + ("RUSTUP_TOOLCHAIN", "nightly"), + ("RUSTUP_AUTO_INSTALL", "1"), + ], + ) .await .extend_redactions([("[RUSTUP_DIR]", &cx.config.rustupdir.to_string())]) .is_ok() @@ -3027,7 +3033,7 @@ error: no active toolchain "show", "active-toolchain", ], - &[("RUSTUP_TOOLCHAIN", &**env_tc)], + [("RUSTUP_TOOLCHAIN", &**env_tc)], ) .await .extend_redactions([("[COMMAND_TC]", command_tc)]) diff --git a/tests/suite/cli_v1.rs b/tests/suite/cli_v1.rs index 40fae3c9b1..04d382f055 100644 --- a/tests/suite/cli_v1.rs +++ b/tests/suite/cli_v1.rs @@ -271,13 +271,14 @@ async fn remove_override_toolchain_err_handling() { .await .is_ok(); cx.config - .expect(["rustc", "--version"]) + .expect_with_env(["rustc", "--version"], [("RUSTUP_AUTO_INSTALL", "1")]) .await .with_stdout(snapbox::str![[r#" 1.2.0 (hash-beta-1.2.0) "#]]) .with_stderr(snapbox::str![[r#" +... info: syncing channel updates for 'beta-[HOST_TRIPLE]' ... "#]]) diff --git a/tests/suite/cli_v2.rs b/tests/suite/cli_v2.rs index ee99048b6c..98f6d68688 100644 --- a/tests/suite/cli_v2.rs +++ b/tests/suite/cli_v2.rs @@ -478,13 +478,14 @@ async fn remove_override_toolchain_err_handling() { .await .is_ok(); cx.config - .expect(["rustc", "--version"]) + .expect_with_env(["rustc", "--version"], [("RUSTUP_AUTO_INSTALL", "1")]) .await .with_stdout(snapbox::str![[r#" 1.2.0 (hash-beta-1.2.0) "#]]) .with_stderr(snapbox::str![[r#" +... info: syncing channel updates for 'beta-[HOST_TRIPLE]' info: latest update on 2015-01-02, rust version 1.2.0 (hash-beta-1.2.0) info: downloading component[..] @@ -511,13 +512,14 @@ async fn file_override_toolchain_err_handling() { let toolchain_file = cwd.join("rust-toolchain"); rustup::utils::raw::write_file(&toolchain_file, "beta").unwrap(); cx.config - .expect(["rustc", "--version"]) + .expect_with_env(["rustc", "--version"], [("RUSTUP_AUTO_INSTALL", "1")]) .await .with_stdout(snapbox::str![[r#" 1.2.0 (hash-beta-1.2.0) "#]]) .with_stderr(snapbox::str![[r#" +... info: syncing channel updates for 'beta-[HOST_TRIPLE]' info: latest update on 2015-01-02, rust version 1.2.0 (hash-beta-1.2.0) info: downloading component[..] @@ -543,7 +545,7 @@ async fn plus_override_toolchain_err_handling() { cx.config .expect_with_env( ["rustc", "+beta", "--version"], - &[("RUSTUP_AUTO_INSTALL", "0")], + [("RUSTUP_AUTO_INSTALL", "0")], ) .await .with_stderr(snapbox::str![[r#" @@ -553,7 +555,10 @@ error: toolchain 'beta-[HOST_TRIPLE]' is not installed "#]]) .is_err(); cx.config - .expect(["rustc", "+beta", "--version"]) + .expect_with_env( + ["rustc", "+beta", "--version"], + [("RUSTUP_AUTO_INSTALL", "1")], + ) .await .with_stdout(snapbox::str![[r#" 1.2.0 (hash-beta-1.2.0) @@ -1191,7 +1196,7 @@ async fn list_targets_no_toolchain() { cx.config .expect_with_env( ["rustup", "target", "list", "--toolchain=nightly"], - &[("RUSTUP_AUTO_INSTALL", "0")], + [("RUSTUP_AUTO_INSTALL", "0")], ) .await .with_stderr(snapbox::str![[r#" @@ -1221,7 +1226,7 @@ error: toolchain 'nightly-[HOST_TRIPLE]' is not installed cx.config .expect_with_env( ["rustup", "target", "list", "--toolchain=nightly"], - &[("RUSTUP_AUTO_INSTALL", "0")], + [("RUSTUP_AUTO_INSTALL", "0")], ) .await .with_stderr(snapbox::str![[r#" @@ -1234,7 +1239,7 @@ error: toolchain 'nightly-[HOST_TRIPLE]' is not installed cx.config .expect_with_env( ["rustup", "target", "list", "--toolchain=nightly"], - &[("RUSTUP_AUTO_INSTALL", "1")], + [("RUSTUP_AUTO_INSTALL", "1")], ) .await .is_ok(); @@ -1502,7 +1507,7 @@ async fn add_target_no_toolchain() { CROSS_ARCH1, "--toolchain=nightly", ], - &[("RUSTUP_AUTO_INSTALL", "0")], + [("RUSTUP_AUTO_INSTALL", "0")], ) .await .with_stderr(snapbox::str![[r#" @@ -1725,7 +1730,7 @@ async fn remove_target_no_toolchain() { CROSS_ARCH1, "--toolchain=nightly", ], - &[("RUSTUP_AUTO_INSTALL", "0")], + [("RUSTUP_AUTO_INSTALL", "0")], ) .await .with_stderr(snapbox::str![[r#"