import os import re import subprocess # dir: string -> directory where installer exist # args: string -> which includes all parameters with space delimiter def spm_install(dir, args): os.chdir(dir) argslist = args.split() try: subprocess.check_call(argslist) print 'retcode' + str(0) + 'retcode' except subprocess.CalledProcessError as e: print 'retcode' + str(e.returncode) + 'retcode' # dir: string -> directory where installer exist # args: string -> which includes all parameters with space delimiter def spm_uninstall(dir, args): os.chdir(dir) argslist = args.split() try: subprocess.check_call(argslist) print 'retcode' + str(0) + 'retcode' except subprocess.CalledProcessError as e: print 'retcode' + str(e.returncode) + 'retcode' def _get_installed_apps(): """Return a de-duplicated list of dicts: name, key, quiet, uninstall.""" import _winreg uninstallkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall' if 'PROGRAMFILES(X86)' in os.environ: reg_list = [ (_winreg.HKEY_LOCAL_MACHINE, _winreg.KEY_WOW64_32KEY | _winreg.KEY_READ), (_winreg.HKEY_LOCAL_MACHINE, _winreg.KEY_WOW64_64KEY | _winreg.KEY_READ), (_winreg.HKEY_CURRENT_USER, _winreg.KEY_WOW64_32KEY | _winreg.KEY_READ), (_winreg.HKEY_CURRENT_USER, _winreg.KEY_WOW64_64KEY | _winreg.KEY_READ)] else: reg_list = [ (_winreg.HKEY_LOCAL_MACHINE, _winreg.KEY_READ), (_winreg.HKEY_CURRENT_USER, _winreg.KEY_READ)] apps = [] seen = set() for hive, access in reg_list: try: root = _winreg.OpenKey(hive, uninstallkey, 0, access) except WindowsError: continue idx = 0 while True: try: key_name = _winreg.EnumKey(root, idx) except WindowsError: break # real end of enumeration idx += 1 try: sub = _winreg.OpenKey(hive, uninstallkey + '\\' + key_name, 0, access) except WindowsError: continue # skip this key only, keep scanning try: try: name = _winreg.QueryValueEx(sub, 'DisplayName')[0].strip() except WindowsError: continue try: quiet = _winreg.QueryValueEx(sub, 'QuietUninstallString')[0] except WindowsError: quiet = None try: unin = _winreg.QueryValueEx(sub, 'UninstallString')[0] except WindowsError: unin = None finally: _winreg.CloseKey(sub) sig = (name, key_name) if sig in seen: continue seen.add(sig) apps.append({'name': name, 'key': key_name, 'quiet': quiet, 'uninstall': unin}) _winreg.CloseKey(root) return apps # dir: string -> directory where installer exist # args: string -> which includes all parameters with space delimiter def spm_update(dir, args): # Older versions to remove. Patterns are matched against DisplayName. # Matches "Blender", "Blender 3.6", "Blender 4.2.1" but NOT "Blender Launcher". patterns = [re.compile(r'^Blender(\s+[\d.]+)?$', re.I)] guid_re = re.compile(r'^\{[0-9A-Fa-f\-]{36}\}$') success_codes = (0, 1641, 3010) # 1641/3010 = success, reboot required for app in _get_installed_apps(): if not any(p.match(app['name']) for p in patterns): continue if guid_re.match(app['key']): command = ['MsiExec.exe', '/X' + app['key'], '/qn', '/norestart'] elif app['quiet']: command = app['quiet'] # string, passed as-is to CreateProcess else: print app['name'] + ' : no silent uninstall command found, skipped' continue try: subprocess.check_call(command) print app['name'] + ' : older version removed' except subprocess.CalledProcessError as e: if e.returncode in success_codes: print app['name'] + ' : older version removed (code ' + str(e.returncode) + ')' elif e.returncode == 1605: print app['name'] + ' : older version not installed (1605)' else: print app['name'] + ' : uninstall failed, returncode: ' + str(e.returncode) except OSError as e: print app['name'] + ' : uninstall could not start: ' + str(e) os.chdir(dir) argslist = args.split() try: subprocess.check_call(argslist) print 'retcode' + str(0) + 'retcode' except subprocess.CalledProcessError as e: print 'retcode' + str(e.returncode) + 'retcode'