Skip to content

Windows: Improve handling of Visual Studio errors #3004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 13, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
@@ -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,22 @@ pub(crate) fn install(
"\nAutomatically download and install Visual Studio 2022 Community edition? (Y/n)",
true,
)? {
try_install_msvc()?;
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);
if !common::confirm("\nContinue? (y/N)", false)? {
71 changes: 57 additions & 14 deletions src/cli/self_update/windows.rs
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ pub(crate) fn do_msvc_check(opts: &InstallOpts<'_>) -> Option<VsInstallPlan> {
}
}

#[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() -> 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<ContinueInstall> {
// download the installer
let visual_studio_url = utils::parse_url("https://aka.ms/vs/17/release/vs_community.exe")?;

@@ -131,16 +144,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",
@@ -154,12 +158,51 @@ pub(crate) fn try_install_msvc() -> Result<()> {
.context("error running Visual Studio installer")?;

if exit_status.success() {
Ok(())
Ok(ContinueInstall::Yes)
} else {
Err(VsInstallError(exit_status.code().unwrap())).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")
}
}
}
}
}

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<utils::ExitCode> {
use std::process::Stdio;