diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index bb996ea101..a4c00d57f9 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -313,7 +313,7 @@ static MSVC_AUTO_INSTALL_MESSAGE: &str = r#"# Rust Visual C++ prerequisites Rust requires a linker and Windows API libraries but they don't seem to be available. -These components can be acquired by installing Visual Studio. +These components can be acquired through a Visual Studio installer. "#; @@ -376,37 +376,38 @@ pub(crate) fn install( warn!("installing msvc toolchain without its prerequisites"); } else if !quiet && plan == VsInstallPlan::Automatic { md(&mut term, MSVC_AUTO_INSTALL_MESSAGE); - if common::confirm( - "\nAutomatically download and install Visual Studio 2022 Community edition? (Y/n)", - true, - )? { - 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"); + match windows::choose_vs_install()? { + Some(VsInstallPlan::Automatic) => { + 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::question_bool("\nContinue?", false)? { + info!("aborting installation"); + return Ok(utils::ExitCode(0)); + } + } + Ok(ContinueInstall::No) => { + ensure_prompt()?; return Ok(utils::ExitCode(0)); } + _ => {} } - Ok(ContinueInstall::No) => { - ensure_prompt()?; + } + Some(VsInstallPlan::Manual) => { + md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE); + if !common::question_bool("\nContinue?", false)? { + info!("aborting installation"); return Ok(utils::ExitCode(0)); } - _ => {} - } - } else { - md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE); - if !common::confirm("\nContinue? (y/N)", false)? { - info!("aborting installation"); - return Ok(utils::ExitCode(0)); } + None => {} } } else { md(&mut term, MSVC_MESSAGE); md(&mut term, MSVC_MANUAL_INSTALL_MESSAGE); - if !common::confirm("\nContinue? (y/N)", false)? { + if !common::question_bool("\nContinue?", false)? { info!("aborting installation"); return Ok(utils::ExitCode(0)); } diff --git a/src/cli/self_update/windows.rs b/src/cli/self_update/windows.rs index 4b34cf552c..04b2ed891a 100644 --- a/src/cli/self_update/windows.rs +++ b/src/cli/self_update/windows.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::env::{consts::EXE_SUFFIX, split_paths}; use std::ffi::{OsStr, OsString}; use std::fmt; +use std::io::Write; use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::path::Path; use std::process::Command; @@ -27,6 +28,58 @@ pub(crate) fn ensure_prompt() -> Result<()> { Ok(()) } +fn choice(max: u8) -> Result> { + write!(process().stdout(), ">")?; + + let _ = std::io::stdout().flush(); + let input = common::read_line()?; + + let r = match str::parse(&input) { + Ok(n) if n <= max => Some(n), + _ => None, + }; + + writeln!(process().stdout())?; + Ok(r) +} + +pub(crate) fn choose_vs_install() -> Result> { + writeln!( + process().stdout(), + "\n1) Quick install via the Visual Studio Community installer" + )?; + writeln!( + process().stdout(), + " (free for individuals, academic uses, and open source)." + )?; + writeln!( + process().stdout(), + "\n2) Manually install the prerequisites" + )?; + writeln!( + process().stdout(), + " (for enterprise and advanced users)." + )?; + writeln!(process().stdout(), "\n3) Don't install the prerequisites")?; + writeln!( + process().stdout(), + " (if you're targetting the GNU ABI).\n" + )?; + + let choice = loop { + if let Some(n) = choice(3)? { + break n; + } + writeln!(process().stdout(), "Select option 1, 2 or 3")?; + }; + let plan = match choice { + 1 => Some(VsInstallPlan::Automatic), + 2 => Some(VsInstallPlan::Manual), + _ => None, + }; + Ok(plan) +} + #[derive(PartialEq, Eq)] pub(crate) enum VsInstallPlan { Automatic,