diff --git a/scripts/spyder_win_post_install.py b/scripts/spyder_win_post_install.py index 2cba9276ec7..68629bf9275 100644 --- a/scripts/spyder_win_post_install.py +++ b/scripts/spyder_win_post_install.py @@ -21,17 +21,103 @@ KEY_C1 = KEY_C0 + r"\command" +# ability to run spyder-win-post-install outside of bdist_wininst installer +# copied from pywin32-win-post-install.py +# http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/file/default/pywin32_postinstall.py +ver_string = "%d.%d" % (sys.version_info[0], sys.version_info[1]) +root_key_name = "Software\\Python\\PythonCore\\" + ver_string + +try: + # When this script is run from inside the bdist_wininst installer, + # file_created() and directory_created() are additional builtin + # functions which write lines to Python23\pywin32-install.log. This is + # a list of actions for the uninstaller, the format is inspired by what + # the Wise installer also creates. + # https://docs.python.org/2/distutils/builtdist.html#the-postinstallation-script + file_created + is_bdist_wininst = True +except NameError: + is_bdist_wininst = False # we know what it is not - but not what it is :) + # file_created() and directory_created() functions do nothing if post install script + # isn't run from bdist_wininst installer, instead if shortcuts and start menu directory + # exist, they are removed when the post install script is called with the -remote option + def file_created(file): + pass + def directory_created(directory): + pass + def get_root_hkey(): + try: + winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, + root_key_name, 0, winreg.KEY_CREATE_SUB_KEY) + return winreg.HKEY_LOCAL_MACHINE + except OSError, details: + # Either not exist, or no permissions to create subkey means + # must be HKCU + return winreg.HKEY_CURRENT_USER +try: + create_shortcut +except NameError: + # Create a function with the same signature as create_shortcut provided + # by bdist_wininst + def create_shortcut(path, description, filename, + arguments="", workdir="", iconpath="", iconindex=0): + try: + import pythoncom + except ImportError: + print("PyWin32 is required to run windows postinstall manually.", + file=sys.stderr) + sys.exit(1) # pywin32 required + from win32com.shell import shell, shellcon + + ilink = pythoncom.CoCreateInstance(shell.CLSID_ShellLink, None, + pythoncom.CLSCTX_INPROC_SERVER, + shell.IID_IShellLink) + ilink.SetPath(path) + ilink.SetDescription(description) + if arguments: + ilink.SetArguments(arguments) + if workdir: + ilink.SetWorkingDirectory(workdir) + if iconpath or iconindex: + ilink.SetIconLocation(iconpath, iconindex) + # now save it. + ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile) + ipf.Save(filename, 0) + + # Support the same list of "path names" as bdist_wininst. + def get_special_folder_path(path_name): + import pythoncom + from win32com.shell import shell, shellcon + + for maybe in """ + CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA + CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY + CSIDL_DESKTOPDIRECTORY CSIDL_COMMON_STARTUP CSIDL_STARTUP + CSIDL_COMMON_PROGRAMS CSIDL_PROGRAMS CSIDL_PROGRAM_FILES_COMMON + CSIDL_PROGRAM_FILES CSIDL_FONTS""".split(): + if maybe == path_name: + csidl = getattr(shellcon, maybe) + return shell.SHGetSpecialFolderPath(0, csidl, False) + raise ValueError("%s is an unknown path ID" % (path_name,)) + + def install(): """Function executed when running the script with the -install switch""" # Create Spyder start menu folder - start_menu = osp.join(get_special_folder_path('CSIDL_COMMON_PROGRAMS'), + # Don't use CSIDL_COMMON_PROGRAMS because it requres admin rights + # This is consistent with use of CSIDL_DESKTOPDIRECTORY below + # CSIDL_COMMON_PROGRAMS = + # C:\ProgramData\Microsoft\Windows\Start Menu\Programs + # CSIDL_PROGRAMS = + # C:\Users\\AppData\Roaming\Microsoft\Windows\Start Menu\Programs + start_menu = osp.join(get_special_folder_path('CSIDL_PROGRAMS'), 'Spyder (Py%i.%i %i bit)' % (sys.version_info[0], sys.version_info[1], struct.calcsize('P')*8)) if not osp.isdir(start_menu): os.mkdir(start_menu) directory_created(start_menu) - + # Create Spyder start menu entries python = osp.abspath(osp.join(sys.prefix, 'python.exe')) pythonw = osp.abspath(osp.join(sys.prefix, 'pythonw.exe')) @@ -40,6 +126,9 @@ def install(): import distutils.sysconfig lib_dir = distutils.sysconfig.get_python_lib(plat_specific=1) ico_dir = osp.join(lib_dir, 'spyderlib', 'windows') + # if user is running -install manually then icons are in Scripts/ + if not osp.isdir(ico_dir): + ico_dir = osp.dirname(osp.abspath(__file__)) desc = 'Scientific Python Development EnvironmEnt, an alternative to IDLE' fname = osp.join(start_menu, 'Spyder (full).lnk') @@ -67,7 +156,7 @@ def install(): winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("NoCon", EWS)), "", 0, winreg.REG_SZ, '"%s" "%s\Scripts\spyder" "%%1"' % (pythonw, sys.prefix)) - + # Create desktop shortcut file desktop_folder = get_special_folder_path("CSIDL_DESKTOPDIRECTORY") fname = osp.join(desktop_folder, 'Spyder.lnk') @@ -87,6 +176,46 @@ def remove(): winreg.DeleteKey(root, key) except WindowsError: pass + else: + if not is_bdist_wininst: + print("Successfully removed Spyder shortcuts from Windows "\ + "Explorer context menu.", file=sys.stdout) + if not is_bdist_wininst: + # clean up desktop + desktop_folder = get_special_folder_path("CSIDL_DESKTOPDIRECTORY") + fname = osp.join(desktop_folder, 'Spyder.lnk') + if osp.isfile(fname): + try: + os.remove(fname) + except OSError: + print("Failed to remove %s; you may be able to remove it "\ + "manually." % fname, file=sys.stderr) + else: + print("Successfully removed Spyder shortcuts from your desktop.", + file=sys.stdout) + # clean up startmenu + start_menu = osp.join(get_special_folder_path('CSIDL_PROGRAMS'), + 'Spyder (Py%i.%i %i bit)' % (sys.version_info[0], + sys.version_info[1], + struct.calcsize('P')*8)) + if osp.isdir(start_menu): + for fname in os.listdir(start_menu): + try: + os.remove(osp.join(start_menu,fname)) + except OSError: + print("Failed to remove %s; you may be able to remove it "\ + "manually." % fname, file=sys.stderr) + else: + print("Successfully removed Spyder shortcuts from your "\ + " start menu.", file=sys.stdout) + try: + os.rmdir(start_menu) + except OSError: + print("Failed to remove %s; you may be able to remove it "\ + "manually." % fname, file=sys.stderr) + else: + print("Successfully removed Spyder shortcut folder from your "\ + " start menu.", file=sys.stdout) if __name__=='__main__': @@ -95,8 +224,7 @@ def remove(): try: install() except OSError: - print("Failed to create Start Menu items, try running "\ - "installer as administrator.", file=sys.stderr) + print("Failed to create Start Menu items.", file=sys.stderr) elif sys.argv[1] == '-remove': remove() else: