[pywin32-checkins] pywin32 setup.py, 1.61, 1.62 pywin32_postinstall.py, 1.19, 1.20
OLD project page for the Python extensions for Windows
Brought to you by:
mhammond
From: Mark H. <mha...@us...> - 2007-07-18 08:50:25
|
Update of /cvsroot/pywin32/pywin32 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26676 Modified Files: setup.py pywin32_postinstall.py Log Message: get things working with a (slightly patched) bdist_msi Index: pywin32_postinstall.py =================================================================== RCS file: /cvsroot/pywin32/pywin32/pywin32_postinstall.py,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** pywin32_postinstall.py 1 Jul 2007 20:05:21 -0000 1.19 --- pywin32_postinstall.py 18 Jul 2007 08:50:25 -0000 1.20 *************** *** 6,9 **** --- 6,22 ---- import _winreg + # Send output somewhere so it can be found if necessary... + import tempfile + tee_f = open(os.path.join(tempfile.gettempdir(), 'pywin32_postinstall.log'), "w") + class Tee: + def __init__(self, file): + self.f = file + def write(self, what): + self.f.write(what) + tee_f.write(what) + + sys.stderr = Tee(sys.stderr) + sys.stdout = Tee(sys.stdout) + com_modules = [ # module_name, class_names *************** *** 30,34 **** --- 43,49 ---- # the Wise installer also creates. file_created + is_bdist_wininst = True except NameError: + is_bdist_wininst = False # we know what it is not - but not what it is :) def file_created(file): pass *************** *** 45,48 **** --- 60,104 ---- 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): + import pythoncom + 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 CopyTo(desc, src, dest): import win32api, win32con *************** *** 126,131 **** func(klass, **flags) ! def RegisterPythonwin(): ! """ Add Pythonwin to context menu for python scripts. ??? Should probably also add Edit command for pys files also. Also need to remove these keys on uninstall, but there's no function --- 182,187 ---- func(klass, **flags) ! def RegisterPythonwin(register=True): ! """ Add (or remove) Pythonwin to context menu for python scripts. ??? Should probably also add Edit command for pys files also. Also need to remove these keys on uninstall, but there's no function *************** *** 140,154 **** pythonwin_edit_command=pythonwin_exe + ' /edit "%1"' ! ## Since _winreg only uses the character Api functions, this can fail if Python ! ## is installed to a path containing non-ascii characters ! pw_key = _winreg.CreateKey(classes_root, 'Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Pythonwin.exe') ! _winreg.SetValueEx(pw_key, None, 0, _winreg.REG_SZ, pythonwin_exe) ! pw_key.Close() ! pw_key = _winreg.CreateKey(classes_root, 'Software\\Classes\\Python.File\\shell\\Edit with Pythonwin\\command') ! _winreg.SetValueEx(pw_key, None, 0, _winreg.REG_SZ, pythonwin_edit_command) ! pw_key.Close() ! pw_key = _winreg.CreateKey(classes_root, 'Software\\Classes\\Python.NoConFile\\shell\\Edit with Pythonwin\\command') ! _winreg.SetValueEx(pw_key, None, 0, _winreg.REG_SZ, pythonwin_edit_command) ! pw_key.Close() def install(): --- 196,245 ---- pythonwin_edit_command=pythonwin_exe + ' /edit "%1"' ! keys_vals = [ ! ('Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Pythonwin.exe', '', pythonwin_exe), ! ('Software\\Classes\\Python.File\\shell\\Edit with Pythonwin', 'command', pythonwin_edit_command), ! ('Software\\Classes\\Python.NoConFile\\shell\\Edit with Pythonwin', 'command', pythonwin_edit_command), ! ] ! ! try: ! if register: ! for key, sub_key, val in keys_vals: ! ## Since _winreg only uses the character Api functions, this can fail if Python ! ## is installed to a path containing non-ascii characters ! hkey = _winreg.CreateKey(classes_root, key) ! if sub_key: ! hkey = _winreg.CreateKey(hkey, sub_key) ! _winreg.SetValueEx(hkey, None, 0, _winreg.REG_SZ, val) ! hkey.Close() ! else: ! for key, sub_key, val in keys_vals: ! try: ! _winreg.DeleteKey(classes_root, key) ! except OSError, why: ! if why.errno != 2: # file not found ! raise ! finally: ! # tell windows about the change ! from win32com.shell import shell, shellcon ! shell.SHChangeNotify(shellcon.SHCNE_ASSOCCHANGED, shellcon.SHCNF_IDLIST, None, None) ! ! def get_shortcuts_folder(): ! if get_root_hkey()==_winreg.HKEY_LOCAL_MACHINE: ! try: ! fldr = get_special_folder_path("CSIDL_COMMON_PROGRAMS") ! except OSError: ! # No CSIDL_COMMON_PROGRAMS on this platform ! fldr = get_special_folder_path("CSIDL_PROGRAMS") ! else: ! # non-admin install - always goes in this user's start menu. ! fldr = get_special_folder_path("CSIDL_PROGRAMS") ! ! try: ! install_group = _winreg.QueryValue(get_root_hkey(), ! root_key_name + "\\InstallPath\\InstallGroup") ! except OSError: ! vi = sys.version_info ! install_group = "Python %d.%d" % (vi[0], vi[1]) ! return os.path.join(fldr, install_group) def install(): *************** *** 268,272 **** traceback.print_exc() else: ! print 'Pythonwin has been registered in context menu' # Create the win32com\gen_py directory. --- 359,364 ---- traceback.print_exc() else: ! if verbose: ! print 'Pythonwin has been registered in context menu' # Create the win32com\gen_py directory. *************** *** 279,311 **** try: ! create_shortcut ! except NameError: ! # todo: create shortcut with win32all ! pass ! else: ! try: ! # use bdist_wininst builtins to create a shortcut. ! # CSIDL_COMMON_PROGRAMS only available works on NT/2000/XP, and ! # will fail there if the user has no admin rights. ! if get_root_hkey()==_winreg.HKEY_LOCAL_MACHINE: ! try: ! fldr = get_special_folder_path("CSIDL_COMMON_PROGRAMS") ! except OSError: ! # No CSIDL_COMMON_PROGRAMS on this platform ! fldr = get_special_folder_path("CSIDL_PROGRAMS") ! else: ! # non-admin install - always goes in this user's start menu. ! fldr = get_special_folder_path("CSIDL_PROGRAMS") ! ! try: ! install_group = _winreg.QueryValue(get_root_hkey(), ! root_key_name + "\\InstallPath\\InstallGroup") ! except OSError: ! vi = sys.version_info ! install_group = "Python %d.%d" % (vi[0], vi[1]) ! fldr = os.path.join(fldr, install_group) ! if not os.path.isdir(fldr): ! os.mkdir(fldr) ! dst = os.path.join(fldr, "PythonWin.lnk") create_shortcut(os.path.join(lib_dir, "Pythonwin\\Pythonwin.exe"), --- 371,381 ---- try: ! # create shortcuts ! # CSIDL_COMMON_PROGRAMS only available works on NT/2000/XP, and ! # will fail there if the user has no admin rights. ! fldr = get_shortcuts_folder() ! # If the group doesn't exist, then we don't make shortcuts - its ! # possible that this isn't a "normal" install. ! if os.path.isdir(fldr): dst = os.path.join(fldr, "PythonWin.lnk") create_shortcut(os.path.join(lib_dir, "Pythonwin\\Pythonwin.exe"), *************** *** 321,327 **** if verbose: print "Shortcut to documentation created" ! except Exception, details: ! if verbose: ! print details # Check the MFC dll exists - it is doesn't, point them at it --- 391,396 ---- if verbose: print "Shortcut to documentation created" ! except Exception, details: ! print details # Check the MFC dll exists - it is doesn't, point them at it *************** *** 353,356 **** --- 422,496 ---- print "The pywin32 extensions were successfully installed." + def uninstall(): + import distutils.sysconfig + lib_dir = distutils.sysconfig.get_python_lib(plat_specific=1) + # First ensure our system modules are loaded from pywin32_system, so + # we can remove the ones we copied... + LoadSystemModule(lib_dir, "pywintypes") + LoadSystemModule(lib_dir, "pythoncom") + + try: + RegisterCOMObjects(False) + except Exception, why: + print "Failed to unregister COM objects:", why + + try: + RegisterPythonwin(False) + except Exception, why: + print "Failed to unregister Pythonwin:", why + else: + if verbose: + print 'Unregistered Pythonwin' + + try: + # remove gen_py directory. + gen_dir = os.path.join(lib_dir, "win32com", "gen_py") + if os.path.isdir(gen_dir): + shutil.rmtree(gen_dir) + if verbose: + print "Removed directory", gen_dir + + # Remove pythonwin compiled "config" files. + pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin") + for fname in glob.glob(os.path.join(pywin_dir, "*.cfc")): + os.remove(fname) + except Exception, why: + print "Failed to remove misc files:", why + + try: + fldr = get_shortcuts_folder() + for link in ("PythonWin.lnk", "Python for Windows Documentation.lnk"): + fqlink = os.path.join(fldr, link) + if os.path.isfile(fqlink): + os.remove(fqlink) + if verbose: + print "Removed", link + except Exception, why: + print "Failed to remove shortcuts:", why + # Now remove the system32 files. + files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*")) + # Try the system32 directory first - if that fails due to "access denied", + # it implies a non-admin user, and we use sys.prefix + try: + import win32api + for dest_dir in [win32api.GetSystemDirectory(), sys.prefix]: + # and copy some files over there + worked = 0 + for fname in files: + base = os.path.basename(fname) + dst = os.path.join(dest_dir, base) + if os.path.isfile(dst): + try: + os.remove(dst) + worked = 1 + if verbose: + print "Removed file %s" % (dst) + except Exception: + print "FAILED to remove", dst + if worked: + break + except Exception, why: + print "FAILED to remove system files:", why + def usage(): msg = \ *************** *** 405,411 **** verbose = 0 elif arg == "-remove": ! # Nothing to do here - we can't unregister much, as we have ! # already been uninstalled. ! pass else: print "Unknown option:", arg --- 545,553 ---- verbose = 0 elif arg == "-remove": ! # bdist_msi calls us before uninstall, so we can undo what we ! # previously did. Sadly, bdist_wininst calls us *after*, so ! # we can't do much at all. ! if not is_bdist_wininst: ! uninstall() else: print "Unknown option:", arg Index: setup.py =================================================================== RCS file: /cvsroot/pywin32/pywin32/setup.py,v retrieving revision 1.61 retrieving revision 1.62 diff -C2 -d -r1.61 -r1.62 *** setup.py 13 Jul 2007 03:06:57 -0000 1.61 --- setup.py 18 Jul 2007 08:50:24 -0000 1.62 *************** *** 1,3 **** ! build_id="210.1" # may optionally include a ".{patchno}" suffix. # Putting buildno at the top prevents automatic __doc__ assignment, and # I *want* the build number at the top :) --- 1,3 ---- ! build_id="210.5" # may optionally include a ".{patchno}" suffix. # Putting buildno at the top prevents automatic __doc__ assignment, and # I *want* the build number at the top :) *************** *** 94,107 **** import _winreg ! from distutils.core import setup, Extension, Command ! from distutils.command.install_lib import install_lib ! from distutils.command.build_ext import build_ext ! from distutils.command.build import build ! from distutils.command.install_data import install_data ! from distutils.dep_util import newer_group, newer ! from distutils import dir_util, file_util ! from distutils.sysconfig import get_python_lib ! from distutils.filelist import FileList ! from distutils.errors import DistutilsExecError # when cross-compiling on a 32bit platform, the variable CPU reflects --- 94,103 ---- import _winreg ! # Python version compatibility hacks ! try: ! True; False ! except NameError: ! True=0==0 ! False=1==0 # when cross-compiling on a 32bit platform, the variable CPU reflects *************** *** 125,128 **** --- 121,159 ---- is_32bit = not is_64bit + # More x64 hacks - all 64bit windows builds have sys.platform=='win32', and + # this is used for the "platform" part of the file and directory names. + # (eg, pywin32-210.1.win32-py2.5.msi) - but this is bad for us - we do + # want a distinction. + # so we monkey-patch distutils :( We must do this before the main distutils + # imports, which generall does 'from distutils.util import get_platform' + def hacked_get_platform(): + """getplaform monkey-patched by pywin32 setup""" + if is_32bit: + return sys.platform + else: + return get_build_architecture().lower() + + import distutils.util + distutils.util.get_platform = hacked_get_platform + + # The rest of our imports. + from distutils.core import setup, Extension, Command + from distutils.command.install import install + from distutils.command.install_lib import install_lib + from distutils.command.build_ext import build_ext + from distutils.command.build import build + from distutils.command.install_data import install_data + try: + from distutils.command.bdist_msi import bdist_msi + except ImportError: + # py23 and earlier + bdist_msi = None + from distutils.dep_util import newer_group, newer + from distutils import dir_util, file_util + from distutils.sysconfig import get_python_lib + from distutils.filelist import FileList + from distutils.errors import DistutilsExecError + import distutils.util + build_id_patch = build_id if not "." in build_id_patch: *************** *** 132,141 **** print "Building pywin32", pywin32_version - # Python 2.2 has no True/False - try: - True; False - except NameError: - True=0==0 - False=1==0 # nor distutils.log try: --- 163,166 ---- *************** *** 1007,1010 **** --- 1032,1066 ---- return new_sources + class my_install(install): + def run(self): + install.run(self) + # Custom script we run at the end of installing - this is the same script + # run by bdist_wininst + # This child process won't be able to install the system DLLs until our + # process has terminated (as distutils imports win32api!), so we must use + # some 'no wait' executor - spawn seems fine! We pass the PID of this + # process so the child will wait for us. + # XXX - hmm - a closer look at distutils shows it only uses win32api + # if _winreg fails - and this never should. Need to revisit this! + if not self.dry_run and not self.skip_build: + # What executable to use? This one I guess. + filename = os.path.join(os.path.dirname(this_file), "pywin32_postinstall.py") + if not os.path.isfile(filename): + raise RuntimeError, "Can't find '%s'" % (filename,) + print "Executing post install script..." + os.spawnl(os.P_NOWAIT, sys.executable, + sys.executable, filename, + "-quiet", "-wait", str(os.getpid()), "-install") + + if bdist_msi: + class my_bdist_msi(bdist_msi): + def get_installer_filename(self, fullname): + # base class hard-codes 'win32' + plat = distutils.util.get_platform() + installer_name = os.path.join(self.dist_dir, + "%s.%s-py%s.msi" % + (fullname, plat, self.target_version)) + return installer_name + # As per get_source_files, we need special handling so .mc file is # processed first. It appears there was an intention to fix distutils *************** *** 1626,1629 **** --- 1682,1693 ---- dll_base_address += 0x30000 + cmdclass = { 'install': my_install, + 'build': my_build, + 'build_ext': my_build_ext, + 'install_data': my_install_data, + } + if bdist_msi: + cmdclass['bdist_msi'] = my_bdist_msi + dist = setup(name="pywin32", version=str(build_id), *************** *** 1637,1645 **** url="http://sourceforge.net/projects/pywin32/", license="PSA", ! cmdclass = { #'install_lib': my_install_lib, ! 'build': my_build, ! 'build_ext': my_build_ext, ! 'install_data': my_install_data, ! }, options = {"bdist_wininst": {"install_script": "pywin32_postinstall.py", --- 1701,1705 ---- url="http://sourceforge.net/projects/pywin32/", license="PSA", ! cmdclass = cmdclass, options = {"bdist_wininst": {"install_script": "pywin32_postinstall.py", *************** *** 1732,1753 **** else: print "All extension modules %s OK" % (what_string,) - - # Custom script we run at the end of installing - this is the same script - # run by bdist_wininst, but the standard 'install' command doesn't seem - # to have such a concept. - # This child process won't be able to install the system DLLs until our - # process has terminated (as distutils imports win32api!), so we must use - # some 'no wait' executor - spawn seems fine! We pass the PID of this - # process so the child will wait for us. - # XXX - hmm - a closer look at distutils shows it only uses win32api - # if _winreg fails - and this never should. Need to revisit this! - if not dist.dry_run and dist.command_obj.has_key('install') \ - and not dist.command_obj.has_key('bdist_wininst'): - # What executable to use? This one I guess. - filename = os.path.join(os.path.dirname(this_file), "pywin32_postinstall.py") - if not os.path.isfile(filename): - raise RuntimeError, "Can't find '%s'" % (filename,) - print "Executing post install script..." - os.spawnl(os.P_NOWAIT, sys.executable, - sys.executable, filename, - "-quiet", "-wait", str(os.getpid()), "-install") --- 1792,1793 ---- |