10000
3
3
from .installs import get_matching_install_tags
4
4
from .install_command import SHORTCUT_HANDLERS , update_all_shortcuts
5
5
from .logging import LOGGER
6
- from .pathutils import PurePath
6
+ from .pathutils import Path , PurePath
7
7
from .tagutils import tag_or_range
8
8
9
9
10
10
def _iterdir (p , only_files = False ):
11
11
try :
12
12
if only_files :
13
- return [f for f in p .iterdir () if p .is_file ()]
14
- return list (p .iterdir ())
13
+ return [f for f in Path ( p ) .iterdir () if f .is_file ()]
14
+ return list (Path ( p ) .iterdir ())
15
15
except FileNotFoundError :
16
16
LOGGER .debug ("Skipping %s because it does not exist" , p )
17
17
return []
18
18
19
19
20
+ def _do_purge_global_dir (global_dir , warn_msg , * , hive = None , subkey = "Environment" ):
21
+ import os
22
+ import winreg
23
+
24
+ if hive is None :
25
+ hive = winreg .HKEY_CURRENT_USER
26
+ try :
27
+ with winreg .OpenKeyEx (hive , subkey ) as key :
28
+ path , kind = winreg .QueryValueEx (key , "Path" )
29
+ if kind not in (winreg .REG_SZ , winreg .REG_EXPAND_SZ ):
30
+ raise ValueError ("Value kind is not a string" )
31
+ except (OSError , ValueError ):
32
+ LOGGER .debug ("Not removing global commands directory from PATH" , exc_info = True )
33
+ else :
34
+ LOGGER .debug ("Current PATH contains %s" , path )
35
+ paths = path .split (";" )
36
+ newpaths = []
37
+ for p in paths :
38
+ # We should expand entries here, but we only want to remove those
39
+ # that we added ourselves (during firstrun), and we never use
40
+ # environment variables. So even if the kind is REG_EXPAND_SZ, we
41
+ # don't need to expand to find our own entry.
42
+ #ep = os.path.expandvars(p) if kind == winreg.REG_EXPAND_SZ else p
43
+ ep = p
44
+ if PurePath (ep ).match (global_dir ):
45
+ LOGGER .debug ("Removing from PATH: %s" , p )
46
+ else :
47
+ newpaths .append (p )
48
+ if len (newpaths ) < len (paths ):
49
+ newpath = ";" .join (newpaths )
50
+ with winreg .CreateKeyEx (hive , subkey , access = winreg .KEY_READ | winreg .KEY_WRITE ) as key :
51
+ path2 , kind2 = winreg .QueryValueEx (key , "Path" )
52
+ if path2 == path and kind2 == kind :
53
+ LOGGER .info ("Removing global commands directory from PATH" )
54
+ LOGGER .debug ("New PATH contains %s" , newpath )
55
+ winreg .SetValueEx (key , "Path" , 0 , kind , newpath )
56
+ else :
57
+ LOGGER .debug ("Not removing global commands directory from PATH "
58
+ "because the registry changed while processing." )
59
+
60
+ try :
61
+ from _native import broadcast_settings_change
62
+ broadcast_settings_change ()
63
+ except (ImportError , OSError ):
64
+ LOGGER .debug ("Did not broadcast settings change notification" ,
65
+ exc_info = True )
66
+
67
+ if not global_dir .is_dir ():
68
+ return
69
+ LOGGER .info ("Purging global commands from %s" , global_dir )
70
+ for f in _iterdir (global_dir ):
71
+ LOGGER .debug ("Purging %s" , f )
72
+ rmtree (f , after_5s_warning = warn_msg )
73
+
74
+
20
75
def execute (cmd ):
21
76
LOGGER .debug ("BEGIN uninstall_command.execute: %r" , cmd .args )
22
77
@@ -31,28 +86,28 @@ def execute(cmd):
31
86
cmd .tags = []
32
87
33
88
if cmd .purge :
34
- if cmd .ask_yn ("Uninstall all runtimes?" ):
35
- for i in installed :
36
- LOGGER . info ( "Purging %s from %s" , i [ "display-name" ], i [ "prefix" ])
37
- try :
38
- rmtree (
39
- i [ "prefix" ],
40
- after_5s_warning = warn_msg . format ( i [ "display-name" ]),
41
- remove_ext_first = ( "exe" , "dll" , "json" )
42
- )
43
- except FilesInUseError :
44
- LOGGER . warn ( "Unable to purge %s because it is still in use." ,
45
- i [ "display-name" ])
46
- continue
47
- LOGGER . info ( "Purging saved downloads from %s" , cmd . download_dir )
48
- rmtree ( cmd . download_dir , after_5s_warning = warn_msg . format ( "cached downloads" ))
49
- LOGGER .info ("Purging global commands from %s" , cmd .global_dir )
50
- for f in _iterdir (cmd .global_dir ):
51
- LOGGER . debug ( "Purging %s" , f )
52
- rmtree ( f , after_5s_warning = warn_msg .format ("global commands" ))
53
- LOGGER .info ("Purging all shortcuts" )
54
- for _ , cleanup in SHORTCUT_HANDLERS .values ():
55
- cleanup (cmd , [])
89
+ if not cmd .ask_yn ("Uninstall all runtimes?" ):
90
+ LOGGER . debug ( "END uninstall_command.execute" )
91
+ return
92
+ for i in installed :
93
+ LOGGER . info ( "Purging %s from %s" , i [ "display-name" ], i [ "prefix" ])
94
+ try :
95
+ rmtree (
96
+ i [ "prefix" ],
97
+ after_5s_warning = warn_msg . format ( i [ "display-name" ]),
98
+ remove_ext_first = ( "exe" , "dll" , "json" )
99
+ )
100
+ except FilesInUseError :
101
+ LOGGER . warn ( "Unable to purge %s because it is still in use." ,
102
+ i [ "display-name" ] )
103
+ continue
104
+ LOGGER .info ("Purging saved downloads from %s" , cmd .download_dir )
105
+ rmtree (cmd .download_dir , after_5s_warning = warn_msg . format ( "cached downloads" ))
106
+ # Purge global commands directory
107
+ _do_purge_global_dir ( cmd . global_dir , warn_msg .format ("global commands" ))
108
+ LOGGER .info ("Purging all shortcuts" )
109
+ for _ , cleanup in SHORTCUT_HANDLERS .values ():
110
+ cleanup (cmd , [])
56
111
LOGGER .debug ("END uninstall_command.execute" )
57
112
return
58
113
0 commit comments