33from  .installs  import  get_matching_install_tags 
44from  .install_command  import  SHORTCUT_HANDLERS , update_all_shortcuts 
55from  .logging  import  LOGGER 
6- from  .pathutils  import  PurePath 
6+ from  .pathutils  import  Path ,  PurePath 
77from  .tagutils  import  tag_or_range 
88
99
1010def  _iterdir (p , only_files = False ):
1111    try :
1212        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 ())
1515    except  FileNotFoundError :
1616        LOGGER .debug ("Skipping %s because it does not exist" , p )
1717        return  []
1818
1919
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+ 
2075def  execute (cmd ):
2176    LOGGER .debug ("BEGIN uninstall_command.execute: %r" , cmd .args )
2277
@@ -31,28 +86,28 @@ def execute(cmd):
3186    cmd .tags  =  []
3287
3388    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 , [])
56111        LOGGER .debug ("END uninstall_command.execute" )
57112        return 
58113
0 commit comments