diff options
author | Ori Bernstein <ori@eigenstate.org> | 2021-06-14 00:00:37 +0000 |
---|---|---|
committer | Ori Bernstein <ori@eigenstate.org> | 2021-06-14 00:00:37 +0000 |
commit | a73a964e51247ed169d322c725a3a18859f109a3 (patch) | |
tree | 3f752d117274d444bda44e85609aeac1acf313f3 /sys/src/cmd/python/Tools/msi/msi.py | |
parent | e64efe273fcb921a61bf27d33b230c4e64fcd425 (diff) |
python, hg: tow outside the environment.
they've served us well, and can ride off into the sunset.
Diffstat (limited to 'sys/src/cmd/python/Tools/msi/msi.py')
-rw-r--r-- | sys/src/cmd/python/Tools/msi/msi.py | 1203 |
1 files changed, 0 insertions, 1203 deletions
diff --git a/sys/src/cmd/python/Tools/msi/msi.py b/sys/src/cmd/python/Tools/msi/msi.py deleted file mode 100644 index 0229fb7bc..000000000 --- a/sys/src/cmd/python/Tools/msi/msi.py +++ /dev/null @@ -1,1203 +0,0 @@ -# Python MSI Generator -# (C) 2003 Martin v. Loewis -# See "FOO" in comments refers to MSDN sections with the title FOO. -import msilib, schema, sequence, os, glob, time, re -from msilib import Feature, CAB, Directory, Dialog, Binary, add_data -import uisample -from win32com.client import constants -from distutils.spawn import find_executable -from uuids import product_codes - -# Settings can be overridden in config.py below -# 0 for official python.org releases -# 1 for intermediate releases by anybody, with -# a new product code for every package. -snapshot = 1 -# 1 means that file extension is px, not py, -# and binaries start with x -testpackage = 0 -# Location of build tree -srcdir = os.path.abspath("../..") -# Text to be displayed as the version in dialogs etc. -# goes into file name and ProductCode. Defaults to -# current_version.day for Snapshot, current_version otherwise -full_current_version = None -# Is Tcl available at all? -have_tcl = True -# Where is sqlite3.dll located, relative to srcdir? -sqlite_dir = "../sqlite-source-3.3.4" - -try: - from config import * -except ImportError: - pass - -# Extract current version from Include/patchlevel.h -lines = open(srcdir + "/Include/patchlevel.h").readlines() -major = minor = micro = level = serial = None -levels = { - 'PY_RELEASE_LEVEL_ALPHA':0xA, - 'PY_RELEASE_LEVEL_BETA': 0xB, - 'PY_RELEASE_LEVEL_GAMMA':0xC, - 'PY_RELEASE_LEVEL_FINAL':0xF - } -for l in lines: - if not l.startswith("#define"): - continue - l = l.split() - if len(l) != 3: - continue - _, name, value = l - if name == 'PY_MAJOR_VERSION': major = value - if name == 'PY_MINOR_VERSION': minor = value - if name == 'PY_MICRO_VERSION': micro = value - if name == 'PY_RELEASE_LEVEL': level = levels[value] - if name == 'PY_RELEASE_SERIAL': serial = value - -short_version = major+"."+minor -# See PC/make_versioninfo.c -FIELD3 = 1000*int(micro) + 10*level + int(serial) -current_version = "%s.%d" % (short_version, FIELD3) - -# This should never change. The UpgradeCode of this package can be -# used in the Upgrade table of future packages to make the future -# package replace this one. See "UpgradeCode Property". -upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}' -upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}' - -if snapshot: - current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24)) - product_code = msilib.gen_uuid() -else: - product_code = product_codes[current_version] - -if full_current_version is None: - full_current_version = current_version - -extensions = [ - 'bz2.pyd', - 'pyexpat.pyd', - 'select.pyd', - 'unicodedata.pyd', - 'winsound.pyd', - '_elementtree.pyd', - '_bsddb.pyd', - '_socket.pyd', - '_ssl.pyd', - '_testcapi.pyd', - '_tkinter.pyd', - '_msi.pyd', - '_ctypes.pyd', - '_ctypes_test.pyd', - '_sqlite3.pyd', - '_hashlib.pyd' -] - -# Well-known component UUIDs -# These are needed for SharedDLLs reference counter; if -# a different UUID was used for each incarnation of, say, -# python24.dll, an upgrade would set the reference counter -# from 1 to 2 (due to what I consider a bug in MSI) -# Using the same UUID is fine since these files are versioned, -# so Installer will always keep the newest version. -msvcr71_uuid = "{8666C8DD-D0B4-4B42-928E-A69E32FA5D4D}" -pythondll_uuid = { - "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}", - "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}" - } [major+minor] - -# Build the mingw import library, libpythonXY.a -# This requires 'nm' and 'dlltool' executables on your PATH -def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib): - warning = "WARNING: %s - libpythonXX.a not built" - nm = find_executable('nm') - dlltool = find_executable('dlltool') - - if not nm or not dlltool: - print warning % "nm and/or dlltool were not found" - return False - - nm_command = '%s -Cs %s' % (nm, lib_file) - dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \ - (dlltool, dll_file, def_file, mingw_lib) - export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match - - f = open(def_file,'w') - print >>f, "LIBRARY %s" % dll_file - print >>f, "EXPORTS" - - nm_pipe = os.popen(nm_command) - for line in nm_pipe.readlines(): - m = export_match(line) - if m: - print >>f, m.group(1) - f.close() - exit = nm_pipe.close() - - if exit: - print warning % "nm did not run successfully" - return False - - if os.system(dlltool_command) != 0: - print warning % "dlltool did not run successfully" - return False - - return True - -# Target files (.def and .a) go in PCBuild directory -lib_file = os.path.join(srcdir, "PCBuild", "python%s%s.lib" % (major, minor)) -def_file = os.path.join(srcdir, "PCBuild", "python%s%s.def" % (major, minor)) -dll_file = "python%s%s.dll" % (major, minor) -mingw_lib = os.path.join(srcdir, "PCBuild", "libpython%s%s.a" % (major, minor)) - -have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib) - -# Determine the target architechture -dll_path = os.path.join(srcdir, "PCBuild", dll_file) -msilib.set_arch_from_file(dll_path) -if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"): - raise SystemError, "msisupport.dll for incorrect architecture" - -if testpackage: - ext = 'px' - testprefix = 'x' -else: - ext = 'py' - testprefix = '' - -if msilib.Win64: - SystemFolderName = "[SystemFolder64]" -else: - SystemFolderName = "[SystemFolder]" - -msilib.reset() - -# condition in which to install pythonxy.dll in system32: -# a) it is Windows 9x or -# b) it is NT, the user is privileged, and has chosen per-machine installation -sys32cond = "(Windows9x or (Privileged and ALLUSERS))" - -def build_database(): - """Generate an empty database, with just the schema and the - Summary information stream.""" - if snapshot: - uc = upgrade_code_snapshot - else: - uc = upgrade_code - # schema represents the installer 2.0 database schema. - # sequence is the set of standard sequences - # (ui/execute, admin/advt/install) - db = msilib.init_database("python-%s%s.msi" % (full_current_version, msilib.arch_ext), - schema, ProductName="Python "+full_current_version, - ProductCode=product_code, - ProductVersion=current_version, - Manufacturer=u"Martin v. L\xf6wis") - # The default sequencing of the RemoveExistingProducts action causes - # removal of files that got just installed. Place it after - # InstallInitialize, so we first uninstall everything, but still roll - # back in case the installation is interrupted - msilib.change_sequence(sequence.InstallExecuteSequence, - "RemoveExistingProducts", 1510) - msilib.add_tables(db, sequence) - # We cannot set ALLUSERS in the property table, as this cannot be - # reset if the user choses a per-user installation. Instead, we - # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages - # this property, and when the execution starts, ALLUSERS is set - # accordingly. - add_data(db, "Property", [("UpgradeCode", uc), - ("WhichUsers", "ALL"), - ("ProductLine", "Python%s%s" % (major, minor)), - ]) - db.Commit() - return db - -def remove_old_versions(db): - "Fill the upgrade table." - start = "%s.%s.0" % (major, minor) - # This requests that feature selection states of an older - # installation should be forwarded into this one. Upgrading - # requires that both the old and the new installation are - # either both per-machine or per-user. - migrate_features = 1 - # See "Upgrade Table". We remove releases with the same major and - # minor version. For an snapshot, we remove all earlier snapshots. For - # a release, we remove all snapshots, and all earlier releases. - if snapshot: - add_data(db, "Upgrade", - [(upgrade_code_snapshot, start, - current_version, - None, # Ignore language - migrate_features, - None, # Migrate ALL features - "REMOVEOLDSNAPSHOT")]) - props = "REMOVEOLDSNAPSHOT" - else: - add_data(db, "Upgrade", - [(upgrade_code, start, current_version, - None, migrate_features, None, "REMOVEOLDVERSION"), - (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1), - None, migrate_features, None, "REMOVEOLDSNAPSHOT")]) - props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION" - # Installer collects the product codes of the earlier releases in - # these properties. In order to allow modification of the properties, - # they must be declared as secure. See "SecureCustomProperties Property" - add_data(db, "Property", [("SecureCustomProperties", props)]) - -class PyDialog(Dialog): - """Dialog class with a fixed layout: controls at the top, then a ruler, - then a list of buttons: back, next, cancel. Optionally a bitmap at the - left.""" - def __init__(self, *args, **kw): - """Dialog(database, name, x, y, w, h, attributes, title, first, - default, cancel, bitmap=true)""" - Dialog.__init__(self, *args) - ruler = self.h - 36 - bmwidth = 152*ruler/328 - if kw.get("bitmap", True): - self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") - self.line("BottomLine", 0, ruler, self.w, 0) - - def title(self, title): - "Set the title text of the dialog at the top." - # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, - # text, in VerdanaBold10 - self.text("Title", 135, 10, 220, 60, 0x30003, - r"{\VerdanaBold10}%s" % title) - - def back(self, title, next, name = "Back", active = 1): - """Add a back button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) - - def cancel(self, title, next, name = "Cancel", active = 1): - """Add a cancel button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) - - def next(self, title, next, name = "Next", active = 1): - """Add a Next button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) - - def xbutton(self, name, title, next, xpos): - """Add a button with a given title, the tab-next button, - its name in the Control table, giving its x position; the - y-position is aligned with the other buttons. - - Return the button, so that events can be associated""" - return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) - -def add_ui(db): - x = y = 50 - w = 370 - h = 300 - title = "[ProductName] Setup" - - # see "Dialog Style Bits" - modal = 3 # visible | modal - modeless = 1 # visible - track_disk_space = 32 - - add_data(db, 'ActionText', uisample.ActionText) - add_data(db, 'UIText', uisample.UIText) - - # Bitmaps - if not os.path.exists(srcdir+r"\PC\python_icon.exe"): - raise "Run icons.mak in PC directory" - add_data(db, "Binary", - [("PythonWin", msilib.Binary(srcdir+r"\PCbuild\installer.bmp")), # 152x328 pixels - ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")), - ]) - add_data(db, "Icon", - [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))]) - - # Scripts - # CheckDir sets TargetExists if TARGETDIR exists. - # UpdateEditIDLE sets the REGISTRY.tcl component into - # the installed/uninstalled state according to both the - # Extensions and TclTk features. - if os.system("nmake /nologo /c /f msisupport.mak") != 0: - raise "'nmake /f msisupport.mak' failed" - add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))]) - # See "Custom Action Type 1" - if msilib.Win64: - CheckDir = "CheckDir" - UpdateEditIDLE = "UpdateEditIDLE" - else: - CheckDir = "_CheckDir@4" - UpdateEditIDLE = "_UpdateEditIDLE@4" - add_data(db, "CustomAction", - [("CheckDir", 1, "Script", CheckDir)]) - if have_tcl: - add_data(db, "CustomAction", - [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)]) - - # UI customization properties - add_data(db, "Property", - # See "DefaultUIFont Property" - [("DefaultUIFont", "DlgFont8"), - # See "ErrorDialog Style Bit" - ("ErrorDialog", "ErrorDlg"), - ("Progress1", "Install"), # modified in maintenance type dlg - ("Progress2", "installs"), - ("MaintenanceForm_Action", "Repair")]) - - # Fonts, see "TextStyle Table" - add_data(db, "TextStyle", - [("DlgFont8", "Tahoma", 9, None, 0), - ("DlgFontBold8", "Tahoma", 8, None, 1), #bold - ("VerdanaBold10", "Verdana", 10, None, 1), - ("VerdanaRed9", "Verdana", 9, 255, 0), - ]) - - compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x bad_coding|badsyntax|site-packages "[TARGETDIR]Lib"' - # See "CustomAction Table" - add_data(db, "CustomAction", [ - # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty - # See "Custom Action Type 51", - # "Custom Action Execution Scheduling Options" - ("InitialTargetDir", 307, "TARGETDIR", - "[WindowsVolume]Python%s%s" % (major, minor)), - ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"), - ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName), - # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile - # See "Custom Action Type 18" - ("CompilePyc", 18, "python.exe", compileargs), - ("CompilePyo", 18, "python.exe", "-O "+compileargs), - ]) - - # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" - # Numbers indicate sequence; see sequence.py for how these action integrate - add_data(db, "InstallUISequence", - [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), - ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), - ("InitialTargetDir", 'TARGETDIR=""', 750), - # In the user interface, assume all-users installation if privileged. - ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), - ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), - ("SelectDirectoryDlg", "Not Installed", 1230), - # XXX no support for resume installations yet - #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), - ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), - ("ProgressDlg", None, 1280)]) - add_data(db, "AdminUISequence", - [("InitialTargetDir", 'TARGETDIR=""', 750), - ("SetDLLDirToTarget", 'DLLDIR=""', 751), - ]) - - # Execute Sequences - add_data(db, "InstallExecuteSequence", - [("InitialTargetDir", 'TARGETDIR=""', 750), - ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), - ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), - ("UpdateEditIDLE", None, 1050), - ("CompilePyc", "COMPILEALL", 6800), - ("CompilePyo", "COMPILEALL", 6801), - ]) - add_data(db, "AdminExecuteSequence", - [("InitialTargetDir", 'TARGETDIR=""', 750), - ("SetDLLDirToTarget", 'DLLDIR=""', 751), - ("CompilePyc", "COMPILEALL", 6800), - ("CompilePyo", "COMPILEALL", 6801), - ]) - - ##################################################################### - # Standard dialogs: FatalError, UserExit, ExitDialog - fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - fatal.title("[ProductName] Installer ended prematurely") - fatal.back("< Back", "Finish", active = 0) - fatal.cancel("Cancel", "Back", active = 0) - fatal.text("Description1", 135, 70, 220, 80, 0x30003, - "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.") - fatal.text("Description2", 135, 155, 220, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c=fatal.next("Finish", "Cancel", name="Finish") - # See "ControlEvent Table". Parameters are the event, the parameter - # to the action, and optionally the condition for the event, and the order - # of events. - c.event("EndDialog", "Exit") - - user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - user_exit.title("[ProductName] Installer was interrupted") - user_exit.back("< Back", "Finish", active = 0) - user_exit.cancel("Cancel", "Back", active = 0) - user_exit.text("Description1", 135, 70, 220, 80, 0x30003, - "[ProductName] setup was interrupted. Your system has not been modified. " - "To install this program at a later time, please run the installation again.") - user_exit.text("Description2", 135, 155, 220, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c = user_exit.next("Finish", "Cancel", name="Finish") - c.event("EndDialog", "Exit") - - exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - exit_dialog.title("Completing the [ProductName] Installer") - exit_dialog.back("< Back", "Finish", active = 0) - exit_dialog.cancel("Cancel", "Back", active = 0) - exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003, - "Special Windows thanks to:\n" - " Mark Hammond, without whose years of freely \n" - " shared Windows expertise, Python for Windows \n" - " would still be Python for DOS.") - - c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003, - "{\\VerdanaRed9}Warning: Python 2.5.x is the last " - "Python release for Windows 9x.") - c.condition("Hide", "NOT Version9X") - - exit_dialog.text("Description", 135, 235, 220, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c = exit_dialog.next("Finish", "Cancel", name="Finish") - c.event("EndDialog", "Return") - - ##################################################################### - # Required dialog: FilesInUse, ErrorDlg - inuse = PyDialog(db, "FilesInUse", - x, y, w, h, - 19, # KeepModeless|Modal|Visible - title, - "Retry", "Retry", "Retry", bitmap=False) - inuse.text("Title", 15, 6, 200, 15, 0x30003, - r"{\DlgFontBold8}Files in Use") - inuse.text("Description", 20, 23, 280, 20, 0x30003, - "Some files that need to be updated are currently in use.") - inuse.text("Text", 20, 55, 330, 50, 3, - "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.") - inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", - None, None, None) - c=inuse.back("Exit", "Ignore", name="Exit") - c.event("EndDialog", "Exit") - c=inuse.next("Ignore", "Retry", name="Ignore") - c.event("EndDialog", "Ignore") - c=inuse.cancel("Retry", "Exit", name="Retry") - c.event("EndDialog","Retry") - - - # See "Error Dialog". See "ICE20" for the required names of the controls. - error = Dialog(db, "ErrorDlg", - 50, 10, 330, 101, - 65543, # Error|Minimize|Modal|Visible - title, - "ErrorText", None, None) - error.text("ErrorText", 50,9,280,48,3, "") - error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) - error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") - error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") - error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") - error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") - error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") - error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") - error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") - - ##################################################################### - # Global "Query Cancel" dialog - cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, - "No", "No", "No") - cancel.text("Text", 48, 15, 194, 30, 3, - "Are you sure you want to cancel [ProductName] installation?") - cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, - "py.ico", None, None) - c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") - c.event("EndDialog", "Exit") - - c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") - c.event("EndDialog", "Return") - - ##################################################################### - # Global "Wait for costing" dialog - costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, - "Return", "Return", "Return") - costing.text("Text", 48, 15, 194, 30, 3, - "Please wait while the installer finishes determining your disk space requirements.") - costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, - "py.ico", None, None) - c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) - c.event("EndDialog", "Exit") - - ##################################################################### - # Preparation dialog: no user input except cancellation - prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel") - prep.text("Description", 135, 70, 220, 40, 0x30003, - "Please wait while the Installer prepares to guide you through the installation.") - prep.title("Welcome to the [ProductName] Installer") - c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...") - c.mapping("ActionText", "Text") - c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None) - c.mapping("ActionData", "Text") - prep.back("Back", None, active=0) - prep.next("Next", None, active=0) - c=prep.cancel("Cancel", None) - c.event("SpawnDialog", "CancelDlg") - - ##################################################################### - # Target directory selection - seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") - seldlg.title("Select Destination Directory") - c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003, - "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.") - c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""') - seldlg.text("Description", 135, 50, 220, 40, 0x30003, - "Please select a directory for the [ProductName] files.") - - seldlg.back("< Back", None, active=0) - c = seldlg.next("Next >", "Cancel") - c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1) - # If the target exists, but we found that we are going to remove old versions, don't bother - # confirming that the target directory exists. Strictly speaking, we should determine that - # the target directory is indeed the target of the product that we are going to remove, but - # I don't know how to do that. - c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2) - c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3) - c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4) - c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5) - - c = seldlg.cancel("Cancel", "DirectoryCombo") - c.event("SpawnDialog", "CancelDlg") - - seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219, - "TARGETDIR", None, "DirectoryList", None) - seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR", - None, "PathEdit", None) - seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None) - c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None) - c.event("DirectoryListUp", "0") - c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None) - c.event("DirectoryListNew", "0") - - ##################################################################### - # SelectFeaturesDlg - features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space, - title, "Tree", "Next", "Cancel") - features.title("Customize [ProductName]") - features.text("Description", 135, 35, 220, 15, 0x30003, - "Select the way you want features to be installed.") - features.text("Text", 135,45,220,30, 3, - "Click on the icons in the tree below to change the way features will be installed.") - - c=features.back("< Back", "Next") - c.event("NewDialog", "SelectDirectoryDlg") - - c=features.next("Next >", "Cancel") - c.mapping("SelectionNoItems", "Enabled") - c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1) - c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2) - - c=features.cancel("Cancel", "Tree") - c.event("SpawnDialog", "CancelDlg") - - # The browse property is not used, since we have only a single target path (selected already) - features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty", - "Tree of selections", "Back", None) - - #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost") - #c.mapping("SelectionNoItems", "Enabled") - #c.event("Reset", "0") - - features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None) - - c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10) - c.mapping("SelectionNoItems","Enabled") - c.event("SpawnDialog", "DiskCostDlg") - - c=features.xbutton("Advanced", "Advanced", None, 0.30) - c.event("SpawnDialog", "AdvancedDlg") - - c=features.text("ItemDescription", 140, 180, 210, 30, 3, - "Multiline description of the currently selected item.") - c.mapping("SelectionDescription","Text") - - c=features.text("ItemSize", 140, 210, 210, 45, 3, - "The size of the currently selected item.") - c.mapping("SelectionSize", "Text") - - ##################################################################### - # Disk cost - cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, - "OK", "OK", "OK", bitmap=False) - cost.text("Title", 15, 6, 200, 15, 0x30003, - "{\DlgFontBold8}Disk Space Requirements") - cost.text("Description", 20, 20, 280, 20, 0x30003, - "The disk space required for the installation of the selected features.") - cost.text("Text", 20, 53, 330, 60, 3, - "The highlighted volumes (if any) do not have enough disk space " - "available for the currently selected features. You can either " - "remove some files from the highlighted volumes, or choose to " - "install less features onto local drive(s), or select different " - "destination drive(s).") - cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, - None, "{120}{70}{70}{70}{70}", None, None) - cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") - - ##################################################################### - # WhichUsers Dialog. Only available on NT, and for privileged users. - # This must be run before FindRelatedProducts, because that will - # take into account whether the previous installation was per-user - # or per-machine. We currently don't support going back to this - # dialog after "Next" was selected; to support this, we would need to - # find how to reset the ALLUSERS property, and how to re-run - # FindRelatedProducts. - # On Windows9x, the ALLUSERS property is ignored on the command line - # and in the Property table, but installer fails according to the documentation - # if a dialog attempts to set ALLUSERS. - whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, - "AdminInstall", "Next", "Cancel") - whichusers.title("Select whether to install [ProductName] for all users of this computer.") - # A radio group with two options: allusers, justme - g = whichusers.radiogroup("AdminInstall", 135, 60, 160, 50, 3, - "WhichUsers", "", "Next") - g.add("ALL", 0, 5, 150, 20, "Install for all users") - g.add("JUSTME", 0, 25, 150, 20, "Install just for me") - - whichusers.back("Back", None, active=0) - - c = whichusers.next("Next >", "Cancel") - c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) - c.event("EndDialog", "Return", order = 2) - - c = whichusers.cancel("Cancel", "AdminInstall") - c.event("SpawnDialog", "CancelDlg") - - ##################################################################### - # Advanced Dialog. - advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title, - "CompilePyc", "Next", "Cancel") - advanced.title("Advanced Options for [ProductName]") - # A radio group with two options: allusers, justme - advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3, - "COMPILEALL", "Compile .py files to byte code after installation", "Next") - - c = advanced.next("Finish", "Cancel") - c.event("EndDialog", "Return") - - c = advanced.cancel("Cancel", "CompilePyc") - c.event("SpawnDialog", "CancelDlg") - - ##################################################################### - # Existing Directory dialog - dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title, - "No", "No", "No") - dlg.text("Title", 10, 20, 180, 40, 3, - "[TARGETDIR] exists. Are you sure you want to overwrite existing files?") - c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No") - c.event("[TargetExists]", "0", order=1) - c.event("[TargetExistsOk]", "1", order=2) - c.event("EndDialog", "Return", order=3) - c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes") - c.event("EndDialog", "Return") - - ##################################################################### - # Installation Progress dialog (modeless) - progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel", bitmap=False) - progress.text("Title", 20, 15, 200, 15, 0x30003, - "{\DlgFontBold8}[Progress1] [ProductName]") - progress.text("Text", 35, 65, 300, 30, 3, - "Please wait while the Installer [Progress2] [ProductName]. " - "This may take several minutes.") - progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") - - c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") - c.mapping("ActionText", "Text") - - #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) - #c.mapping("ActionData", "Text") - - c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, - None, "Progress done", None, None) - c.mapping("SetProgress", "Progress") - - progress.back("< Back", "Next", active=False) - progress.next("Next >", "Cancel", active=False) - progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg") - - # Maintenance type: repair/uninstall - maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") - maint.title("Welcome to the [ProductName] Setup Wizard") - maint.text("BodyText", 135, 63, 230, 42, 3, - "Select whether you want to repair or remove [ProductName].") - g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3, - "MaintenanceForm_Action", "", "Next") - g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") - g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") - g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") - - maint.back("< Back", None, active=False) - c=maint.next("Finish", "Cancel") - # Change installation: Change progress dialog to "Change", then ask - # for feature selection - c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) - c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) - - # Reinstall: Change progress dialog to "Repair", then invoke reinstall - # Also set list of reinstalled features to "ALL" - c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5) - c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6) - c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7) - c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8) - - # Uninstall: Change progress to "Remove", then invoke uninstall - # Also set list of removed features to "ALL" - c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11) - c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12) - c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13) - c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14) - - # Close dialog when maintenance action scheduled - c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) - c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) - - maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") - - -# See "Feature Table". The feature level is 1 for all features, -# and the feature attributes are 0 for the DefaultFeature, and -# FollowParent for all other features. The numbers are the Display -# column. -def add_features(db): - # feature attributes: - # msidbFeatureAttributesFollowParent == 2 - # msidbFeatureAttributesDisallowAdvertise == 8 - # Features that need to be installed with together with the main feature - # (i.e. additional Python libraries) need to follow the parent feature. - # Features that have no advertisement trigger (e.g. the test suite) - # must not support advertisement - global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature - default_feature = Feature(db, "DefaultFeature", "Python", - "Python Interpreter and Libraries", - 1, directory = "TARGETDIR") - # We don't support advertisement of extensions - ext_feature = Feature(db, "Extensions", "Register Extensions", - "Make this Python installation the default Python installation", 3, - parent = default_feature, attributes=2|8) - if have_tcl: - tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5, - parent = default_feature, attributes=2) - htmlfiles = Feature(db, "Documentation", "Documentation", - "Python HTMLHelp File", 7, parent = default_feature) - tools = Feature(db, "Tools", "Utility Scripts", - "Python utility scripts (Tools/", 9, - parent = default_feature, attributes=2) - testsuite = Feature(db, "Testsuite", "Test suite", - "Python test suite (Lib/test/)", 11, - parent = default_feature, attributes=2|8) - -def extract_msvcr71(): - import _winreg - # Find the location of the merge modules - k = _winreg.OpenKey( - _winreg.HKEY_LOCAL_MACHINE, - r"Software\Microsoft\VisualStudio\7.1\Setup\VS") - dir = _winreg.QueryValueEx(k, "MSMDir")[0] - _winreg.CloseKey(k) - files = glob.glob1(dir, "*CRT71*") - assert len(files) == 1 - file = os.path.join(dir, files[0]) - # Extract msvcr71.dll - m = msilib.MakeMerge2() - m.OpenModule(file, 0) - m.ExtractFiles(".") - m.CloseModule() - # Find the version/language of msvcr71.dll - installer = msilib.MakeInstaller() - return installer.FileVersion("msvcr71.dll", 0), \ - installer.FileVersion("msvcr71.dll", 1) - -class PyDirectory(Directory): - """By default, all components in the Python installer - can run from source.""" - def __init__(self, *args, **kw): - if not kw.has_key("componentflags"): - kw['componentflags'] = 2 #msidbComponentAttributesOptional - Directory.__init__(self, *args, **kw) - -# See "File Table", "Component Table", "Directory Table", -# "FeatureComponents Table" -def add_files(db): - cab = CAB("python") - tmpfiles = [] - # Add all executables, icons, text files into the TARGETDIR component - root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir") - default_feature.set_current() - if not msilib.Win64: - root.add_file("PCBuild/w9xpopen.exe") - root.add_file("README.txt", src="README") - root.add_file("NEWS.txt", src="Misc/NEWS") - root.add_file("LICENSE.txt", src="LICENSE") - root.start_component("python.exe", keyfile="python.exe") - root.add_file("PCBuild/python.exe") - root.start_component("pythonw.exe", keyfile="pythonw.exe") - root.add_file("PCBuild/pythonw.exe") - - # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table" - dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".") - pydll = "python%s%s.dll" % (major, minor) - pydllsrc = srcdir + "/PCBuild/" + pydll - dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid) - installer = msilib.MakeInstaller() - pyversion = installer.FileVersion(pydllsrc, 0) - if not snapshot: - # For releases, the Python DLL has the same version as the - # installer package. - assert pyversion.split(".")[:3] == current_version.split(".") - dlldir.add_file("PCBuild/python%s%s.dll" % (major, minor), - version=pyversion, - language=installer.FileVersion(pydllsrc, 1)) - # XXX determine dependencies - version, lang = extract_msvcr71() - dlldir.start_component("msvcr71", flags=8, keyfile="msvcr71.dll", uuid=msvcr71_uuid) - dlldir.add_file("msvcr71.dll", src=os.path.abspath("msvcr71.dll"), - version=version, language=lang) - tmpfiles.append("msvcr71.dll") - - # Check if _ctypes.pyd exists - have_ctypes = os.path.exists(srcdir+"/PCBuild/_ctypes.pyd") - if not have_ctypes: - print "WARNING: _ctypes.pyd not found, ctypes will not be included" - extensions.remove("_ctypes.pyd") - - # Add all .py files in Lib, except lib-tk, test - dirs={} - pydirs = [(root,"Lib")] - while pydirs: - parent, dir = pydirs.pop() - if dir == ".svn" or dir.startswith("plat-"): - continue - elif dir in ["lib-tk", "idlelib", "Icons"]: - if not have_tcl: - continue - tcltk.set_current() - elif dir in ['test', 'tests', 'data', 'output']: - # test: Lib, Lib/email, Lib/bsddb, Lib/ctypes, Lib/sqlite3 - # tests: Lib/distutils - # data: Lib/email/test - # output: Lib/test - testsuite.set_current() - elif not have_ctypes and dir == "ctypes": - continue - else: - default_feature.set_current() - lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir)) - # Add additional files - dirs[dir]=lib - lib.glob("*.txt") - if dir=='site-packages': - lib.add_file("README.txt", src="README") - continue - files = lib.glob("*.py") - files += lib.glob("*.pyw") - if files: - # Add an entry to the RemoveFile table to remove bytecode files. - lib.remove_pyc() - if dir.endswith('.egg-info'): - lib.add_file('entry_points.txt') - lib.add_file('PKG-INFO') - lib.add_file('top_level.txt') - lib.add_file('zip-safe') - continue - if dir=='test' and parent.physical=='Lib': - lib.add_file("185test.db") - lib.add_file("audiotest.au") - lib.add_file("cfgparser.1") - lib.add_file("sgml_input.html") - lib.add_file("test.xml") - lib.add_file("test.xml.out") - lib.add_file("testtar.tar") - lib.add_file("test_difflib_expect.html") - lib.add_file("check_soundcard.vbs") - lib.add_file("empty.vbs") - lib.glob("*.uue") - lib.add_file("readme.txt", src="README") - if dir=='decimaltestdata': - lib.glob("*.decTest") - if dir=='output': - lib.glob("test_*") - if dir=='idlelib': - lib.glob("*.def") - lib.add_file("idle.bat") - if dir=="Icons": - lib.glob("*.gif") - lib.add_file("idle.icns") - if dir=="command" and parent.physical=="distutils": - lib.add_file("wininst-6.exe") - lib.add_file("wininst-7.1.exe") - if dir=="setuptools": - lib.add_file("cli.exe") - lib.add_file("gui.exe") - if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email": - # This should contain all non-.svn files listed in subversion - for f in os.listdir(lib.absolute): - if f.endswith(".txt") or f==".svn":continue - if f.endswith(".au") or f.endswith(".gif"): - lib.add_file(f) - else: - print "WARNING: New file %s in email/test/data" % f - for f in os.listdir(lib.absolute): - if os.path.isdir(os.path.join(lib.absolute, f)): - pydirs.append((lib, f)) - # Add DLLs - default_feature.set_current() - lib = PyDirectory(db, cab, root, srcdir+"/PCBuild", "DLLs", "DLLS|DLLs") - lib.add_file("py.ico", src="../PC/py.ico") - lib.add_file("pyc.ico", src="../PC/pyc.ico") - dlls = [] - tclfiles = [] - for f in extensions: - if f=="_tkinter.pyd": - continue - if not os.path.exists(srcdir+"/PCBuild/"+f): - print "WARNING: Missing extension", f - continue - dlls.append(f) - lib.add_file(f) - # Add sqlite - if msilib.msi_type=="Intel64;1033": - sqlite_arch = "/ia64" - elif msilib.msi_type=="x64;1033": - sqlite_arch = "/amd64" - else: - sqlite_arch = "" - lib.add_file(srcdir+"/"+sqlite_dir+sqlite_arch+"/sqlite3.dll") - if have_tcl: - if not os.path.exists(srcdir+"/PCBuild/_tkinter.pyd"): - print "WARNING: Missing _tkinter.pyd" - else: - lib.start_component("TkDLLs", tcltk) - lib.add_file("_tkinter.pyd") - dlls.append("_tkinter.pyd") - tcldir = os.path.normpath(srcdir+"/../tcltk/bin") - for f in glob.glob1(tcldir, "*.dll"): - lib.add_file(f, src=os.path.join(tcldir, f)) - # check whether there are any unknown extensions - for f in glob.glob1(srcdir+"/PCBuild", "*.pyd"): - if f.endswith("_d.pyd"): continue # debug version - if f in dlls: continue - print "WARNING: Unknown extension", f - - # Add headers - default_feature.set_current() - lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include") - lib.glob("*.h") - lib.add_file("pyconfig.h", src="../PC/pyconfig.h") - # Add import libraries - lib = PyDirectory(db, cab, root, "PCBuild", "libs", "LIBS|libs") - for f in dlls: - lib.add_file(f.replace('pyd','lib')) - lib.add_file('python%s%s.lib' % (major, minor)) - # Add the mingw-format library - if have_mingw: - lib.add_file('libpython%s%s.a' % (major, minor)) - if have_tcl: - # Add Tcl/Tk - tcldirs = [(root, '../tcltk/lib', 'tcl')] - tcltk.set_current() - while tcldirs: - parent, phys, dir = tcldirs.pop() - lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir)) - if not os.path.exists(lib.absolute): - continue - for f in os.listdir(lib.absolute): - if os.path.isdir(os.path.join(lib.absolute, f)): - tcldirs.append((lib, f, f)) - else: - lib.add_file(f) - # Add tools - tools.set_current() - tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools") - for f in ['i18n', 'pynche', 'Scripts', 'versioncheck', 'webchecker']: - lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f)) - lib.glob("*.py") - lib.glob("*.pyw", exclude=['pydocgui.pyw']) - lib.remove_pyc() - lib.glob("*.txt") - if f == "pynche": - x = PyDirectory(db, cab, lib, "X", "X", "X|X") - x.glob("*.txt") - if os.path.exists(os.path.join(lib.absolute, "README")): - lib.add_file("README.txt", src="README") - if f == 'Scripts': - if have_tcl: - lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw") - lib.add_file("pydocgui.pyw") - # Add documentation - htmlfiles.set_current() - lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc") - lib.start_component("documentation", keyfile="Python%s%s.chm" % (major,minor)) - lib.add_file("Python%s%s.chm" % (major, minor)) - - cab.commit(db) - - for f in tmpfiles: - os.unlink(f) - -# See "Registry Table", "Component Table" -def add_registry(db): - # File extensions, associated with the REGISTRY.def component - # IDLE verbs depend on the tcltk feature. - # msidbComponentAttributesRegistryKeyPath = 4 - # -1 for Root specifies "dependent on ALLUSERS property" - tcldata = [] - if have_tcl: - tcldata = [ - ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", 4, None, - "py.IDLE")] - add_data(db, "Component", - # msidbComponentAttributesRegistryKeyPath = 4 - [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", 4, None, - "InstallPath"), - ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", 4, None, - "Documentation"), - ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", 4, - None, None)] + tcldata) - # See "FeatureComponents Table". - # The association between TclTk and pythonw.exe is necessary to make ICE59 - # happy, because the installer otherwise believes that the IDLE and PyDoc - # shortcuts might get installed without pythonw.exe being install. This - # is not true, since installing TclTk will install the default feature, which - # will cause pythonw.exe to be installed. - # REGISTRY.tcl is not associated with any feature, as it will be requested - # through a custom action - tcldata = [] - if have_tcl: - tcldata = [(tcltk.id, "pythonw.exe")] - add_data(db, "FeatureComponents", - [(default_feature.id, "REGISTRY"), - (htmlfiles.id, "REGISTRY.doc"), - (ext_feature.id, "REGISTRY.def")] + - tcldata - ) - # Extensions are not advertised. For advertised extensions, - # we would need separate binaries that install along with the - # extension. - pat = r"Software\Classes\%sPython.%sFile\shell\%s\command" - ewi = "Edit with IDLE" - pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon" - pat3 = r"Software\Classes\%sPython.%sFile" - tcl_verbs = [] - if have_tcl: - tcl_verbs=[ - ("py.IDLE", -1, pat % (testprefix, "", ewi), "", - r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"', - "REGISTRY.tcl"), - ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "", - r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"', - "REGISTRY.tcl"), - ] - add_data(db, "Registry", - [# Extensions - ("py.ext", -1, r"Software\Classes\."+ext, "", - "Python.File", "REGISTRY.def"), - ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "", - "Python.NoConFile", "REGISTRY.def"), - ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "", - "Python.CompiledFile", "REGISTRY.def"), - ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "", - "Python.CompiledFile", "REGISTRY.def"), - # MIME types - ("py.mime", -1, r"Software\Classes\."+ext, "Content Type", - "text/plain", "REGISTRY.def"), - ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type", - "text/plain", "REGISTRY.def"), - #Verbs - ("py.open", -1, pat % (testprefix, "", "open"), "", - r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"), - ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "", - r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"), - ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "", - r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"), - ] + tcl_verbs + [ - #Icons - ("py.icon", -1, pat2 % (testprefix, ""), "", - r'[DLLs]py.ico', "REGISTRY.def"), - ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "", - r'[DLLs]py.ico', "REGISTRY.def"), - ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "", - r'[DLLs]pyc.ico', "REGISTRY.def"), - # Descriptions - ("py.txt", -1, pat3 % (testprefix, ""), "", - "Python File", "REGISTRY.def"), - ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "", - "Python File (no console)", "REGISTRY.def"), - ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "", - "Compiled Python File", "REGISTRY.def"), - ]) - - # Registry keys - prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version) - add_data(db, "Registry", - [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"), - ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "", - "Python %s" % short_version, "REGISTRY"), - ("PythonPath", -1, prefix+r"\PythonPath", "", - r"[TARGETDIR]Lib;[TARGETDIR]DLLs;[TARGETDIR]Lib\lib-tk", "REGISTRY"), - ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "", - r"[TARGETDIR]Doc\Python%s%s.chm" % (major, minor), "REGISTRY.doc"), - ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"), - ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe", - "", r"[TARGETDIR]Python.exe", "REGISTRY.def") - ]) - # Shortcuts, see "Shortcut Table" - add_data(db, "Directory", - [("ProgramMenuFolder", "TARGETDIR", "."), - ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))]) - add_data(db, "RemoveFile", - [("MenuDir", "TARGETDIR", None, "MenuDir", 2)]) - tcltkshortcuts = [] - if have_tcl: - tcltkshortcuts = [ - ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe", - tcltk.id, r'"[TARGETDIR]Lib\idlelib\idle.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"), - ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe", - tcltk.id, r'"[TARGETDIR]Tools\scripts\pydocgui.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"), - ] - add_data(db, "Shortcut", - tcltkshortcuts + - [# Advertised shortcuts: targets are features, not files - ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe", - default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"), - # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an - # icon first. - #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation", - # htmlfiles.id, None, None, None, None, None, None, None), - ## Non-advertised shortcuts: must be associated with a registry component - ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc", - "[#Python%s%s.chm]" % (major,minor), None, - None, None, None, None, None, None), - ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY", - SystemFolderName+"msiexec", "/x%s" % product_code, - None, None, None, None, None, None), - ]) - db.Commit() - -db = build_database() -try: - add_features(db) - add_ui(db) - add_files(db) - add_registry(db) - remove_old_versions(db) - db.Commit() -finally: - del db |