diff --git a/src/cli/common.rs b/src/cli/common.rs index cc554a38df..3c1c581d2f 100644 --- a/src/cli/common.rs +++ b/src/cli/common.rs @@ -280,35 +280,26 @@ fn show_channel_updates( pub(crate) async fn update_all_channels( cfg: &Cfg<'_>, - do_self_update: bool, force_update: bool, ) -> Result { let toolchains = cfg.update_all_channels(force_update).await?; let has_update_error = toolchains.iter().any(|(_, r)| r.is_err()); - let mut exit_code = utils::ExitCode(if has_update_error { 1 } else { 0 }); + let exit_code = utils::ExitCode(if has_update_error { 1 } else { 0 }); if toolchains.is_empty() { info!("no updatable toolchains installed"); } - let show_channel_updates = || { - if !toolchains.is_empty() { - writeln!(cfg.process.stdout().lock())?; - - let t = toolchains - .into_iter() - .map(|(p, s)| (PackageUpdate::Toolchain(p), s)) - .collect(); - show_channel_updates(cfg, t)?; - } - Ok(()) - }; + if !toolchains.is_empty() { + writeln!(cfg.process.stdout().lock())?; - if do_self_update { - exit_code &= self_update(show_channel_updates, cfg.process).await?; - } else { - show_channel_updates()?; + let t = toolchains + .into_iter() + .map(|(p, s)| (PackageUpdate::Toolchain(p), s)) + .collect(); + show_channel_updates(cfg, t)?; } + Ok(exit_code) } @@ -350,10 +341,7 @@ pub(crate) fn self_update_permitted(explicit: bool) -> Result(before_restart: F, process: &Process) -> Result -where - F: FnOnce() -> Result<()>, -{ +pub(crate) async fn self_update(process: &Process) -> Result { match self_update_permitted(false)? { SelfUpdatePermission::HardFail => { error!("Unable to self-update. STOP"); @@ -366,8 +354,6 @@ where let setup_path = self_update::prepare_update(process).await?; - before_restart()?; - if let Some(ref setup_path) = setup_path { return self_update::run_update(setup_path); } else { diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 7476d32fa9..c7d01df8a5 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -19,7 +19,7 @@ use crate::{ common::{self, PackageUpdate, update_console_filter}, errors::CLIError, help::*, - self_update::{self, RustupUpdateAvailable, SelfUpdateMode, check_rustup_update}, + self_update::{self, SelfUpdateMode, check_rustup_update}, topical_doc, }, command, @@ -829,21 +829,8 @@ async fn check_updates(cfg: &Cfg<'_>, opts: CheckOpts) -> Result self_update_mode > no-self-update args. - // Check for update only if rustup does **not** have the no-self-update feature, - // and auto-self-update is configured to **enable** - // and has **no** no-self-update parameter. - let self_update = !self_update::NEVER_SELF_UPDATE - && self_update_mode == SelfUpdateMode::Enable - && !opts.no_self_update; - - if self_update - && matches!( - check_rustup_update(cfg.process).await?, - RustupUpdateAvailable::True - ) - { + let self_update_mode = SelfUpdateMode::from_cfg(cfg)?; + if check_rustup_update(self_update_mode, opts.no_self_update, cfg).await? { update_available = true; } @@ -859,12 +846,12 @@ async fn update( let mut exit_code = utils::ExitCode(0); common::warn_if_host_is_emulated(cfg.process); - let self_update_mode = cfg.get_self_update_mode()?; + let self_update_mode = SelfUpdateMode::from_cfg(cfg)?; // Priority: no-self-update feature > self_update_mode > no-self-update args. // Update only if rustup does **not** have the no-self-update feature, // and auto-self-update is configured to **enable** // and has **no** no-self-update parameter. - let self_update = !self_update::NEVER_SELF_UPDATE + let self_update = !cfg!(feature = "no-self-update") && self_update_mode == SelfUpdateMode::Enable && !opts.no_self_update; let force_non_host = opts.force_non_host; @@ -927,27 +914,21 @@ async fn update( cfg.set_default(Some(&desc.into()))?; } } - if self_update { - exit_code &= common::self_update(|| Ok(()), cfg.process).await?; - } } else if ensure_active_toolchain { let (toolchain, reason) = cfg.ensure_active_toolchain(force_non_host, true).await?; info!("the active toolchain `{toolchain}` has been installed"); info!("it's active because: {reason}"); } else { - exit_code &= common::update_all_channels(cfg, self_update, opts.force).await?; + exit_code &= common::update_all_channels(cfg, opts.force).await?; info!("cleaning up downloads & tmp directories"); utils::delete_dir_contents_following_links(&cfg.download_dir); cfg.tmp_cx.clean(); } - if !self_update::NEVER_SELF_UPDATE && self_update_mode == SelfUpdateMode::CheckOnly { - check_rustup_update(cfg.process).await?; - } - - if self_update::NEVER_SELF_UPDATE { - info!("self-update is disabled for this build of rustup"); - info!("any updates to rustup will need to be fetched with your system package manager") + if self_update && !ensure_active_toolchain { + exit_code &= common::self_update(cfg.process).await?; + } else { + check_rustup_update(self_update_mode, opts.no_self_update, cfg).await?; } Ok(exit_code) @@ -1727,7 +1708,7 @@ fn set_auto_self_update( cfg: &mut Cfg<'_>, auto_self_update_mode: SelfUpdateMode, ) -> Result { - if self_update::NEVER_SELF_UPDATE { + if cfg!(feature = "no-self-update") { let mut args = cfg.process.args_os(); let arg0 = args.next().map(PathBuf::from); let arg0 = arg0 diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index e347556138..9fb54bee8a 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -246,11 +246,6 @@ impl InstallOpts<'_> { } } -#[cfg(feature = "no-self-update")] -pub(crate) const NEVER_SELF_UPDATE: bool = true; -#[cfg(not(feature = "no-self-update"))] -pub(crate) const NEVER_SELF_UPDATE: bool = false; - #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "kebab-case")] pub enum SelfUpdateMode { @@ -261,6 +256,21 @@ pub enum SelfUpdateMode { } impl SelfUpdateMode { + pub(crate) fn from_cfg(cfg: &Cfg<'_>) -> anyhow::Result { + if cfg.process.var("CI").is_ok() && cfg.process.var("RUSTUP_CI").is_err() { + // If we're in CI (but not rustup's own CI, which wants to test this stuff!), + // disable automatic self updates. + return Ok(SelfUpdateMode::Disable); + } + + cfg.settings_file.with(|s| { + Ok(match s.auto_self_update { + Some(mode) => mode, + None => SelfUpdateMode::Enable, + }) + }) + } + pub(crate) fn as_str(&self) -> &'static str { match self { Self::Enable => "enable", @@ -940,7 +950,7 @@ async fn maybe_install_rust( } pub(crate) fn uninstall(no_prompt: bool, process: &Process) -> Result { - if NEVER_SELF_UPDATE { + if cfg!(feature = "no-self-update") { error!("self-uninstall is disabled for this build of rustup"); error!("you should probably use your system package manager to uninstall rustup"); return Ok(utils::ExitCode(1)); @@ -1058,7 +1068,7 @@ pub(crate) async fn update(cfg: &Cfg<'_>) -> Result { common::warn_if_host_is_emulated(cfg.process); use common::SelfUpdatePermission::*; - let update_permitted = if NEVER_SELF_UPDATE { + let update_permitted = if cfg!(feature = "no-self-update") { HardFail } else { common::self_update_permitted(true)? @@ -1250,40 +1260,47 @@ impl fmt::Display for SchemaVersion { } } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(crate) enum RustupUpdateAvailable { - True, - False, -} - -pub(crate) async fn check_rustup_update(process: &Process) -> Result { - let mut update_available = RustupUpdateAvailable::False; +/// Returns whether an update was available +pub(crate) async fn check_rustup_update( + mode: SelfUpdateMode, + disabled: bool, + cfg: &Cfg<'_>, +) -> anyhow::Result { + // Priority: no-self-update feature > self_update_mode > no-self-update args. + // Check for update only if rustup does **not** have the no-self-update feature, + // and auto-self-update is configured to **enable** + // and has **no** no-self-update parameter. + if cfg!(feature = "no-self-update") { + info!("self-update is disabled for this build of rustup"); + info!("any updates to rustup will need to be fetched with your system package manager"); + return Ok(false); + } else if mode == SelfUpdateMode::Disable || disabled { + return Ok(false); + } - let mut t = process.stdout().terminal(process); + let mut t = cfg.process.stdout().terminal(cfg.process); // Get current rustup version let current_version = env!("CARGO_PKG_VERSION"); // Get available rustup version - let available_version = get_available_rustup_version(process).await?; + let available_version = get_available_rustup_version(cfg.process).await?; let _ = t.attr(terminalsource::Attr::Bold); write!(t.lock(), "rustup - ")?; - if current_version != available_version { - update_available = RustupUpdateAvailable::True; - + Ok(if current_version != available_version { let _ = t.fg(terminalsource::Color::Yellow); write!(t.lock(), "Update available")?; let _ = t.reset(); writeln!(t.lock(), " : {current_version} -> {available_version}")?; + true } else { let _ = t.fg(terminalsource::Color::Green); write!(t.lock(), "Up to date")?; let _ = t.reset(); writeln!(t.lock(), " : {current_version}")?; - } - - Ok(update_available) + false + }) } #[tracing::instrument(level = "trace")] diff --git a/src/config.rs b/src/config.rs index 635c8eade8..5057fcffab 100644 --- a/src/config.rs +++ b/src/config.rs @@ -409,21 +409,6 @@ impl<'a> Cfg<'a> { .with(|s| Ok(s.profile.unwrap_or_default())) } - pub(crate) fn get_self_update_mode(&self) -> Result { - if self.process.var("CI").is_ok() && self.process.var("RUSTUP_CI").is_err() { - // If we're in CI (but not rustup's own CI, which wants to test this stuff!), - // disable automatic self updates. - return Ok(SelfUpdateMode::Disable); - } - - self.settings_file.with(|s| { - Ok(match s.auto_self_update { - Some(mode) => mode, - None => SelfUpdateMode::Enable, - }) - }) - } - pub(crate) fn ensure_toolchains_dir(&self) -> Result<(), anyhow::Error> { utils::ensure_dir_exists("toolchains", &self.toolchains_dir, &|n| { (self.notify_handler)(n)