3232
3333use std:: borrow:: Cow ;
3434use std:: env:: { self , consts:: EXE_SUFFIX } ;
35- use std :: fmt ;
36- use std:: fs ;
35+ # [ cfg ( not ( windows ) ) ]
36+ use std:: io ;
3737use std:: io:: Write ;
3838use std:: path:: { Component , MAIN_SEPARATOR , Path , PathBuf } ;
3939use std:: process:: Command ;
4040use std:: str:: FromStr ;
41+ use std:: { fmt, fs} ;
4142
4243use anyhow:: { Context , Result , anyhow} ;
4344use cfg_if:: cfg_if;
@@ -1071,6 +1072,67 @@ pub(crate) fn uninstall(no_prompt: bool, process: &Process) -> Result<utils::Exi
10711072 Ok ( utils:: ExitCode ( 0 ) )
10721073}
10731074
1075+ #[ derive( Clone , Copy , Debug ) ]
1076+ pub ( crate ) enum SelfUpdatePermission {
1077+ HardFail ,
1078+ #[ cfg( not( windows) ) ]
1079+ Skip ,
1080+ Permit ,
1081+ }
1082+
1083+ #[ cfg( windows) ]
1084+ pub ( crate ) fn self_update_permitted ( _explicit : bool ) -> Result < SelfUpdatePermission > {
1085+ Ok ( SelfUpdatePermission :: Permit )
1086+ }
1087+
1088+ #[ cfg( not( windows) ) ]
1089+ pub ( crate ) fn self_update_permitted ( explicit : bool ) -> Result < SelfUpdatePermission > {
1090+ // Detect if rustup is not meant to self-update
1091+ let current_exe = env:: current_exe ( ) ?;
1092+ let current_exe_dir = current_exe. parent ( ) . expect ( "Rustup isn't in a directory‽" ) ;
1093+ if let Err ( e) = tempfile:: Builder :: new ( )
1094+ . prefix ( "updtest" )
1095+ . tempdir_in ( current_exe_dir)
1096+ {
1097+ match e. kind ( ) {
1098+ io:: ErrorKind :: PermissionDenied => {
1099+ trace ! ( "Skipping self-update because we cannot write to the rustup dir" ) ;
1100+ if explicit {
1101+ return Ok ( SelfUpdatePermission :: HardFail ) ;
1102+ } else {
1103+ return Ok ( SelfUpdatePermission :: Skip ) ;
1104+ }
1105+ }
1106+ _ => return Err ( e. into ( ) ) ,
1107+ }
1108+ }
1109+ Ok ( SelfUpdatePermission :: Permit )
1110+ }
1111+
1112+ /// Performs all of a self-update: check policy, download, apply and exit.
1113+ pub ( crate ) async fn self_update ( process : & Process ) -> Result < utils:: ExitCode > {
1114+ match self_update_permitted ( false ) ? {
1115+ SelfUpdatePermission :: HardFail => {
1116+ error ! ( "Unable to self-update. STOP" ) ;
1117+ return Ok ( utils:: ExitCode ( 1 ) ) ;
1118+ }
1119+ #[ cfg( not( windows) ) ]
1120+ SelfUpdatePermission :: Skip => return Ok ( utils:: ExitCode ( 0 ) ) ,
1121+ SelfUpdatePermission :: Permit => { }
1122+ }
1123+
1124+ let setup_path = prepare_update ( process) . await ?;
1125+
1126+ if let Some ( setup_path) = & setup_path {
1127+ return run_update ( setup_path) ;
1128+ } else {
1129+ // Try again in case we emitted "tool `{}` is already installed" last time.
1130+ install_proxies ( process) ?;
1131+ }
1132+
1133+ Ok ( utils:: ExitCode ( 0 ) )
1134+ }
1135+
10741136/// Self update downloads rustup-init to `CARGO_HOME`/bin/rustup-init
10751137/// and runs it.
10761138///
@@ -1089,11 +1151,11 @@ pub(crate) fn uninstall(no_prompt: bool, process: &Process) -> Result<utils::Exi
10891151pub ( crate ) async fn update ( cfg : & Cfg < ' _ > ) -> Result < utils:: ExitCode > {
10901152 common:: warn_if_host_is_emulated ( cfg. process ) ;
10911153
1092- use common :: SelfUpdatePermission :: * ;
1154+ use SelfUpdatePermission :: * ;
10931155 let update_permitted = if cfg ! ( feature = "no-self-update" ) {
10941156 HardFail
10951157 } else {
1096- common :: self_update_permitted ( true ) ?
1158+ self_update_permitted ( true ) ?
10971159 } ;
10981160 match update_permitted {
10991161 HardFail => {
0 commit comments