JFIFxxC      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbrimport os import platform from datetime import datetime from io import open from .shells import DEFAULT_SHELLS, SHELLS from .utils import ensure_parent_dir_exists, get_flat_output, get_parent_process_name, location_in_path, normpath try: import winreg except ImportError: try: import _winreg as winreg except ImportError: winreg = None class WindowsInterface: def __init__(self, **kwargs): pass @staticmethod def _get_new_path(): with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_READ) as key: return winreg.QueryValueEx(key, 'PATH')[0] def location_in_new_path(self, location, check=False): locations = normpath(location).split(os.pathsep) new_path = self._get_new_path() for location in locations: if not location_in_path(location, new_path): if check: raise Exception('Unable to find `{}` in:\n{}'.format(location, new_path)) else: return False else: return True def put(self, location, front=True, check=False, **kwargs): import ctypes location = normpath(location) head, tail = (location, self._get_new_path()) if front else (self._get_new_path(), location) new_path = '{}{}{}'.format(head, os.pathsep, tail) with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_WRITE) as key: winreg.SetValueEx(key, 'PATH', 0, winreg.REG_EXPAND_SZ, new_path) # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessagetimeoutw # https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-settingchange ctypes.windll.user32.SendMessageTimeoutW( 0xFFFF, # HWND_BROADCAST 0x1A, # WM_SETTINGCHANGE 0, # must be NULL 'Environment', 0x0002, # SMTO_ABORTIFHUNG 5000, # milliseconds ctypes.wintypes.DWORD(), ) return self.location_in_new_path(location, check=check) class UnixInterface: def __init__(self, shells=None, all_shells=False, home=None): if shells: all_shells = False else: if all_shells: shells = sorted(SHELLS) else: shells = [self.detect_shell()] shells = [os.path.basename(shell).lower() for shell in shells if shell] shells = [shell for shell in shells if shell in SHELLS] if not shells: shells = DEFAULT_SHELLS # De-dup and retain order deduplicated_shells = set() selected_shells = [] for shell in shells: if shell not in deduplicated_shells: deduplicated_shells.add(shell) selected_shells.append(shell) self.shells = [SHELLS[shell](home) for shell in selected_shells] self.shells_to_verify = [SHELLS[shell](home) for shell in DEFAULT_SHELLS] if all_shells else self.shells @classmethod def detect_shell(cls): # First, try to see what spawned this process shell = get_parent_process_name().lower() if shell in SHELLS: return shell # Then, search for environment variables that are known to be set by certain shells # NOTE: This likely does not work when not directly in the shell if 'BASH_VERSION' in os.environ: return 'bash' # Finally, try global environment shell = os.path.basename(os.environ.get('SHELL', '')).lower() if shell in SHELLS: return shell def location_in_new_path(self, location, check=False): locations = normpath(location).split(os.pathsep) for shell in self.shells_to_verify: for show_path_command in shell.show_path_commands(): new_path = get_flat_output(show_path_command) for location in locations: if not location_in_path(location, new_path): if check: raise Exception( 'Unable to find `{}` in the output of `{}`:\n{}'.format( location, show_path_command, new_path ) ) else: return False else: return True def put(self, location, front=True, app_name=None, check=False): location = normpath(location) app_name = app_name or 'userpath' for shell in self.shells: for file, contents in shell.config(location, front=front).items(): try: ensure_parent_dir_exists(file) if os.path.exists(file): with open(file, 'r', encoding='utf-8') as f: lines = f.readlines() else: lines = [] if any(contents in line for line in lines): continue lines.append( u'\n{} Created by `{}` on {}\n'.format( shell.comment_starter, app_name, datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') ) ) lines.append(u'{}\n'.format(contents)) with open(file, 'w', encoding='utf-8') as f: f.writelines(lines) except Exception: continue return self.location_in_new_path(location, check=check) __default_interface = WindowsInterface if os.name == 'nt' or platform.system() == 'Windows' else UnixInterface class Interface(__default_interface): pass