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