From cfe8bd7ca8b01bac356ef8a972d81f8424b862b8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 11 Jun 2022 18:07:37 +0100 Subject: [PATCH 1/2] Improve handling of Visual Studio errors Make sure the user can always sees Visual Studio install errors even if the console closes when rustup-init exits. Also turn errors into warnings if the VS installer returned a non-zero exit code but all necessary components were installed. --- src/cli/self_update.rs | 12 +++++++++-- src/cli/self_update/windows.rs | 39 +++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index acc11d3594..61233d37d9 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -57,7 +57,7 @@ use anyhow::{anyhow, Context, Result}; use cfg_if::cfg_if; use same_file::Handle; -use super::common::{self, ignorable_error, Confirm}; +use super::common::{self, ignorable_error, report_error, Confirm}; use super::errors::*; use super::markdown::md; use super::term2; @@ -380,7 +380,15 @@ pub(crate) fn install( "\nAutomatically download and install Visual Studio 2022 Community edition? (Y/n)", true, )? { - try_install_msvc()?; + if let Err(e) = try_install_msvc(&opts) { + // Make sure the console doesn't exit before the user can + // see the error and give the option to continue anyway. + report_error(&e); + if !common::confirm("\nContinue installing rustup? (y/N)", false)? { + info!("aborting installation"); + return Ok(utils::ExitCode(0)); + } + } } else { md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE); if !common::confirm("\nContinue? (y/N)", false)? { diff --git a/src/cli/self_update/windows.rs b/src/cli/self_update/windows.rs index fac6a8bf18..e2c30222d7 100644 --- a/src/cli/self_update/windows.rs +++ b/src/cli/self_update/windows.rs @@ -98,7 +98,7 @@ impl fmt::Display for VsInstallError { } } -pub(crate) fn try_install_msvc() -> Result<()> { +pub(crate) fn try_install_msvc(opts: &InstallOpts<'_>) -> Result<()> { // download the installer let visual_studio_url = utils::parse_url("https://aka.ms/vs/17/release/vs_community.exe")?; @@ -131,16 +131,7 @@ pub(crate) fn try_install_msvc() -> Result<()> { // It's possible an earlier or later version of the Windows SDK has been // installed separately from Visual Studio so installing it can be skipped. - let mut has_libs = false; - if let Some(paths) = process().var_os("lib") { - for mut path in split_paths(&paths) { - path.push("kernel32.lib"); - if path.exists() { - has_libs = true; - } - } - }; - if !has_libs { + if !has_windows_sdk_libs() { cmd.args([ "--add", "Microsoft.VisualStudio.Component.Windows11SDK.22000", @@ -156,10 +147,34 @@ pub(crate) fn try_install_msvc() -> Result<()> { if exit_status.success() { Ok(()) } else { - Err(VsInstallError(exit_status.code().unwrap())).context("failed to install Visual Studio") + let err = VsInstallError(exit_status.code().unwrap()); + // It's possible that the installer returned a non-zero exit code + // even though the required components were successfully installed. + // In that case we warn about the error but continue on. + let have_msvc = do_msvc_check(opts).is_none(); + let has_libs = has_windows_sdk_libs(); + if have_msvc && has_libs { + warn!("Visual Studio is installed but a problem ocurred during installation"); + warn!("{}", err); + Ok(()) + } else { + Err(err).context("failed to install Visual Studio") + } } } +fn has_windows_sdk_libs() -> bool { + if let Some(paths) = process().var_os("lib") { + for mut path in split_paths(&paths) { + path.push("kernel32.lib"); + if path.exists() { + return true; + } + } + }; + false +} + /// Run by rustup-gc-$num.exe to delete CARGO_HOME pub fn complete_windows_uninstall() -> Result { use std::process::Stdio; From 60d75df54aed46c32911c1263a45ca08f0da133e Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 11 Jun 2022 19:58:10 +0100 Subject: [PATCH 2/2] Explicitly handle Visual Studio needing a restart --- src/cli/self_update.rs | 19 +++++++---- src/cli/self_update/windows.rs | 58 +++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 61233d37d9..bb996ea101 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -380,14 +380,21 @@ pub(crate) fn install( "\nAutomatically download and install Visual Studio 2022 Community edition? (Y/n)", true, )? { - if let Err(e) = try_install_msvc(&opts) { - // Make sure the console doesn't exit before the user can - // see the error and give the option to continue anyway. - report_error(&e); - if !common::confirm("\nContinue installing rustup? (y/N)", false)? { - info!("aborting installation"); + match try_install_msvc(&opts) { + Err(e) => { + // Make sure the console doesn't exit before the user can + // see the error and give the option to continue anyway. + report_error(&e); + if !common::confirm("\nContinue installing rustup? (y/N)", false)? { + info!("aborting installation"); + return Ok(utils::ExitCode(0)); + } + } + Ok(ContinueInstall::No) => { + ensure_prompt()?; return Ok(utils::ExitCode(0)); } + _ => {} } } else { md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE); diff --git a/src/cli/self_update/windows.rs b/src/cli/self_update/windows.rs index e2c30222d7..eaf559b1ee 100644 --- a/src/cli/self_update/windows.rs +++ b/src/cli/self_update/windows.rs @@ -66,7 +66,7 @@ pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> Option { } } -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] struct VsInstallError(i32); impl std::error::Error for VsInstallError {} impl fmt::Display for VsInstallError { @@ -97,8 +97,21 @@ impl fmt::Display for VsInstallError { write!(f, "{} (exit code {})", message, self.0) } } +impl VsInstallError { + const REBOOTING_NOW: Self = Self(1641); + const REBOOT_REQUIRED: Self = Self(3010); +} + +pub(crate) enum ContinueInstall { + Yes, + No, +} -pub(crate) fn try_install_msvc(opts: &InstallOpts<'_>) -> Result<()> { +/// Tries to install the needed Visual Studio components. +/// +/// Returns `Ok(ContinueInstall::No)` if installing Visual Studio was successful +/// but the rustup install should not be continued at this time. +pub(crate) fn try_install_msvc(opts: &InstallOpts<'_>) -> Result { // download the installer let visual_studio_url = utils::parse_url("https://aka.ms/vs/17/release/vs_community.exe")?; @@ -145,20 +158,35 @@ pub(crate) fn try_install_msvc(opts: &InstallOpts<'_>) -> Result<()> { .context("error running Visual Studio installer")?; if exit_status.success() { - Ok(()) + Ok(ContinueInstall::Yes) } else { - let err = VsInstallError(exit_status.code().unwrap()); - // It's possible that the installer returned a non-zero exit code - // even though the required components were successfully installed. - // In that case we warn about the error but continue on. - let have_msvc = do_msvc_check(opts).is_none(); - let has_libs = has_windows_sdk_libs(); - if have_msvc && has_libs { - warn!("Visual Studio is installed but a problem ocurred during installation"); - warn!("{}", err); - Ok(()) - } else { - Err(err).context("failed to install Visual Studio") + match VsInstallError(exit_status.code().unwrap()) { + err @ VsInstallError::REBOOT_REQUIRED => { + // A reboot is required but the user opted to delay it. + warn!("{}", err); + Ok(ContinueInstall::Yes) + } + err @ VsInstallError::REBOOTING_NOW => { + // The user is wanting to reboot right now, so we should + // not continue the install. + warn!("{}", err); + info!("\nRun rustup-init after restart to continue install"); + Ok(ContinueInstall::No) + } + err => { + // It's possible that the installer returned a non-zero exit code + // even though the required components were successfully installed. + // In that case we warn about the error but continue on. + let have_msvc = do_msvc_check(opts).is_none(); + let has_libs = has_windows_sdk_libs(); + if have_msvc && has_libs { + warn!("Visual Studio is installed but a problem ocurred during installation"); + warn!("{}", err); + Ok(ContinueInstall::Yes) + } else { + Err(err).context("failed to install Visual Studio") + } + } } } }