From ed93e7f85828eb4f8808cbc4f439812c09270802 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 14 Jul 2025 10:46:07 +0200 Subject: [PATCH] cli: move more self update logic into self_update module --- src/cli/common.rs | 64 -------------------------------------- src/cli/rustup_mode.rs | 4 +-- src/cli/self_update.rs | 70 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 68 insertions(+), 70 deletions(-) diff --git a/src/cli/common.rs b/src/cli/common.rs index 12bdad7dbd..1e5abced4b 100644 --- a/src/cli/common.rs +++ b/src/cli/common.rs @@ -3,8 +3,6 @@ use std::cell::RefCell; use std::fmt::Display; use std::fs; -#[cfg(not(windows))] -use std::io::ErrorKind; use std::io::{BufRead, Write}; use std::path::{Path, PathBuf}; use std::sync::{Arc, LazyLock, Mutex}; @@ -15,7 +13,6 @@ use git_testament::{git_testament, render_testament}; use tracing::{debug, error, info, trace, warn}; use tracing_subscriber::{EnvFilter, Registry, reload::Handle}; -use super::self_update; use crate::{ cli::download_tracker::DownloadTracker, config::Cfg, @@ -303,67 +300,6 @@ pub(crate) async fn update_all_channels( Ok(exit_code) } -#[derive(Clone, Copy, Debug)] -pub(crate) enum SelfUpdatePermission { - HardFail, - #[cfg(not(windows))] - Skip, - Permit, -} - -#[cfg(windows)] -pub(crate) fn self_update_permitted(_explicit: bool) -> Result { - Ok(SelfUpdatePermission::Permit) -} - -#[cfg(not(windows))] -pub(crate) fn self_update_permitted(explicit: bool) -> Result { - // Detect if rustup is not meant to self-update - let current_exe = env::current_exe()?; - let current_exe_dir = current_exe.parent().expect("Rustup isn't in a directory‽"); - if let Err(e) = tempfile::Builder::new() - .prefix("updtest") - .tempdir_in(current_exe_dir) - { - match e.kind() { - ErrorKind::PermissionDenied => { - trace!("Skipping self-update because we cannot write to the rustup dir"); - if explicit { - return Ok(SelfUpdatePermission::HardFail); - } else { - return Ok(SelfUpdatePermission::Skip); - } - } - _ => return Err(e.into()), - } - } - Ok(SelfUpdatePermission::Permit) -} - -/// Performs all of a self-update: check policy, download, apply and exit. -pub(crate) async fn self_update(process: &Process) -> Result { - match self_update_permitted(false)? { - SelfUpdatePermission::HardFail => { - error!("Unable to self-update. STOP"); - return Ok(utils::ExitCode(1)); - } - #[cfg(not(windows))] - SelfUpdatePermission::Skip => return Ok(utils::ExitCode(0)), - SelfUpdatePermission::Permit => {} - } - - let setup_path = self_update::prepare_update(process).await?; - - if let Some(setup_path) = &setup_path { - return self_update::run_update(setup_path); - } else { - // Try again in case we emitted "tool `{}` is already installed" last time. - self_update::install_proxies(process)?; - } - - Ok(utils::ExitCode(0)) -} - /// Print a list of items (targets or components) to stdout. /// /// `items` represents the list of items, with the name and a boolean diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index d643aafba6..44fe79e63b 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -996,7 +996,7 @@ async fn update( } } if self_update { - exit_code &= common::self_update(cfg.process).await?; + exit_code &= self_update::self_update(cfg.process).await?; } } else if ensure_active_toolchain { let (toolchain, reason) = cfg.ensure_active_toolchain(force_non_host, true).await?; @@ -1005,7 +1005,7 @@ async fn update( } else { exit_code &= common::update_all_channels(cfg, opts.force).await?; if self_update { - exit_code &= common::self_update(cfg.process).await?; + exit_code &= self_update::self_update(cfg.process).await?; } info!("cleaning up downloads & tmp directories"); diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index f076e615cb..c318cdca08 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -32,12 +32,13 @@ use std::borrow::Cow; use std::env::{self, consts::EXE_SUFFIX}; -use std::fmt; -use std::fs; +#[cfg(not(windows))] +use std::io; use std::io::Write; use std::path::{Component, MAIN_SEPARATOR, Path, PathBuf}; use std::process::Command; use std::str::FromStr; +use std::{fmt, fs}; use anyhow::{Context, Result, anyhow}; use cfg_if::cfg_if; @@ -1071,6 +1072,67 @@ pub(crate) fn uninstall(no_prompt: bool, process: &Process) -> Result Result { + Ok(SelfUpdatePermission::Permit) +} + +#[cfg(not(windows))] +pub(crate) fn self_update_permitted(explicit: bool) -> Result { + // Detect if rustup is not meant to self-update + let current_exe = env::current_exe()?; + let current_exe_dir = current_exe.parent().expect("Rustup isn't in a directory‽"); + if let Err(e) = tempfile::Builder::new() + .prefix("updtest") + .tempdir_in(current_exe_dir) + { + match e.kind() { + io::ErrorKind::PermissionDenied => { + trace!("Skipping self-update because we cannot write to the rustup dir"); + if explicit { + return Ok(SelfUpdatePermission::HardFail); + } else { + return Ok(SelfUpdatePermission::Skip); + } + } + _ => return Err(e.into()), + } + } + Ok(SelfUpdatePermission::Permit) +} + +/// Performs all of a self-update: check policy, download, apply and exit. +pub(crate) async fn self_update(process: &Process) -> Result { + match self_update_permitted(false)? { + SelfUpdatePermission::HardFail => { + error!("Unable to self-update. STOP"); + return Ok(utils::ExitCode(1)); + } + #[cfg(not(windows))] + SelfUpdatePermission::Skip => return Ok(utils::ExitCode(0)), + SelfUpdatePermission::Permit => {} + } + + let setup_path = prepare_update(process).await?; + + if let Some(setup_path) = &setup_path { + return run_update(setup_path); + } else { + // Try again in case we emitted "tool `{}` is already installed" last time. + install_proxies(process)?; + } + + Ok(utils::ExitCode(0)) +} + /// Self update downloads rustup-init to `CARGO_HOME`/bin/rustup-init /// and runs it. /// @@ -1089,11 +1151,11 @@ pub(crate) fn uninstall(no_prompt: bool, process: &Process) -> Result) -> Result { common::warn_if_host_is_emulated(cfg.process); - use common::SelfUpdatePermission::*; + use SelfUpdatePermission::*; let update_permitted = if cfg!(feature = "no-self-update") { HardFail } else { - common::self_update_permitted(true)? + self_update_permitted(true)? }; match update_permitted { HardFail => {