Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1 | # Python MSI Generator |
| 2 | # (C) 2003 Martin v. Loewis |
| 3 | # See "FOO" in comments refers to MSDN sections with the title FOO. |
Martin v. Löwis | 3a72b25 | 2010-11-14 18:13:49 +0000 | [diff] [blame^] | 4 | import msilib, schema, sequence, os, glob, time, re, shutil, zipfile |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 5 | from msilib import Feature, CAB, Directory, Dialog, Binary, add_data |
| 6 | import uisample |
| 7 | from win32com.client import constants |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 8 | from distutils.spawn import find_executable |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 9 | from uuids import product_codes |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 10 | |
| 11 | # Settings can be overridden in config.py below |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 12 | # 0 for official python.org releases |
| 13 | # 1 for intermediate releases by anybody, with |
| 14 | # a new product code for every package. |
| 15 | snapshot = 1 |
| 16 | # 1 means that file extension is px, not py, |
| 17 | # and binaries start with x |
| 18 | testpackage = 0 |
| 19 | # Location of build tree |
| 20 | srcdir = os.path.abspath("../..") |
| 21 | # Text to be displayed as the version in dialogs etc. |
| 22 | # goes into file name and ProductCode. Defaults to |
| 23 | # current_version.day for Snapshot, current_version otherwise |
| 24 | full_current_version = None |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 25 | # Is Tcl available at all? |
| 26 | have_tcl = True |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 27 | # path to PCbuild directory |
Christian Heimes | faf2f63 | 2008-01-06 16:59:19 +0000 | [diff] [blame] | 28 | PCBUILD="PCbuild" |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 29 | # msvcrt version |
Christian Heimes | faf2f63 | 2008-01-06 16:59:19 +0000 | [diff] [blame] | 30 | MSVCR = "90" |
Martin v. Löwis | 3a72b25 | 2010-11-14 18:13:49 +0000 | [diff] [blame^] | 31 | # Make a zip file containing the PDB files for this build? |
| 32 | pdbzip = True |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 33 | |
| 34 | try: |
| 35 | from config import * |
| 36 | except ImportError: |
| 37 | pass |
| 38 | |
| 39 | # Extract current version from Include/patchlevel.h |
| 40 | lines = open(srcdir + "/Include/patchlevel.h").readlines() |
| 41 | major = minor = micro = level = serial = None |
| 42 | levels = { |
| 43 | 'PY_RELEASE_LEVEL_ALPHA':0xA, |
| 44 | 'PY_RELEASE_LEVEL_BETA': 0xB, |
| 45 | 'PY_RELEASE_LEVEL_GAMMA':0xC, |
| 46 | 'PY_RELEASE_LEVEL_FINAL':0xF |
| 47 | } |
| 48 | for l in lines: |
| 49 | if not l.startswith("#define"): |
| 50 | continue |
| 51 | l = l.split() |
| 52 | if len(l) != 3: |
| 53 | continue |
| 54 | _, name, value = l |
| 55 | if name == 'PY_MAJOR_VERSION': major = value |
| 56 | if name == 'PY_MINOR_VERSION': minor = value |
| 57 | if name == 'PY_MICRO_VERSION': micro = value |
| 58 | if name == 'PY_RELEASE_LEVEL': level = levels[value] |
| 59 | if name == 'PY_RELEASE_SERIAL': serial = value |
| 60 | |
| 61 | short_version = major+"."+minor |
| 62 | # See PC/make_versioninfo.c |
| 63 | FIELD3 = 1000*int(micro) + 10*level + int(serial) |
| 64 | current_version = "%s.%d" % (short_version, FIELD3) |
| 65 | |
| 66 | # This should never change. The UpgradeCode of this package can be |
| 67 | # used in the Upgrade table of future packages to make the future |
| 68 | # package replace this one. See "UpgradeCode Property". |
Martin v. Löwis | f27f8a1 | 2008-09-13 08:14:01 +0000 | [diff] [blame] | 69 | # upgrade_code gets set to upgrade_code_64 when we have determined |
| 70 | # that the target is Win64. |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 71 | upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}' |
| 72 | upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}' |
Martin v. Löwis | f27f8a1 | 2008-09-13 08:14:01 +0000 | [diff] [blame] | 73 | upgrade_code_64='{6A965A0C-6EE6-4E3A-9983-3263F56311EC}' |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 74 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 75 | if snapshot: |
| 76 | current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24)) |
| 77 | product_code = msilib.gen_uuid() |
| 78 | else: |
| 79 | product_code = product_codes[current_version] |
| 80 | |
| 81 | if full_current_version is None: |
| 82 | full_current_version = current_version |
| 83 | |
| 84 | extensions = [ |
| 85 | 'bz2.pyd', |
| 86 | 'pyexpat.pyd', |
| 87 | 'select.pyd', |
| 88 | 'unicodedata.pyd', |
| 89 | 'winsound.pyd', |
Trent Mick | e97e5a7 | 2005-12-15 22:08:46 +0000 | [diff] [blame] | 90 | '_elementtree.pyd', |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 91 | '_socket.pyd', |
| 92 | '_ssl.pyd', |
| 93 | '_testcapi.pyd', |
| 94 | '_tkinter.pyd', |
Martin v. Löwis | 8c7c56e | 2006-03-05 14:04:26 +0000 | [diff] [blame] | 95 | '_msi.pyd', |
Martin v. Löwis | a09655e | 2006-03-10 15:36:28 +0000 | [diff] [blame] | 96 | '_ctypes.pyd', |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 97 | '_ctypes_test.pyd', |
Thomas Wouters | 00ee7ba | 2006-08-21 19:07:27 +0000 | [diff] [blame] | 98 | '_sqlite3.pyd', |
Martin v. Löwis | 9aa04c4 | 2008-06-30 07:03:57 +0000 | [diff] [blame] | 99 | '_hashlib.pyd', |
| 100 | '_multiprocessing.pyd' |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 101 | ] |
| 102 | |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 103 | # Well-known component UUIDs |
| 104 | # These are needed for SharedDLLs reference counter; if |
| 105 | # a different UUID was used for each incarnation of, say, |
| 106 | # python24.dll, an upgrade would set the reference counter |
| 107 | # from 1 to 2 (due to what I consider a bug in MSI) |
| 108 | # Using the same UUID is fine since these files are versioned, |
| 109 | # so Installer will always keep the newest version. |
Christian Heimes | d0764e2 | 2007-12-04 15:00:33 +0000 | [diff] [blame] | 110 | # NOTE: All uuids are self generated. |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 111 | pythondll_uuid = { |
| 112 | "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}", |
Martin v. Löwis | 4c6c7ca | 2007-08-30 15:23:04 +0000 | [diff] [blame] | 113 | "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}", |
Guido van Rossum | af554a0 | 2007-08-16 23:48:43 +0000 | [diff] [blame] | 114 | "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}", |
Martin v. Löwis | 7a63fc4 | 2008-10-02 20:09:01 +0000 | [diff] [blame] | 115 | "27":"{4fe21c76-1760-437b-a2f2-99909130a175}", |
Martin v. Löwis | 4c6c7ca | 2007-08-30 15:23:04 +0000 | [diff] [blame] | 116 | "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}", |
Martin v. Löwis | fc97249 | 2008-10-02 20:09:47 +0000 | [diff] [blame] | 117 | "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}", |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 118 | } [major+minor] |
Tim Peters | eba28be | 2005-03-28 01:08:02 +0000 | [diff] [blame] | 119 | |
Alexandre Vassalotti | 6461e10 | 2008-05-15 22:09:29 +0000 | [diff] [blame] | 120 | # Compute the name that Sphinx gives to the docfile |
| 121 | docfile = "" |
Martin v. Löwis | a01bd62 | 2009-06-28 12:29:40 +0000 | [diff] [blame] | 122 | if int(micro): |
| 123 | docfile = micro |
Alexandre Vassalotti | 6461e10 | 2008-05-15 22:09:29 +0000 | [diff] [blame] | 124 | if level < 0xf: |
Benjamin Peterson | b48f634 | 2009-06-22 19:36:31 +0000 | [diff] [blame] | 125 | if level == 0xC: |
Martin v. Löwis | a01bd62 | 2009-06-28 12:29:40 +0000 | [diff] [blame] | 126 | docfile += "rc%s" % (serial,) |
Benjamin Peterson | b48f634 | 2009-06-22 19:36:31 +0000 | [diff] [blame] | 127 | else: |
Martin v. Löwis | a01bd62 | 2009-06-28 12:29:40 +0000 | [diff] [blame] | 128 | docfile += '%x%s' % (level, serial) |
Alexandre Vassalotti | 6461e10 | 2008-05-15 22:09:29 +0000 | [diff] [blame] | 129 | docfile = 'python%s%s%s.chm' % (major, minor, docfile) |
| 130 | |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 131 | # Build the mingw import library, libpythonXY.a |
| 132 | # This requires 'nm' and 'dlltool' executables on your PATH |
| 133 | def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib): |
| 134 | warning = "WARNING: %s - libpythonXX.a not built" |
| 135 | nm = find_executable('nm') |
| 136 | dlltool = find_executable('dlltool') |
| 137 | |
| 138 | if not nm or not dlltool: |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 139 | print(warning % "nm and/or dlltool were not found") |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 140 | return False |
| 141 | |
| 142 | nm_command = '%s -Cs %s' % (nm, lib_file) |
| 143 | dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \ |
| 144 | (dlltool, dll_file, def_file, mingw_lib) |
| 145 | export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match |
| 146 | |
| 147 | f = open(def_file,'w') |
Martin v. Löwis | 4c6c7ca | 2007-08-30 15:23:04 +0000 | [diff] [blame] | 148 | f.write("LIBRARY %s\n" % dll_file) |
| 149 | f.write("EXPORTS\n") |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 150 | |
| 151 | nm_pipe = os.popen(nm_command) |
| 152 | for line in nm_pipe.readlines(): |
| 153 | m = export_match(line) |
| 154 | if m: |
Martin v. Löwis | 4c6c7ca | 2007-08-30 15:23:04 +0000 | [diff] [blame] | 155 | f.write(m.group(1)+"\n") |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 156 | f.close() |
| 157 | exit = nm_pipe.close() |
| 158 | |
| 159 | if exit: |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 160 | print(warning % "nm did not run successfully") |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 161 | return False |
| 162 | |
| 163 | if os.system(dlltool_command) != 0: |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 164 | print(warning % "dlltool did not run successfully") |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 165 | return False |
| 166 | |
| 167 | return True |
| 168 | |
| 169 | # Target files (.def and .a) go in PCBuild directory |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 170 | lib_file = os.path.join(srcdir, PCBUILD, "python%s%s.lib" % (major, minor)) |
| 171 | def_file = os.path.join(srcdir, PCBUILD, "python%s%s.def" % (major, minor)) |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 172 | dll_file = "python%s%s.dll" % (major, minor) |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 173 | mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor)) |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 174 | |
| 175 | have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib) |
| 176 | |
Martin v. Löwis | 856bf9a | 2006-02-14 20:42:55 +0000 | [diff] [blame] | 177 | # Determine the target architechture |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 178 | dll_path = os.path.join(srcdir, PCBUILD, dll_file) |
Martin v. Löwis | 856bf9a | 2006-02-14 20:42:55 +0000 | [diff] [blame] | 179 | msilib.set_arch_from_file(dll_path) |
| 180 | if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"): |
Collin Winter | a817e58 | 2007-08-22 23:05:06 +0000 | [diff] [blame] | 181 | raise SystemError("msisupport.dll for incorrect architecture") |
Martin v. Löwis | f27f8a1 | 2008-09-13 08:14:01 +0000 | [diff] [blame] | 182 | if msilib.Win64: |
| 183 | upgrade_code = upgrade_code_64 |
Martin v. Löwis | e40a213 | 2008-09-13 08:37:17 +0000 | [diff] [blame] | 184 | # Bump the last digit of the code by one, so that 32-bit and 64-bit |
| 185 | # releases get separate product codes |
| 186 | digit = hex((int(product_code[-2],16)+1)%16)[-1] |
| 187 | product_code = product_code[:-2] + digit + '}' |
Martin v. Löwis | 856bf9a | 2006-02-14 20:42:55 +0000 | [diff] [blame] | 188 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 189 | if testpackage: |
| 190 | ext = 'px' |
| 191 | testprefix = 'x' |
| 192 | else: |
| 193 | ext = 'py' |
| 194 | testprefix = '' |
| 195 | |
| 196 | if msilib.Win64: |
Martin v. Löwis | 47cc2a0 | 2007-08-30 18:27:06 +0000 | [diff] [blame] | 197 | SystemFolderName = "[System64Folder]" |
Martin v. Löwis | 283e35f | 2007-08-31 09:59:29 +0000 | [diff] [blame] | 198 | registry_component = 4|256 |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 199 | else: |
| 200 | SystemFolderName = "[SystemFolder]" |
Martin v. Löwis | 283e35f | 2007-08-31 09:59:29 +0000 | [diff] [blame] | 201 | registry_component = 4 |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 202 | |
| 203 | msilib.reset() |
| 204 | |
| 205 | # condition in which to install pythonxy.dll in system32: |
| 206 | # a) it is Windows 9x or |
| 207 | # b) it is NT, the user is privileged, and has chosen per-machine installation |
| 208 | sys32cond = "(Windows9x or (Privileged and ALLUSERS))" |
| 209 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 210 | def build_database(): |
| 211 | """Generate an empty database, with just the schema and the |
| 212 | Summary information stream.""" |
| 213 | if snapshot: |
| 214 | uc = upgrade_code_snapshot |
| 215 | else: |
| 216 | uc = upgrade_code |
Martin v. Löwis | e40a213 | 2008-09-13 08:37:17 +0000 | [diff] [blame] | 217 | if msilib.Win64: |
| 218 | productsuffix = " (64-bit)" |
| 219 | else: |
| 220 | productsuffix = "" |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 221 | # schema represents the installer 2.0 database schema. |
| 222 | # sequence is the set of standard sequences |
| 223 | # (ui/execute, admin/advt/install) |
Martin v. Löwis | 856bf9a | 2006-02-14 20:42:55 +0000 | [diff] [blame] | 224 | db = msilib.init_database("python-%s%s.msi" % (full_current_version, msilib.arch_ext), |
Martin v. Löwis | e40a213 | 2008-09-13 08:37:17 +0000 | [diff] [blame] | 225 | schema, ProductName="Python "+full_current_version+productsuffix, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 226 | ProductCode=product_code, |
| 227 | ProductVersion=current_version, |
Martin v. Löwis | f63921f | 2008-10-13 11:30:30 +0000 | [diff] [blame] | 228 | Manufacturer=u"Python Software Foundation", |
| 229 | request_uac = True) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 230 | # The default sequencing of the RemoveExistingProducts action causes |
| 231 | # removal of files that got just installed. Place it after |
| 232 | # InstallInitialize, so we first uninstall everything, but still roll |
| 233 | # back in case the installation is interrupted |
| 234 | msilib.change_sequence(sequence.InstallExecuteSequence, |
| 235 | "RemoveExistingProducts", 1510) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 236 | msilib.add_tables(db, sequence) |
| 237 | # We cannot set ALLUSERS in the property table, as this cannot be |
| 238 | # reset if the user choses a per-user installation. Instead, we |
| 239 | # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages |
| 240 | # this property, and when the execution starts, ALLUSERS is set |
| 241 | # accordingly. |
| 242 | add_data(db, "Property", [("UpgradeCode", uc), |
| 243 | ("WhichUsers", "ALL"), |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 244 | ("ProductLine", "Python%s%s" % (major, minor)), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 245 | ]) |
| 246 | db.Commit() |
| 247 | return db |
| 248 | |
| 249 | def remove_old_versions(db): |
| 250 | "Fill the upgrade table." |
| 251 | start = "%s.%s.0" % (major, minor) |
| 252 | # This requests that feature selection states of an older |
| 253 | # installation should be forwarded into this one. Upgrading |
| 254 | # requires that both the old and the new installation are |
| 255 | # either both per-machine or per-user. |
| 256 | migrate_features = 1 |
| 257 | # See "Upgrade Table". We remove releases with the same major and |
| 258 | # minor version. For an snapshot, we remove all earlier snapshots. For |
| 259 | # a release, we remove all snapshots, and all earlier releases. |
| 260 | if snapshot: |
| 261 | add_data(db, "Upgrade", |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 262 | [(upgrade_code_snapshot, start, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 263 | current_version, |
| 264 | None, # Ignore language |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 265 | migrate_features, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 266 | None, # Migrate ALL features |
| 267 | "REMOVEOLDSNAPSHOT")]) |
| 268 | props = "REMOVEOLDSNAPSHOT" |
| 269 | else: |
| 270 | add_data(db, "Upgrade", |
| 271 | [(upgrade_code, start, current_version, |
| 272 | None, migrate_features, None, "REMOVEOLDVERSION"), |
| 273 | (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1), |
| 274 | None, migrate_features, None, "REMOVEOLDSNAPSHOT")]) |
| 275 | props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION" |
Martin v. Löwis | 1c4c306 | 2008-09-08 16:27:54 +0000 | [diff] [blame] | 276 | |
| 277 | props += ";TARGETDIR;DLLDIR" |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 278 | # Installer collects the product codes of the earlier releases in |
| 279 | # these properties. In order to allow modification of the properties, |
| 280 | # they must be declared as secure. See "SecureCustomProperties Property" |
| 281 | add_data(db, "Property", [("SecureCustomProperties", props)]) |
| 282 | |
| 283 | class PyDialog(Dialog): |
| 284 | """Dialog class with a fixed layout: controls at the top, then a ruler, |
| 285 | then a list of buttons: back, next, cancel. Optionally a bitmap at the |
| 286 | left.""" |
| 287 | def __init__(self, *args, **kw): |
| 288 | """Dialog(database, name, x, y, w, h, attributes, title, first, |
| 289 | default, cancel, bitmap=true)""" |
| 290 | Dialog.__init__(self, *args) |
| 291 | ruler = self.h - 36 |
| 292 | bmwidth = 152*ruler/328 |
| 293 | if kw.get("bitmap", True): |
| 294 | self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") |
| 295 | self.line("BottomLine", 0, ruler, self.w, 0) |
| 296 | |
| 297 | def title(self, title): |
| 298 | "Set the title text of the dialog at the top." |
| 299 | # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, |
| 300 | # text, in VerdanaBold10 |
| 301 | self.text("Title", 135, 10, 220, 60, 0x30003, |
| 302 | r"{\VerdanaBold10}%s" % title) |
| 303 | |
| 304 | def back(self, title, next, name = "Back", active = 1): |
| 305 | """Add a back button with a given title, the tab-next button, |
| 306 | its name in the Control table, possibly initially disabled. |
| 307 | |
| 308 | Return the button, so that events can be associated""" |
| 309 | if active: |
| 310 | flags = 3 # Visible|Enabled |
| 311 | else: |
| 312 | flags = 1 # Visible |
| 313 | return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) |
| 314 | |
| 315 | def cancel(self, title, next, name = "Cancel", active = 1): |
| 316 | """Add a cancel button with a given title, the tab-next button, |
| 317 | its name in the Control table, possibly initially disabled. |
| 318 | |
| 319 | Return the button, so that events can be associated""" |
| 320 | if active: |
| 321 | flags = 3 # Visible|Enabled |
| 322 | else: |
| 323 | flags = 1 # Visible |
| 324 | return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) |
| 325 | |
| 326 | def next(self, title, next, name = "Next", active = 1): |
| 327 | """Add a Next button with a given title, the tab-next button, |
| 328 | its name in the Control table, possibly initially disabled. |
| 329 | |
| 330 | Return the button, so that events can be associated""" |
| 331 | if active: |
| 332 | flags = 3 # Visible|Enabled |
| 333 | else: |
| 334 | flags = 1 # Visible |
| 335 | return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) |
| 336 | |
| 337 | def xbutton(self, name, title, next, xpos): |
| 338 | """Add a button with a given title, the tab-next button, |
| 339 | its name in the Control table, giving its x position; the |
| 340 | y-position is aligned with the other buttons. |
| 341 | |
| 342 | Return the button, so that events can be associated""" |
| 343 | return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) |
| 344 | |
| 345 | def add_ui(db): |
| 346 | x = y = 50 |
| 347 | w = 370 |
| 348 | h = 300 |
| 349 | title = "[ProductName] Setup" |
| 350 | |
| 351 | # see "Dialog Style Bits" |
| 352 | modal = 3 # visible | modal |
| 353 | modeless = 1 # visible |
| 354 | track_disk_space = 32 |
| 355 | |
| 356 | add_data(db, 'ActionText', uisample.ActionText) |
| 357 | add_data(db, 'UIText', uisample.UIText) |
| 358 | |
| 359 | # Bitmaps |
| 360 | if not os.path.exists(srcdir+r"\PC\python_icon.exe"): |
Georg Brandl | bf82e37 | 2008-05-16 17:02:34 +0000 | [diff] [blame] | 361 | raise RuntimeError("Run icons.mak in PC directory") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 362 | add_data(db, "Binary", |
Christian Heimes | d9a4d1d | 2008-01-01 14:42:15 +0000 | [diff] [blame] | 363 | [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 364 | ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")), |
| 365 | ]) |
| 366 | add_data(db, "Icon", |
| 367 | [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))]) |
| 368 | |
| 369 | # Scripts |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 370 | # CheckDir sets TargetExists if TARGETDIR exists. |
| 371 | # UpdateEditIDLE sets the REGISTRY.tcl component into |
| 372 | # the installed/uninstalled state according to both the |
| 373 | # Extensions and TclTk features. |
Martin v. Löwis | eb68be4 | 2004-12-12 15:29:21 +0000 | [diff] [blame] | 374 | if os.system("nmake /nologo /c /f msisupport.mak") != 0: |
Georg Brandl | bf82e37 | 2008-05-16 17:02:34 +0000 | [diff] [blame] | 375 | raise RuntimeError("'nmake /f msisupport.mak' failed") |
Martin v. Löwis | eb68be4 | 2004-12-12 15:29:21 +0000 | [diff] [blame] | 376 | add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))]) |
| 377 | # See "Custom Action Type 1" |
Martin v. Löwis | 3390d33 | 2005-03-14 17:20:13 +0000 | [diff] [blame] | 378 | if msilib.Win64: |
| 379 | CheckDir = "CheckDir" |
Martin v. Löwis | df40ce3 | 2006-02-16 14:38:30 +0000 | [diff] [blame] | 380 | UpdateEditIDLE = "UpdateEditIDLE" |
Martin v. Löwis | 3390d33 | 2005-03-14 17:20:13 +0000 | [diff] [blame] | 381 | else: |
| 382 | CheckDir = "_CheckDir@4" |
| 383 | UpdateEditIDLE = "_UpdateEditIDLE@4" |
Tim Peters | 0e9980f | 2004-09-12 03:49:31 +0000 | [diff] [blame] | 384 | add_data(db, "CustomAction", |
Martin v. Löwis | 3390d33 | 2005-03-14 17:20:13 +0000 | [diff] [blame] | 385 | [("CheckDir", 1, "Script", CheckDir)]) |
Martin v. Löwis | eac02e6 | 2004-11-18 08:00:33 +0000 | [diff] [blame] | 386 | if have_tcl: |
| 387 | add_data(db, "CustomAction", |
Martin v. Löwis | 3390d33 | 2005-03-14 17:20:13 +0000 | [diff] [blame] | 388 | [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)]) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 389 | |
| 390 | # UI customization properties |
| 391 | add_data(db, "Property", |
| 392 | # See "DefaultUIFont Property" |
| 393 | [("DefaultUIFont", "DlgFont8"), |
| 394 | # See "ErrorDialog Style Bit" |
| 395 | ("ErrorDialog", "ErrorDlg"), |
| 396 | ("Progress1", "Install"), # modified in maintenance type dlg |
| 397 | ("Progress2", "installs"), |
| 398 | ("MaintenanceForm_Action", "Repair")]) |
| 399 | |
| 400 | # Fonts, see "TextStyle Table" |
| 401 | add_data(db, "TextStyle", |
| 402 | [("DlgFont8", "Tahoma", 9, None, 0), |
| 403 | ("DlgFontBold8", "Tahoma", 8, None, 1), #bold |
| 404 | ("VerdanaBold10", "Verdana", 10, None, 1), |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 405 | ("VerdanaRed9", "Verdana", 9, 255, 0), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 406 | ]) |
| 407 | |
Martin v. Löwis | e96ac3a | 2010-03-21 22:02:42 +0000 | [diff] [blame] | 408 | compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests" "[TARGETDIR]Lib"' |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 409 | lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"' |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 410 | # See "CustomAction Table" |
| 411 | add_data(db, "CustomAction", [ |
| 412 | # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty |
| 413 | # See "Custom Action Type 51", |
| 414 | # "Custom Action Execution Scheduling Options" |
| 415 | ("InitialTargetDir", 307, "TARGETDIR", |
| 416 | "[WindowsVolume]Python%s%s" % (major, minor)), |
| 417 | ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"), |
| 418 | ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName), |
| 419 | # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile |
| 420 | # See "Custom Action Type 18" |
Martin v. Löwis | 7b2563b | 2004-11-02 22:59:56 +0000 | [diff] [blame] | 421 | ("CompilePyc", 18, "python.exe", compileargs), |
| 422 | ("CompilePyo", 18, "python.exe", "-O "+compileargs), |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 423 | ("CompileGrammar", 18, "python.exe", lib2to3args), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 424 | ]) |
| 425 | |
| 426 | # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" |
| 427 | # Numbers indicate sequence; see sequence.py for how these action integrate |
| 428 | add_data(db, "InstallUISequence", |
| 429 | [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), |
| 430 | ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), |
| 431 | ("InitialTargetDir", 'TARGETDIR=""', 750), |
| 432 | # In the user interface, assume all-users installation if privileged. |
| 433 | ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), |
| 434 | ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), |
| 435 | ("SelectDirectoryDlg", "Not Installed", 1230), |
| 436 | # XXX no support for resume installations yet |
| 437 | #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), |
| 438 | ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), |
| 439 | ("ProgressDlg", None, 1280)]) |
| 440 | add_data(db, "AdminUISequence", |
| 441 | [("InitialTargetDir", 'TARGETDIR=""', 750), |
| 442 | ("SetDLLDirToTarget", 'DLLDIR=""', 751), |
| 443 | ]) |
| 444 | |
| 445 | # Execute Sequences |
| 446 | add_data(db, "InstallExecuteSequence", |
| 447 | [("InitialTargetDir", 'TARGETDIR=""', 750), |
| 448 | ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), |
| 449 | ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 450 | ("UpdateEditIDLE", None, 1050), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 451 | ("CompilePyc", "COMPILEALL", 6800), |
| 452 | ("CompilePyo", "COMPILEALL", 6801), |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 453 | ("CompileGrammar", "COMPILEALL", 6802), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 454 | ]) |
| 455 | add_data(db, "AdminExecuteSequence", |
| 456 | [("InitialTargetDir", 'TARGETDIR=""', 750), |
| 457 | ("SetDLLDirToTarget", 'DLLDIR=""', 751), |
| 458 | ("CompilePyc", "COMPILEALL", 6800), |
| 459 | ("CompilePyo", "COMPILEALL", 6801), |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 460 | ("CompileGrammar", "COMPILEALL", 6802), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 461 | ]) |
| 462 | |
| 463 | ##################################################################### |
| 464 | # Standard dialogs: FatalError, UserExit, ExitDialog |
| 465 | fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, |
| 466 | "Finish", "Finish", "Finish") |
| 467 | fatal.title("[ProductName] Installer ended prematurely") |
| 468 | fatal.back("< Back", "Finish", active = 0) |
| 469 | fatal.cancel("Cancel", "Back", active = 0) |
| 470 | fatal.text("Description1", 135, 70, 220, 80, 0x30003, |
| 471 | "[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.") |
| 472 | fatal.text("Description2", 135, 155, 220, 20, 0x30003, |
| 473 | "Click the Finish button to exit the Installer.") |
| 474 | c=fatal.next("Finish", "Cancel", name="Finish") |
| 475 | # See "ControlEvent Table". Parameters are the event, the parameter |
| 476 | # to the action, and optionally the condition for the event, and the order |
| 477 | # of events. |
| 478 | c.event("EndDialog", "Exit") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 479 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 480 | user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, |
| 481 | "Finish", "Finish", "Finish") |
| 482 | user_exit.title("[ProductName] Installer was interrupted") |
| 483 | user_exit.back("< Back", "Finish", active = 0) |
| 484 | user_exit.cancel("Cancel", "Back", active = 0) |
| 485 | user_exit.text("Description1", 135, 70, 220, 80, 0x30003, |
| 486 | "[ProductName] setup was interrupted. Your system has not been modified. " |
| 487 | "To install this program at a later time, please run the installation again.") |
| 488 | user_exit.text("Description2", 135, 155, 220, 20, 0x30003, |
| 489 | "Click the Finish button to exit the Installer.") |
| 490 | c = user_exit.next("Finish", "Cancel", name="Finish") |
| 491 | c.event("EndDialog", "Exit") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 492 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 493 | exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, |
| 494 | "Finish", "Finish", "Finish") |
| 495 | exit_dialog.title("Completing the [ProductName] Installer") |
| 496 | exit_dialog.back("< Back", "Finish", active = 0) |
| 497 | exit_dialog.cancel("Cancel", "Back", active = 0) |
Martin v. Löwis | 2dd2a28 | 2004-08-22 17:10:12 +0000 | [diff] [blame] | 498 | exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003, |
| 499 | "Special Windows thanks to:\n" |
Martin v. Löwis | d3f61a2 | 2004-08-30 09:22:30 +0000 | [diff] [blame] | 500 | " Mark Hammond, without whose years of freely \n" |
| 501 | " shared Windows expertise, Python for Windows \n" |
| 502 | " would still be Python for DOS.") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 503 | |
Martin v. Löwis | 8c7c56e | 2006-03-05 14:04:26 +0000 | [diff] [blame] | 504 | c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003, |
| 505 | "{\\VerdanaRed9}Warning: Python 2.5.x is the last " |
| 506 | "Python release for Windows 9x.") |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 507 | c.condition("Hide", "NOT Version9X") |
Martin v. Löwis | 8c7c56e | 2006-03-05 14:04:26 +0000 | [diff] [blame] | 508 | |
Martin v. Löwis | 2dd2a28 | 2004-08-22 17:10:12 +0000 | [diff] [blame] | 509 | exit_dialog.text("Description", 135, 235, 220, 20, 0x30003, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 510 | "Click the Finish button to exit the Installer.") |
| 511 | c = exit_dialog.next("Finish", "Cancel", name="Finish") |
| 512 | c.event("EndDialog", "Return") |
| 513 | |
| 514 | ##################################################################### |
| 515 | # Required dialog: FilesInUse, ErrorDlg |
| 516 | inuse = PyDialog(db, "FilesInUse", |
| 517 | x, y, w, h, |
| 518 | 19, # KeepModeless|Modal|Visible |
| 519 | title, |
| 520 | "Retry", "Retry", "Retry", bitmap=False) |
| 521 | inuse.text("Title", 15, 6, 200, 15, 0x30003, |
| 522 | r"{\DlgFontBold8}Files in Use") |
| 523 | inuse.text("Description", 20, 23, 280, 20, 0x30003, |
| 524 | "Some files that need to be updated are currently in use.") |
| 525 | inuse.text("Text", 20, 55, 330, 50, 3, |
| 526 | "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.") |
| 527 | inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", |
| 528 | None, None, None) |
| 529 | c=inuse.back("Exit", "Ignore", name="Exit") |
| 530 | c.event("EndDialog", "Exit") |
| 531 | c=inuse.next("Ignore", "Retry", name="Ignore") |
| 532 | c.event("EndDialog", "Ignore") |
| 533 | c=inuse.cancel("Retry", "Exit", name="Retry") |
| 534 | c.event("EndDialog","Retry") |
| 535 | |
| 536 | |
| 537 | # See "Error Dialog". See "ICE20" for the required names of the controls. |
| 538 | error = Dialog(db, "ErrorDlg", |
| 539 | 50, 10, 330, 101, |
| 540 | 65543, # Error|Minimize|Modal|Visible |
| 541 | title, |
| 542 | "ErrorText", None, None) |
| 543 | error.text("ErrorText", 50,9,280,48,3, "") |
| 544 | error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) |
| 545 | error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") |
| 546 | error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") |
| 547 | error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") |
| 548 | error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") |
| 549 | error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") |
| 550 | error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") |
| 551 | error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") |
| 552 | |
| 553 | ##################################################################### |
| 554 | # Global "Query Cancel" dialog |
| 555 | cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, |
| 556 | "No", "No", "No") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 557 | cancel.text("Text", 48, 15, 194, 30, 3, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 558 | "Are you sure you want to cancel [ProductName] installation?") |
| 559 | cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, |
| 560 | "py.ico", None, None) |
| 561 | c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") |
| 562 | c.event("EndDialog", "Exit") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 563 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 564 | c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") |
| 565 | c.event("EndDialog", "Return") |
| 566 | |
| 567 | ##################################################################### |
| 568 | # Global "Wait for costing" dialog |
| 569 | costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, |
| 570 | "Return", "Return", "Return") |
| 571 | costing.text("Text", 48, 15, 194, 30, 3, |
| 572 | "Please wait while the installer finishes determining your disk space requirements.") |
| 573 | costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, |
| 574 | "py.ico", None, None) |
| 575 | c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) |
| 576 | c.event("EndDialog", "Exit") |
| 577 | |
| 578 | ##################################################################### |
| 579 | # Preparation dialog: no user input except cancellation |
| 580 | prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, |
| 581 | "Cancel", "Cancel", "Cancel") |
| 582 | prep.text("Description", 135, 70, 220, 40, 0x30003, |
| 583 | "Please wait while the Installer prepares to guide you through the installation.") |
| 584 | prep.title("Welcome to the [ProductName] Installer") |
| 585 | c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...") |
| 586 | c.mapping("ActionText", "Text") |
| 587 | c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None) |
| 588 | c.mapping("ActionData", "Text") |
| 589 | prep.back("Back", None, active=0) |
| 590 | prep.next("Next", None, active=0) |
| 591 | c=prep.cancel("Cancel", None) |
| 592 | c.event("SpawnDialog", "CancelDlg") |
| 593 | |
| 594 | ##################################################################### |
| 595 | # Target directory selection |
| 596 | seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title, |
| 597 | "Next", "Next", "Cancel") |
| 598 | seldlg.title("Select Destination Directory") |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 599 | c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003, |
| 600 | "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.") |
| 601 | c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""') |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 602 | seldlg.text("Description", 135, 50, 220, 40, 0x30003, |
| 603 | "Please select a directory for the [ProductName] files.") |
| 604 | |
| 605 | seldlg.back("< Back", None, active=0) |
| 606 | c = seldlg.next("Next >", "Cancel") |
| 607 | c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1) |
| 608 | # If the target exists, but we found that we are going to remove old versions, don't bother |
| 609 | # confirming that the target directory exists. Strictly speaking, we should determine that |
| 610 | # the target directory is indeed the target of the product that we are going to remove, but |
| 611 | # I don't know how to do that. |
| 612 | c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2) |
| 613 | c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3) |
| 614 | c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4) |
| 615 | c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5) |
| 616 | |
| 617 | c = seldlg.cancel("Cancel", "DirectoryCombo") |
| 618 | c.event("SpawnDialog", "CancelDlg") |
| 619 | |
| 620 | seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219, |
| 621 | "TARGETDIR", None, "DirectoryList", None) |
| 622 | seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR", |
| 623 | None, "PathEdit", None) |
| 624 | seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None) |
| 625 | c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None) |
| 626 | c.event("DirectoryListUp", "0") |
| 627 | c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None) |
| 628 | c.event("DirectoryListNew", "0") |
| 629 | |
| 630 | ##################################################################### |
| 631 | # SelectFeaturesDlg |
| 632 | features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space, |
| 633 | title, "Tree", "Next", "Cancel") |
| 634 | features.title("Customize [ProductName]") |
| 635 | features.text("Description", 135, 35, 220, 15, 0x30003, |
| 636 | "Select the way you want features to be installed.") |
| 637 | features.text("Text", 135,45,220,30, 3, |
| 638 | "Click on the icons in the tree below to change the way features will be installed.") |
| 639 | |
| 640 | c=features.back("< Back", "Next") |
| 641 | c.event("NewDialog", "SelectDirectoryDlg") |
| 642 | |
| 643 | c=features.next("Next >", "Cancel") |
| 644 | c.mapping("SelectionNoItems", "Enabled") |
| 645 | c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1) |
| 646 | c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2) |
| 647 | |
| 648 | c=features.cancel("Cancel", "Tree") |
| 649 | c.event("SpawnDialog", "CancelDlg") |
| 650 | |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 651 | # The browse property is not used, since we have only a single target path (selected already) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 652 | features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty", |
| 653 | "Tree of selections", "Back", None) |
| 654 | |
| 655 | #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost") |
| 656 | #c.mapping("SelectionNoItems", "Enabled") |
| 657 | #c.event("Reset", "0") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 658 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 659 | features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None) |
| 660 | |
| 661 | c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10) |
| 662 | c.mapping("SelectionNoItems","Enabled") |
| 663 | c.event("SpawnDialog", "DiskCostDlg") |
| 664 | |
| 665 | c=features.xbutton("Advanced", "Advanced", None, 0.30) |
| 666 | c.event("SpawnDialog", "AdvancedDlg") |
| 667 | |
| 668 | c=features.text("ItemDescription", 140, 180, 210, 30, 3, |
| 669 | "Multiline description of the currently selected item.") |
| 670 | c.mapping("SelectionDescription","Text") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 671 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 672 | c=features.text("ItemSize", 140, 210, 210, 45, 3, |
| 673 | "The size of the currently selected item.") |
| 674 | c.mapping("SelectionSize", "Text") |
| 675 | |
| 676 | ##################################################################### |
| 677 | # Disk cost |
| 678 | cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, |
| 679 | "OK", "OK", "OK", bitmap=False) |
| 680 | cost.text("Title", 15, 6, 200, 15, 0x30003, |
| 681 | "{\DlgFontBold8}Disk Space Requirements") |
| 682 | cost.text("Description", 20, 20, 280, 20, 0x30003, |
| 683 | "The disk space required for the installation of the selected features.") |
| 684 | cost.text("Text", 20, 53, 330, 60, 3, |
| 685 | "The highlighted volumes (if any) do not have enough disk space " |
| 686 | "available for the currently selected features. You can either " |
| 687 | "remove some files from the highlighted volumes, or choose to " |
| 688 | "install less features onto local drive(s), or select different " |
| 689 | "destination drive(s).") |
| 690 | cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, |
| 691 | None, "{120}{70}{70}{70}{70}", None, None) |
| 692 | cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") |
| 693 | |
| 694 | ##################################################################### |
| 695 | # WhichUsers Dialog. Only available on NT, and for privileged users. |
| 696 | # This must be run before FindRelatedProducts, because that will |
| 697 | # take into account whether the previous installation was per-user |
| 698 | # or per-machine. We currently don't support going back to this |
| 699 | # dialog after "Next" was selected; to support this, we would need to |
| 700 | # find how to reset the ALLUSERS property, and how to re-run |
| 701 | # FindRelatedProducts. |
| 702 | # On Windows9x, the ALLUSERS property is ignored on the command line |
| 703 | # and in the Property table, but installer fails according to the documentation |
| 704 | # if a dialog attempts to set ALLUSERS. |
| 705 | whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, |
| 706 | "AdminInstall", "Next", "Cancel") |
| 707 | whichusers.title("Select whether to install [ProductName] for all users of this computer.") |
| 708 | # A radio group with two options: allusers, justme |
Martin v. Löwis | f63921f | 2008-10-13 11:30:30 +0000 | [diff] [blame] | 709 | g = whichusers.radiogroup("AdminInstall", 135, 60, 235, 80, 3, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 710 | "WhichUsers", "", "Next") |
Martin v. Löwis | f63921f | 2008-10-13 11:30:30 +0000 | [diff] [blame] | 711 | g.condition("Disable", "VersionNT=600") # Not available on Vista and Windows 2008 |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 712 | g.add("ALL", 0, 5, 150, 20, "Install for all users") |
Martin v. Löwis | f63921f | 2008-10-13 11:30:30 +0000 | [diff] [blame] | 713 | g.add("JUSTME", 0, 25, 235, 20, "Install just for me (not available on Windows Vista)") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 714 | |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 715 | whichusers.back("Back", None, active=0) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 716 | |
| 717 | c = whichusers.next("Next >", "Cancel") |
| 718 | c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) |
| 719 | c.event("EndDialog", "Return", order = 2) |
| 720 | |
| 721 | c = whichusers.cancel("Cancel", "AdminInstall") |
| 722 | c.event("SpawnDialog", "CancelDlg") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 723 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 724 | ##################################################################### |
| 725 | # Advanced Dialog. |
| 726 | advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title, |
Martin v. Löwis | a632a75 | 2008-11-19 13:55:07 +0000 | [diff] [blame] | 727 | "CompilePyc", "Ok", "Ok") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 728 | advanced.title("Advanced Options for [ProductName]") |
| 729 | # A radio group with two options: allusers, justme |
| 730 | advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3, |
Martin v. Löwis | a632a75 | 2008-11-19 13:55:07 +0000 | [diff] [blame] | 731 | "COMPILEALL", "Compile .py files to byte code after installation", "Ok") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 732 | |
Martin v. Löwis | a632a75 | 2008-11-19 13:55:07 +0000 | [diff] [blame] | 733 | c = advanced.cancel("Ok", "CompilePyc", name="Ok") # Button just has location of cancel button. |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 734 | c.event("EndDialog", "Return") |
| 735 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 736 | ##################################################################### |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 737 | # Existing Directory dialog |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 738 | dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title, |
| 739 | "No", "No", "No") |
| 740 | dlg.text("Title", 10, 20, 180, 40, 3, |
| 741 | "[TARGETDIR] exists. Are you sure you want to overwrite existing files?") |
| 742 | c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No") |
| 743 | c.event("[TargetExists]", "0", order=1) |
| 744 | c.event("[TargetExistsOk]", "1", order=2) |
| 745 | c.event("EndDialog", "Return", order=3) |
| 746 | c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes") |
| 747 | c.event("EndDialog", "Return") |
| 748 | |
| 749 | ##################################################################### |
| 750 | # Installation Progress dialog (modeless) |
| 751 | progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, |
| 752 | "Cancel", "Cancel", "Cancel", bitmap=False) |
| 753 | progress.text("Title", 20, 15, 200, 15, 0x30003, |
| 754 | "{\DlgFontBold8}[Progress1] [ProductName]") |
| 755 | progress.text("Text", 35, 65, 300, 30, 3, |
| 756 | "Please wait while the Installer [Progress2] [ProductName]. " |
| 757 | "This may take several minutes.") |
| 758 | progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") |
| 759 | |
| 760 | c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") |
| 761 | c.mapping("ActionText", "Text") |
| 762 | |
| 763 | #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) |
| 764 | #c.mapping("ActionData", "Text") |
| 765 | |
| 766 | c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, |
| 767 | None, "Progress done", None, None) |
| 768 | c.mapping("SetProgress", "Progress") |
| 769 | |
| 770 | progress.back("< Back", "Next", active=False) |
| 771 | progress.next("Next >", "Cancel", active=False) |
| 772 | progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg") |
| 773 | |
| 774 | # Maintenance type: repair/uninstall |
| 775 | maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, |
| 776 | "Next", "Next", "Cancel") |
| 777 | maint.title("Welcome to the [ProductName] Setup Wizard") |
| 778 | maint.text("BodyText", 135, 63, 230, 42, 3, |
| 779 | "Select whether you want to repair or remove [ProductName].") |
| 780 | g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3, |
| 781 | "MaintenanceForm_Action", "", "Next") |
| 782 | g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") |
| 783 | g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") |
| 784 | g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 785 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 786 | maint.back("< Back", None, active=False) |
| 787 | c=maint.next("Finish", "Cancel") |
| 788 | # Change installation: Change progress dialog to "Change", then ask |
| 789 | # for feature selection |
| 790 | c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) |
| 791 | c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) |
| 792 | |
| 793 | # Reinstall: Change progress dialog to "Repair", then invoke reinstall |
| 794 | # Also set list of reinstalled features to "ALL" |
| 795 | c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5) |
| 796 | c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6) |
Raymond Hettinger | 72f0801 | 2004-11-07 07:08:25 +0000 | [diff] [blame] | 797 | c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 798 | c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8) |
| 799 | |
| 800 | # Uninstall: Change progress to "Remove", then invoke uninstall |
| 801 | # Also set list of removed features to "ALL" |
| 802 | c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11) |
| 803 | c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12) |
| 804 | c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13) |
| 805 | c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14) |
| 806 | |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 807 | # Close dialog when maintenance action scheduled |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 808 | c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) |
| 809 | c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 810 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 811 | maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 812 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 813 | |
| 814 | # See "Feature Table". The feature level is 1 for all features, |
| 815 | # and the feature attributes are 0 for the DefaultFeature, and |
| 816 | # FollowParent for all other features. The numbers are the Display |
| 817 | # column. |
| 818 | def add_features(db): |
| 819 | # feature attributes: |
| 820 | # msidbFeatureAttributesFollowParent == 2 |
| 821 | # msidbFeatureAttributesDisallowAdvertise == 8 |
| 822 | # Features that need to be installed with together with the main feature |
| 823 | # (i.e. additional Python libraries) need to follow the parent feature. |
| 824 | # Features that have no advertisement trigger (e.g. the test suite) |
| 825 | # must not support advertisement |
Martin v. Löwis | 21c80f2 | 2008-04-07 21:14:19 +0000 | [diff] [blame] | 826 | global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 827 | default_feature = Feature(db, "DefaultFeature", "Python", |
| 828 | "Python Interpreter and Libraries", |
| 829 | 1, directory = "TARGETDIR") |
Martin v. Löwis | 2a241ca | 2008-04-05 18:58:09 +0000 | [diff] [blame] | 830 | shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0, |
| 831 | level=0) |
| 832 | private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0, |
| 833 | level=0) |
| 834 | add_data(db, "Condition", [("SharedCRT", 1, sys32cond), |
| 835 | ("PrivateCRT", 1, "not "+sys32cond)]) |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 836 | # We don't support advertisement of extensions |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 837 | ext_feature = Feature(db, "Extensions", "Register Extensions", |
| 838 | "Make this Python installation the default Python installation", 3, |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 839 | parent = default_feature, attributes=2|8) |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 840 | if have_tcl: |
| 841 | tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 842 | parent = default_feature, attributes=2) |
| 843 | htmlfiles = Feature(db, "Documentation", "Documentation", |
| 844 | "Python HTMLHelp File", 7, parent = default_feature) |
| 845 | tools = Feature(db, "Tools", "Utility Scripts", |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 846 | "Python utility scripts (Tools/", 9, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 847 | parent = default_feature, attributes=2) |
| 848 | testsuite = Feature(db, "Testsuite", "Test suite", |
| 849 | "Python test suite (Lib/test/)", 11, |
| 850 | parent = default_feature, attributes=2|8) |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 851 | |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 852 | def extract_msvcr90(): |
Martin v. Löwis | ee7498e | 2008-02-28 23:01:33 +0000 | [diff] [blame] | 853 | # Find the redistributable files |
Martin v. Löwis | 8a2e90e | 2008-09-19 19:21:20 +0000 | [diff] [blame] | 854 | if msilib.Win64: |
| 855 | arch = "amd64" |
| 856 | else: |
| 857 | arch = "x86" |
| 858 | dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC90.CRT" % arch) |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 859 | |
Christian Heimes | e1feb2e | 2008-02-28 20:52:40 +0000 | [diff] [blame] | 860 | result = [] |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 861 | installer = msilib.MakeInstaller() |
Christian Heimes | e1feb2e | 2008-02-28 20:52:40 +0000 | [diff] [blame] | 862 | # omit msvcm90 and msvcp90, as they aren't really needed |
| 863 | files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"] |
| 864 | for f in files: |
| 865 | path = os.path.join(dir, f) |
| 866 | kw = {'src':path} |
| 867 | if f.endswith('.dll'): |
| 868 | kw['version'] = installer.FileVersion(path, 0) |
| 869 | kw['language'] = installer.FileVersion(path, 1) |
| 870 | result.append((f, kw)) |
| 871 | return result |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 872 | |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 873 | def generate_license(): |
| 874 | import shutil, glob |
| 875 | out = open("LICENSE.txt", "w") |
| 876 | shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out) |
Martin v. Löwis | b29f2d7 | 2008-09-14 20:27:52 +0000 | [diff] [blame] | 877 | shutil.copyfileobj(open("crtlicense.txt"), out) |
Martin v. Löwis | f38e0d0 | 2008-06-13 14:11:59 +0000 | [diff] [blame] | 878 | for name, pat, file in (("bzip2","bzip2-*", "LICENSE"), |
| 879 | ("Berkeley DB", "db-*", "LICENSE"), |
| 880 | ("openssl", "openssl-*", "LICENSE"), |
| 881 | ("Tcl", "tcl8*", "license.terms"), |
| 882 | ("Tk", "tk8*", "license.terms"), |
| 883 | ("Tix", "tix-*", "license.terms")): |
| 884 | out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name) |
| 885 | dirs = glob.glob(srcdir+"/../"+pat) |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 886 | if not dirs: |
Martin v. Löwis | f38e0d0 | 2008-06-13 14:11:59 +0000 | [diff] [blame] | 887 | raise ValueError, "Could not find "+srcdir+"/../"+pat |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 888 | if len(dirs) > 2: |
Martin v. Löwis | f38e0d0 | 2008-06-13 14:11:59 +0000 | [diff] [blame] | 889 | raise ValueError, "Multiple copies of "+pat |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 890 | dir = dirs[0] |
| 891 | shutil.copyfileobj(open(os.path.join(dir, file)), out) |
| 892 | out.close() |
| 893 | |
| 894 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 895 | class PyDirectory(Directory): |
| 896 | """By default, all components in the Python installer |
| 897 | can run from source.""" |
| 898 | def __init__(self, *args, **kw): |
Georg Brandl | bf82e37 | 2008-05-16 17:02:34 +0000 | [diff] [blame] | 899 | if "componentflags" not in kw: |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 900 | kw['componentflags'] = 2 #msidbComponentAttributesOptional |
| 901 | Directory.__init__(self, *args, **kw) |
| 902 | |
| 903 | # See "File Table", "Component Table", "Directory Table", |
| 904 | # "FeatureComponents Table" |
| 905 | def add_files(db): |
| 906 | cab = CAB("python") |
| 907 | tmpfiles = [] |
| 908 | # Add all executables, icons, text files into the TARGETDIR component |
| 909 | root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir") |
| 910 | default_feature.set_current() |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 911 | if not msilib.Win64: |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 912 | root.add_file("%s/w9xpopen.exe" % PCBUILD) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 913 | root.add_file("README.txt", src="README") |
| 914 | root.add_file("NEWS.txt", src="Misc/NEWS") |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 915 | generate_license() |
| 916 | root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt")) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 917 | root.start_component("python.exe", keyfile="python.exe") |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 918 | root.add_file("%s/python.exe" % PCBUILD) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 919 | root.start_component("pythonw.exe", keyfile="pythonw.exe") |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 920 | root.add_file("%s/pythonw.exe" % PCBUILD) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 921 | |
| 922 | # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table" |
Martin v. Löwis | c820eaf | 2008-10-17 13:47:20 +0000 | [diff] [blame] | 923 | dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".") |
Christian Heimes | e1feb2e | 2008-02-28 20:52:40 +0000 | [diff] [blame] | 924 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 925 | pydll = "python%s%s.dll" % (major, minor) |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 926 | pydllsrc = os.path.join(srcdir, PCBUILD, pydll) |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 927 | dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 928 | installer = msilib.MakeInstaller() |
| 929 | pyversion = installer.FileVersion(pydllsrc, 0) |
| 930 | if not snapshot: |
| 931 | # For releases, the Python DLL has the same version as the |
| 932 | # installer package. |
| 933 | assert pyversion.split(".")[:3] == current_version.split(".") |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 934 | dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 935 | version=pyversion, |
| 936 | language=installer.FileVersion(pydllsrc, 1)) |
Christian Heimes | e1feb2e | 2008-02-28 20:52:40 +0000 | [diff] [blame] | 937 | DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs") |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 938 | |
Martin v. Löwis | 21c80f2 | 2008-04-07 21:14:19 +0000 | [diff] [blame] | 939 | # msvcr90.dll: Need to place the DLL and the manifest into the root directory, |
| 940 | # plus another copy of the manifest in the DLLs directory, with the manifest |
| 941 | # pointing to the root directory |
| 942 | root.start_component("msvcr90", feature=private_crt) |
| 943 | # Results are ID,keyword pairs |
| 944 | manifest, crtdll = extract_msvcr90() |
| 945 | root.add_file(manifest[0], **manifest[1]) |
| 946 | root.add_file(crtdll[0], **crtdll[1]) |
| 947 | # Copy the manifest |
Martin v. Löwis | 9184556 | 2008-11-06 19:46:56 +0000 | [diff] [blame] | 948 | # Actually, don't do that anymore - no DLL in DLLs should have a manifest |
| 949 | # dependency on msvcr90.dll anymore, so this should not be necessary |
| 950 | #manifest_dlls = manifest[0]+".root" |
| 951 | #open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr")) |
| 952 | #DLLs.start_component("msvcr90_dlls", feature=private_crt) |
| 953 | #DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls)) |
Martin v. Löwis | 21c80f2 | 2008-04-07 21:14:19 +0000 | [diff] [blame] | 954 | |
| 955 | # Now start the main component for the DLLs directory; |
| 956 | # no regular files have been added to the directory yet. |
| 957 | DLLs.start_component() |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 958 | |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 959 | # Check if _ctypes.pyd exists |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 960 | have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD) |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 961 | if not have_ctypes: |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 962 | print("WARNING: _ctypes.pyd not found, ctypes will not be included") |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 963 | extensions.remove("_ctypes.pyd") |
| 964 | |
Georg Brandl | 6e47a33 | 2008-05-17 19:15:58 +0000 | [diff] [blame] | 965 | # Add all .py files in Lib, except tkinter, test |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 966 | dirs={} |
| 967 | pydirs = [(root,"Lib")] |
| 968 | while pydirs: |
Martin v. Löwis | 94b8b82 | 2008-06-13 19:00:35 +0000 | [diff] [blame] | 969 | # Commit every now and then, or else installer will complain |
| 970 | db.Commit() |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 971 | parent, dir = pydirs.pop() |
Martin v. Löwis | 9ca9f56 | 2006-01-03 06:29:53 +0000 | [diff] [blame] | 972 | if dir == ".svn" or dir.startswith("plat-"): |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 973 | continue |
Georg Brandl | 6e47a33 | 2008-05-17 19:15:58 +0000 | [diff] [blame] | 974 | elif dir in ["tkinter", "idlelib", "Icons"]: |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 975 | if not have_tcl: |
| 976 | continue |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 977 | tcltk.set_current() |
Martin v. Löwis | 5c9e55e | 2004-12-30 14:08:18 +0000 | [diff] [blame] | 978 | elif dir in ['test', 'tests', 'data', 'output']: |
Amaury Forgeot d'Arc | f7bfcfb | 2008-09-09 06:42:00 +0000 | [diff] [blame] | 979 | # test: Lib, Lib/email, Lib/ctypes, Lib/sqlite3 |
Martin v. Löwis | 5c9e55e | 2004-12-30 14:08:18 +0000 | [diff] [blame] | 980 | # tests: Lib/distutils |
| 981 | # data: Lib/email/test |
| 982 | # output: Lib/test |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 983 | testsuite.set_current() |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 984 | elif not have_ctypes and dir == "ctypes": |
| 985 | continue |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 986 | else: |
| 987 | default_feature.set_current() |
| 988 | lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir)) |
| 989 | # Add additional files |
| 990 | dirs[dir]=lib |
| 991 | lib.glob("*.txt") |
| 992 | if dir=='site-packages': |
Martin v. Löwis | 6d60c09 | 2004-11-21 10:16:26 +0000 | [diff] [blame] | 993 | lib.add_file("README.txt", src="README") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 994 | continue |
| 995 | files = lib.glob("*.py") |
| 996 | files += lib.glob("*.pyw") |
| 997 | if files: |
| 998 | # Add an entry to the RemoveFile table to remove bytecode files. |
| 999 | lib.remove_pyc() |
Thomas Wouters | 3fc2ca3 | 2006-04-21 11:28:17 +0000 | [diff] [blame] | 1000 | if dir.endswith('.egg-info'): |
| 1001 | lib.add_file('entry_points.txt') |
| 1002 | lib.add_file('PKG-INFO') |
| 1003 | lib.add_file('top_level.txt') |
| 1004 | lib.add_file('zip-safe') |
| 1005 | continue |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1006 | if dir=='test' and parent.physical=='Lib': |
| 1007 | lib.add_file("185test.db") |
| 1008 | lib.add_file("audiotest.au") |
| 1009 | lib.add_file("cfgparser.1") |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 1010 | lib.add_file("sgml_input.html") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1011 | lib.add_file("test.xml") |
| 1012 | lib.add_file("test.xml.out") |
| 1013 | lib.add_file("testtar.tar") |
Martin v. Löwis | 7d3755d | 2004-09-06 06:31:12 +0000 | [diff] [blame] | 1014 | lib.add_file("test_difflib_expect.html") |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 1015 | lib.add_file("check_soundcard.vbs") |
| 1016 | lib.add_file("empty.vbs") |
Martin v. Löwis | bb6db34 | 2009-06-01 04:12:01 +0000 | [diff] [blame] | 1017 | lib.add_file("Sine-1000Hz-300ms.aif") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1018 | lib.glob("*.uue") |
Christian Heimes | 5d14c2b | 2007-11-20 23:38:09 +0000 | [diff] [blame] | 1019 | lib.glob("*.pem") |
Christian Heimes | cbf3b5c | 2007-12-03 21:02:03 +0000 | [diff] [blame] | 1020 | lib.glob("*.pck") |
Martin v. Löwis | 270a9ce | 2009-04-04 18:48:39 +0000 | [diff] [blame] | 1021 | lib.add_file("zipdir.zip") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1022 | if dir=='decimaltestdata': |
| 1023 | lib.glob("*.decTest") |
| 1024 | if dir=='output': |
| 1025 | lib.glob("test_*") |
| 1026 | if dir=='idlelib': |
| 1027 | lib.glob("*.def") |
| 1028 | lib.add_file("idle.bat") |
| 1029 | if dir=="Icons": |
| 1030 | lib.glob("*.gif") |
| 1031 | lib.add_file("idle.icns") |
Thomas Wouters | 3fc2ca3 | 2006-04-21 11:28:17 +0000 | [diff] [blame] | 1032 | if dir=="command" and parent.physical=="distutils": |
Martin v. Löwis | 5680d0c | 2008-04-10 03:06:53 +0000 | [diff] [blame] | 1033 | lib.glob("wininst*.exe") |
Thomas Wouters | 3fc2ca3 | 2006-04-21 11:28:17 +0000 | [diff] [blame] | 1034 | if dir=="setuptools": |
| 1035 | lib.add_file("cli.exe") |
| 1036 | lib.add_file("gui.exe") |
Martin v. Löwis | 90cc5ab | 2008-06-02 10:04:16 +0000 | [diff] [blame] | 1037 | if dir=="lib2to3": |
| 1038 | lib.removefile("pickle", "*.pickle") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1039 | if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email": |
Martin v. Löwis | 9ca9f56 | 2006-01-03 06:29:53 +0000 | [diff] [blame] | 1040 | # This should contain all non-.svn files listed in subversion |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1041 | for f in os.listdir(lib.absolute): |
Martin v. Löwis | 9ca9f56 | 2006-01-03 06:29:53 +0000 | [diff] [blame] | 1042 | if f.endswith(".txt") or f==".svn":continue |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1043 | if f.endswith(".au") or f.endswith(".gif"): |
| 1044 | lib.add_file(f) |
| 1045 | else: |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 1046 | print("WARNING: New file %s in email/test/data" % f) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1047 | for f in os.listdir(lib.absolute): |
| 1048 | if os.path.isdir(os.path.join(lib.absolute, f)): |
| 1049 | pydirs.append((lib, f)) |
| 1050 | # Add DLLs |
| 1051 | default_feature.set_current() |
Christian Heimes | e1feb2e | 2008-02-28 20:52:40 +0000 | [diff] [blame] | 1052 | lib = DLLs |
Christian Heimes | d9a4d1d | 2008-01-01 14:42:15 +0000 | [diff] [blame] | 1053 | lib.add_file("py.ico", src=srcdir+"/PC/py.ico") |
| 1054 | lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1055 | dlls = [] |
| 1056 | tclfiles = [] |
| 1057 | for f in extensions: |
| 1058 | if f=="_tkinter.pyd": |
| 1059 | continue |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 1060 | if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f): |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 1061 | print("WARNING: Missing extension", f) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1062 | continue |
| 1063 | dlls.append(f) |
| 1064 | lib.add_file(f) |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1065 | # Add sqlite |
| 1066 | if msilib.msi_type=="Intel64;1033": |
| 1067 | sqlite_arch = "/ia64" |
| 1068 | elif msilib.msi_type=="x64;1033": |
| 1069 | sqlite_arch = "/amd64" |
Martin v. Löwis | 20c892d | 2008-02-29 21:03:38 +0000 | [diff] [blame] | 1070 | tclsuffix = "64" |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1071 | else: |
| 1072 | sqlite_arch = "" |
Martin v. Löwis | 20c892d | 2008-02-29 21:03:38 +0000 | [diff] [blame] | 1073 | tclsuffix = "" |
Martin v. Löwis | 94b8b82 | 2008-06-13 19:00:35 +0000 | [diff] [blame] | 1074 | lib.add_file("sqlite3.dll") |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1075 | if have_tcl: |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 1076 | if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)): |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 1077 | print("WARNING: Missing _tkinter.pyd") |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1078 | else: |
| 1079 | lib.start_component("TkDLLs", tcltk) |
| 1080 | lib.add_file("_tkinter.pyd") |
| 1081 | dlls.append("_tkinter.pyd") |
Martin v. Löwis | 20c892d | 2008-02-29 21:03:38 +0000 | [diff] [blame] | 1082 | tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix)) |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1083 | for f in glob.glob1(tcldir, "*.dll"): |
| 1084 | lib.add_file(f, src=os.path.join(tcldir, f)) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1085 | # check whether there are any unknown extensions |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 1086 | for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"): |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1087 | if f.endswith("_d.pyd"): continue # debug version |
| 1088 | if f in dlls: continue |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 1089 | print("WARNING: Unknown extension", f) |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 1090 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1091 | # Add headers |
| 1092 | default_feature.set_current() |
| 1093 | lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include") |
| 1094 | lib.glob("*.h") |
| 1095 | lib.add_file("pyconfig.h", src="../PC/pyconfig.h") |
| 1096 | # Add import libraries |
Christian Heimes | 81ca7c7 | 2007-11-18 18:18:41 +0000 | [diff] [blame] | 1097 | lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1098 | for f in dlls: |
| 1099 | lib.add_file(f.replace('pyd','lib')) |
| 1100 | lib.add_file('python%s%s.lib' % (major, minor)) |
Martin v. Löwis | 9fda931 | 2004-12-22 13:41:49 +0000 | [diff] [blame] | 1101 | # Add the mingw-format library |
| 1102 | if have_mingw: |
Tim Peters | 5a9fb3c | 2005-01-07 16:01:32 +0000 | [diff] [blame] | 1103 | lib.add_file('libpython%s%s.a' % (major, minor)) |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1104 | if have_tcl: |
| 1105 | # Add Tcl/Tk |
Martin v. Löwis | 20c892d | 2008-02-29 21:03:38 +0000 | [diff] [blame] | 1106 | tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')] |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1107 | tcltk.set_current() |
| 1108 | while tcldirs: |
| 1109 | parent, phys, dir = tcldirs.pop() |
| 1110 | lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir)) |
| 1111 | if not os.path.exists(lib.absolute): |
| 1112 | continue |
| 1113 | for f in os.listdir(lib.absolute): |
| 1114 | if os.path.isdir(os.path.join(lib.absolute, f)): |
| 1115 | tcldirs.append((lib, f, f)) |
| 1116 | else: |
| 1117 | lib.add_file(f) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1118 | # Add tools |
| 1119 | tools.set_current() |
| 1120 | tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools") |
Martin v. Löwis | 3a72b25 | 2010-11-14 18:13:49 +0000 | [diff] [blame^] | 1121 | for f in ['i18n', 'pynche', 'Scripts', 'webchecker']: |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1122 | lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f)) |
| 1123 | lib.glob("*.py") |
| 1124 | lib.glob("*.pyw", exclude=['pydocgui.pyw']) |
| 1125 | lib.remove_pyc() |
| 1126 | lib.glob("*.txt") |
| 1127 | if f == "pynche": |
| 1128 | x = PyDirectory(db, cab, lib, "X", "X", "X|X") |
| 1129 | x.glob("*.txt") |
Martin v. Löwis | 4d930be | 2004-12-01 21:46:35 +0000 | [diff] [blame] | 1130 | if os.path.exists(os.path.join(lib.absolute, "README")): |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1131 | lib.add_file("README.txt", src="README") |
Martin v. Löwis | 4d930be | 2004-12-01 21:46:35 +0000 | [diff] [blame] | 1132 | if f == 'Scripts': |
Martin v. Löwis | fe21884 | 2008-10-01 11:22:32 +0000 | [diff] [blame] | 1133 | lib.add_file("2to3.py", src="2to3") |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1134 | if have_tcl: |
| 1135 | lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw") |
| 1136 | lib.add_file("pydocgui.pyw") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1137 | # Add documentation |
| 1138 | htmlfiles.set_current() |
| 1139 | lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc") |
Alexandre Vassalotti | 6461e10 | 2008-05-15 22:09:29 +0000 | [diff] [blame] | 1140 | lib.start_component("documentation", keyfile=docfile) |
| 1141 | lib.add_file(docfile, src="build/htmlhelp/"+docfile) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1142 | |
| 1143 | cab.commit(db) |
| 1144 | |
| 1145 | for f in tmpfiles: |
| 1146 | os.unlink(f) |
| 1147 | |
| 1148 | # See "Registry Table", "Component Table" |
| 1149 | def add_registry(db): |
| 1150 | # File extensions, associated with the REGISTRY.def component |
| 1151 | # IDLE verbs depend on the tcltk feature. |
| 1152 | # msidbComponentAttributesRegistryKeyPath = 4 |
| 1153 | # -1 for Root specifies "dependent on ALLUSERS property" |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1154 | tcldata = [] |
| 1155 | if have_tcl: |
| 1156 | tcldata = [ |
Martin v. Löwis | 283e35f | 2007-08-31 09:59:29 +0000 | [diff] [blame] | 1157 | ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None, |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1158 | "py.IDLE")] |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1159 | add_data(db, "Component", |
| 1160 | # msidbComponentAttributesRegistryKeyPath = 4 |
Martin v. Löwis | 283e35f | 2007-08-31 09:59:29 +0000 | [diff] [blame] | 1161 | [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None, |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1162 | "InstallPath"), |
Martin v. Löwis | 283e35f | 2007-08-31 09:59:29 +0000 | [diff] [blame] | 1163 | ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None, |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 1164 | "Documentation"), |
Martin v. Löwis | 283e35f | 2007-08-31 09:59:29 +0000 | [diff] [blame] | 1165 | ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component, |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1166 | None, None)] + tcldata) |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1167 | # See "FeatureComponents Table". |
| 1168 | # The association between TclTk and pythonw.exe is necessary to make ICE59 |
| 1169 | # happy, because the installer otherwise believes that the IDLE and PyDoc |
| 1170 | # shortcuts might get installed without pythonw.exe being install. This |
| 1171 | # is not true, since installing TclTk will install the default feature, which |
| 1172 | # will cause pythonw.exe to be installed. |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1173 | # REGISTRY.tcl is not associated with any feature, as it will be requested |
| 1174 | # through a custom action |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1175 | tcldata = [] |
| 1176 | if have_tcl: |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1177 | tcldata = [(tcltk.id, "pythonw.exe")] |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1178 | add_data(db, "FeatureComponents", |
| 1179 | [(default_feature.id, "REGISTRY"), |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 1180 | (htmlfiles.id, "REGISTRY.doc"), |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1181 | (ext_feature.id, "REGISTRY.def")] + |
| 1182 | tcldata |
| 1183 | ) |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1184 | # Extensions are not advertised. For advertised extensions, |
| 1185 | # we would need separate binaries that install along with the |
| 1186 | # extension. |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1187 | pat = r"Software\Classes\%sPython.%sFile\shell\%s\command" |
| 1188 | ewi = "Edit with IDLE" |
| 1189 | pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon" |
| 1190 | pat3 = r"Software\Classes\%sPython.%sFile" |
Martin v. Löwis | bfda544 | 2008-11-07 18:54:51 +0000 | [diff] [blame] | 1191 | pat4 = r"Software\Classes\%sPython.%sFile\shellex\DropHandler" |
Martin v. Löwis | eac02e6 | 2004-11-18 08:00:33 +0000 | [diff] [blame] | 1192 | tcl_verbs = [] |
| 1193 | if have_tcl: |
| 1194 | tcl_verbs=[ |
| 1195 | ("py.IDLE", -1, pat % (testprefix, "", ewi), "", |
Martin v. Löwis | 8482ef9 | 2009-05-05 16:14:30 +0000 | [diff] [blame] | 1196 | r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"', |
Martin v. Löwis | eac02e6 | 2004-11-18 08:00:33 +0000 | [diff] [blame] | 1197 | "REGISTRY.tcl"), |
| 1198 | ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "", |
Martin v. Löwis | 8482ef9 | 2009-05-05 16:14:30 +0000 | [diff] [blame] | 1199 | r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"', |
Martin v. Löwis | eac02e6 | 2004-11-18 08:00:33 +0000 | [diff] [blame] | 1200 | "REGISTRY.tcl"), |
| 1201 | ] |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1202 | add_data(db, "Registry", |
| 1203 | [# Extensions |
| 1204 | ("py.ext", -1, r"Software\Classes\."+ext, "", |
| 1205 | "Python.File", "REGISTRY.def"), |
| 1206 | ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "", |
| 1207 | "Python.NoConFile", "REGISTRY.def"), |
| 1208 | ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "", |
| 1209 | "Python.CompiledFile", "REGISTRY.def"), |
| 1210 | ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "", |
| 1211 | "Python.CompiledFile", "REGISTRY.def"), |
| 1212 | # MIME types |
| 1213 | ("py.mime", -1, r"Software\Classes\."+ext, "Content Type", |
| 1214 | "text/plain", "REGISTRY.def"), |
| 1215 | ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type", |
| 1216 | "text/plain", "REGISTRY.def"), |
| 1217 | #Verbs |
| 1218 | ("py.open", -1, pat % (testprefix, "", "open"), "", |
| 1219 | r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"), |
| 1220 | ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "", |
| 1221 | r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"), |
| 1222 | ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "", |
| 1223 | r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"), |
Martin v. Löwis | eac02e6 | 2004-11-18 08:00:33 +0000 | [diff] [blame] | 1224 | ] + tcl_verbs + [ |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1225 | #Icons |
| 1226 | ("py.icon", -1, pat2 % (testprefix, ""), "", |
Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1227 | r'[DLLs]py.ico', "REGISTRY.def"), |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1228 | ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "", |
Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1229 | r'[DLLs]py.ico', "REGISTRY.def"), |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1230 | ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "", |
Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1231 | r'[DLLs]pyc.ico', "REGISTRY.def"), |
Martin v. Löwis | dff68d0 | 2004-09-10 09:20:10 +0000 | [diff] [blame] | 1232 | # Descriptions |
| 1233 | ("py.txt", -1, pat3 % (testprefix, ""), "", |
| 1234 | "Python File", "REGISTRY.def"), |
| 1235 | ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "", |
| 1236 | "Python File (no console)", "REGISTRY.def"), |
| 1237 | ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "", |
| 1238 | "Compiled Python File", "REGISTRY.def"), |
Martin v. Löwis | bfda544 | 2008-11-07 18:54:51 +0000 | [diff] [blame] | 1239 | # Drop Handler |
| 1240 | ("py.drop", -1, pat4 % (testprefix, ""), "", |
| 1241 | "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"), |
| 1242 | ("pyw.drop", -1, pat4 % (testprefix, "NoCon"), "", |
| 1243 | "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"), |
| 1244 | ("pyc.drop", -1, pat4 % (testprefix, "Compiled"), "", |
| 1245 | "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1246 | ]) |
Tim Peters | 66cb018 | 2004-08-26 05:23:19 +0000 | [diff] [blame] | 1247 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1248 | # Registry keys |
| 1249 | prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version) |
| 1250 | add_data(db, "Registry", |
| 1251 | [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"), |
| 1252 | ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "", |
| 1253 | "Python %s" % short_version, "REGISTRY"), |
| 1254 | ("PythonPath", -1, prefix+r"\PythonPath", "", |
Georg Brandl | 6e47a33 | 2008-05-17 19:15:58 +0000 | [diff] [blame] | 1255 | r"[TARGETDIR]Lib;[TARGETDIR]DLLs", "REGISTRY"), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1256 | ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "", |
Alexandre Vassalotti | 6461e10 | 2008-05-15 22:09:29 +0000 | [diff] [blame] | 1257 | "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1258 | ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"), |
| 1259 | ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe", |
Martin v. Löwis | 45a6b9f | 2008-11-30 11:12:00 +0000 | [diff] [blame] | 1260 | "", r"[TARGETDIR]Python.exe", "REGISTRY.def"), |
| 1261 | ("DisplayIcon", -1, |
| 1262 | r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code, |
Martin v. Löwis | 9d49c1d | 2009-06-28 09:40:34 +0000 | [diff] [blame] | 1263 | "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY") |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1264 | ]) |
| 1265 | # Shortcuts, see "Shortcut Table" |
| 1266 | add_data(db, "Directory", |
| 1267 | [("ProgramMenuFolder", "TARGETDIR", "."), |
| 1268 | ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))]) |
| 1269 | add_data(db, "RemoveFile", |
| 1270 | [("MenuDir", "TARGETDIR", None, "MenuDir", 2)]) |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1271 | tcltkshortcuts = [] |
| 1272 | if have_tcl: |
| 1273 | tcltkshortcuts = [ |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1274 | ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe", |
Martin v. Löwis | ac191da | 2004-12-22 12:55:44 +0000 | [diff] [blame] | 1275 | tcltk.id, r'"[TARGETDIR]Lib\idlelib\idle.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1276 | ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe", |
Martin v. Löwis | ac191da | 2004-12-22 12:55:44 +0000 | [diff] [blame] | 1277 | tcltk.id, r'"[TARGETDIR]Tools\scripts\pydocgui.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"), |
Martin v. Löwis | e0f780d | 2004-09-01 14:51:06 +0000 | [diff] [blame] | 1278 | ] |
| 1279 | add_data(db, "Shortcut", |
| 1280 | tcltkshortcuts + |
| 1281 | [# Advertised shortcuts: targets are features, not files |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1282 | ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe", |
| 1283 | default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"), |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 1284 | # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an |
| 1285 | # icon first. |
| 1286 | #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation", |
| 1287 | # htmlfiles.id, None, None, None, None, None, None, None), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1288 | ## Non-advertised shortcuts: must be associated with a registry component |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 1289 | ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc", |
Alexandre Vassalotti | 6461e10 | 2008-05-15 22:09:29 +0000 | [diff] [blame] | 1290 | "[#%s]" % docfile, None, |
Martin v. Löwis | 141f41a | 2005-03-15 00:39:40 +0000 | [diff] [blame] | 1291 | None, None, None, None, None, None), |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1292 | ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY", |
| 1293 | SystemFolderName+"msiexec", "/x%s" % product_code, |
| 1294 | None, None, None, None, None, None), |
| 1295 | ]) |
| 1296 | db.Commit() |
| 1297 | |
Martin v. Löwis | 3a72b25 | 2010-11-14 18:13:49 +0000 | [diff] [blame^] | 1298 | def build_pdbzip(): |
| 1299 | pdbexclude = ['kill_python.pdb', 'make_buildinfo.pdb', |
| 1300 | 'make_versioninfo.pdb'] |
| 1301 | path = "python-%s%s-pdb.zip" % (full_current_version, msilib.arch_ext) |
| 1302 | pdbzip = zipfile.ZipFile(path, 'w') |
| 1303 | for f in glob.glob1(os.path.join(srcdir, PCBUILD), "*.pdb"): |
| 1304 | if f not in pdbexclude and not f.endswith('_d.pdb'): |
| 1305 | pdbzip.write(os.path.join(srcdir, PCBUILD, f), f) |
| 1306 | pdbzip.close() |
| 1307 | |
Martin v. Löwis | 8ffe9ab | 2004-08-22 13:34:34 +0000 | [diff] [blame] | 1308 | db = build_database() |
| 1309 | try: |
| 1310 | add_features(db) |
| 1311 | add_ui(db) |
| 1312 | add_files(db) |
| 1313 | add_registry(db) |
| 1314 | remove_old_versions(db) |
| 1315 | db.Commit() |
| 1316 | finally: |
| 1317 | del db |
Martin v. Löwis | 3a72b25 | 2010-11-14 18:13:49 +0000 | [diff] [blame^] | 1318 | |
| 1319 | if pdbzip: |
| 1320 | build_pdbzip() |