@@ -143,26 +143,11 @@ pub fn do_add_to_path(methods: &[PathUpdateMethod]) -> Result<()> {
143
143
use winreg:: enums:: { RegType , HKEY_CURRENT_USER , KEY_READ , KEY_WRITE } ;
144
144
use winreg:: { RegKey , RegValue } ;
145
145
146
- let old_path = if let Some ( s) = get_windows_path_var ( ) ? {
147
- s
148
- } else {
149
- // Non-unicode path
150
- return Ok ( ( ) ) ;
146
+ let new_path = match _with_path_cargo_home_bin ( _add_to_path) ? {
147
+ Some ( new_path) => new_path,
148
+ None => return Ok ( ( ) ) , // No need to set the path
151
149
} ;
152
150
153
- let mut new_path = utils:: cargo_home ( ) ?
154
- . join ( "bin" )
155
- . to_string_lossy ( )
156
- . into_owned ( ) ;
157
- if old_path. contains ( & new_path) {
158
- return Ok ( ( ) ) ;
159
- }
160
-
161
- if !old_path. is_empty ( ) {
162
- new_path. push_str ( ";" ) ;
163
- new_path. push_str ( & old_path) ;
164
- }
165
-
166
151
let root = RegKey :: predef ( HKEY_CURRENT_USER ) ;
167
152
let environment = root
168
153
. open_subkey_with_flags ( "Environment" , KEY_READ | KEY_WRITE )
@@ -222,8 +207,23 @@ fn get_windows_path_var() -> Result<Option<String>> {
222
207
}
223
208
}
224
209
210
+ // Returns None if the existing old_path does not need changing, otherwise
211
+ // prepends the path_str to old_path, handling empty old_path appropriately.
212
+ fn _add_to_path ( old_path : & str , path_str : String ) -> Option < String > {
213
+ if old_path. is_empty ( ) {
214
+ Some ( path_str)
215
+ } else if old_path. contains ( & path_str) {
216
+ None
217
+ } else {
218
+ let mut new_path = path_str. clone ( ) ;
219
+ new_path. push_str ( ";" ) ;
220
+ new_path. push_str ( & old_path) ;
221
+ Some ( new_path)
222
+ }
223
+ }
224
+
225
225
// Returns None if the existing old_path does not need changing
226
- fn _remove_from_path ( old_path : & str , path_str : & str ) -> Option < String > {
226
+ fn _remove_from_path ( old_path : & str , path_str : String ) -> Option < String > {
227
227
let idx = old_path. find ( & path_str) ?;
228
228
// If there's a trailing semicolon (likely, since we probably added one
229
229
// during install), include that in the substring to remove. We don't search
@@ -244,20 +244,16 @@ fn _remove_from_path(old_path: &str, path_str: &str) -> Option<String> {
244
244
Some ( new_path)
245
245
}
246
246
247
- fn _path_without_cargo_home_bin ( ) -> Result < Option < String > > {
248
- let old_path = if let Some ( s) = get_windows_path_var ( ) ? {
249
- s
250
- } else {
251
- // Non-unicode path
252
- return Ok ( None ) ;
253
- } ;
254
-
247
+ fn _with_path_cargo_home_bin < F > ( f : F ) -> Result < Option < String > >
248
+ where
249
+ F : FnOnce ( & str , String ) -> Option < String > ,
250
+ {
251
+ let windows_path = get_windows_path_var ( ) ?;
255
252
let path_str = utils:: cargo_home ( ) ?
256
253
. join ( "bin" )
257
254
. to_string_lossy ( )
258
255
. into_owned ( ) ;
259
-
260
- Ok ( _remove_from_path ( & old_path, & path_str) )
256
+ Ok ( windows_path. and_then ( |old_path| f ( & old_path, path_str) ) )
261
257
}
262
258
263
259
pub fn do_remove_from_path ( methods : & [ PathUpdateMethod ] ) -> Result < ( ) > {
@@ -271,7 +267,7 @@ pub fn do_remove_from_path(methods: &[PathUpdateMethod]) -> Result<()> {
271
267
use winreg:: enums:: { RegType , HKEY_CURRENT_USER , KEY_READ , KEY_WRITE } ;
272
268
use winreg:: { RegKey , RegValue } ;
273
269
274
- let new_path = match _path_without_cargo_home_bin ( ) ? {
270
+ let new_path = match _with_path_cargo_home_bin ( _remove_from_path ) ? {
275
271
Some ( new_path) => new_path,
276
272
None => return Ok ( ( ) ) , // No need to set the path
277
273
} ;
@@ -503,9 +499,26 @@ mod tests {
503
499
}
504
500
505
501
#[ test]
506
- fn windows_uninstall_doesnt_mess_with_a_non_unicode_path ( ) {
502
+ fn windows_install_does_not_add_path_twice ( ) {
503
+ assert_eq ! (
504
+ None ,
505
+ super :: _add_to_path(
506
+ r"c:\users\example\.cargo\bin;foo" ,
507
+ r"c:\users\example\.cargo\bin" . into( )
508
+ )
509
+ ) ;
510
+ }
511
+
512
+ #[ test]
513
+ fn windows_doesnt_mess_with_a_non_unicode_path ( ) {
507
514
// This writes an error, so we want a sink for it.
508
- let tp = Box :: new ( currentprocess:: TestProcess :: default ( ) ) ;
515
+ let tp = Box :: new ( currentprocess:: TestProcess {
516
+ vars : [ ( "HOME" . to_string ( ) , "/unused" . to_string ( ) ) ]
517
+ . iter ( )
518
+ . cloned ( )
519
+ . collect ( ) ,
520
+ ..Default :: default ( )
521
+ } ) ;
509
522
with_registry_edits ( & || {
510
523
currentprocess:: with ( tp. clone ( ) , || {
511
524
let root = RegKey :: predef ( HKEY_CURRENT_USER ) ;
@@ -522,7 +535,10 @@ mod tests {
522
535
} ;
523
536
environment. set_raw_value ( "PATH" , & reg_value) . unwrap ( ) ;
524
537
// Ok(None) signals no change to the PATH setting layer
525
- assert_eq ! ( None , super :: _path_without_cargo_home_bin( ) . unwrap( ) ) ;
538
+ fn panic ( _: & str , _: String ) -> Option < String > {
539
+ panic ! ( "called" ) ;
540
+ }
541
+ assert_eq ! ( None , super :: _with_path_cargo_home_bin( panic) . unwrap( ) ) ;
526
542
} )
527
543
} ) ;
528
544
assert_eq ! (
@@ -538,7 +554,7 @@ mod tests {
538
554
"foo" ,
539
555
super :: _remove_from_path(
540
556
r"c:\users\example\.cargo\bin;foo" ,
541
- r"c:\users\example\.cargo\bin"
557
+ r"c:\users\example\.cargo\bin" . into ( )
542
558
)
543
559
. unwrap( )
544
560
)
@@ -550,7 +566,7 @@ mod tests {
550
566
"foo" ,
551
567
super :: _remove_from_path(
552
568
r"foo;c:\users\example\.cargo\bin" ,
553
- r"c:\users\example\.cargo\bin"
569
+ r"c:\users\example\.cargo\bin" . into ( )
554
570
)
555
571
. unwrap( )
556
572
)
0 commit comments