diff --git a/src/cli/common.rs b/src/cli/common.rs index 4a272b19bc..ea5e38b7e8 100644 --- a/src/cli/common.rs +++ b/src/cli/common.rs @@ -293,6 +293,8 @@ pub(crate) async fn update_all_channels( 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 }); if toolchains.is_empty() { info!("no updatable toolchains installed"); @@ -308,14 +310,15 @@ pub(crate) async fn update_all_channels( .collect(); show_channel_updates(cfg, t)?; } - Ok(utils::ExitCode(0)) + Ok(()) }; if do_self_update { - self_update(show_channel_updates, cfg.process).await + exit_code &= self_update(show_channel_updates, cfg.process).await?; } else { - show_channel_updates() + show_channel_updates()?; } + Ok(exit_code) } #[derive(Clone, Copy, Debug)] @@ -358,7 +361,7 @@ pub(crate) fn self_update_permitted(explicit: bool) -> Result(before_restart: F, process: &Process) -> Result where - F: FnOnce() -> Result, + F: FnOnce() -> Result<()>, { match self_update_permitted(false)? { SelfUpdatePermission::HardFail => { diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 5d482e046c..a82176fb23 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -789,6 +789,8 @@ async fn check_updates(cfg: &Cfg<'_>) -> Result { } async fn update(cfg: &mut Cfg<'_>, opts: UpdateOpts) -> Result { + let mut exit_code = utils::ExitCode(0); + common::warn_if_host_is_emulated(cfg.process); let self_update_mode = cfg.get_self_update_mode()?; // Priority: no-self-update feature > self_update_mode > no-self-update args. @@ -862,10 +864,10 @@ async fn update(cfg: &mut Cfg<'_>, opts: UpdateOpts) -> Result } } if self_update { - common::self_update(|| Ok(utils::ExitCode(0)), cfg.process).await?; + common::self_update(|| Ok(()), cfg.process).await?; } } else { - common::update_all_channels(cfg, self_update, opts.force).await?; + exit_code &= common::update_all_channels(cfg, self_update, opts.force).await?; info!("cleaning up downloads & tmp directories"); utils::delete_dir_contents_following_links(&cfg.download_dir); cfg.tmp_cx.clean(); @@ -880,7 +882,7 @@ async fn update(cfg: &mut Cfg<'_>, opts: UpdateOpts) -> Result info!("any updates to rustup will need to be fetched with your system package manager") } - Ok(utils::ExitCode(0)) + Ok(exit_code) } async fn run( diff --git a/src/utils/utils.rs b/src/utils/utils.rs index 4ccddab200..40855b35ab 100644 --- a/src/utils/utils.rs +++ b/src/utils/utils.rs @@ -1,6 +1,7 @@ use std::env; use std::fs::{self, File}; use std::io::{self, BufReader, Write}; +use std::ops::{BitAnd, BitAndAssign}; use std::path::{Path, PathBuf}; use std::process::ExitStatus; @@ -21,8 +22,30 @@ pub(crate) use crate::utils::utils::raw::is_directory; pub use crate::utils::utils::raw::{is_file, path_exists}; +#[derive(Debug, PartialEq, Eq)] pub struct ExitCode(pub i32); +impl BitAnd for ExitCode { + type Output = Self; + + // If `self` is `0` (success), yield `rhs`. + fn bitand(self, rhs: Self) -> Self::Output { + match self.0 { + 0 => rhs, + _ => self, + } + } +} + +impl BitAndAssign for ExitCode { + // If `self` is `0` (success), set `self` to `rhs`. + fn bitand_assign(&mut self, rhs: Self) { + if self.0 == 0 { + *self = rhs + } + } +} + impl From for ExitCode { fn from(status: ExitStatus) -> Self { Self(match status.success() {