11//! toolchain installation logic
22
3+ use std:: process:: { Command , Stdio } ;
4+
35use anyhow:: Context as _;
46use crossterm:: tty:: IsTty as _;
7+ use rustc_codegen_spirv_cache:: toolchain:: is_toolchain_installed;
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
12- pub fn ensure_toolchain_and_components_exist (
13- channel : & str ,
14- skip_toolchain_install_consent : bool ,
15- ) -> anyhow:: Result < ( ) > {
16- // Check for the required toolchain
17- let output_toolchain_list = std:: process:: Command :: new ( "rustup" )
18- . args ( [ "toolchain" , "list" ] )
9+ use crate :: user_output;
10+
11+ /// Installs the given toolchain using `rustup`.
12+ pub fn install_toolchain ( channel : & str ) -> anyhow:: Result < ( ) > {
13+ let output_toolchain_add = Command :: new ( "rustup" )
14+ . args ( [ "toolchain" , "add" ] )
15+ . arg ( channel)
16+ . stdout ( Stdio :: inherit ( ) )
17+ . stderr ( Stdio :: inherit ( ) )
1918 . output ( )
20- . context ( "running rustup command " ) ?;
19+ . context ( "adding toolchain " ) ?;
2120 anyhow:: ensure!(
22- output_toolchain_list . status. success( ) ,
23- "could not list installed toolchains "
21+ output_toolchain_add . status. success( ) ,
22+ "could not install required toolchain "
2423 ) ;
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 {
32- let message = format ! ( "Rust {channel} with `rustup`" ) ;
33- get_consent_for_toolchain_install (
34- format ! ( "Install {message}" ) . as_ref ( ) ,
35- skip_toolchain_install_consent,
36- ) ?;
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"
49- ) ;
50- }
24+ Ok ( ( ) )
25+ }
5126
52- // Check for the required components
53- let output_component_list = std:: process:: Command :: new ( "rustup" )
27+ /// Components which are required to be installed for a toolchain to be usable with `rust-gpu`.
28+ pub const REQUIRED_TOOLCHAIN_COMPONENTS : [ & str ; 3 ] = [ "rust-src" , "rustc-dev" , "llvm-tools" ] ;
29+
30+ /// Checks if all the required components of the given toolchain are installed using `rustup`.
31+ pub fn all_required_toolchain_components_installed ( channel : & str ) -> anyhow:: Result < bool > {
32+ let output_component_list = Command :: new ( "rustup" )
5433 . args ( [ "component" , "list" , "--toolchain" ] )
5534 . arg ( channel)
5635 . output ( )
@@ -59,38 +38,72 @@ pub fn ensure_toolchain_and_components_exist(
5938 output_component_list. status. success( ) ,
6039 "could not list installed components"
6140 ) ;
41+
6242 let string_component_list = String :: from_utf8_lossy ( & output_component_list. stdout ) ;
63- let required_components = [ "rust-src" , "rustc-dev" , "llvm-tools" ] ;
6443 let installed_components = string_component_list. lines ( ) . collect :: < Vec < _ > > ( ) ;
65- let all_components_installed = required_components . iter ( ) . all ( |component| {
44+ let all_components_installed = REQUIRED_TOOLCHAIN_COMPONENTS . iter ( ) . all ( |component| {
6645 installed_components. iter ( ) . any ( |installed_component| {
6746 let is_component = installed_component. starts_with ( component) ;
6847 let is_installed = installed_component. ends_with ( "(installed)" ) ;
6948 is_component && is_installed
7049 } )
7150 } ) ;
72- if all_components_installed {
73- log:: debug!( "all required components are installed" ) ;
51+ Ok ( all_components_installed)
52+ }
53+
54+ /// Installs all the required components for the given toolchain using `rustup`.
55+ pub fn install_required_toolchain_components ( channel : & str ) -> anyhow:: Result < ( ) > {
56+ let output_component_add = Command :: new ( "rustup" )
57+ . args ( [ "component" , "add" , "--toolchain" ] )
58+ . arg ( channel)
59+ . args ( REQUIRED_TOOLCHAIN_COMPONENTS )
60+ . stdout ( Stdio :: inherit ( ) )
61+ . stderr ( Stdio :: inherit ( ) )
62+ . output ( )
63+ . context ( "adding rustup component" ) ?;
64+ anyhow:: ensure!(
65+ output_component_add. status. success( ) ,
66+ "could not install required components"
67+ ) ;
68+ Ok ( ( ) )
69+ }
70+
71+ /// Use `rustup` to install the toolchain and components, if not already installed.
72+ ///
73+ /// Pretty much runs:
74+ ///
75+ /// * rustup toolchain add nightly-2024-04-24
76+ /// * rustup component add --toolchain nightly-2024-04-24 rust-src rustc-dev llvm-tools
77+ pub fn ensure_toolchain_and_components_exist (
78+ channel : & str ,
79+ skip_toolchain_install_consent : bool ,
80+ ) -> anyhow:: Result < ( ) > {
81+ // Check for the required toolchain
82+ if is_toolchain_installed ( channel) ? {
83+ log:: debug!( "toolchain {channel} is already installed" ) ;
7484 } else {
75- let message = "toolchain components [rust-src, rustc-dev, llvm-tools] with `rustup`";
85+ let message = format ! ( "Rust {channel} with `rustup`") ;
7686 get_consent_for_toolchain_install (
7787 format ! ( "Install {message}" ) . as_ref ( ) ,
7888 skip_toolchain_install_consent,
7989 ) ?;
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"
90+ user_output ! ( "Installing {message}\n " ) ?;
91+ install_toolchain ( channel) ?;
92+ }
93+
94+ // Check for the required components
95+ if all_required_toolchain_components_installed ( channel) ? {
96+ log:: debug!( "all required components of toolchain {channel} are installed" ) ;
97+ } else {
98+ let message = format ! (
99+ "components {REQUIRED_TOOLCHAIN_COMPONENTS:?} for toolchain {channel} with `rustup`"
93100 ) ;
101+ get_consent_for_toolchain_install (
102+ format ! ( "Install {message}" ) . as_ref ( ) ,
103+ skip_toolchain_install_consent,
104+ ) ?;
105+ user_output ! ( "Installing {message}\n " ) ?;
106+ install_required_toolchain_components ( channel) ?;
94107 }
95108
96109 Ok ( ( ) )
@@ -112,7 +125,7 @@ fn get_consent_for_toolchain_install(
112125
113126 log:: debug!( "asking for consent to install the required toolchain" ) ;
114127 crossterm:: terminal:: enable_raw_mode ( ) . context ( "enabling raw mode" ) ?;
115- crate :: user_output!( "{prompt} [y/n]: " ) ?;
128+ user_output ! ( "{prompt} [y/n]: " ) ?;
116129 let mut input = crossterm:: event:: read ( ) . context ( "reading crossterm event" ) ?;
117130
118131 if let crossterm:: event:: Event :: Key ( crossterm:: event:: KeyEvent {
0 commit comments