11use std:: env:: { consts:: EXE_SUFFIX , split_paths} ;
22use std:: ffi:: { OsStr , OsString } ;
33use std:: fmt;
4- use std:: io:: Write ;
4+ use std:: io:: { self , Write } ;
55use std:: os:: windows:: ffi:: { OsStrExt , OsStringExt } ;
66use std:: path:: Path ;
77use std:: process:: Command ;
8- use std:: sync:: { Arc , Mutex } ;
8+ use std:: sync:: { Arc , LockResult , Mutex , MutexGuard } ;
99
1010use anyhow:: { anyhow, Context , Result } ;
1111use tracing:: { info, warn} ;
@@ -20,6 +20,7 @@ use crate::utils::utils;
2020use crate :: utils:: Notification ;
2121
2222use winreg:: enums:: { RegType , HKEY_CURRENT_USER , KEY_READ , KEY_WRITE } ;
23+ use winreg:: types:: { FromRegValue , ToRegValue } ;
2324use winreg:: { RegKey , RegValue } ;
2425
2526pub ( crate ) fn ensure_prompt ( process : & Process ) -> Result < ( ) > {
@@ -807,16 +808,85 @@ pub(crate) fn delete_rustup_and_cargo_home(process: &Process) -> Result<()> {
807808 Ok ( ( ) )
808809}
809810
810- #[ cfg( test) ]
811- mod tests {
812- use std:: ffi:: OsString ;
813- use std:: os:: windows:: ffi:: OsStrExt ;
811+ #[ cfg( any( test, feature = "test" ) ) ]
812+ pub fn get_path ( ) -> io:: Result < Option < RegValue > > {
813+ USER_PATH . get ( )
814+ }
815+
816+ #[ cfg( any( test, feature = "test" ) ) ]
817+ pub struct RegistryGuard < ' a > {
818+ _locked : LockResult < MutexGuard < ' a , ( ) > > ,
819+ id : & ' static RegistryValueId ,
820+ prev : Option < RegValue > ,
821+ }
822+
823+ #[ cfg( any( test, feature = "test" ) ) ]
824+ impl < ' a > RegistryGuard < ' a > {
825+ pub fn new ( id : & ' static RegistryValueId ) -> io:: Result < Self > {
826+ Ok ( Self {
827+ _locked : REGISTRY_LOCK . lock ( ) ,
828+ id,
829+ prev : id. get ( ) ?,
830+ } )
831+ }
832+ }
833+
834+ #[ cfg( any( test, feature = "test" ) ) ]
835+ impl < ' a > Drop for RegistryGuard < ' a > {
836+ fn drop ( & mut self ) {
837+ self . id . set ( self . prev . as_ref ( ) ) . unwrap ( ) ;
838+ }
839+ }
840+
841+ #[ cfg( any( test, feature = "test" ) ) ]
842+ static REGISTRY_LOCK : Mutex < ( ) > = Mutex :: new ( ( ) ) ;
843+
844+ #[ cfg( any( test, feature = "test" ) ) ]
845+ pub const USER_PATH : RegistryValueId = RegistryValueId {
846+ sub_key : "Environment" ,
847+ value_name : "PATH" ,
848+ } ;
814849
815- use winreg:: enums:: { RegType , HKEY_CURRENT_USER , KEY_READ , KEY_WRITE } ;
816- use winreg:: { RegKey , RegValue } ;
850+ #[ cfg( any( test, feature = "test" ) ) ]
851+ pub struct RegistryValueId {
852+ pub sub_key : & ' static str ,
853+ pub value_name : & ' static str ,
854+ }
855+
856+ #[ cfg( any( test, feature = "test" ) ) ]
857+ impl RegistryValueId {
858+ pub fn get_value < T : FromRegValue > ( & self ) -> io:: Result < Option < T > > {
859+ self . get ( ) ?. map ( |v| T :: from_reg_value ( & v) ) . transpose ( )
860+ }
861+
862+ fn get ( & self ) -> io:: Result < Option < RegValue > > {
863+ let sub_key = RegKey :: predef ( HKEY_CURRENT_USER )
864+ . open_subkey_with_flags ( self . sub_key , KEY_READ | KEY_WRITE ) ?;
865+ match sub_key. get_raw_value ( self . value_name ) {
866+ Ok ( val) => Ok ( Some ( val) ) ,
867+ Err ( ref e) if e. kind ( ) == io:: ErrorKind :: NotFound => Ok ( None ) ,
868+ Err ( e) => Err ( e) ,
869+ }
870+ }
871+
872+ pub fn set_value ( & self , new : Option < impl ToRegValue > ) -> io:: Result < ( ) > {
873+ self . set ( new. map ( |s| s. to_reg_value ( ) ) . as_ref ( ) )
874+ }
817875
876+ fn set ( & self , new : Option < & RegValue > ) -> io:: Result < ( ) > {
877+ let sub_key = RegKey :: predef ( HKEY_CURRENT_USER )
878+ . open_subkey_with_flags ( self . sub_key , KEY_READ | KEY_WRITE ) ?;
879+ match new {
880+ Some ( new) => sub_key. set_raw_value ( self . value_name , new) ,
881+ None => sub_key. delete_value ( self . value_name ) ,
882+ }
883+ }
884+ }
885+
886+ #[ cfg( test) ]
887+ mod tests {
888+ use super :: * ;
818889 use crate :: currentprocess:: TestProcess ;
819- use crate :: test:: { RegistryGuard , USER_PATH } ;
820890
821891 fn wide ( str : & str ) -> Vec < u16 > {
822892 OsString :: from ( str) . encode_wide ( ) . collect ( )
0 commit comments