22
33use anyhow:: Context as _;
44use crossterm:: tty:: IsTty as _;
5+ use rustc_codegen_spirv_cache:: toolchain:: {
6+ ensure_toolchain_installation, REQUIRED_TOOLCHAIN_COMPONENTS ,
7+ } ;
58
6- /// Use `rustup` to install the toolchain and components, if not already installed.
7- ///
8- /// Pretty much runs:
9- ///
10- /// * rustup toolchain add nightly-2024-04-24
11- /// * rustup component add --toolchain nightly-2024-04-24 rust-src rustc-dev llvm-tools
9+ use crate :: user_output;
10+
11+ /// Uses `rustup` to install the toolchain and all the [required components](REQUIRED_TOOLCHAIN_COMPONENTS),
12+ /// if not already installed, while additionally asking for the user consent.
1213pub fn ensure_toolchain_and_components_exist (
1314 channel : & str ,
1415 skip_toolchain_install_consent : bool ,
1516) -> anyhow:: Result < ( ) > {
16- // Check for the required toolchain
17- let output_toolchain_list = std:: process:: Command :: new ( "rustup" )
18- . args ( [ "toolchain" , "list" ] )
19- . output ( )
20- . context ( "running rustup command" ) ?;
21- anyhow:: ensure!(
22- output_toolchain_list. status. success( ) ,
23- "could not list installed toolchains"
24- ) ;
25- let string_toolchain_list = String :: from_utf8_lossy ( & output_toolchain_list. stdout ) ;
26- if string_toolchain_list
27- . split_whitespace ( )
28- . any ( |toolchain| toolchain. starts_with ( channel) )
29- {
30- log:: debug!( "toolchain {channel} is already installed" ) ;
31- } else {
17+ let on_toolchain_install = || {
3218 let message = format ! ( "Rust {channel} with `rustup`" ) ;
3319 get_consent_for_toolchain_install (
3420 format ! ( "Install {message}" ) . as_ref ( ) ,
3521 skip_toolchain_install_consent,
3622 ) ?;
37- crate :: user_output!( "Installing {message}\n " ) ?;
38-
39- let output_toolchain_add = std:: process:: Command :: new ( "rustup" )
40- . args ( [ "toolchain" , "add" ] )
41- . arg ( channel)
42- . stdout ( std:: process:: Stdio :: inherit ( ) )
43- . stderr ( std:: process:: Stdio :: inherit ( ) )
44- . output ( )
45- . context ( "adding toolchain" ) ?;
46- anyhow:: ensure!(
47- output_toolchain_add. status. success( ) ,
48- "could not install required toolchain"
23+ log:: debug!( "installing toolchain {channel}" ) ;
24+ user_output ! ( "Installing {message}\n " ) ?;
25+ Ok ( ( ) )
26+ } ;
27+ let on_components_install = || {
28+ let message = format ! (
29+ "components {REQUIRED_TOOLCHAIN_COMPONENTS:?} for toolchain {channel} with `rustup`"
4930 ) ;
50- }
51-
52- // Check for the required components
53- let output_component_list = std:: process:: Command :: new ( "rustup" )
54- . args ( [ "component" , "list" , "--toolchain" ] )
55- . arg ( channel)
56- . output ( )
57- . context ( "getting toolchain list" ) ?;
58- anyhow:: ensure!(
59- output_component_list. status. success( ) ,
60- "could not list installed components"
61- ) ;
62- let string_component_list = String :: from_utf8_lossy ( & output_component_list. stdout ) ;
63- let required_components = [ "rust-src" , "rustc-dev" , "llvm-tools" ] ;
64- let installed_components = string_component_list. lines ( ) . collect :: < Vec < _ > > ( ) ;
65- let all_components_installed = required_components. iter ( ) . all ( |component| {
66- installed_components. iter ( ) . any ( |installed_component| {
67- let is_component = installed_component. starts_with ( component) ;
68- let is_installed = installed_component. ends_with ( "(installed)" ) ;
69- is_component && is_installed
70- } )
71- } ) ;
72- if all_components_installed {
73- log:: debug!( "all required components are installed" ) ;
74- } else {
75- let message = "toolchain components [rust-src, rustc-dev, llvm-tools] with `rustup`" ;
7631 get_consent_for_toolchain_install (
7732 format ! ( "Install {message}" ) . as_ref ( ) ,
7833 skip_toolchain_install_consent,
7934 ) ?;
80- crate :: user_output!( "Installing {message}\n " ) ?;
81-
82- let output_component_add = std:: process:: Command :: new ( "rustup" )
83- . args ( [ "component" , "add" , "--toolchain" ] )
84- . arg ( channel)
85- . args ( [ "rust-src" , "rustc-dev" , "llvm-tools" ] )
86- . stdout ( std:: process:: Stdio :: inherit ( ) )
87- . stderr ( std:: process:: Stdio :: inherit ( ) )
88- . output ( )
89- . context ( "adding rustup component" ) ?;
90- anyhow:: ensure!(
91- output_component_add. status. success( ) ,
92- "could not install required components"
93- ) ;
94- }
95-
96- Ok ( ( ) )
35+ log:: debug!( "installing required components of toolchain {channel}" ) ;
36+ user_output ! ( "Installing {message}\n " ) ?;
37+ Ok ( ( ) )
38+ } ;
39+ ensure_toolchain_installation ( channel, on_toolchain_install, on_components_install)
9740}
9841
9942/// Prompt user if they want to install a new Rust toolchain.
@@ -106,13 +49,13 @@ fn get_consent_for_toolchain_install(
10649 }
10750
10851 if !std:: io:: stdout ( ) . is_tty ( ) {
109- log:: error!( "Attempted to ask for consent when there's no TTY" ) ;
52+ log:: error!( "attempted to ask for consent when there's no TTY" ) ;
11053 anyhow:: bail!( "no TTY detected, so can't ask for consent to install Rust toolchain" )
11154 }
11255
11356 log:: debug!( "asking for consent to install the required toolchain" ) ;
11457 crossterm:: terminal:: enable_raw_mode ( ) . context ( "enabling raw mode" ) ?;
115- crate :: user_output!( "{prompt} [y/n]: " ) ?;
58+ user_output ! ( "{prompt} [y/n]: " ) ?;
11659 let mut input = crossterm:: event:: read ( ) . context ( "reading crossterm event" ) ?;
11760
11861 if let crossterm:: event:: Event :: Key ( crossterm:: event:: KeyEvent {
0 commit comments