|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
import re |
|
import sys |
|
import traceback |
|
from os import environ |
|
from os.path import basename, exists, isfile, join |
|
from subprocess import STDOUT, CalledProcessError, check_output |
|
|
|
try: |
|
import winreg |
|
except ImportError: |
|
import _winreg as winreg |
|
|
|
ROOT_PREFIX = sys.prefix |
|
|
|
|
|
|
|
|
|
old_excepthook = sys.excepthook |
|
|
|
|
|
|
|
|
|
def ensure_comspec_set(): |
|
if basename(environ.get("COMSPEC", "")).lower() != "cmd.exe": |
|
cmd_exe = join(environ.get('SystemRoot'), 'System32', 'cmd.exe') |
|
if not isfile(cmd_exe): |
|
cmd_exe = join(environ.get('windir'), 'System32', 'cmd.exe') |
|
if not isfile(cmd_exe): |
|
print("cmd.exe could not be found. " |
|
"Looked in SystemRoot and windir env vars.\n") |
|
else: |
|
environ['COMSPEC'] = cmd_exe |
|
|
|
|
|
def gui_excepthook(exctype, value, tb): |
|
try: |
|
import ctypes |
|
import traceback |
|
MB_ICONERROR = 0x00000010 |
|
title = u'Installation Error' |
|
msg = u''.join(traceback.format_exception(exctype, value, tb)) |
|
ctypes.windll.user32.MessageBoxW(0, msg, title, MB_ICONERROR) |
|
finally: |
|
|
|
|
|
old_excepthook(exctype, value, tb) |
|
|
|
|
|
sys.excepthook = gui_excepthook |
|
|
|
|
|
if sys.stdout and sys.stdout.write: |
|
out = sys.stdout.write |
|
err = sys.stderr.write |
|
else: |
|
import ctypes |
|
OutputDebugString = ctypes.windll.kernel32.OutputDebugStringW |
|
OutputDebugString.argtypes = [ctypes.c_wchar_p] |
|
|
|
def out(x): |
|
OutputDebugString('_nsis.py: ' + x) |
|
|
|
def err(x): |
|
OutputDebugString('_nsis.py: Error: ' + x) |
|
|
|
|
|
class NSISReg: |
|
def __init__(self, reg_path): |
|
self.reg_path = reg_path |
|
if exists(join(ROOT_PREFIX, '.nonadmin')): |
|
self.main_key = winreg.HKEY_CURRENT_USER |
|
else: |
|
self.main_key = winreg.HKEY_LOCAL_MACHINE |
|
|
|
def set(self, name, value): |
|
try: |
|
winreg.CreateKey(self.main_key, self.reg_path) |
|
registry_key = winreg.OpenKey(self.main_key, self.reg_path, 0, |
|
winreg.KEY_WRITE) |
|
winreg.SetValueEx(registry_key, name, 0, winreg.REG_SZ, value) |
|
winreg.CloseKey(registry_key) |
|
return True |
|
except WindowsError: |
|
return False |
|
|
|
def get(self, name): |
|
try: |
|
registry_key = winreg.OpenKey(self.main_key, self.reg_path, 0, |
|
winreg.KEY_READ) |
|
value, regtype = winreg.QueryValueEx(registry_key, name) |
|
winreg.CloseKey(registry_key) |
|
return value |
|
except WindowsError: |
|
return None |
|
|
|
|
|
def mk_menus(remove=False, prefix=None, pkg_names=None, root_prefix=None): |
|
try: |
|
import menuinst |
|
except (ImportError, OSError): |
|
return |
|
if prefix is None: |
|
prefix = sys.prefix |
|
if root_prefix is None: |
|
root_prefix = sys.prefix |
|
menu_dir = join(prefix, 'Menu') |
|
if not os.path.isdir(menu_dir): |
|
return |
|
for fn in os.listdir(menu_dir): |
|
if not fn.endswith('.json'): |
|
continue |
|
if pkg_names is not None and len(pkg_names) > 0 and fn[:-5] not in pkg_names: |
|
|
|
|
|
|
|
continue |
|
shortcut = join(menu_dir, fn) |
|
try: |
|
menuinst.install(shortcut, remove, prefix=prefix, |
|
root_prefix=root_prefix) |
|
except Exception as e: |
|
out("Failed to process %s...\n" % shortcut) |
|
err("Error: %s\n" % str(e)) |
|
err("Traceback:\n%s\n" % traceback.format_exc(20)) |
|
else: |
|
out("Processed %s successfully.\n" % shortcut) |
|
|
|
|
|
def mk_dirs(): |
|
envs_dir = join(ROOT_PREFIX, 'envs') |
|
if not exists(envs_dir): |
|
os.mkdir(envs_dir) |
|
|
|
|
|
def get_conda_envs_from_python_api(): |
|
try: |
|
from conda.cli.python_api import Commands, run_command |
|
except (ImportError, OSError): |
|
return |
|
from json import loads |
|
c_stdout, c_stderr, return_code = run_command(Commands.INFO, "--json") |
|
json_conda_info = loads(c_stdout) |
|
return json_conda_info["envs"] |
|
|
|
|
|
get_conda_envs = get_conda_envs_from_python_api |
|
|
|
|
|
def rm_menus(prefix=None, root_prefix=None): |
|
try: |
|
import menuinst |
|
from conda.base.context import context |
|
except (ImportError, OSError): |
|
return |
|
try: |
|
envs = get_conda_envs() |
|
envs = list(envs) |
|
except Exception as e: |
|
out("Failed to get conda environments list\n") |
|
err("Error: %s\n" % str(e)) |
|
err("Traceback:\n%s\n" % traceback.format_exc(20)) |
|
if prefix is not None: |
|
out("Will only remove shortcuts created from '%s'" % prefix) |
|
mk_menus(remove=True, prefix=prefix, root_prefix=root_prefix) |
|
else: |
|
envs_dirs = list(context.envs_dirs) |
|
if prefix is not None: |
|
envs_dirs.append(prefix) |
|
for env in envs: |
|
env = str(env) |
|
for envs_dir in envs_dirs: |
|
|
|
|
|
|
|
if envs_dir in env: |
|
mk_menus(remove=True, prefix=env, root_prefix=root_prefix) |
|
|
|
|
|
def run_post_install(): |
|
""" |
|
call the post install script, if the file exists |
|
""" |
|
path = join(ROOT_PREFIX, 'pkgs', 'post_install.bat') |
|
if not isfile(path): |
|
return |
|
env = os.environ.copy() |
|
env.setdefault('PREFIX', str(ROOT_PREFIX)) |
|
cmd_exe = os.path.join(os.environ['SystemRoot'], 'System32', 'cmd.exe') |
|
if not os.path.isfile(cmd_exe): |
|
cmd_exe = os.path.join(os.environ['windir'], 'System32', 'cmd.exe') |
|
if not os.path.isfile(cmd_exe): |
|
err("Error: running %s failed. cmd.exe could not be found. " |
|
"Looked in SystemRoot and windir env vars.\n" % path) |
|
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"): |
|
sys.exit(1) |
|
args = [cmd_exe, '/d', '/c', path] |
|
import subprocess |
|
try: |
|
subprocess.check_call(args, env=env) |
|
except subprocess.CalledProcessError: |
|
err("Error: running %s failed\n" % path) |
|
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"): |
|
sys.exit(1) |
|
|
|
|
|
def run_pre_uninstall(): |
|
""" |
|
call the pre uninstall script, if the file exists |
|
""" |
|
path = join(ROOT_PREFIX, 'pre_uninstall.bat') |
|
if not isfile(path): |
|
return |
|
env = os.environ.copy() |
|
env.setdefault('PREFIX', str(ROOT_PREFIX)) |
|
cmd_exe = os.path.join(os.environ['SystemRoot'], 'System32', 'cmd.exe') |
|
if not os.path.isfile(cmd_exe): |
|
cmd_exe = os.path.join(os.environ['windir'], 'System32', 'cmd.exe') |
|
if not os.path.isfile(cmd_exe): |
|
err("Error: running %s failed. cmd.exe could not be found. " |
|
"Looked in SystemRoot and windir env vars.\n" % path) |
|
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"): |
|
sys.exit(1) |
|
args = [cmd_exe, '/d', '/c', path] |
|
import subprocess |
|
try: |
|
subprocess.check_call(args, env=env) |
|
except subprocess.CalledProcessError: |
|
err("Error: running %s failed\n" % path) |
|
if os.environ.get("NSIS_SCRIPTS_RAISE_ERRORS"): |
|
sys.exit(1) |
|
|
|
|
|
allusers = (not exists(join(ROOT_PREFIX, '.nonadmin'))) |
|
|
|
|
|
|
|
PATH_SUFFIXES = ('', |
|
os.path.join('Library', 'mingw-w64', 'bin'), |
|
os.path.join('Library', 'usr', 'bin'), |
|
os.path.join('Library', 'bin'), |
|
'Scripts') |
|
|
|
|
|
def remove_from_path(root_prefix=None): |
|
from _system_path import broadcast_environment_settings_change, remove_from_system_path |
|
|
|
if root_prefix is None: |
|
root_prefix = ROOT_PREFIX |
|
for path in [os.path.normpath(os.path.join(root_prefix, path_suffix)) |
|
for path_suffix in PATH_SUFFIXES]: |
|
remove_from_system_path(path, allusers) |
|
broadcast_environment_settings_change() |
|
|
|
|
|
def add_to_path(pyversion, arch): |
|
from _system_path import ( |
|
add_to_system_path, |
|
broadcast_environment_settings_change, |
|
get_previous_install_prefixes, |
|
) |
|
|
|
|
|
|
|
remove_from_path(ROOT_PREFIX) |
|
|
|
|
|
try: |
|
old_prefixes = get_previous_install_prefixes(pyversion, arch, allusers) |
|
except IOError: |
|
old_prefixes = [] |
|
for prefix in old_prefixes: |
|
out('Removing old installation at %s from PATH (if any entries get found)\n' % (prefix)) |
|
remove_from_path(prefix) |
|
|
|
|
|
add_to_system_path([os.path.normpath(os.path.join(ROOT_PREFIX, path_suffix)) |
|
for path_suffix in PATH_SUFFIXES], allusers) |
|
broadcast_environment_settings_change() |
|
|
|
|
|
def rm_regkeys(): |
|
cmdproc_reg_entry = NSISReg(r'Software\Microsoft\Command Processor') |
|
cmdproc_autorun_val = cmdproc_reg_entry.get('AutoRun') |
|
conda_hook_regex_pat = r'((\s+&\s+)?(if +exist)?(\s*?\"[^\"]*?conda[-_]hook\.bat\"))' |
|
if join(ROOT_PREFIX, 'condabin') in (cmdproc_autorun_val or ''): |
|
cmdproc_autorun_newval = re.sub(conda_hook_regex_pat, '', |
|
cmdproc_autorun_val) |
|
try: |
|
cmdproc_reg_entry.set('AutoRun', cmdproc_autorun_newval) |
|
except Exception: |
|
|
|
pass |
|
|
|
|
|
def win_del(dirname): |
|
|
|
ensure_comspec_set() |
|
out = "unknown error (exception not caught)" |
|
|
|
try: |
|
out = check_output('DEL /F/Q/S *.* > NUL', shell=True, stderr=STDOUT, cwd=dirname) |
|
except CalledProcessError as e: |
|
|
|
if e.returncode != 5: |
|
print("Removing folder {} the fast way failed. " |
|
"Output was: {}".format(dirname, out)) |
|
raise |
|
else: |
|
print("removing dir contents the fast way failed. " |
|
"Output was: {}".format(out)) |
|
else: |
|
print("Unexpected error removing dirname {}. " |
|
"Uninstall was probably not successful".format(dirname)) |
|
|
|
try: |
|
out = check_output('RD /S /Q "{}" > NUL'.format(dirname), shell=True, stderr=STDOUT) |
|
except CalledProcessError as e: |
|
|
|
if e.returncode != 5: |
|
print("Removing folder {} the fast way failed. " |
|
"Output was: {}".format(dirname, out)) |
|
raise |
|
else: |
|
print("Removing directory folders the fast way failed. " |
|
"Output was: {}".format(out)) |
|
else: |
|
print("Unexpected error removing dirname {}. " |
|
"Uninstall was probably not successful".format(dirname)) |
|
|
|
|
|
def main(): |
|
cmd = sys.argv[1].strip() |
|
if cmd == 'mkmenus': |
|
pkg_names = [s.strip() for s in sys.argv[2:]] |
|
mk_menus(remove=False, pkg_names=pkg_names) |
|
elif cmd == 'post_install': |
|
run_post_install() |
|
elif cmd == 'rmmenus': |
|
rm_menus() |
|
elif cmd == 'rmreg': |
|
rm_regkeys() |
|
elif cmd == 'mkdirs': |
|
mk_dirs() |
|
elif cmd == 'addpath': |
|
|
|
|
|
if len(sys.argv) > 2: |
|
pyver = sys.argv[2] |
|
else: |
|
pyver = '%s.%s.%s' % (sys.version_info.major, |
|
sys.version_info.minor, |
|
sys.version_info.micro) |
|
if len(sys.argv) > 3: |
|
arch = sys.argv[2] |
|
else: |
|
arch = '32-bit' if tuple.__itemsize__ == 4 else '64-bit' |
|
add_to_path(pyver, arch) |
|
elif cmd == 'rmpath': |
|
remove_from_path() |
|
elif cmd == 'pre_uninstall': |
|
run_pre_uninstall() |
|
elif cmd == 'del': |
|
assert len(sys.argv) == 3 |
|
win_del(sys.argv[2].strip()) |
|
else: |
|
sys.exit("ERROR: did not expect %r" % cmd) |
|
|
|
|
|
if __name__ == '__main__': |
|
main() |
|
|