blob: cbdf227d00adb4254bd256ce651716eb7d92dff5 [file] [log] [blame]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001# 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öwisa5e31092010-09-04 14:38:09 +00004import msilib, schema, sequence, os, glob, time, re, shutil, zipfile
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00005from msilib import Feature, CAB, Directory, Dialog, Binary, add_data
6import uisample
7from win32com.client import constants
Martin v. Löwis9fda9312004-12-22 13:41:49 +00008from distutils.spawn import find_executable
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00009from uuids import product_codes
Martin v. Löwis0077b652010-03-16 18:53:33 +000010import tempfile
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000011
12# Settings can be overridden in config.py below
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000013# 0 for official python.org releases
14# 1 for intermediate releases by anybody, with
15# a new product code for every package.
16snapshot = 1
17# 1 means that file extension is px, not py,
18# and binaries start with x
19testpackage = 0
20# Location of build tree
21srcdir = os.path.abspath("../..")
22# Text to be displayed as the version in dialogs etc.
23# goes into file name and ProductCode. Defaults to
24# current_version.day for Snapshot, current_version otherwise
25full_current_version = None
Martin v. Löwise0f780d2004-09-01 14:51:06 +000026# Is Tcl available at all?
27have_tcl = True
Christian Heimes81ca7c72007-11-18 18:18:41 +000028# path to PCbuild directory
Christian Heimesfaf2f632008-01-06 16:59:19 +000029PCBUILD="PCbuild"
Christian Heimes81ca7c72007-11-18 18:18:41 +000030# msvcrt version
Christian Heimesfaf2f632008-01-06 16:59:19 +000031MSVCR = "90"
Martin v. Löwis0077b652010-03-16 18:53:33 +000032# Name of certificate in default store to sign MSI with
33certname = None
Martin v. Löwisa5e31092010-09-04 14:38:09 +000034# Make a zip file containing the PDB files for this build?
35pdbzip = True
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000036
37try:
38 from config import *
39except ImportError:
40 pass
41
42# Extract current version from Include/patchlevel.h
43lines = open(srcdir + "/Include/patchlevel.h").readlines()
44major = minor = micro = level = serial = None
45levels = {
46 'PY_RELEASE_LEVEL_ALPHA':0xA,
47 'PY_RELEASE_LEVEL_BETA': 0xB,
48 'PY_RELEASE_LEVEL_GAMMA':0xC,
49 'PY_RELEASE_LEVEL_FINAL':0xF
50 }
51for l in lines:
52 if not l.startswith("#define"):
53 continue
54 l = l.split()
55 if len(l) != 3:
56 continue
57 _, name, value = l
58 if name == 'PY_MAJOR_VERSION': major = value
59 if name == 'PY_MINOR_VERSION': minor = value
60 if name == 'PY_MICRO_VERSION': micro = value
61 if name == 'PY_RELEASE_LEVEL': level = levels[value]
62 if name == 'PY_RELEASE_SERIAL': serial = value
63
64short_version = major+"."+minor
65# See PC/make_versioninfo.c
66FIELD3 = 1000*int(micro) + 10*level + int(serial)
67current_version = "%s.%d" % (short_version, FIELD3)
68
69# This should never change. The UpgradeCode of this package can be
70# used in the Upgrade table of future packages to make the future
71# package replace this one. See "UpgradeCode Property".
Martin v. Löwisf27f8a12008-09-13 08:14:01 +000072# upgrade_code gets set to upgrade_code_64 when we have determined
73# that the target is Win64.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000074upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}'
75upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}'
Martin v. Löwisf27f8a12008-09-13 08:14:01 +000076upgrade_code_64='{6A965A0C-6EE6-4E3A-9983-3263F56311EC}'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000077
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000078if snapshot:
79 current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24))
80 product_code = msilib.gen_uuid()
81else:
82 product_code = product_codes[current_version]
83
84if full_current_version is None:
85 full_current_version = current_version
86
87extensions = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000088 'pyexpat.pyd',
89 'select.pyd',
90 'unicodedata.pyd',
91 'winsound.pyd',
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +010092 '_bz2.pyd',
Trent Micke97e5a72005-12-15 22:08:46 +000093 '_elementtree.pyd',
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000094 '_socket.pyd',
95 '_ssl.pyd',
96 '_testcapi.pyd',
97 '_tkinter.pyd',
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +000098 '_msi.pyd',
Martin v. Löwisa09655e2006-03-10 15:36:28 +000099 '_ctypes.pyd',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000100 '_ctypes_test.pyd',
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000101 '_sqlite3.pyd',
Martin v. Löwis9aa04c42008-06-30 07:03:57 +0000102 '_hashlib.pyd',
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +0100103 '_multiprocessing.pyd',
104 '_lzma.pyd'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000105]
106
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000107# Well-known component UUIDs
108# These are needed for SharedDLLs reference counter; if
109# a different UUID was used for each incarnation of, say,
110# python24.dll, an upgrade would set the reference counter
111# from 1 to 2 (due to what I consider a bug in MSI)
112# Using the same UUID is fine since these files are versioned,
113# so Installer will always keep the newest version.
Christian Heimesd0764e22007-12-04 15:00:33 +0000114# NOTE: All uuids are self generated.
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000115pythondll_uuid = {
116 "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000117 "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}",
Guido van Rossumaf554a02007-08-16 23:48:43 +0000118 "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}",
Martin v. Löwis7a63fc42008-10-02 20:09:01 +0000119 "27":"{4fe21c76-1760-437b-a2f2-99909130a175}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000120 "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}",
Martin v. Löwisfc972492008-10-02 20:09:47 +0000121 "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}",
Martin v. Löwisb4f4e722010-03-16 14:16:09 +0000122 "32":"{3ff95315-1096-4d31-bd86-601d5438ad5e}",
Vinay Sajip4334d742011-07-03 10:35:41 +0100123 "33":"{f7581ca4-d368-4eea-8f82-d48c64c4f047}",
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000124 } [major+minor]
Tim Peterseba28be2005-03-28 01:08:02 +0000125
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000126# Compute the name that Sphinx gives to the docfile
127docfile = ""
Martin v. Löwisdb7b5702009-06-28 12:28:29 +0000128if int(micro):
129 docfile = micro
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000130if level < 0xf:
Benjamin Petersonb48f6342009-06-22 19:36:31 +0000131 if level == 0xC:
Martin v. Löwisdb7b5702009-06-28 12:28:29 +0000132 docfile += "rc%s" % (serial,)
Benjamin Petersonb48f6342009-06-22 19:36:31 +0000133 else:
Martin v. Löwisdb7b5702009-06-28 12:28:29 +0000134 docfile += '%x%s' % (level, serial)
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000135docfile = 'python%s%s%s.chm' % (major, minor, docfile)
136
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000137# Build the mingw import library, libpythonXY.a
138# This requires 'nm' and 'dlltool' executables on your PATH
139def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib):
140 warning = "WARNING: %s - libpythonXX.a not built"
141 nm = find_executable('nm')
142 dlltool = find_executable('dlltool')
143
144 if not nm or not dlltool:
Collin Winter6afaeb72007-08-03 17:06:41 +0000145 print(warning % "nm and/or dlltool were not found")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000146 return False
147
148 nm_command = '%s -Cs %s' % (nm, lib_file)
149 dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \
150 (dlltool, dll_file, def_file, mingw_lib)
151 export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match
152
153 f = open(def_file,'w')
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000154 f.write("LIBRARY %s\n" % dll_file)
155 f.write("EXPORTS\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000156
157 nm_pipe = os.popen(nm_command)
158 for line in nm_pipe.readlines():
159 m = export_match(line)
160 if m:
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000161 f.write(m.group(1)+"\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000162 f.close()
163 exit = nm_pipe.close()
164
165 if exit:
Collin Winter6afaeb72007-08-03 17:06:41 +0000166 print(warning % "nm did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000167 return False
168
169 if os.system(dlltool_command) != 0:
Collin Winter6afaeb72007-08-03 17:06:41 +0000170 print(warning % "dlltool did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000171 return False
172
173 return True
174
175# Target files (.def and .a) go in PCBuild directory
Christian Heimes81ca7c72007-11-18 18:18:41 +0000176lib_file = os.path.join(srcdir, PCBUILD, "python%s%s.lib" % (major, minor))
177def_file = os.path.join(srcdir, PCBUILD, "python%s%s.def" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000178dll_file = "python%s%s.dll" % (major, minor)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000179mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000180
181have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib)
182
Ezio Melotti42da6632011-03-15 05:18:48 +0200183# Determine the target architecture
Martin v. Löwisdbd3f612012-02-21 18:06:22 +0100184if os.system("nmake /nologo /c /f msisupport.mak") != 0:
185 raise RuntimeError("'nmake /f msisupport.mak' failed")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000186dll_path = os.path.join(srcdir, PCBUILD, dll_file)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000187msilib.set_arch_from_file(dll_path)
188if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"):
Collin Wintera817e582007-08-22 23:05:06 +0000189 raise SystemError("msisupport.dll for incorrect architecture")
Martin v. Löwisf27f8a12008-09-13 08:14:01 +0000190if msilib.Win64:
191 upgrade_code = upgrade_code_64
Martin v. Löwise40a2132008-09-13 08:37:17 +0000192 # Bump the last digit of the code by one, so that 32-bit and 64-bit
193 # releases get separate product codes
194 digit = hex((int(product_code[-2],16)+1)%16)[-1]
195 product_code = product_code[:-2] + digit + '}'
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000196
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000197if testpackage:
198 ext = 'px'
199 testprefix = 'x'
200else:
201 ext = 'py'
202 testprefix = ''
203
204if msilib.Win64:
Martin v. Löwis47cc2a02007-08-30 18:27:06 +0000205 SystemFolderName = "[System64Folder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000206 registry_component = 4|256
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000207else:
208 SystemFolderName = "[SystemFolder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000209 registry_component = 4
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000210
211msilib.reset()
212
213# condition in which to install pythonxy.dll in system32:
214# a) it is Windows 9x or
215# b) it is NT, the user is privileged, and has chosen per-machine installation
216sys32cond = "(Windows9x or (Privileged and ALLUSERS))"
217
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000218def build_database():
219 """Generate an empty database, with just the schema and the
220 Summary information stream."""
221 if snapshot:
222 uc = upgrade_code_snapshot
223 else:
224 uc = upgrade_code
Martin v. Löwise40a2132008-09-13 08:37:17 +0000225 if msilib.Win64:
226 productsuffix = " (64-bit)"
227 else:
228 productsuffix = ""
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000229 # schema represents the installer 2.0 database schema.
230 # sequence is the set of standard sequences
231 # (ui/execute, admin/advt/install)
Martin v. Löwis0077b652010-03-16 18:53:33 +0000232 msiname = "python-%s%s.msi" % (full_current_version, msilib.arch_ext)
233 db = msilib.init_database(msiname,
Martin v. Löwise40a2132008-09-13 08:37:17 +0000234 schema, ProductName="Python "+full_current_version+productsuffix,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000235 ProductCode=product_code,
236 ProductVersion=current_version,
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000237 Manufacturer=u"Python Software Foundation",
238 request_uac = True)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000239 # The default sequencing of the RemoveExistingProducts action causes
240 # removal of files that got just installed. Place it after
241 # InstallInitialize, so we first uninstall everything, but still roll
242 # back in case the installation is interrupted
243 msilib.change_sequence(sequence.InstallExecuteSequence,
244 "RemoveExistingProducts", 1510)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000245 msilib.add_tables(db, sequence)
246 # We cannot set ALLUSERS in the property table, as this cannot be
247 # reset if the user choses a per-user installation. Instead, we
248 # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages
249 # this property, and when the execution starts, ALLUSERS is set
250 # accordingly.
251 add_data(db, "Property", [("UpgradeCode", uc),
252 ("WhichUsers", "ALL"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000253 ("ProductLine", "Python%s%s" % (major, minor)),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000254 ])
255 db.Commit()
Martin v. Löwis0077b652010-03-16 18:53:33 +0000256 return db, msiname
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000257
258def remove_old_versions(db):
259 "Fill the upgrade table."
260 start = "%s.%s.0" % (major, minor)
261 # This requests that feature selection states of an older
262 # installation should be forwarded into this one. Upgrading
263 # requires that both the old and the new installation are
264 # either both per-machine or per-user.
265 migrate_features = 1
266 # See "Upgrade Table". We remove releases with the same major and
267 # minor version. For an snapshot, we remove all earlier snapshots. For
268 # a release, we remove all snapshots, and all earlier releases.
269 if snapshot:
270 add_data(db, "Upgrade",
Tim Peters66cb0182004-08-26 05:23:19 +0000271 [(upgrade_code_snapshot, start,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000272 current_version,
273 None, # Ignore language
Tim Peters66cb0182004-08-26 05:23:19 +0000274 migrate_features,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000275 None, # Migrate ALL features
276 "REMOVEOLDSNAPSHOT")])
277 props = "REMOVEOLDSNAPSHOT"
278 else:
279 add_data(db, "Upgrade",
280 [(upgrade_code, start, current_version,
281 None, migrate_features, None, "REMOVEOLDVERSION"),
282 (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1),
283 None, migrate_features, None, "REMOVEOLDSNAPSHOT")])
284 props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION"
Martin v. Löwis1c4c3062008-09-08 16:27:54 +0000285
286 props += ";TARGETDIR;DLLDIR"
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000287 # Installer collects the product codes of the earlier releases in
288 # these properties. In order to allow modification of the properties,
289 # they must be declared as secure. See "SecureCustomProperties Property"
290 add_data(db, "Property", [("SecureCustomProperties", props)])
291
292class PyDialog(Dialog):
293 """Dialog class with a fixed layout: controls at the top, then a ruler,
294 then a list of buttons: back, next, cancel. Optionally a bitmap at the
295 left."""
296 def __init__(self, *args, **kw):
297 """Dialog(database, name, x, y, w, h, attributes, title, first,
298 default, cancel, bitmap=true)"""
299 Dialog.__init__(self, *args)
300 ruler = self.h - 36
301 bmwidth = 152*ruler/328
302 if kw.get("bitmap", True):
303 self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin")
304 self.line("BottomLine", 0, ruler, self.w, 0)
305
306 def title(self, title):
307 "Set the title text of the dialog at the top."
308 # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
309 # text, in VerdanaBold10
310 self.text("Title", 135, 10, 220, 60, 0x30003,
311 r"{\VerdanaBold10}%s" % title)
312
313 def back(self, title, next, name = "Back", active = 1):
314 """Add a back button with a given title, the tab-next button,
315 its name in the Control table, possibly initially disabled.
316
317 Return the button, so that events can be associated"""
318 if active:
319 flags = 3 # Visible|Enabled
320 else:
321 flags = 1 # Visible
322 return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next)
323
324 def cancel(self, title, next, name = "Cancel", active = 1):
325 """Add a cancel button with a given title, the tab-next button,
326 its name in the Control table, possibly initially disabled.
327
328 Return the button, so that events can be associated"""
329 if active:
330 flags = 3 # Visible|Enabled
331 else:
332 flags = 1 # Visible
333 return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next)
334
335 def next(self, title, next, name = "Next", active = 1):
336 """Add a Next button with a given title, the tab-next button,
337 its name in the Control table, possibly initially disabled.
338
339 Return the button, so that events can be associated"""
340 if active:
341 flags = 3 # Visible|Enabled
342 else:
343 flags = 1 # Visible
344 return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next)
345
346 def xbutton(self, name, title, next, xpos):
347 """Add a button with a given title, the tab-next button,
348 its name in the Control table, giving its x position; the
349 y-position is aligned with the other buttons.
350
351 Return the button, so that events can be associated"""
352 return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next)
353
354def add_ui(db):
355 x = y = 50
356 w = 370
357 h = 300
358 title = "[ProductName] Setup"
359
360 # see "Dialog Style Bits"
361 modal = 3 # visible | modal
362 modeless = 1 # visible
363 track_disk_space = 32
364
365 add_data(db, 'ActionText', uisample.ActionText)
366 add_data(db, 'UIText', uisample.UIText)
367
368 # Bitmaps
369 if not os.path.exists(srcdir+r"\PC\python_icon.exe"):
Georg Brandlbf82e372008-05-16 17:02:34 +0000370 raise RuntimeError("Run icons.mak in PC directory")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000371 add_data(db, "Binary",
Christian Heimesd9a4d1d2008-01-01 14:42:15 +0000372 [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000373 ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")),
374 ])
375 add_data(db, "Icon",
376 [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))])
377
378 # Scripts
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000379 # CheckDir sets TargetExists if TARGETDIR exists.
380 # UpdateEditIDLE sets the REGISTRY.tcl component into
381 # the installed/uninstalled state according to both the
382 # Extensions and TclTk features.
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000383 add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))])
384 # See "Custom Action Type 1"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000385 if msilib.Win64:
386 CheckDir = "CheckDir"
Martin v. Löwisdf40ce32006-02-16 14:38:30 +0000387 UpdateEditIDLE = "UpdateEditIDLE"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000388 else:
389 CheckDir = "_CheckDir@4"
390 UpdateEditIDLE = "_UpdateEditIDLE@4"
Tim Peters0e9980f2004-09-12 03:49:31 +0000391 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000392 [("CheckDir", 1, "Script", CheckDir)])
Martin v. Löwiseac02e62004-11-18 08:00:33 +0000393 if have_tcl:
394 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000395 [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)])
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000396
397 # UI customization properties
398 add_data(db, "Property",
399 # See "DefaultUIFont Property"
400 [("DefaultUIFont", "DlgFont8"),
401 # See "ErrorDialog Style Bit"
402 ("ErrorDialog", "ErrorDlg"),
403 ("Progress1", "Install"), # modified in maintenance type dlg
404 ("Progress2", "installs"),
405 ("MaintenanceForm_Action", "Repair")])
406
407 # Fonts, see "TextStyle Table"
408 add_data(db, "TextStyle",
409 [("DlgFont8", "Tahoma", 9, None, 0),
410 ("DlgFontBold8", "Tahoma", 8, None, 1), #bold
411 ("VerdanaBold10", "Verdana", 10, None, 1),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000412 ("VerdanaRed9", "Verdana", 9, 255, 0),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000413 ])
414
Martin v. Löwis4ad70df2010-03-16 16:19:47 +0000415 compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests" "[TARGETDIR]Lib"'
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000416 lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000417 # See "CustomAction Table"
418 add_data(db, "CustomAction", [
419 # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty
420 # See "Custom Action Type 51",
421 # "Custom Action Execution Scheduling Options"
422 ("InitialTargetDir", 307, "TARGETDIR",
423 "[WindowsVolume]Python%s%s" % (major, minor)),
424 ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
425 ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
426 # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
427 # See "Custom Action Type 18"
Martin v. Löwis7b2563b2004-11-02 22:59:56 +0000428 ("CompilePyc", 18, "python.exe", compileargs),
429 ("CompilePyo", 18, "python.exe", "-O "+compileargs),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000430 ("CompileGrammar", 18, "python.exe", lib2to3args),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000431 ])
432
433 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
434 # Numbers indicate sequence; see sequence.py for how these action integrate
435 add_data(db, "InstallUISequence",
436 [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
437 ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141),
438 ("InitialTargetDir", 'TARGETDIR=""', 750),
439 # In the user interface, assume all-users installation if privileged.
440 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
441 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
442 ("SelectDirectoryDlg", "Not Installed", 1230),
443 # XXX no support for resume installations yet
444 #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
445 ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250),
446 ("ProgressDlg", None, 1280)])
447 add_data(db, "AdminUISequence",
448 [("InitialTargetDir", 'TARGETDIR=""', 750),
449 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
450 ])
451
452 # Execute Sequences
453 add_data(db, "InstallExecuteSequence",
454 [("InitialTargetDir", 'TARGETDIR=""', 750),
455 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
456 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000457 ("UpdateEditIDLE", None, 1050),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000458 ("CompilePyc", "COMPILEALL", 6800),
459 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000460 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000461 ])
462 add_data(db, "AdminExecuteSequence",
463 [("InitialTargetDir", 'TARGETDIR=""', 750),
464 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
465 ("CompilePyc", "COMPILEALL", 6800),
466 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000467 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000468 ])
469
470 #####################################################################
471 # Standard dialogs: FatalError, UserExit, ExitDialog
472 fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title,
473 "Finish", "Finish", "Finish")
474 fatal.title("[ProductName] Installer ended prematurely")
475 fatal.back("< Back", "Finish", active = 0)
476 fatal.cancel("Cancel", "Back", active = 0)
477 fatal.text("Description1", 135, 70, 220, 80, 0x30003,
478 "[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.")
479 fatal.text("Description2", 135, 155, 220, 20, 0x30003,
480 "Click the Finish button to exit the Installer.")
481 c=fatal.next("Finish", "Cancel", name="Finish")
482 # See "ControlEvent Table". Parameters are the event, the parameter
483 # to the action, and optionally the condition for the event, and the order
484 # of events.
485 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000486
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000487 user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title,
488 "Finish", "Finish", "Finish")
489 user_exit.title("[ProductName] Installer was interrupted")
490 user_exit.back("< Back", "Finish", active = 0)
491 user_exit.cancel("Cancel", "Back", active = 0)
492 user_exit.text("Description1", 135, 70, 220, 80, 0x30003,
493 "[ProductName] setup was interrupted. Your system has not been modified. "
494 "To install this program at a later time, please run the installation again.")
495 user_exit.text("Description2", 135, 155, 220, 20, 0x30003,
496 "Click the Finish button to exit the Installer.")
497 c = user_exit.next("Finish", "Cancel", name="Finish")
498 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000499
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000500 exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title,
501 "Finish", "Finish", "Finish")
Martin v. Löwis26bb3cf2012-02-21 17:23:55 +0100502 exit_dialog.title("Complete the [ProductName] Installer")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000503 exit_dialog.back("< Back", "Finish", active = 0)
504 exit_dialog.cancel("Cancel", "Back", active = 0)
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000505 exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003,
506 "Special Windows thanks to:\n"
Martin v. Löwisd3f61a22004-08-30 09:22:30 +0000507 " Mark Hammond, without whose years of freely \n"
508 " shared Windows expertise, Python for Windows \n"
509 " would still be Python for DOS.")
Tim Peters66cb0182004-08-26 05:23:19 +0000510
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000511 c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003,
512 "{\\VerdanaRed9}Warning: Python 2.5.x is the last "
513 "Python release for Windows 9x.")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000514 c.condition("Hide", "NOT Version9X")
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000515
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000516 exit_dialog.text("Description", 135, 235, 220, 20, 0x30003,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000517 "Click the Finish button to exit the Installer.")
518 c = exit_dialog.next("Finish", "Cancel", name="Finish")
519 c.event("EndDialog", "Return")
520
521 #####################################################################
522 # Required dialog: FilesInUse, ErrorDlg
523 inuse = PyDialog(db, "FilesInUse",
524 x, y, w, h,
525 19, # KeepModeless|Modal|Visible
526 title,
527 "Retry", "Retry", "Retry", bitmap=False)
528 inuse.text("Title", 15, 6, 200, 15, 0x30003,
529 r"{\DlgFontBold8}Files in Use")
530 inuse.text("Description", 20, 23, 280, 20, 0x30003,
531 "Some files that need to be updated are currently in use.")
532 inuse.text("Text", 20, 55, 330, 50, 3,
533 "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.")
534 inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess",
535 None, None, None)
536 c=inuse.back("Exit", "Ignore", name="Exit")
537 c.event("EndDialog", "Exit")
538 c=inuse.next("Ignore", "Retry", name="Ignore")
539 c.event("EndDialog", "Ignore")
540 c=inuse.cancel("Retry", "Exit", name="Retry")
541 c.event("EndDialog","Retry")
542
543
544 # See "Error Dialog". See "ICE20" for the required names of the controls.
545 error = Dialog(db, "ErrorDlg",
546 50, 10, 330, 101,
547 65543, # Error|Minimize|Modal|Visible
548 title,
549 "ErrorText", None, None)
550 error.text("ErrorText", 50,9,280,48,3, "")
551 error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
552 error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo")
553 error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes")
554 error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort")
555 error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel")
556 error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore")
557 error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk")
558 error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry")
559
560 #####################################################################
561 # Global "Query Cancel" dialog
562 cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title,
563 "No", "No", "No")
Tim Peters66cb0182004-08-26 05:23:19 +0000564 cancel.text("Text", 48, 15, 194, 30, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000565 "Are you sure you want to cancel [ProductName] installation?")
566 cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
567 "py.ico", None, None)
568 c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
569 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000570
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000571 c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
572 c.event("EndDialog", "Return")
573
574 #####################################################################
575 # Global "Wait for costing" dialog
576 costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title,
577 "Return", "Return", "Return")
578 costing.text("Text", 48, 15, 194, 30, 3,
579 "Please wait while the installer finishes determining your disk space requirements.")
580 costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
581 "py.ico", None, None)
582 c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
583 c.event("EndDialog", "Exit")
584
585 #####################################################################
586 # Preparation dialog: no user input except cancellation
587 prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title,
588 "Cancel", "Cancel", "Cancel")
589 prep.text("Description", 135, 70, 220, 40, 0x30003,
590 "Please wait while the Installer prepares to guide you through the installation.")
591 prep.title("Welcome to the [ProductName] Installer")
592 c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...")
593 c.mapping("ActionText", "Text")
594 c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None)
595 c.mapping("ActionData", "Text")
596 prep.back("Back", None, active=0)
597 prep.next("Next", None, active=0)
598 c=prep.cancel("Cancel", None)
599 c.event("SpawnDialog", "CancelDlg")
600
601 #####################################################################
602 # Target directory selection
603 seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title,
604 "Next", "Next", "Cancel")
605 seldlg.title("Select Destination Directory")
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000606 c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003,
607 "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.")
608 c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000609 seldlg.text("Description", 135, 50, 220, 40, 0x30003,
610 "Please select a directory for the [ProductName] files.")
611
612 seldlg.back("< Back", None, active=0)
613 c = seldlg.next("Next >", "Cancel")
614 c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1)
615 # If the target exists, but we found that we are going to remove old versions, don't bother
616 # confirming that the target directory exists. Strictly speaking, we should determine that
617 # the target directory is indeed the target of the product that we are going to remove, but
618 # I don't know how to do that.
619 c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2)
620 c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3)
621 c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4)
622 c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5)
623
624 c = seldlg.cancel("Cancel", "DirectoryCombo")
625 c.event("SpawnDialog", "CancelDlg")
626
627 seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219,
628 "TARGETDIR", None, "DirectoryList", None)
629 seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR",
630 None, "PathEdit", None)
631 seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None)
632 c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
633 c.event("DirectoryListUp", "0")
634 c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
635 c.event("DirectoryListNew", "0")
636
637 #####################################################################
638 # SelectFeaturesDlg
639 features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space,
640 title, "Tree", "Next", "Cancel")
641 features.title("Customize [ProductName]")
642 features.text("Description", 135, 35, 220, 15, 0x30003,
643 "Select the way you want features to be installed.")
644 features.text("Text", 135,45,220,30, 3,
645 "Click on the icons in the tree below to change the way features will be installed.")
646
647 c=features.back("< Back", "Next")
648 c.event("NewDialog", "SelectDirectoryDlg")
649
650 c=features.next("Next >", "Cancel")
651 c.mapping("SelectionNoItems", "Enabled")
652 c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1)
653 c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2)
654
655 c=features.cancel("Cancel", "Tree")
656 c.event("SpawnDialog", "CancelDlg")
657
Tim Peters66cb0182004-08-26 05:23:19 +0000658 # The browse property is not used, since we have only a single target path (selected already)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000659 features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty",
660 "Tree of selections", "Back", None)
661
662 #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost")
663 #c.mapping("SelectionNoItems", "Enabled")
664 #c.event("Reset", "0")
Tim Peters66cb0182004-08-26 05:23:19 +0000665
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000666 features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None)
667
668 c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10)
669 c.mapping("SelectionNoItems","Enabled")
670 c.event("SpawnDialog", "DiskCostDlg")
671
672 c=features.xbutton("Advanced", "Advanced", None, 0.30)
673 c.event("SpawnDialog", "AdvancedDlg")
674
675 c=features.text("ItemDescription", 140, 180, 210, 30, 3,
676 "Multiline description of the currently selected item.")
677 c.mapping("SelectionDescription","Text")
Tim Peters66cb0182004-08-26 05:23:19 +0000678
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000679 c=features.text("ItemSize", 140, 210, 210, 45, 3,
680 "The size of the currently selected item.")
681 c.mapping("SelectionSize", "Text")
682
683 #####################################################################
684 # Disk cost
685 cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title,
686 "OK", "OK", "OK", bitmap=False)
687 cost.text("Title", 15, 6, 200, 15, 0x30003,
688 "{\DlgFontBold8}Disk Space Requirements")
689 cost.text("Description", 20, 20, 280, 20, 0x30003,
690 "The disk space required for the installation of the selected features.")
691 cost.text("Text", 20, 53, 330, 60, 3,
692 "The highlighted volumes (if any) do not have enough disk space "
693 "available for the currently selected features. You can either "
694 "remove some files from the highlighted volumes, or choose to "
695 "install less features onto local drive(s), or select different "
696 "destination drive(s).")
697 cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223,
698 None, "{120}{70}{70}{70}{70}", None, None)
699 cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
700
701 #####################################################################
702 # WhichUsers Dialog. Only available on NT, and for privileged users.
703 # This must be run before FindRelatedProducts, because that will
704 # take into account whether the previous installation was per-user
705 # or per-machine. We currently don't support going back to this
706 # dialog after "Next" was selected; to support this, we would need to
707 # find how to reset the ALLUSERS property, and how to re-run
708 # FindRelatedProducts.
709 # On Windows9x, the ALLUSERS property is ignored on the command line
710 # and in the Property table, but installer fails according to the documentation
711 # if a dialog attempts to set ALLUSERS.
712 whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title,
713 "AdminInstall", "Next", "Cancel")
714 whichusers.title("Select whether to install [ProductName] for all users of this computer.")
715 # A radio group with two options: allusers, justme
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000716 g = whichusers.radiogroup("AdminInstall", 135, 60, 235, 80, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000717 "WhichUsers", "", "Next")
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000718 g.condition("Disable", "VersionNT=600") # Not available on Vista and Windows 2008
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000719 g.add("ALL", 0, 5, 150, 20, "Install for all users")
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000720 g.add("JUSTME", 0, 25, 235, 20, "Install just for me (not available on Windows Vista)")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000721
Tim Peters66cb0182004-08-26 05:23:19 +0000722 whichusers.back("Back", None, active=0)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000723
724 c = whichusers.next("Next >", "Cancel")
725 c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
726 c.event("EndDialog", "Return", order = 2)
727
728 c = whichusers.cancel("Cancel", "AdminInstall")
729 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000730
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000731 #####################################################################
732 # Advanced Dialog.
733 advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title,
Martin v. Löwisa632a752008-11-19 13:55:07 +0000734 "CompilePyc", "Ok", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000735 advanced.title("Advanced Options for [ProductName]")
736 # A radio group with two options: allusers, justme
737 advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3,
Martin v. Löwisa632a752008-11-19 13:55:07 +0000738 "COMPILEALL", "Compile .py files to byte code after installation", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000739
Martin v. Löwisa632a752008-11-19 13:55:07 +0000740 c = advanced.cancel("Ok", "CompilePyc", name="Ok") # Button just has location of cancel button.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000741 c.event("EndDialog", "Return")
742
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000743 #####################################################################
Tim Peters66cb0182004-08-26 05:23:19 +0000744 # Existing Directory dialog
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000745 dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title,
746 "No", "No", "No")
747 dlg.text("Title", 10, 20, 180, 40, 3,
748 "[TARGETDIR] exists. Are you sure you want to overwrite existing files?")
749 c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No")
750 c.event("[TargetExists]", "0", order=1)
751 c.event("[TargetExistsOk]", "1", order=2)
752 c.event("EndDialog", "Return", order=3)
753 c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes")
754 c.event("EndDialog", "Return")
755
756 #####################################################################
757 # Installation Progress dialog (modeless)
758 progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title,
759 "Cancel", "Cancel", "Cancel", bitmap=False)
760 progress.text("Title", 20, 15, 200, 15, 0x30003,
761 "{\DlgFontBold8}[Progress1] [ProductName]")
762 progress.text("Text", 35, 65, 300, 30, 3,
763 "Please wait while the Installer [Progress2] [ProductName]. "
764 "This may take several minutes.")
765 progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
766
767 c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...")
768 c.mapping("ActionText", "Text")
769
770 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
771 #c.mapping("ActionData", "Text")
772
773 c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537,
774 None, "Progress done", None, None)
775 c.mapping("SetProgress", "Progress")
776
777 progress.back("< Back", "Next", active=False)
778 progress.next("Next >", "Cancel", active=False)
779 progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
780
781 # Maintenance type: repair/uninstall
782 maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title,
783 "Next", "Next", "Cancel")
784 maint.title("Welcome to the [ProductName] Setup Wizard")
785 maint.text("BodyText", 135, 63, 230, 42, 3,
786 "Select whether you want to repair or remove [ProductName].")
787 g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3,
788 "MaintenanceForm_Action", "", "Next")
789 g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
790 g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
791 g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
Tim Peters66cb0182004-08-26 05:23:19 +0000792
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000793 maint.back("< Back", None, active=False)
794 c=maint.next("Finish", "Cancel")
795 # Change installation: Change progress dialog to "Change", then ask
796 # for feature selection
797 c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
798 c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
799
800 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
801 # Also set list of reinstalled features to "ALL"
802 c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
803 c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
Raymond Hettinger72f08012004-11-07 07:08:25 +0000804 c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000805 c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
806
807 # Uninstall: Change progress to "Remove", then invoke uninstall
808 # Also set list of removed features to "ALL"
809 c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
810 c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
811 c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
812 c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
813
Tim Peters66cb0182004-08-26 05:23:19 +0000814 # Close dialog when maintenance action scheduled
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000815 c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
816 c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
Tim Peters66cb0182004-08-26 05:23:19 +0000817
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000818 maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000819
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000820
821# See "Feature Table". The feature level is 1 for all features,
822# and the feature attributes are 0 for the DefaultFeature, and
823# FollowParent for all other features. The numbers are the Display
824# column.
825def add_features(db):
826 # feature attributes:
827 # msidbFeatureAttributesFollowParent == 2
828 # msidbFeatureAttributesDisallowAdvertise == 8
829 # Features that need to be installed with together with the main feature
830 # (i.e. additional Python libraries) need to follow the parent feature.
831 # Features that have no advertisement trigger (e.g. the test suite)
832 # must not support advertisement
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000833 global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000834 default_feature = Feature(db, "DefaultFeature", "Python",
835 "Python Interpreter and Libraries",
836 1, directory = "TARGETDIR")
Martin v. Löwis2a241ca2008-04-05 18:58:09 +0000837 shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0,
838 level=0)
839 private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0,
840 level=0)
841 add_data(db, "Condition", [("SharedCRT", 1, sys32cond),
842 ("PrivateCRT", 1, "not "+sys32cond)])
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000843 # We don't support advertisement of extensions
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000844 ext_feature = Feature(db, "Extensions", "Register Extensions",
845 "Make this Python installation the default Python installation", 3,
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000846 parent = default_feature, attributes=2|8)
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000847 if have_tcl:
848 tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000849 parent = default_feature, attributes=2)
850 htmlfiles = Feature(db, "Documentation", "Documentation",
851 "Python HTMLHelp File", 7, parent = default_feature)
852 tools = Feature(db, "Tools", "Utility Scripts",
Tim Peters66cb0182004-08-26 05:23:19 +0000853 "Python utility scripts (Tools/", 9,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000854 parent = default_feature, attributes=2)
855 testsuite = Feature(db, "Testsuite", "Test suite",
856 "Python test suite (Lib/test/)", 11,
857 parent = default_feature, attributes=2|8)
Tim Peters66cb0182004-08-26 05:23:19 +0000858
Christian Heimes81ca7c72007-11-18 18:18:41 +0000859def extract_msvcr90():
Martin v. Löwisee7498e2008-02-28 23:01:33 +0000860 # Find the redistributable files
Martin v. Löwis8a2e90e2008-09-19 19:21:20 +0000861 if msilib.Win64:
862 arch = "amd64"
863 else:
864 arch = "x86"
865 dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC90.CRT" % arch)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000866
Christian Heimese1feb2e2008-02-28 20:52:40 +0000867 result = []
Christian Heimes81ca7c72007-11-18 18:18:41 +0000868 installer = msilib.MakeInstaller()
Christian Heimese1feb2e2008-02-28 20:52:40 +0000869 # omit msvcm90 and msvcp90, as they aren't really needed
870 files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"]
871 for f in files:
872 path = os.path.join(dir, f)
873 kw = {'src':path}
874 if f.endswith('.dll'):
875 kw['version'] = installer.FileVersion(path, 0)
876 kw['language'] = installer.FileVersion(path, 1)
877 result.append((f, kw))
878 return result
Christian Heimes81ca7c72007-11-18 18:18:41 +0000879
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000880def generate_license():
881 import shutil, glob
882 out = open("LICENSE.txt", "w")
883 shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out)
Martin v. Löwisb29f2d72008-09-14 20:27:52 +0000884 shutil.copyfileobj(open("crtlicense.txt"), out)
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000885 for name, pat, file in (("bzip2","bzip2-*", "LICENSE"),
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000886 ("openssl", "openssl-*", "LICENSE"),
887 ("Tcl", "tcl8*", "license.terms"),
888 ("Tk", "tk8*", "license.terms"),
889 ("Tix", "tix-*", "license.terms")):
890 out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name)
891 dirs = glob.glob(srcdir+"/../"+pat)
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000892 if not dirs:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000893 raise ValueError, "Could not find "+srcdir+"/../"+pat
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000894 if len(dirs) > 2:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000895 raise ValueError, "Multiple copies of "+pat
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000896 dir = dirs[0]
897 shutil.copyfileobj(open(os.path.join(dir, file)), out)
898 out.close()
899
900
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000901class PyDirectory(Directory):
902 """By default, all components in the Python installer
903 can run from source."""
904 def __init__(self, *args, **kw):
Georg Brandlbf82e372008-05-16 17:02:34 +0000905 if "componentflags" not in kw:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000906 kw['componentflags'] = 2 #msidbComponentAttributesOptional
907 Directory.__init__(self, *args, **kw)
908
Martin v. Löwis797721b2010-08-03 18:35:55 +0000909 def check_unpackaged(self):
910 self.unpackaged_files.discard('__pycache__')
911 self.unpackaged_files.discard('.svn')
912 if self.unpackaged_files:
913 print "Warning: Unpackaged files in %s" % self.absolute
914 print self.unpackaged_files
915
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +0100916
917def inside_test(dir):
918 if dir.physical in ('test', 'tests'):
919 return True
920 if dir.basedir:
921 return inside_test(dir.basedir)
922 return False
923
924def in_packaging_tests(dir):
925 if dir.physical == 'tests' and dir.basedir.physical == 'packaging':
926 return True
927 if dir.basedir:
928 return in_packaging_tests(dir.basedir)
929 return False
930
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000931# See "File Table", "Component Table", "Directory Table",
932# "FeatureComponents Table"
933def add_files(db):
934 cab = CAB("python")
935 tmpfiles = []
936 # Add all executables, icons, text files into the TARGETDIR component
937 root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir")
938 default_feature.set_current()
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000939 if not msilib.Win64:
Christian Heimes81ca7c72007-11-18 18:18:41 +0000940 root.add_file("%s/w9xpopen.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000941 root.add_file("README.txt", src="README")
942 root.add_file("NEWS.txt", src="Misc/NEWS")
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000943 generate_license()
944 root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000945 root.start_component("python.exe", keyfile="python.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000946 root.add_file("%s/python.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000947 root.start_component("pythonw.exe", keyfile="pythonw.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000948 root.add_file("%s/pythonw.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000949
950 # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
Martin v. Löwisc820eaf2008-10-17 13:47:20 +0000951 dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
Christian Heimese1feb2e2008-02-28 20:52:40 +0000952
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000953 pydll = "python%s%s.dll" % (major, minor)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000954 pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000955 dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000956 installer = msilib.MakeInstaller()
957 pyversion = installer.FileVersion(pydllsrc, 0)
958 if not snapshot:
959 # For releases, the Python DLL has the same version as the
960 # installer package.
961 assert pyversion.split(".")[:3] == current_version.split(".")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000962 dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000963 version=pyversion,
964 language=installer.FileVersion(pydllsrc, 1))
Christian Heimese1feb2e2008-02-28 20:52:40 +0000965 DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000966
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000967 # msvcr90.dll: Need to place the DLL and the manifest into the root directory,
968 # plus another copy of the manifest in the DLLs directory, with the manifest
969 # pointing to the root directory
970 root.start_component("msvcr90", feature=private_crt)
971 # Results are ID,keyword pairs
972 manifest, crtdll = extract_msvcr90()
973 root.add_file(manifest[0], **manifest[1])
974 root.add_file(crtdll[0], **crtdll[1])
975 # Copy the manifest
Martin v. Löwis91845562008-11-06 19:46:56 +0000976 # Actually, don't do that anymore - no DLL in DLLs should have a manifest
977 # dependency on msvcr90.dll anymore, so this should not be necessary
978 #manifest_dlls = manifest[0]+".root"
979 #open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr"))
980 #DLLs.start_component("msvcr90_dlls", feature=private_crt)
981 #DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls))
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000982
983 # Now start the main component for the DLLs directory;
984 # no regular files have been added to the directory yet.
985 DLLs.start_component()
Tim Peters66cb0182004-08-26 05:23:19 +0000986
Thomas Wouters89f507f2006-12-13 04:49:30 +0000987 # Check if _ctypes.pyd exists
Christian Heimes81ca7c72007-11-18 18:18:41 +0000988 have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000989 if not have_ctypes:
Collin Winter6afaeb72007-08-03 17:06:41 +0000990 print("WARNING: _ctypes.pyd not found, ctypes will not be included")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000991 extensions.remove("_ctypes.pyd")
992
Georg Brandl6e47a332008-05-17 19:15:58 +0000993 # Add all .py files in Lib, except tkinter, test
Martin v. Löwis797721b2010-08-03 18:35:55 +0000994 dirs = []
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000995 pydirs = [(root,"Lib")]
996 while pydirs:
Martin v. Löwis94b8b822008-06-13 19:00:35 +0000997 # Commit every now and then, or else installer will complain
998 db.Commit()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000999 parent, dir = pydirs.pop()
Martin v. Löwis797721b2010-08-03 18:35:55 +00001000 if dir == ".svn" or dir == '__pycache__' or dir.startswith("plat-"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001001 continue
Georg Brandl6e47a332008-05-17 19:15:58 +00001002 elif dir in ["tkinter", "idlelib", "Icons"]:
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001003 if not have_tcl:
1004 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001005 tcltk.set_current()
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +01001006 elif dir in ('test', 'tests') or inside_test(parent):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001007 testsuite.set_current()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001008 elif not have_ctypes and dir == "ctypes":
1009 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001010 else:
1011 default_feature.set_current()
1012 lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
1013 # Add additional files
Martin v. Löwis797721b2010-08-03 18:35:55 +00001014 dirs.append(lib)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001015 lib.glob("*.txt")
1016 if dir=='site-packages':
Martin v. Löwis6d60c092004-11-21 10:16:26 +00001017 lib.add_file("README.txt", src="README")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001018 continue
1019 files = lib.glob("*.py")
1020 files += lib.glob("*.pyw")
1021 if files:
1022 # Add an entry to the RemoveFile table to remove bytecode files.
1023 lib.remove_pyc()
Martin v. Löwis797721b2010-08-03 18:35:55 +00001024 # package READMEs if present
1025 lib.glob("README")
Vinay Sajip4334d742011-07-03 10:35:41 +01001026 if dir=='Lib':
1027 lib.add_file("sysconfig.cfg")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001028 if dir=='test' and parent.physical=='Lib':
1029 lib.add_file("185test.db")
1030 lib.add_file("audiotest.au")
Thomas Wouters89f507f2006-12-13 04:49:30 +00001031 lib.add_file("sgml_input.html")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001032 lib.add_file("testtar.tar")
Martin v. Löwis7d3755d2004-09-06 06:31:12 +00001033 lib.add_file("test_difflib_expect.html")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001034 lib.add_file("check_soundcard.vbs")
1035 lib.add_file("empty.vbs")
Martin v. Löwisbb6db342009-06-01 04:12:01 +00001036 lib.add_file("Sine-1000Hz-300ms.aif")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001037 lib.glob("*.uue")
Christian Heimes5d14c2b2007-11-20 23:38:09 +00001038 lib.glob("*.pem")
Christian Heimescbf3b5c2007-12-03 21:02:03 +00001039 lib.glob("*.pck")
Martin v. Löwis797721b2010-08-03 18:35:55 +00001040 lib.glob("cfgparser.*")
Martin v. Löwis678fa9f2011-01-15 19:43:18 +00001041 lib.add_file("zip_cp437_header.zip")
Martin v. Löwis270a9ce2009-04-04 18:48:39 +00001042 lib.add_file("zipdir.zip")
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +01001043 lib.add_file("mime.types")
Martin v. Löwis797721b2010-08-03 18:35:55 +00001044 if dir=='capath':
1045 lib.glob("*.0")
Georg Brandl8708e382010-08-01 09:17:53 +00001046 if dir=='tests' and parent.physical=='distutils':
1047 lib.add_file("Setup.sample")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001048 if dir=='decimaltestdata':
1049 lib.glob("*.decTest")
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001050 if dir=='xmltestdata':
1051 lib.glob("*.xml")
1052 lib.add_file("test.xml.out")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001053 if dir=='output':
1054 lib.glob("test_*")
Martin v. Löwis797721b2010-08-03 18:35:55 +00001055 if dir=='sndhdrdata':
1056 lib.glob("sndhdr.*")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001057 if dir=='idlelib':
1058 lib.glob("*.def")
1059 lib.add_file("idle.bat")
Martin v. Löwis797721b2010-08-03 18:35:55 +00001060 lib.add_file("ChangeLog")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001061 if dir=="Icons":
1062 lib.glob("*.gif")
1063 lib.add_file("idle.icns")
Vinay Sajip4334d742011-07-03 10:35:41 +01001064 if dir=="command" and parent.physical in ("distutils", "packaging"):
Martin v. Löwis5680d0c2008-04-10 03:06:53 +00001065 lib.glob("wininst*.exe")
Martin v. Löwis797721b2010-08-03 18:35:55 +00001066 lib.add_file("command_template")
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +00001067 if dir=="lib2to3":
1068 lib.removefile("pickle", "*.pickle")
Martin v. Löwis797721b2010-08-03 18:35:55 +00001069 if dir=="macholib":
1070 lib.add_file("README.ctypes")
1071 lib.glob("fetch_macholib*")
Martin v. Löwisd53ee5d2010-12-05 23:07:58 +00001072 if dir=='turtledemo':
1073 lib.add_file("turtle.cfg")
1074 if dir=="pydoc_data":
1075 lib.add_file("_pydoc.css")
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +01001076 if dir.endswith('.dist-info'):
1077 lib.add_file('INSTALLER')
1078 lib.add_file('REQUESTED')
1079 lib.add_file('RECORD')
1080 lib.add_file('METADATA')
1081 lib.glob('RESOURCES')
1082 if dir.endswith('.egg-info') or dir == 'EGG-INFO':
1083 lib.add_file('PKG-INFO')
1084 if in_packaging_tests(parent):
1085 lib.glob('*.html')
1086 lib.glob('*.tar.gz')
1087 if dir=='fake_dists':
1088 # cannot use glob since there are also egg-info directories here
1089 lib.add_file('cheese-2.0.2.egg-info')
1090 lib.add_file('nut-funkyversion.egg-info')
1091 lib.add_file('strawberry-0.6.egg')
1092 lib.add_file('truffles-5.0.egg-info')
1093 lib.add_file('babar.cfg')
1094 lib.add_file('babar.png')
R David Murray6a738452011-06-18 11:45:59 -04001095 if dir=="data" and parent.physical=="test_email":
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001096 # This should contain all non-.svn files listed in subversion
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001097 for f in os.listdir(lib.absolute):
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001098 if f.endswith(".txt") or f==".svn":continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001099 if f.endswith(".au") or f.endswith(".gif"):
1100 lib.add_file(f)
1101 else:
R David Murray6a738452011-06-18 11:45:59 -04001102 print("WARNING: New file %s in test/test_email/data" % f)
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +01001103 if dir=='tests' and parent.physical == 'packaging':
1104 lib.add_file('SETUPTOOLS-PKG-INFO2')
1105 lib.add_file('SETUPTOOLS-PKG-INFO')
1106 lib.add_file('PKG-INFO')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001107 for f in os.listdir(lib.absolute):
1108 if os.path.isdir(os.path.join(lib.absolute, f)):
1109 pydirs.append((lib, f))
Martin v. Löwis797721b2010-08-03 18:35:55 +00001110 for d in dirs:
1111 d.check_unpackaged()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001112 # Add DLLs
1113 default_feature.set_current()
Christian Heimese1feb2e2008-02-28 20:52:40 +00001114 lib = DLLs
Christian Heimesd9a4d1d2008-01-01 14:42:15 +00001115 lib.add_file("py.ico", src=srcdir+"/PC/py.ico")
1116 lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001117 dlls = []
1118 tclfiles = []
1119 for f in extensions:
1120 if f=="_tkinter.pyd":
1121 continue
Christian Heimes81ca7c72007-11-18 18:18:41 +00001122 if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f):
Collin Winter6afaeb72007-08-03 17:06:41 +00001123 print("WARNING: Missing extension", f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001124 continue
1125 dlls.append(f)
1126 lib.add_file(f)
Martin v. Löwisd53ee5d2010-12-05 23:07:58 +00001127 lib.add_file('python3.dll')
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001128 # Add sqlite
1129 if msilib.msi_type=="Intel64;1033":
1130 sqlite_arch = "/ia64"
1131 elif msilib.msi_type=="x64;1033":
1132 sqlite_arch = "/amd64"
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001133 tclsuffix = "64"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001134 else:
1135 sqlite_arch = ""
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001136 tclsuffix = ""
Martin v. Löwis94b8b822008-06-13 19:00:35 +00001137 lib.add_file("sqlite3.dll")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001138 if have_tcl:
Christian Heimes81ca7c72007-11-18 18:18:41 +00001139 if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)):
Collin Winter6afaeb72007-08-03 17:06:41 +00001140 print("WARNING: Missing _tkinter.pyd")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001141 else:
1142 lib.start_component("TkDLLs", tcltk)
1143 lib.add_file("_tkinter.pyd")
1144 dlls.append("_tkinter.pyd")
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001145 tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001146 for f in glob.glob1(tcldir, "*.dll"):
1147 lib.add_file(f, src=os.path.join(tcldir, f))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001148 # check whether there are any unknown extensions
Christian Heimes81ca7c72007-11-18 18:18:41 +00001149 for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001150 if f.endswith("_d.pyd"): continue # debug version
1151 if f in dlls: continue
Collin Winter6afaeb72007-08-03 17:06:41 +00001152 print("WARNING: Unknown extension", f)
Tim Peters66cb0182004-08-26 05:23:19 +00001153
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001154 # Add headers
1155 default_feature.set_current()
1156 lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include")
1157 lib.glob("*.h")
1158 lib.add_file("pyconfig.h", src="../PC/pyconfig.h")
1159 # Add import libraries
Christian Heimes81ca7c72007-11-18 18:18:41 +00001160 lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001161 for f in dlls:
1162 lib.add_file(f.replace('pyd','lib'))
1163 lib.add_file('python%s%s.lib' % (major, minor))
Martin v. Löwisd53ee5d2010-12-05 23:07:58 +00001164 lib.add_file('python3.lib')
Martin v. Löwis9fda9312004-12-22 13:41:49 +00001165 # Add the mingw-format library
1166 if have_mingw:
Tim Peters5a9fb3c2005-01-07 16:01:32 +00001167 lib.add_file('libpython%s%s.a' % (major, minor))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001168 if have_tcl:
1169 # Add Tcl/Tk
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001170 tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')]
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001171 tcltk.set_current()
1172 while tcldirs:
1173 parent, phys, dir = tcldirs.pop()
1174 lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir))
1175 if not os.path.exists(lib.absolute):
1176 continue
1177 for f in os.listdir(lib.absolute):
1178 if os.path.isdir(os.path.join(lib.absolute, f)):
1179 tcldirs.append((lib, f, f))
1180 else:
1181 lib.add_file(f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001182 # Add tools
1183 tools.set_current()
1184 tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools")
Martin v. Löwisa6207482010-08-28 13:40:10 +00001185 for f in ['i18n', 'pynche', 'Scripts']:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001186 lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f))
1187 lib.glob("*.py")
1188 lib.glob("*.pyw", exclude=['pydocgui.pyw'])
1189 lib.remove_pyc()
1190 lib.glob("*.txt")
1191 if f == "pynche":
1192 x = PyDirectory(db, cab, lib, "X", "X", "X|X")
1193 x.glob("*.txt")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001194 if os.path.exists(os.path.join(lib.absolute, "README")):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001195 lib.add_file("README.txt", src="README")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001196 if f == 'Scripts':
Martin v. Löwisfe218842008-10-01 11:22:32 +00001197 lib.add_file("2to3.py", src="2to3")
Vinay Sajip4334d742011-07-03 10:35:41 +01001198 lib.add_file("pydoc3.py", src="pydoc3")
1199 lib.add_file("pysetup3.py", src="pysetup3")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001200 if have_tcl:
1201 lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
1202 lib.add_file("pydocgui.pyw")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001203 # Add documentation
1204 htmlfiles.set_current()
1205 lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc")
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001206 lib.start_component("documentation", keyfile=docfile)
1207 lib.add_file(docfile, src="build/htmlhelp/"+docfile)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001208
1209 cab.commit(db)
1210
1211 for f in tmpfiles:
1212 os.unlink(f)
1213
1214# See "Registry Table", "Component Table"
1215def add_registry(db):
1216 # File extensions, associated with the REGISTRY.def component
1217 # IDLE verbs depend on the tcltk feature.
1218 # msidbComponentAttributesRegistryKeyPath = 4
1219 # -1 for Root specifies "dependent on ALLUSERS property"
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001220 tcldata = []
1221 if have_tcl:
1222 tcldata = [
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001223 ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001224 "py.IDLE")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001225 add_data(db, "Component",
1226 # msidbComponentAttributesRegistryKeyPath = 4
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001227 [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001228 "InstallPath"),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001229 ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001230 "Documentation"),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001231 ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001232 None, None)] + tcldata)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001233 # See "FeatureComponents Table".
1234 # The association between TclTk and pythonw.exe is necessary to make ICE59
1235 # happy, because the installer otherwise believes that the IDLE and PyDoc
1236 # shortcuts might get installed without pythonw.exe being install. This
1237 # is not true, since installing TclTk will install the default feature, which
1238 # will cause pythonw.exe to be installed.
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001239 # REGISTRY.tcl is not associated with any feature, as it will be requested
1240 # through a custom action
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001241 tcldata = []
1242 if have_tcl:
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001243 tcldata = [(tcltk.id, "pythonw.exe")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001244 add_data(db, "FeatureComponents",
1245 [(default_feature.id, "REGISTRY"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001246 (htmlfiles.id, "REGISTRY.doc"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001247 (ext_feature.id, "REGISTRY.def")] +
1248 tcldata
1249 )
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001250 # Extensions are not advertised. For advertised extensions,
1251 # we would need separate binaries that install along with the
1252 # extension.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001253 pat = r"Software\Classes\%sPython.%sFile\shell\%s\command"
1254 ewi = "Edit with IDLE"
1255 pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon"
1256 pat3 = r"Software\Classes\%sPython.%sFile"
Martin v. Löwisbfda5442008-11-07 18:54:51 +00001257 pat4 = r"Software\Classes\%sPython.%sFile\shellex\DropHandler"
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001258 tcl_verbs = []
1259 if have_tcl:
1260 tcl_verbs=[
1261 ("py.IDLE", -1, pat % (testprefix, "", ewi), "",
Martin v. Löwis8482ef92009-05-05 16:14:30 +00001262 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001263 "REGISTRY.tcl"),
1264 ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "",
Martin v. Löwis8482ef92009-05-05 16:14:30 +00001265 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001266 "REGISTRY.tcl"),
1267 ]
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001268 add_data(db, "Registry",
1269 [# Extensions
1270 ("py.ext", -1, r"Software\Classes\."+ext, "",
1271 "Python.File", "REGISTRY.def"),
1272 ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "",
1273 "Python.NoConFile", "REGISTRY.def"),
1274 ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "",
1275 "Python.CompiledFile", "REGISTRY.def"),
1276 ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "",
1277 "Python.CompiledFile", "REGISTRY.def"),
1278 # MIME types
1279 ("py.mime", -1, r"Software\Classes\."+ext, "Content Type",
1280 "text/plain", "REGISTRY.def"),
1281 ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type",
1282 "text/plain", "REGISTRY.def"),
1283 #Verbs
1284 ("py.open", -1, pat % (testprefix, "", "open"), "",
1285 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
1286 ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
1287 r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"),
1288 ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
1289 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001290 ] + tcl_verbs + [
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001291 #Icons
1292 ("py.icon", -1, pat2 % (testprefix, ""), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001293 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001294 ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001295 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001296 ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001297 r'[DLLs]pyc.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001298 # Descriptions
1299 ("py.txt", -1, pat3 % (testprefix, ""), "",
1300 "Python File", "REGISTRY.def"),
1301 ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "",
1302 "Python File (no console)", "REGISTRY.def"),
1303 ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "",
1304 "Compiled Python File", "REGISTRY.def"),
Martin v. Löwisbfda5442008-11-07 18:54:51 +00001305 # Drop Handler
1306 ("py.drop", -1, pat4 % (testprefix, ""), "",
1307 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1308 ("pyw.drop", -1, pat4 % (testprefix, "NoCon"), "",
1309 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1310 ("pyc.drop", -1, pat4 % (testprefix, "Compiled"), "",
1311 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001312 ])
Tim Peters66cb0182004-08-26 05:23:19 +00001313
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001314 # Registry keys
1315 prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version)
1316 add_data(db, "Registry",
1317 [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"),
1318 ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "",
1319 "Python %s" % short_version, "REGISTRY"),
1320 ("PythonPath", -1, prefix+r"\PythonPath", "",
Georg Brandl6e47a332008-05-17 19:15:58 +00001321 r"[TARGETDIR]Lib;[TARGETDIR]DLLs", "REGISTRY"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001322 ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001323 "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001324 ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"),
1325 ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe",
Martin v. Löwis45a6b9f2008-11-30 11:12:00 +00001326 "", r"[TARGETDIR]Python.exe", "REGISTRY.def"),
1327 ("DisplayIcon", -1,
1328 r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code,
Martin v. Löwis95c46012009-06-28 09:36:14 +00001329 "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001330 ])
1331 # Shortcuts, see "Shortcut Table"
1332 add_data(db, "Directory",
1333 [("ProgramMenuFolder", "TARGETDIR", "."),
1334 ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))])
1335 add_data(db, "RemoveFile",
1336 [("MenuDir", "TARGETDIR", None, "MenuDir", 2)])
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001337 tcltkshortcuts = []
1338 if have_tcl:
1339 tcltkshortcuts = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001340 ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001341 tcltk.id, r'"[TARGETDIR]Lib\idlelib\idle.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001342 ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001343 tcltk.id, r'"[TARGETDIR]Tools\scripts\pydocgui.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001344 ]
1345 add_data(db, "Shortcut",
1346 tcltkshortcuts +
1347 [# Advertised shortcuts: targets are features, not files
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001348 ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe",
1349 default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001350 # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an
1351 # icon first.
1352 #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation",
1353 # htmlfiles.id, None, None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001354 ## Non-advertised shortcuts: must be associated with a registry component
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001355 ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001356 "[#%s]" % docfile, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001357 None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001358 ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY",
1359 SystemFolderName+"msiexec", "/x%s" % product_code,
1360 None, None, None, None, None, None),
1361 ])
1362 db.Commit()
1363
Martin v. Löwisa5e31092010-09-04 14:38:09 +00001364def build_pdbzip():
1365 pdbexclude = ['kill_python.pdb', 'make_buildinfo.pdb',
1366 'make_versioninfo.pdb']
1367 path = "python-%s%s-pdb.zip" % (full_current_version, msilib.arch_ext)
1368 pdbzip = zipfile.ZipFile(path, 'w')
1369 for f in glob.glob1(os.path.join(srcdir, PCBUILD), "*.pdb"):
1370 if f not in pdbexclude and not f.endswith('_d.pdb'):
1371 pdbzip.write(os.path.join(srcdir, PCBUILD, f), f)
1372 pdbzip.close()
1373
Martin v. Löwis0077b652010-03-16 18:53:33 +00001374db,msiname = build_database()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001375try:
1376 add_features(db)
1377 add_ui(db)
1378 add_files(db)
1379 add_registry(db)
1380 remove_old_versions(db)
1381 db.Commit()
1382finally:
1383 del db
Martin v. Löwis0077b652010-03-16 18:53:33 +00001384
1385# Merge CRT into MSI file. This requires the database to be closed.
1386mod_dir = os.path.join(os.environ["ProgramFiles"], "Common Files", "Merge Modules")
1387if msilib.Win64:
1388 modules = ["Microsoft_VC90_CRT_x86_x64.msm", "policy_9_0_Microsoft_VC90_CRT_x86_x64.msm"]
1389else:
1390 modules = ["Microsoft_VC90_CRT_x86.msm","policy_9_0_Microsoft_VC90_CRT_x86.msm"]
1391
1392for i, n in enumerate(modules):
1393 modules[i] = os.path.join(mod_dir, n)
1394
1395def merge(msi, feature, rootdir, modules):
1396 cab_and_filecount = []
1397 # Step 1: Merge databases, extract cabfiles
1398 m = msilib.MakeMerge2()
1399 m.OpenLog("merge.log")
1400 m.OpenDatabase(msi)
1401 for module in modules:
1402 print module
1403 m.OpenModule(module,0)
1404 m.Merge(feature, rootdir)
1405 print "Errors:"
1406 for e in m.Errors:
1407 print e.Type, e.ModuleTable, e.DatabaseTable
1408 print " Modkeys:",
1409 for s in e.ModuleKeys: print s,
1410 print
1411 print " DBKeys:",
1412 for s in e.DatabaseKeys: print s,
1413 print
1414 cabname = tempfile.mktemp(suffix=".cab")
1415 m.ExtractCAB(cabname)
1416 cab_and_filecount.append((cabname, len(m.ModuleFiles)))
1417 m.CloseModule()
1418 m.CloseDatabase(True)
1419 m.CloseLog()
1420
1421 # Step 2: Add CAB files
1422 i = msilib.MakeInstaller()
1423 db = i.OpenDatabase(msi, constants.msiOpenDatabaseModeTransact)
1424
1425 v = db.OpenView("SELECT LastSequence FROM Media")
1426 v.Execute(None)
1427 maxmedia = -1
1428 while 1:
1429 r = v.Fetch()
1430 if not r: break
1431 seq = r.IntegerData(1)
1432 if seq > maxmedia:
1433 maxmedia = seq
1434 print "Start of Media", maxmedia
1435
1436 for cabname, count in cab_and_filecount:
1437 stream = "merged%d" % maxmedia
1438 msilib.add_data(db, "Media",
1439 [(maxmedia+1, maxmedia+count, None, "#"+stream, None, None)])
1440 msilib.add_stream(db, stream, cabname)
1441 os.unlink(cabname)
1442 maxmedia += count
1443 # The merge module sets ALLUSERS to 1 in the property table.
1444 # This is undesired; delete that
1445 v = db.OpenView("DELETE FROM Property WHERE Property='ALLUSERS'")
1446 v.Execute(None)
1447 v.Close()
1448 db.Commit()
1449
1450merge(msiname, "SharedCRT", "TARGETDIR", modules)
1451
1452# certname (from config.py) should be (a substring of)
1453# the certificate subject, e.g. "Python Software Foundation"
1454if certname:
1455 os.system('signtool sign /n "%s" /t http://timestamp.verisign.com/scripts/timestamp.dll %s' % (certname, msiname))
Martin v. Löwisa5e31092010-09-04 14:38:09 +00001456
1457if pdbzip:
1458 build_pdbzip()