blob: f9b477f26473432372ded10c44123e902aba9b7e [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öwis41add012012-03-06 17:53:12 +01005import subprocess, tempfile
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00006from msilib import Feature, CAB, Directory, Dialog, Binary, add_data
7import uisample
8from win32com.client import constants
Martin v. Löwis9fda9312004-12-22 13:41:49 +00009from distutils.spawn import find_executable
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000010
11# Settings can be overridden in config.py below
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000012# 0 for official python.org releases
13# 1 for intermediate releases by anybody, with
14# a new product code for every package.
15snapshot = 1
16# 1 means that file extension is px, not py,
17# and binaries start with x
18testpackage = 0
19# Location of build tree
20srcdir = 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
24full_current_version = None
Martin v. Löwise0f780d2004-09-01 14:51:06 +000025# Is Tcl available at all?
26have_tcl = True
Christian Heimes81ca7c72007-11-18 18:18:41 +000027# path to PCbuild directory
Christian Heimesfaf2f632008-01-06 16:59:19 +000028PCBUILD="PCbuild"
Christian Heimes81ca7c72007-11-18 18:18:41 +000029# msvcrt version
Brian Curtin401f9f32012-05-13 11:19:23 -050030MSVCR = "100"
Martin v. Löwis0077b652010-03-16 18:53:33 +000031# Name of certificate in default store to sign MSI with
32certname = None
Martin v. Löwisa5e31092010-09-04 14:38:09 +000033# Make a zip file containing the PDB files for this build?
34pdbzip = True
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000035
36try:
37 from config import *
38except ImportError:
39 pass
40
41# Extract current version from Include/patchlevel.h
42lines = open(srcdir + "/Include/patchlevel.h").readlines()
43major = minor = micro = level = serial = None
44levels = {
45 'PY_RELEASE_LEVEL_ALPHA':0xA,
46 'PY_RELEASE_LEVEL_BETA': 0xB,
47 'PY_RELEASE_LEVEL_GAMMA':0xC,
48 'PY_RELEASE_LEVEL_FINAL':0xF
49 }
50for l in lines:
51 if not l.startswith("#define"):
52 continue
53 l = l.split()
54 if len(l) != 3:
55 continue
56 _, name, value = l
57 if name == 'PY_MAJOR_VERSION': major = value
58 if name == 'PY_MINOR_VERSION': minor = value
59 if name == 'PY_MICRO_VERSION': micro = value
60 if name == 'PY_RELEASE_LEVEL': level = levels[value]
61 if name == 'PY_RELEASE_SERIAL': serial = value
62
63short_version = major+"."+minor
64# See PC/make_versioninfo.c
65FIELD3 = 1000*int(micro) + 10*level + int(serial)
66current_version = "%s.%d" % (short_version, FIELD3)
67
68# This should never change. The UpgradeCode of this package can be
69# used in the Upgrade table of future packages to make the future
70# package replace this one. See "UpgradeCode Property".
Martin v. Löwisf27f8a12008-09-13 08:14:01 +000071# upgrade_code gets set to upgrade_code_64 when we have determined
72# that the target is Win64.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000073upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}'
74upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}'
Martin v. Löwisf27f8a12008-09-13 08:14:01 +000075upgrade_code_64='{6A965A0C-6EE6-4E3A-9983-3263F56311EC}'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000076
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000077if snapshot:
78 current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000079
80if full_current_version is None:
81 full_current_version = current_version
82
83extensions = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000084 'pyexpat.pyd',
85 'select.pyd',
86 'unicodedata.pyd',
87 'winsound.pyd',
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +010088 '_bz2.pyd',
Trent Micke97e5a72005-12-15 22:08:46 +000089 '_elementtree.pyd',
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000090 '_socket.pyd',
91 '_ssl.pyd',
92 '_testcapi.pyd',
93 '_tkinter.pyd',
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +000094 '_msi.pyd',
Martin v. Löwisa09655e2006-03-10 15:36:28 +000095 '_ctypes.pyd',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000096 '_ctypes_test.pyd',
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000097 '_sqlite3.pyd',
Martin v. Löwis9aa04c42008-06-30 07:03:57 +000098 '_hashlib.pyd',
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +010099 '_multiprocessing.pyd',
Martin v. Löwis8dbbae92012-04-01 19:55:48 +0200100 '_lzma.pyd',
101 '_decimal.pyd',
Christian Heimesefb15992012-10-22 17:01:13 +0200102 '_testbuffer.pyd',
103 '_sha3.pyd',
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000104]
105
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000106# Well-known component UUIDs
107# These are needed for SharedDLLs reference counter; if
108# a different UUID was used for each incarnation of, say,
109# python24.dll, an upgrade would set the reference counter
110# from 1 to 2 (due to what I consider a bug in MSI)
111# Using the same UUID is fine since these files are versioned,
112# so Installer will always keep the newest version.
Christian Heimesd0764e22007-12-04 15:00:33 +0000113# NOTE: All uuids are self generated.
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000114pythondll_uuid = {
115 "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000116 "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}",
Guido van Rossumaf554a02007-08-16 23:48:43 +0000117 "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}",
Martin v. Löwis7a63fc42008-10-02 20:09:01 +0000118 "27":"{4fe21c76-1760-437b-a2f2-99909130a175}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000119 "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}",
Martin v. Löwisfc972492008-10-02 20:09:47 +0000120 "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}",
Martin v. Löwisb4f4e722010-03-16 14:16:09 +0000121 "32":"{3ff95315-1096-4d31-bd86-601d5438ad5e}",
Vinay Sajip4334d742011-07-03 10:35:41 +0100122 "33":"{f7581ca4-d368-4eea-8f82-d48c64c4f047}",
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000123 } [major+minor]
Tim Peterseba28be2005-03-28 01:08:02 +0000124
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000125# Compute the name that Sphinx gives to the docfile
Martin v. Löwisbd31db62012-05-01 16:37:44 +0200126docfile = micro
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000127if level < 0xf:
Benjamin Petersonb48f6342009-06-22 19:36:31 +0000128 if level == 0xC:
Martin v. Löwisdb7b5702009-06-28 12:28:29 +0000129 docfile += "rc%s" % (serial,)
Benjamin Petersonb48f6342009-06-22 19:36:31 +0000130 else:
Martin v. Löwisdb7b5702009-06-28 12:28:29 +0000131 docfile += '%x%s' % (level, serial)
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000132docfile = 'python%s%s%s.chm' % (major, minor, docfile)
133
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000134# Build the mingw import library, libpythonXY.a
135# This requires 'nm' and 'dlltool' executables on your PATH
136def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib):
137 warning = "WARNING: %s - libpythonXX.a not built"
138 nm = find_executable('nm')
139 dlltool = find_executable('dlltool')
140
141 if not nm or not dlltool:
Collin Winter6afaeb72007-08-03 17:06:41 +0000142 print(warning % "nm and/or dlltool were not found")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000143 return False
144
145 nm_command = '%s -Cs %s' % (nm, lib_file)
146 dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \
147 (dlltool, dll_file, def_file, mingw_lib)
148 export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match
149
150 f = open(def_file,'w')
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000151 f.write("LIBRARY %s\n" % dll_file)
152 f.write("EXPORTS\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000153
154 nm_pipe = os.popen(nm_command)
155 for line in nm_pipe.readlines():
156 m = export_match(line)
157 if m:
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000158 f.write(m.group(1)+"\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000159 f.close()
160 exit = nm_pipe.close()
161
162 if exit:
Collin Winter6afaeb72007-08-03 17:06:41 +0000163 print(warning % "nm did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000164 return False
165
166 if os.system(dlltool_command) != 0:
Collin Winter6afaeb72007-08-03 17:06:41 +0000167 print(warning % "dlltool did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000168 return False
169
170 return True
171
172# Target files (.def and .a) go in PCBuild directory
Christian Heimes81ca7c72007-11-18 18:18:41 +0000173lib_file = os.path.join(srcdir, PCBUILD, "python%s%s.lib" % (major, minor))
174def_file = os.path.join(srcdir, PCBUILD, "python%s%s.def" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000175dll_file = "python%s%s.dll" % (major, minor)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000176mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000177
178have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib)
179
Ezio Melotti42da6632011-03-15 05:18:48 +0200180# Determine the target architecture
Martin v. Löwisdbd3f612012-02-21 18:06:22 +0100181if os.system("nmake /nologo /c /f msisupport.mak") != 0:
182 raise RuntimeError("'nmake /f msisupport.mak' failed")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000183dll_path = os.path.join(srcdir, PCBUILD, dll_file)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000184msilib.set_arch_from_file(dll_path)
185if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"):
Collin Wintera817e582007-08-22 23:05:06 +0000186 raise SystemError("msisupport.dll for incorrect architecture")
Martin v. Löwisf2f592d2012-03-04 19:48:25 +0100187
Martin v. Löwisf27f8a12008-09-13 08:14:01 +0000188if msilib.Win64:
189 upgrade_code = upgrade_code_64
Martin v. Löwisf2f592d2012-03-04 19:48:25 +0100190
191if snapshot:
192 product_code = msilib.gen_uuid()
193else:
194 # official release: generate UUID from the download link that the file will have
195 import uuid
196 product_code = uuid.uuid3(uuid.NAMESPACE_URL,
197 'http://www.python.org/ftp/python/%s.%s.%s/python-%s%s.msi' %
198 (major, minor, micro, full_current_version, msilib.arch_ext))
199 product_code = '{%s}' % product_code
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000200
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000201if testpackage:
202 ext = 'px'
203 testprefix = 'x'
204else:
205 ext = 'py'
206 testprefix = ''
207
208if msilib.Win64:
Martin v. Löwis47cc2a02007-08-30 18:27:06 +0000209 SystemFolderName = "[System64Folder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000210 registry_component = 4|256
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000211else:
212 SystemFolderName = "[SystemFolder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000213 registry_component = 4
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000214
215msilib.reset()
216
217# condition in which to install pythonxy.dll in system32:
218# a) it is Windows 9x or
219# b) it is NT, the user is privileged, and has chosen per-machine installation
220sys32cond = "(Windows9x or (Privileged and ALLUSERS))"
221
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000222def build_database():
223 """Generate an empty database, with just the schema and the
224 Summary information stream."""
225 if snapshot:
226 uc = upgrade_code_snapshot
227 else:
228 uc = upgrade_code
Martin v. Löwise40a2132008-09-13 08:37:17 +0000229 if msilib.Win64:
230 productsuffix = " (64-bit)"
231 else:
232 productsuffix = ""
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000233 # schema represents the installer 2.0 database schema.
234 # sequence is the set of standard sequences
235 # (ui/execute, admin/advt/install)
Martin v. Löwis0077b652010-03-16 18:53:33 +0000236 msiname = "python-%s%s.msi" % (full_current_version, msilib.arch_ext)
237 db = msilib.init_database(msiname,
Martin v. Löwise40a2132008-09-13 08:37:17 +0000238 schema, ProductName="Python "+full_current_version+productsuffix,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000239 ProductCode=product_code,
240 ProductVersion=current_version,
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000241 Manufacturer=u"Python Software Foundation",
242 request_uac = True)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000243 # The default sequencing of the RemoveExistingProducts action causes
244 # removal of files that got just installed. Place it after
245 # InstallInitialize, so we first uninstall everything, but still roll
246 # back in case the installation is interrupted
247 msilib.change_sequence(sequence.InstallExecuteSequence,
248 "RemoveExistingProducts", 1510)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000249 msilib.add_tables(db, sequence)
250 # We cannot set ALLUSERS in the property table, as this cannot be
251 # reset if the user choses a per-user installation. Instead, we
252 # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages
253 # this property, and when the execution starts, ALLUSERS is set
254 # accordingly.
255 add_data(db, "Property", [("UpgradeCode", uc),
256 ("WhichUsers", "ALL"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000257 ("ProductLine", "Python%s%s" % (major, minor)),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000258 ])
259 db.Commit()
Martin v. Löwis0077b652010-03-16 18:53:33 +0000260 return db, msiname
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000261
262def remove_old_versions(db):
263 "Fill the upgrade table."
264 start = "%s.%s.0" % (major, minor)
265 # This requests that feature selection states of an older
266 # installation should be forwarded into this one. Upgrading
267 # requires that both the old and the new installation are
268 # either both per-machine or per-user.
269 migrate_features = 1
270 # See "Upgrade Table". We remove releases with the same major and
271 # minor version. For an snapshot, we remove all earlier snapshots. For
272 # a release, we remove all snapshots, and all earlier releases.
273 if snapshot:
274 add_data(db, "Upgrade",
Tim Peters66cb0182004-08-26 05:23:19 +0000275 [(upgrade_code_snapshot, start,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000276 current_version,
277 None, # Ignore language
Tim Peters66cb0182004-08-26 05:23:19 +0000278 migrate_features,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000279 None, # Migrate ALL features
280 "REMOVEOLDSNAPSHOT")])
281 props = "REMOVEOLDSNAPSHOT"
282 else:
283 add_data(db, "Upgrade",
284 [(upgrade_code, start, current_version,
285 None, migrate_features, None, "REMOVEOLDVERSION"),
286 (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1),
287 None, migrate_features, None, "REMOVEOLDSNAPSHOT")])
288 props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION"
Martin v. Löwis1c4c3062008-09-08 16:27:54 +0000289
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200290 props += ";TARGETDIR;DLLDIR;LAUNCHERDIR"
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000291 # Installer collects the product codes of the earlier releases in
292 # these properties. In order to allow modification of the properties,
293 # they must be declared as secure. See "SecureCustomProperties Property"
294 add_data(db, "Property", [("SecureCustomProperties", props)])
295
296class PyDialog(Dialog):
297 """Dialog class with a fixed layout: controls at the top, then a ruler,
298 then a list of buttons: back, next, cancel. Optionally a bitmap at the
299 left."""
300 def __init__(self, *args, **kw):
301 """Dialog(database, name, x, y, w, h, attributes, title, first,
302 default, cancel, bitmap=true)"""
303 Dialog.__init__(self, *args)
304 ruler = self.h - 36
305 bmwidth = 152*ruler/328
306 if kw.get("bitmap", True):
307 self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin")
308 self.line("BottomLine", 0, ruler, self.w, 0)
309
310 def title(self, title):
311 "Set the title text of the dialog at the top."
312 # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
313 # text, in VerdanaBold10
314 self.text("Title", 135, 10, 220, 60, 0x30003,
315 r"{\VerdanaBold10}%s" % title)
316
317 def back(self, title, next, name = "Back", active = 1):
318 """Add a back button with a given title, the tab-next button,
319 its name in the Control table, possibly initially disabled.
320
321 Return the button, so that events can be associated"""
322 if active:
323 flags = 3 # Visible|Enabled
324 else:
325 flags = 1 # Visible
326 return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next)
327
328 def cancel(self, title, next, name = "Cancel", active = 1):
329 """Add a cancel button with a given title, the tab-next button,
330 its name in the Control table, possibly initially disabled.
331
332 Return the button, so that events can be associated"""
333 if active:
334 flags = 3 # Visible|Enabled
335 else:
336 flags = 1 # Visible
337 return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next)
338
339 def next(self, title, next, name = "Next", active = 1):
340 """Add a Next button with a given title, the tab-next button,
341 its name in the Control table, possibly initially disabled.
342
343 Return the button, so that events can be associated"""
344 if active:
345 flags = 3 # Visible|Enabled
346 else:
347 flags = 1 # Visible
348 return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next)
349
350 def xbutton(self, name, title, next, xpos):
351 """Add a button with a given title, the tab-next button,
352 its name in the Control table, giving its x position; the
353 y-position is aligned with the other buttons.
354
355 Return the button, so that events can be associated"""
356 return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next)
357
358def add_ui(db):
359 x = y = 50
360 w = 370
361 h = 300
362 title = "[ProductName] Setup"
363
364 # see "Dialog Style Bits"
365 modal = 3 # visible | modal
366 modeless = 1 # visible
367 track_disk_space = 32
368
369 add_data(db, 'ActionText', uisample.ActionText)
370 add_data(db, 'UIText', uisample.UIText)
371
372 # Bitmaps
373 if not os.path.exists(srcdir+r"\PC\python_icon.exe"):
Georg Brandlbf82e372008-05-16 17:02:34 +0000374 raise RuntimeError("Run icons.mak in PC directory")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000375 add_data(db, "Binary",
Christian Heimesd9a4d1d2008-01-01 14:42:15 +0000376 [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000377 ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")),
378 ])
379 add_data(db, "Icon",
380 [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))])
381
382 # Scripts
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000383 # CheckDir sets TargetExists if TARGETDIR exists.
384 # UpdateEditIDLE sets the REGISTRY.tcl component into
385 # the installed/uninstalled state according to both the
386 # Extensions and TclTk features.
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000387 add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))])
388 # See "Custom Action Type 1"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000389 if msilib.Win64:
390 CheckDir = "CheckDir"
Martin v. Löwisdf40ce32006-02-16 14:38:30 +0000391 UpdateEditIDLE = "UpdateEditIDLE"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000392 else:
393 CheckDir = "_CheckDir@4"
394 UpdateEditIDLE = "_UpdateEditIDLE@4"
Tim Peters0e9980f2004-09-12 03:49:31 +0000395 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000396 [("CheckDir", 1, "Script", CheckDir)])
Martin v. Löwiseac02e62004-11-18 08:00:33 +0000397 if have_tcl:
398 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000399 [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)])
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000400
401 # UI customization properties
402 add_data(db, "Property",
403 # See "DefaultUIFont Property"
404 [("DefaultUIFont", "DlgFont8"),
405 # See "ErrorDialog Style Bit"
406 ("ErrorDialog", "ErrorDlg"),
407 ("Progress1", "Install"), # modified in maintenance type dlg
408 ("Progress2", "installs"),
409 ("MaintenanceForm_Action", "Repair")])
410
411 # Fonts, see "TextStyle Table"
412 add_data(db, "TextStyle",
413 [("DlgFont8", "Tahoma", 9, None, 0),
414 ("DlgFontBold8", "Tahoma", 8, None, 1), #bold
415 ("VerdanaBold10", "Verdana", 10, None, 1),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000416 ("VerdanaRed9", "Verdana", 9, 255, 0),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000417 ])
418
Vinay Sajip65e2bef2012-10-28 09:11:00 +0000419 compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TARGETDIR]Lib"'
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000420 lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000421 # See "CustomAction Table"
422 add_data(db, "CustomAction", [
423 # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty
424 # See "Custom Action Type 51",
425 # "Custom Action Execution Scheduling Options"
426 ("InitialTargetDir", 307, "TARGETDIR",
427 "[WindowsVolume]Python%s%s" % (major, minor)),
428 ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
429 ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200430 ("SetLauncherDirToTarget", 307, "LAUNCHERDIR", "[TARGETDIR]"),
431 ("SetLauncherDirToWindows", 307, "LAUNCHERDIR", "[WindowsFolder]"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000432 # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
433 # See "Custom Action Type 18"
Martin v. Löwis7b2563b2004-11-02 22:59:56 +0000434 ("CompilePyc", 18, "python.exe", compileargs),
435 ("CompilePyo", 18, "python.exe", "-O "+compileargs),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000436 ("CompileGrammar", 18, "python.exe", lib2to3args),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000437 ])
438
439 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
440 # Numbers indicate sequence; see sequence.py for how these action integrate
441 add_data(db, "InstallUISequence",
442 [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
443 ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141),
444 ("InitialTargetDir", 'TARGETDIR=""', 750),
445 # In the user interface, assume all-users installation if privileged.
446 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
447 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200448 ("SetLauncherDirToWindows", 'LAUNCHERDIR="" and ' + sys32cond, 753),
449 ("SetLauncherDirToTarget", 'LAUNCHERDIR="" and not ' + sys32cond, 754),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000450 ("SelectDirectoryDlg", "Not Installed", 1230),
451 # XXX no support for resume installations yet
452 #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
453 ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250),
454 ("ProgressDlg", None, 1280)])
455 add_data(db, "AdminUISequence",
456 [("InitialTargetDir", 'TARGETDIR=""', 750),
457 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200458 ("SetLauncherDirToTarget", 'LAUNCHERDIR=""', 752),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000459 ])
460
Brian Curtinae775842012-04-25 08:12:37 -0500461 # Prepend TARGETDIR to the system path, and remove it on uninstall.
462 add_data(db, "Environment",
463 [("PathAddition", "=-*Path", "[TARGETDIR];[~]", "REGISTRY.path")])
464
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000465 # Execute Sequences
466 add_data(db, "InstallExecuteSequence",
467 [("InitialTargetDir", 'TARGETDIR=""', 750),
468 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
469 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200470 ("SetLauncherDirToWindows", 'LAUNCHERDIR="" and ' + sys32cond, 753),
471 ("SetLauncherDirToTarget", 'LAUNCHERDIR="" and not ' + sys32cond, 754),
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000472 ("UpdateEditIDLE", None, 1050),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000473 ("CompilePyc", "COMPILEALL", 6800),
474 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000475 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000476 ])
477 add_data(db, "AdminExecuteSequence",
478 [("InitialTargetDir", 'TARGETDIR=""', 750),
479 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200480 ("SetLauncherDirToTarget", 'LAUNCHERDIR=""', 752),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000481 ("CompilePyc", "COMPILEALL", 6800),
482 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000483 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000484 ])
485
486 #####################################################################
487 # Standard dialogs: FatalError, UserExit, ExitDialog
488 fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title,
489 "Finish", "Finish", "Finish")
490 fatal.title("[ProductName] Installer ended prematurely")
491 fatal.back("< Back", "Finish", active = 0)
492 fatal.cancel("Cancel", "Back", active = 0)
493 fatal.text("Description1", 135, 70, 220, 80, 0x30003,
494 "[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.")
495 fatal.text("Description2", 135, 155, 220, 20, 0x30003,
496 "Click the Finish button to exit the Installer.")
497 c=fatal.next("Finish", "Cancel", name="Finish")
498 # See "ControlEvent Table". Parameters are the event, the parameter
499 # to the action, and optionally the condition for the event, and the order
500 # of events.
501 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000502
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000503 user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title,
504 "Finish", "Finish", "Finish")
505 user_exit.title("[ProductName] Installer was interrupted")
506 user_exit.back("< Back", "Finish", active = 0)
507 user_exit.cancel("Cancel", "Back", active = 0)
508 user_exit.text("Description1", 135, 70, 220, 80, 0x30003,
509 "[ProductName] setup was interrupted. Your system has not been modified. "
510 "To install this program at a later time, please run the installation again.")
511 user_exit.text("Description2", 135, 155, 220, 20, 0x30003,
512 "Click the Finish button to exit the Installer.")
513 c = user_exit.next("Finish", "Cancel", name="Finish")
514 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000515
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000516 exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title,
517 "Finish", "Finish", "Finish")
Martin v. Löwis26bb3cf2012-02-21 17:23:55 +0100518 exit_dialog.title("Complete the [ProductName] Installer")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000519 exit_dialog.back("< Back", "Finish", active = 0)
520 exit_dialog.cancel("Cancel", "Back", active = 0)
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000521 exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003,
522 "Special Windows thanks to:\n"
Martin v. Löwisd3f61a22004-08-30 09:22:30 +0000523 " Mark Hammond, without whose years of freely \n"
524 " shared Windows expertise, Python for Windows \n"
525 " would still be Python for DOS.")
Tim Peters66cb0182004-08-26 05:23:19 +0000526
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000527 c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003,
528 "{\\VerdanaRed9}Warning: Python 2.5.x is the last "
529 "Python release for Windows 9x.")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000530 c.condition("Hide", "NOT Version9X")
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000531
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000532 exit_dialog.text("Description", 135, 235, 220, 20, 0x30003,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000533 "Click the Finish button to exit the Installer.")
534 c = exit_dialog.next("Finish", "Cancel", name="Finish")
535 c.event("EndDialog", "Return")
536
537 #####################################################################
538 # Required dialog: FilesInUse, ErrorDlg
539 inuse = PyDialog(db, "FilesInUse",
540 x, y, w, h,
541 19, # KeepModeless|Modal|Visible
542 title,
543 "Retry", "Retry", "Retry", bitmap=False)
544 inuse.text("Title", 15, 6, 200, 15, 0x30003,
545 r"{\DlgFontBold8}Files in Use")
546 inuse.text("Description", 20, 23, 280, 20, 0x30003,
547 "Some files that need to be updated are currently in use.")
548 inuse.text("Text", 20, 55, 330, 50, 3,
549 "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.")
550 inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess",
551 None, None, None)
552 c=inuse.back("Exit", "Ignore", name="Exit")
553 c.event("EndDialog", "Exit")
554 c=inuse.next("Ignore", "Retry", name="Ignore")
555 c.event("EndDialog", "Ignore")
556 c=inuse.cancel("Retry", "Exit", name="Retry")
557 c.event("EndDialog","Retry")
558
559
560 # See "Error Dialog". See "ICE20" for the required names of the controls.
561 error = Dialog(db, "ErrorDlg",
562 50, 10, 330, 101,
563 65543, # Error|Minimize|Modal|Visible
564 title,
565 "ErrorText", None, None)
566 error.text("ErrorText", 50,9,280,48,3, "")
567 error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
568 error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo")
569 error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes")
570 error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort")
571 error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel")
572 error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore")
573 error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk")
574 error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry")
575
576 #####################################################################
577 # Global "Query Cancel" dialog
578 cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title,
579 "No", "No", "No")
Tim Peters66cb0182004-08-26 05:23:19 +0000580 cancel.text("Text", 48, 15, 194, 30, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000581 "Are you sure you want to cancel [ProductName] installation?")
582 cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
583 "py.ico", None, None)
584 c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
585 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000586
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000587 c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
588 c.event("EndDialog", "Return")
589
590 #####################################################################
591 # Global "Wait for costing" dialog
592 costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title,
593 "Return", "Return", "Return")
594 costing.text("Text", 48, 15, 194, 30, 3,
595 "Please wait while the installer finishes determining your disk space requirements.")
596 costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
597 "py.ico", None, None)
598 c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
599 c.event("EndDialog", "Exit")
600
601 #####################################################################
602 # Preparation dialog: no user input except cancellation
603 prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title,
604 "Cancel", "Cancel", "Cancel")
605 prep.text("Description", 135, 70, 220, 40, 0x30003,
606 "Please wait while the Installer prepares to guide you through the installation.")
607 prep.title("Welcome to the [ProductName] Installer")
608 c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...")
609 c.mapping("ActionText", "Text")
610 c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None)
611 c.mapping("ActionData", "Text")
612 prep.back("Back", None, active=0)
613 prep.next("Next", None, active=0)
614 c=prep.cancel("Cancel", None)
615 c.event("SpawnDialog", "CancelDlg")
616
617 #####################################################################
618 # Target directory selection
619 seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title,
620 "Next", "Next", "Cancel")
621 seldlg.title("Select Destination Directory")
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000622 c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003,
623 "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.")
624 c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000625 seldlg.text("Description", 135, 50, 220, 40, 0x30003,
626 "Please select a directory for the [ProductName] files.")
627
628 seldlg.back("< Back", None, active=0)
629 c = seldlg.next("Next >", "Cancel")
630 c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1)
631 # If the target exists, but we found that we are going to remove old versions, don't bother
632 # confirming that the target directory exists. Strictly speaking, we should determine that
633 # the target directory is indeed the target of the product that we are going to remove, but
634 # I don't know how to do that.
635 c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2)
636 c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3)
637 c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4)
Brian Curtinfafd9ee2012-06-22 21:40:52 -0500638 c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000639
640 c = seldlg.cancel("Cancel", "DirectoryCombo")
641 c.event("SpawnDialog", "CancelDlg")
642
643 seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219,
644 "TARGETDIR", None, "DirectoryList", None)
645 seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR",
646 None, "PathEdit", None)
647 seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None)
648 c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
649 c.event("DirectoryListUp", "0")
650 c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
651 c.event("DirectoryListNew", "0")
652
653 #####################################################################
654 # SelectFeaturesDlg
655 features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space,
656 title, "Tree", "Next", "Cancel")
657 features.title("Customize [ProductName]")
658 features.text("Description", 135, 35, 220, 15, 0x30003,
659 "Select the way you want features to be installed.")
660 features.text("Text", 135,45,220,30, 3,
661 "Click on the icons in the tree below to change the way features will be installed.")
662
663 c=features.back("< Back", "Next")
Brian Curtinfafd9ee2012-06-22 21:40:52 -0500664 c.event("NewDialog", "SelectDirectoryDlg")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000665
666 c=features.next("Next >", "Cancel")
667 c.mapping("SelectionNoItems", "Enabled")
668 c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1)
669 c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2)
670
671 c=features.cancel("Cancel", "Tree")
672 c.event("SpawnDialog", "CancelDlg")
673
Tim Peters66cb0182004-08-26 05:23:19 +0000674 # 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 +0000675 features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty",
676 "Tree of selections", "Back", None)
677
678 #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost")
679 #c.mapping("SelectionNoItems", "Enabled")
680 #c.event("Reset", "0")
Tim Peters66cb0182004-08-26 05:23:19 +0000681
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000682 features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None)
683
684 c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10)
685 c.mapping("SelectionNoItems","Enabled")
686 c.event("SpawnDialog", "DiskCostDlg")
687
688 c=features.xbutton("Advanced", "Advanced", None, 0.30)
689 c.event("SpawnDialog", "AdvancedDlg")
690
Brian Curtinae775842012-04-25 08:12:37 -0500691 c=features.text("ItemDescription", 140, 180, 210, 40, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000692 "Multiline description of the currently selected item.")
693 c.mapping("SelectionDescription","Text")
Tim Peters66cb0182004-08-26 05:23:19 +0000694
Brian Curtinae775842012-04-25 08:12:37 -0500695 c=features.text("ItemSize", 140, 225, 210, 33, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000696 "The size of the currently selected item.")
697 c.mapping("SelectionSize", "Text")
698
699 #####################################################################
700 # Disk cost
701 cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title,
702 "OK", "OK", "OK", bitmap=False)
703 cost.text("Title", 15, 6, 200, 15, 0x30003,
704 "{\DlgFontBold8}Disk Space Requirements")
705 cost.text("Description", 20, 20, 280, 20, 0x30003,
706 "The disk space required for the installation of the selected features.")
707 cost.text("Text", 20, 53, 330, 60, 3,
708 "The highlighted volumes (if any) do not have enough disk space "
709 "available for the currently selected features. You can either "
710 "remove some files from the highlighted volumes, or choose to "
711 "install less features onto local drive(s), or select different "
712 "destination drive(s).")
713 cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223,
714 None, "{120}{70}{70}{70}{70}", None, None)
715 cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
716
717 #####################################################################
718 # WhichUsers Dialog. Only available on NT, and for privileged users.
719 # This must be run before FindRelatedProducts, because that will
720 # take into account whether the previous installation was per-user
721 # or per-machine. We currently don't support going back to this
722 # dialog after "Next" was selected; to support this, we would need to
723 # find how to reset the ALLUSERS property, and how to re-run
724 # FindRelatedProducts.
725 # On Windows9x, the ALLUSERS property is ignored on the command line
726 # and in the Property table, but installer fails according to the documentation
727 # if a dialog attempts to set ALLUSERS.
728 whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title,
729 "AdminInstall", "Next", "Cancel")
730 whichusers.title("Select whether to install [ProductName] for all users of this computer.")
731 # A radio group with two options: allusers, justme
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000732 g = whichusers.radiogroup("AdminInstall", 135, 60, 235, 80, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000733 "WhichUsers", "", "Next")
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000734 g.condition("Disable", "VersionNT=600") # Not available on Vista and Windows 2008
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000735 g.add("ALL", 0, 5, 150, 20, "Install for all users")
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000736 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 +0000737
Tim Peters66cb0182004-08-26 05:23:19 +0000738 whichusers.back("Back", None, active=0)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000739
740 c = whichusers.next("Next >", "Cancel")
741 c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
742 c.event("EndDialog", "Return", order = 2)
743
744 c = whichusers.cancel("Cancel", "AdminInstall")
745 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000746
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000747 #####################################################################
748 # Advanced Dialog.
749 advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title,
Martin v. Löwisa632a752008-11-19 13:55:07 +0000750 "CompilePyc", "Ok", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000751 advanced.title("Advanced Options for [ProductName]")
752 # A radio group with two options: allusers, justme
753 advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3,
Martin v. Löwisa632a752008-11-19 13:55:07 +0000754 "COMPILEALL", "Compile .py files to byte code after installation", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000755
Martin v. Löwisa632a752008-11-19 13:55:07 +0000756 c = advanced.cancel("Ok", "CompilePyc", name="Ok") # Button just has location of cancel button.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000757 c.event("EndDialog", "Return")
758
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000759 #####################################################################
Tim Peters66cb0182004-08-26 05:23:19 +0000760 # Existing Directory dialog
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000761 dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title,
762 "No", "No", "No")
763 dlg.text("Title", 10, 20, 180, 40, 3,
764 "[TARGETDIR] exists. Are you sure you want to overwrite existing files?")
765 c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No")
766 c.event("[TargetExists]", "0", order=1)
767 c.event("[TargetExistsOk]", "1", order=2)
768 c.event("EndDialog", "Return", order=3)
769 c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes")
770 c.event("EndDialog", "Return")
771
772 #####################################################################
773 # Installation Progress dialog (modeless)
774 progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title,
775 "Cancel", "Cancel", "Cancel", bitmap=False)
776 progress.text("Title", 20, 15, 200, 15, 0x30003,
777 "{\DlgFontBold8}[Progress1] [ProductName]")
778 progress.text("Text", 35, 65, 300, 30, 3,
779 "Please wait while the Installer [Progress2] [ProductName]. "
780 "This may take several minutes.")
781 progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
782
783 c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...")
784 c.mapping("ActionText", "Text")
785
786 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
787 #c.mapping("ActionData", "Text")
788
789 c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537,
790 None, "Progress done", None, None)
791 c.mapping("SetProgress", "Progress")
792
793 progress.back("< Back", "Next", active=False)
794 progress.next("Next >", "Cancel", active=False)
795 progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
796
797 # Maintenance type: repair/uninstall
798 maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title,
799 "Next", "Next", "Cancel")
800 maint.title("Welcome to the [ProductName] Setup Wizard")
801 maint.text("BodyText", 135, 63, 230, 42, 3,
802 "Select whether you want to repair or remove [ProductName].")
803 g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3,
804 "MaintenanceForm_Action", "", "Next")
805 g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
806 g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
807 g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
Tim Peters66cb0182004-08-26 05:23:19 +0000808
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000809 maint.back("< Back", None, active=False)
810 c=maint.next("Finish", "Cancel")
811 # Change installation: Change progress dialog to "Change", then ask
812 # for feature selection
813 c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
814 c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
815
816 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
817 # Also set list of reinstalled features to "ALL"
818 c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
819 c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
Raymond Hettinger72f08012004-11-07 07:08:25 +0000820 c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000821 c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
822
823 # Uninstall: Change progress to "Remove", then invoke uninstall
824 # Also set list of removed features to "ALL"
825 c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
826 c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
827 c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
828 c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
829
Tim Peters66cb0182004-08-26 05:23:19 +0000830 # Close dialog when maintenance action scheduled
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000831 c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
832 c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
Tim Peters66cb0182004-08-26 05:23:19 +0000833
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000834 maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000835
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000836
837# See "Feature Table". The feature level is 1 for all features,
838# and the feature attributes are 0 for the DefaultFeature, and
839# FollowParent for all other features. The numbers are the Display
840# column.
841def add_features(db):
842 # feature attributes:
843 # msidbFeatureAttributesFollowParent == 2
844 # msidbFeatureAttributesDisallowAdvertise == 8
845 # Features that need to be installed with together with the main feature
846 # (i.e. additional Python libraries) need to follow the parent feature.
847 # Features that have no advertisement trigger (e.g. the test suite)
848 # must not support advertisement
Brian Curtinae775842012-04-25 08:12:37 -0500849 global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt, prepend_path
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000850 default_feature = Feature(db, "DefaultFeature", "Python",
851 "Python Interpreter and Libraries",
852 1, directory = "TARGETDIR")
Martin v. Löwis2a241ca2008-04-05 18:58:09 +0000853 shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0,
854 level=0)
855 private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0,
856 level=0)
Brian Curtinfafd9ee2012-06-22 21:40:52 -0500857 add_data(db, "Condition", [("SharedCRT", 1, sys32cond),
858 ("PrivateCRT", 1, "not "+sys32cond)])
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000859 # We don't support advertisement of extensions
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000860 ext_feature = Feature(db, "Extensions", "Register Extensions",
861 "Make this Python installation the default Python installation", 3,
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000862 parent = default_feature, attributes=2|8)
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000863 if have_tcl:
864 tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000865 parent = default_feature, attributes=2)
866 htmlfiles = Feature(db, "Documentation", "Documentation",
867 "Python HTMLHelp File", 7, parent = default_feature)
868 tools = Feature(db, "Tools", "Utility Scripts",
Brian Curtin790a9b42012-04-25 23:38:05 -0500869 "Python utility scripts (Tools/)", 9,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000870 parent = default_feature, attributes=2)
871 testsuite = Feature(db, "Testsuite", "Test suite",
872 "Python test suite (Lib/test/)", 11,
873 parent = default_feature, attributes=2|8)
Brian Curtinae775842012-04-25 08:12:37 -0500874 # prepend_path is an additional feature which is to be off by default.
875 # Since the default level for the above features is 1, this needs to be
876 # at least level higher.
877 prepend_path = Feature(db, "PrependPath", "Add python.exe to Path",
878 "Prepend [TARGETDIR] to the system Path variable. "
879 "This allows you to type 'python' into a command "
880 "prompt without needing the full path.", 13,
881 parent = default_feature, attributes=2|8,
882 level=2)
Tim Peters66cb0182004-08-26 05:23:19 +0000883
Brian Curtin401f9f32012-05-13 11:19:23 -0500884def extract_msvcr100():
Martin v. Löwisee7498e2008-02-28 23:01:33 +0000885 # Find the redistributable files
Martin v. Löwis8a2e90e2008-09-19 19:21:20 +0000886 if msilib.Win64:
Martin v. Löwis4b10e192012-05-31 21:58:21 +0200887 arch = "x64"
Martin v. Löwis8a2e90e2008-09-19 19:21:20 +0000888 else:
889 arch = "x86"
Brian Curtin401f9f32012-05-13 11:19:23 -0500890 dir = os.path.join(os.environ['VS100COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC100.CRT" % arch)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000891
Christian Heimese1feb2e2008-02-28 20:52:40 +0000892 result = []
Christian Heimes81ca7c72007-11-18 18:18:41 +0000893 installer = msilib.MakeInstaller()
Brian Curtin401f9f32012-05-13 11:19:23 -0500894 # At least for VS2010, manifests are no longer provided
895 name = "msvcr100.dll"
896 path = os.path.join(dir, name)
897 kw = {'src':path}
898 kw['version'] = installer.FileVersion(path, 0)
899 kw['language'] = installer.FileVersion(path, 1)
900 return name, kw
Christian Heimes81ca7c72007-11-18 18:18:41 +0000901
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000902def generate_license():
903 import shutil, glob
904 out = open("LICENSE.txt", "w")
905 shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out)
Martin v. Löwisb29f2d72008-09-14 20:27:52 +0000906 shutil.copyfileobj(open("crtlicense.txt"), out)
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000907 for name, pat, file in (("bzip2","bzip2-*", "LICENSE"),
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000908 ("openssl", "openssl-*", "LICENSE"),
909 ("Tcl", "tcl8*", "license.terms"),
910 ("Tk", "tk8*", "license.terms"),
911 ("Tix", "tix-*", "license.terms")):
912 out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name)
913 dirs = glob.glob(srcdir+"/../"+pat)
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000914 if not dirs:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000915 raise ValueError, "Could not find "+srcdir+"/../"+pat
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200916 if len(dirs) > 2 and not snapshot:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000917 raise ValueError, "Multiple copies of "+pat
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000918 dir = dirs[0]
919 shutil.copyfileobj(open(os.path.join(dir, file)), out)
920 out.close()
921
922
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000923class PyDirectory(Directory):
924 """By default, all components in the Python installer
925 can run from source."""
926 def __init__(self, *args, **kw):
Georg Brandlbf82e372008-05-16 17:02:34 +0000927 if "componentflags" not in kw:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000928 kw['componentflags'] = 2 #msidbComponentAttributesOptional
929 Directory.__init__(self, *args, **kw)
930
Martin v. Löwis41add012012-03-06 17:53:12 +0100931def hgmanifest():
932 # Fetch file list from Mercurial
933 process = subprocess.Popen(['hg', 'manifest'], stdout=subprocess.PIPE)
934 stdout, stderr = process.communicate()
935 # Create nested directories for file tree
936 result = {}
937 for line in stdout.splitlines():
938 components = line.split('/')
939 d = result
940 while len(components) > 1:
941 d1 = d.setdefault(components[0], {})
942 d = d1
943 del components[0]
944 d[components[0]] = None
945 return result
Martin v. Löwis797721b2010-08-03 18:35:55 +0000946
Martin v. Löwis6ca5a4d2012-02-21 19:54:26 +0100947
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000948# See "File Table", "Component Table", "Directory Table",
949# "FeatureComponents Table"
950def add_files(db):
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200951 installer = msilib.MakeInstaller()
Martin v. Löwis41add012012-03-06 17:53:12 +0100952 hgfiles = hgmanifest()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000953 cab = CAB("python")
954 tmpfiles = []
955 # Add all executables, icons, text files into the TARGETDIR component
956 root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir")
957 default_feature.set_current()
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000958 if not msilib.Win64:
Christian Heimes81ca7c72007-11-18 18:18:41 +0000959 root.add_file("%s/w9xpopen.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000960 root.add_file("README.txt", src="README")
961 root.add_file("NEWS.txt", src="Misc/NEWS")
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000962 generate_license()
963 root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000964 root.start_component("python.exe", keyfile="python.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000965 root.add_file("%s/python.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000966 root.start_component("pythonw.exe", keyfile="pythonw.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000967 root.add_file("%s/pythonw.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000968
969 # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
Martin v. Löwisc820eaf2008-10-17 13:47:20 +0000970 dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200971 launcherdir = PyDirectory(db, cab, root, srcdir, "LAUNCHERDIR", ".")
972
973 # msidbComponentAttributes64bit = 256; this disables registry redirection
974 # to allow setting the SharedDLLs key in the 64-bit portion even for a
975 # 32-bit installer.
976 # XXX does this still allow to install the component on a 32-bit system?
Martin v. Löwis8559b3c2012-06-21 18:24:32 +0200977 # Pick up 32-bit binary always
Martin v. Löwis5951ec02012-08-24 16:06:10 +0200978 launchersrc = PCBUILD
979 if launchersrc.lower() == 'pcbuild\\x64-pgo':
980 launchersrc = 'PCBuild\\win32-pgo'
Martin v. Löwis77cc86f2012-09-29 13:08:41 +0200981 if launchersrc.lower() == 'pcbuild\\amd64':
982 launchersrc = 'PCBuild'
Martin v. Löwis5951ec02012-08-24 16:06:10 +0200983 launcher = os.path.join(srcdir, launchersrc, "py.exe")
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200984 launcherdir.start_component("launcher", flags = 8+256, keyfile="py.exe")
Martin v. Löwis5951ec02012-08-24 16:06:10 +0200985 launcherdir.add_file(launcher,
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200986 version=installer.FileVersion(launcher, 0),
987 language=installer.FileVersion(launcher, 1))
Martin v. Löwis5951ec02012-08-24 16:06:10 +0200988 launcherw = os.path.join(srcdir, launchersrc, "pyw.exe")
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200989 launcherdir.start_component("launcherw", flags = 8+256, keyfile="pyw.exe")
Martin v. Löwis5951ec02012-08-24 16:06:10 +0200990 launcherdir.add_file(launcherw,
Martin v. Löwis7dae2342012-06-21 17:36:05 +0200991 version=installer.FileVersion(launcherw, 0),
992 language=installer.FileVersion(launcherw, 1))
Christian Heimese1feb2e2008-02-28 20:52:40 +0000993
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000994 pydll = "python%s%s.dll" % (major, minor)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000995 pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000996 dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000997 pyversion = installer.FileVersion(pydllsrc, 0)
998 if not snapshot:
999 # For releases, the Python DLL has the same version as the
1000 # installer package.
1001 assert pyversion.split(".")[:3] == current_version.split(".")
Christian Heimes81ca7c72007-11-18 18:18:41 +00001002 dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001003 version=pyversion,
1004 language=installer.FileVersion(pydllsrc, 1))
Christian Heimese1feb2e2008-02-28 20:52:40 +00001005 DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs")
Christian Heimes81ca7c72007-11-18 18:18:41 +00001006
Martin v. Löwis21c80f22008-04-07 21:14:19 +00001007 # msvcr90.dll: Need to place the DLL and the manifest into the root directory,
1008 # plus another copy of the manifest in the DLLs directory, with the manifest
1009 # pointing to the root directory
1010 root.start_component("msvcr90", feature=private_crt)
1011 # Results are ID,keyword pairs
Brian Curtin401f9f32012-05-13 11:19:23 -05001012 crtdll, kwds = extract_msvcr100()
1013 root.add_file(crtdll, **kwds)
Martin v. Löwis21c80f22008-04-07 21:14:19 +00001014 # Copy the manifest
Martin v. Löwis91845562008-11-06 19:46:56 +00001015 # Actually, don't do that anymore - no DLL in DLLs should have a manifest
1016 # dependency on msvcr90.dll anymore, so this should not be necessary
1017 #manifest_dlls = manifest[0]+".root"
1018 #open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr"))
1019 #DLLs.start_component("msvcr90_dlls", feature=private_crt)
1020 #DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls))
Martin v. Löwis21c80f22008-04-07 21:14:19 +00001021
1022 # Now start the main component for the DLLs directory;
1023 # no regular files have been added to the directory yet.
1024 DLLs.start_component()
Tim Peters66cb0182004-08-26 05:23:19 +00001025
Thomas Wouters89f507f2006-12-13 04:49:30 +00001026 # Check if _ctypes.pyd exists
Christian Heimes81ca7c72007-11-18 18:18:41 +00001027 have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD)
Thomas Wouters89f507f2006-12-13 04:49:30 +00001028 if not have_ctypes:
Collin Winter6afaeb72007-08-03 17:06:41 +00001029 print("WARNING: _ctypes.pyd not found, ctypes will not be included")
Thomas Wouters89f507f2006-12-13 04:49:30 +00001030 extensions.remove("_ctypes.pyd")
1031
Georg Brandl6e47a332008-05-17 19:15:58 +00001032 # Add all .py files in Lib, except tkinter, test
Martin v. Löwis797721b2010-08-03 18:35:55 +00001033 dirs = []
Martin v. Löwis41add012012-03-06 17:53:12 +01001034 pydirs = [(root, "Lib", hgfiles["Lib"], default_feature)]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001035 while pydirs:
Martin v. Löwis94b8b822008-06-13 19:00:35 +00001036 # Commit every now and then, or else installer will complain
1037 db.Commit()
Martin v. Löwis41add012012-03-06 17:53:12 +01001038 parent, dir, files, feature = pydirs.pop()
1039 if dir.startswith("plat-"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001040 continue
Martin v. Löwis41add012012-03-06 17:53:12 +01001041 if dir in ["tkinter", "idlelib", "turtledemo"]:
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001042 if not have_tcl:
1043 continue
Martin v. Löwis41add012012-03-06 17:53:12 +01001044 feature = tcltk
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001045 tcltk.set_current()
Martin v. Löwis41add012012-03-06 17:53:12 +01001046 elif dir in ('test', 'tests'):
1047 feature = testsuite
Thomas Wouters89f507f2006-12-13 04:49:30 +00001048 elif not have_ctypes and dir == "ctypes":
1049 continue
Martin v. Löwis41add012012-03-06 17:53:12 +01001050 feature.set_current()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001051 lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
Martin v. Löwis797721b2010-08-03 18:35:55 +00001052 dirs.append(lib)
Martin v. Löwis41add012012-03-06 17:53:12 +01001053 has_py = False
1054 for name, subdir in files.items():
1055 if subdir is None:
1056 assert os.path.isfile(os.path.join(lib.absolute, name))
1057 if name == 'README':
1058 lib.add_file("README.txt", src="README")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001059 else:
Martin v. Löwis41add012012-03-06 17:53:12 +01001060 lib.add_file(name)
1061 has_py = has_py or name.endswith(".py") or name.endswith(".pyw")
1062 else:
1063 assert os.path.isdir(os.path.join(lib.absolute, name))
1064 pydirs.append((lib, name, subdir, feature))
1065
1066 if has_py:
1067 lib.remove_pyc()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001068 # Add DLLs
1069 default_feature.set_current()
Christian Heimese1feb2e2008-02-28 20:52:40 +00001070 lib = DLLs
Christian Heimesd9a4d1d2008-01-01 14:42:15 +00001071 lib.add_file("py.ico", src=srcdir+"/PC/py.ico")
1072 lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001073 dlls = []
1074 tclfiles = []
1075 for f in extensions:
1076 if f=="_tkinter.pyd":
1077 continue
Christian Heimes81ca7c72007-11-18 18:18:41 +00001078 if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f):
Collin Winter6afaeb72007-08-03 17:06:41 +00001079 print("WARNING: Missing extension", f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001080 continue
1081 dlls.append(f)
1082 lib.add_file(f)
Martin v. Löwisd53ee5d2010-12-05 23:07:58 +00001083 lib.add_file('python3.dll')
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001084 # Add sqlite
1085 if msilib.msi_type=="Intel64;1033":
1086 sqlite_arch = "/ia64"
1087 elif msilib.msi_type=="x64;1033":
1088 sqlite_arch = "/amd64"
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001089 tclsuffix = "64"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001090 else:
1091 sqlite_arch = ""
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001092 tclsuffix = ""
Martin v. Löwis94b8b822008-06-13 19:00:35 +00001093 lib.add_file("sqlite3.dll")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001094 if have_tcl:
Christian Heimes81ca7c72007-11-18 18:18:41 +00001095 if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)):
Collin Winter6afaeb72007-08-03 17:06:41 +00001096 print("WARNING: Missing _tkinter.pyd")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001097 else:
1098 lib.start_component("TkDLLs", tcltk)
1099 lib.add_file("_tkinter.pyd")
1100 dlls.append("_tkinter.pyd")
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001101 tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001102 for f in glob.glob1(tcldir, "*.dll"):
1103 lib.add_file(f, src=os.path.join(tcldir, f))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001104 # check whether there are any unknown extensions
Christian Heimes81ca7c72007-11-18 18:18:41 +00001105 for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001106 if f.endswith("_d.pyd"): continue # debug version
1107 if f in dlls: continue
Collin Winter6afaeb72007-08-03 17:06:41 +00001108 print("WARNING: Unknown extension", f)
Tim Peters66cb0182004-08-26 05:23:19 +00001109
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001110 # Add headers
1111 default_feature.set_current()
1112 lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include")
1113 lib.glob("*.h")
1114 lib.add_file("pyconfig.h", src="../PC/pyconfig.h")
1115 # Add import libraries
Christian Heimes81ca7c72007-11-18 18:18:41 +00001116 lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001117 for f in dlls:
1118 lib.add_file(f.replace('pyd','lib'))
1119 lib.add_file('python%s%s.lib' % (major, minor))
Martin v. Löwisd53ee5d2010-12-05 23:07:58 +00001120 lib.add_file('python3.lib')
Martin v. Löwis9fda9312004-12-22 13:41:49 +00001121 # Add the mingw-format library
1122 if have_mingw:
Tim Peters5a9fb3c2005-01-07 16:01:32 +00001123 lib.add_file('libpython%s%s.a' % (major, minor))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001124 if have_tcl:
1125 # Add Tcl/Tk
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001126 tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')]
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001127 tcltk.set_current()
1128 while tcldirs:
1129 parent, phys, dir = tcldirs.pop()
1130 lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir))
1131 if not os.path.exists(lib.absolute):
1132 continue
1133 for f in os.listdir(lib.absolute):
1134 if os.path.isdir(os.path.join(lib.absolute, f)):
1135 tcldirs.append((lib, f, f))
1136 else:
1137 lib.add_file(f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001138 # Add tools
1139 tools.set_current()
1140 tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools")
Martin v. Löwisa6207482010-08-28 13:40:10 +00001141 for f in ['i18n', 'pynche', 'Scripts']:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001142 lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f))
1143 lib.glob("*.py")
1144 lib.glob("*.pyw", exclude=['pydocgui.pyw'])
1145 lib.remove_pyc()
1146 lib.glob("*.txt")
1147 if f == "pynche":
1148 x = PyDirectory(db, cab, lib, "X", "X", "X|X")
1149 x.glob("*.txt")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001150 if os.path.exists(os.path.join(lib.absolute, "README")):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001151 lib.add_file("README.txt", src="README")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001152 if f == 'Scripts':
Martin v. Löwisfe218842008-10-01 11:22:32 +00001153 lib.add_file("2to3.py", src="2to3")
Vinay Sajip4334d742011-07-03 10:35:41 +01001154 lib.add_file("pydoc3.py", src="pydoc3")
Vinay Sajip7ded1f02012-05-26 03:45:29 +01001155 lib.add_file("pyvenv.py", src="pyvenv")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001156 if have_tcl:
1157 lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
1158 lib.add_file("pydocgui.pyw")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001159 # Add documentation
1160 htmlfiles.set_current()
1161 lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc")
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001162 lib.start_component("documentation", keyfile=docfile)
1163 lib.add_file(docfile, src="build/htmlhelp/"+docfile)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001164
1165 cab.commit(db)
1166
1167 for f in tmpfiles:
1168 os.unlink(f)
1169
1170# See "Registry Table", "Component Table"
1171def add_registry(db):
1172 # File extensions, associated with the REGISTRY.def component
1173 # IDLE verbs depend on the tcltk feature.
1174 # msidbComponentAttributesRegistryKeyPath = 4
1175 # -1 for Root specifies "dependent on ALLUSERS property"
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001176 tcldata = []
1177 if have_tcl:
1178 tcldata = [
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001179 ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001180 "py.IDLE")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001181 add_data(db, "Component",
1182 # msidbComponentAttributesRegistryKeyPath = 4
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001183 [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001184 "InstallPath"),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001185 ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001186 "Documentation"),
Brian Curtinae775842012-04-25 08:12:37 -05001187 ("REGISTRY.path", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
1188 None),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001189 ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001190 None, None)] + tcldata)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001191 # See "FeatureComponents Table".
1192 # The association between TclTk and pythonw.exe is necessary to make ICE59
1193 # happy, because the installer otherwise believes that the IDLE and PyDoc
1194 # shortcuts might get installed without pythonw.exe being install. This
1195 # is not true, since installing TclTk will install the default feature, which
1196 # will cause pythonw.exe to be installed.
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001197 # REGISTRY.tcl is not associated with any feature, as it will be requested
1198 # through a custom action
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001199 tcldata = []
1200 if have_tcl:
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001201 tcldata = [(tcltk.id, "pythonw.exe")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001202 add_data(db, "FeatureComponents",
1203 [(default_feature.id, "REGISTRY"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001204 (htmlfiles.id, "REGISTRY.doc"),
Brian Curtinae775842012-04-25 08:12:37 -05001205 (prepend_path.id, "REGISTRY.path"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001206 (ext_feature.id, "REGISTRY.def")] +
1207 tcldata
1208 )
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001209 # Extensions are not advertised. For advertised extensions,
1210 # we would need separate binaries that install along with the
1211 # extension.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001212 pat = r"Software\Classes\%sPython.%sFile\shell\%s\command"
1213 ewi = "Edit with IDLE"
1214 pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon"
1215 pat3 = r"Software\Classes\%sPython.%sFile"
Martin v. Löwisbfda5442008-11-07 18:54:51 +00001216 pat4 = r"Software\Classes\%sPython.%sFile\shellex\DropHandler"
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001217 tcl_verbs = []
1218 if have_tcl:
1219 tcl_verbs=[
1220 ("py.IDLE", -1, pat % (testprefix, "", ewi), "",
Martin v. Löwis8482ef92009-05-05 16:14:30 +00001221 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001222 "REGISTRY.tcl"),
1223 ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "",
Martin v. Löwis8482ef92009-05-05 16:14:30 +00001224 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001225 "REGISTRY.tcl"),
1226 ]
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001227 add_data(db, "Registry",
1228 [# Extensions
1229 ("py.ext", -1, r"Software\Classes\."+ext, "",
1230 "Python.File", "REGISTRY.def"),
1231 ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "",
1232 "Python.NoConFile", "REGISTRY.def"),
1233 ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "",
1234 "Python.CompiledFile", "REGISTRY.def"),
1235 ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "",
1236 "Python.CompiledFile", "REGISTRY.def"),
1237 # MIME types
1238 ("py.mime", -1, r"Software\Classes\."+ext, "Content Type",
1239 "text/plain", "REGISTRY.def"),
1240 ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type",
1241 "text/plain", "REGISTRY.def"),
1242 #Verbs
1243 ("py.open", -1, pat % (testprefix, "", "open"), "",
Martin v. Löwis7dae2342012-06-21 17:36:05 +02001244 r'"[LAUNCHERDIR]py.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001245 ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
Martin v. Löwis7dae2342012-06-21 17:36:05 +02001246 r'"[LAUNCHERDIR]pyw.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001247 ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
Martin v. Löwis7dae2342012-06-21 17:36:05 +02001248 r'"[LAUNCHERDIR]py.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001249 ] + tcl_verbs + [
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001250 #Icons
1251 ("py.icon", -1, pat2 % (testprefix, ""), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001252 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001253 ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001254 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001255 ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001256 r'[DLLs]pyc.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001257 # Descriptions
1258 ("py.txt", -1, pat3 % (testprefix, ""), "",
1259 "Python File", "REGISTRY.def"),
1260 ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "",
1261 "Python File (no console)", "REGISTRY.def"),
1262 ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "",
1263 "Compiled Python File", "REGISTRY.def"),
Martin v. Löwisbfda5442008-11-07 18:54:51 +00001264 # Drop Handler
1265 ("py.drop", -1, pat4 % (testprefix, ""), "",
1266 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1267 ("pyw.drop", -1, pat4 % (testprefix, "NoCon"), "",
1268 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1269 ("pyc.drop", -1, pat4 % (testprefix, "Compiled"), "",
1270 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001271 ])
Tim Peters66cb0182004-08-26 05:23:19 +00001272
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001273 # Registry keys
1274 prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version)
1275 add_data(db, "Registry",
1276 [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"),
1277 ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "",
1278 "Python %s" % short_version, "REGISTRY"),
1279 ("PythonPath", -1, prefix+r"\PythonPath", "",
Georg Brandl6e47a332008-05-17 19:15:58 +00001280 r"[TARGETDIR]Lib;[TARGETDIR]DLLs", "REGISTRY"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001281 ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001282 "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001283 ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"),
1284 ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe",
Martin v. Löwis45a6b9f2008-11-30 11:12:00 +00001285 "", r"[TARGETDIR]Python.exe", "REGISTRY.def"),
1286 ("DisplayIcon", -1,
1287 r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code,
Martin v. Löwis95c46012009-06-28 09:36:14 +00001288 "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001289 ])
1290 # Shortcuts, see "Shortcut Table"
1291 add_data(db, "Directory",
1292 [("ProgramMenuFolder", "TARGETDIR", "."),
1293 ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))])
1294 add_data(db, "RemoveFile",
1295 [("MenuDir", "TARGETDIR", None, "MenuDir", 2)])
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001296 tcltkshortcuts = []
1297 if have_tcl:
1298 tcltkshortcuts = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001299 ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001300 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 +00001301 ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001302 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 +00001303 ]
1304 add_data(db, "Shortcut",
1305 tcltkshortcuts +
1306 [# Advertised shortcuts: targets are features, not files
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001307 ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe",
1308 default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001309 # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an
1310 # icon first.
1311 #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation",
1312 # htmlfiles.id, None, None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001313 ## Non-advertised shortcuts: must be associated with a registry component
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001314 ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001315 "[#%s]" % docfile, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001316 None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001317 ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY",
1318 SystemFolderName+"msiexec", "/x%s" % product_code,
1319 None, None, None, None, None, None),
1320 ])
1321 db.Commit()
1322
Martin v. Löwisa5e31092010-09-04 14:38:09 +00001323def build_pdbzip():
1324 pdbexclude = ['kill_python.pdb', 'make_buildinfo.pdb',
1325 'make_versioninfo.pdb']
1326 path = "python-%s%s-pdb.zip" % (full_current_version, msilib.arch_ext)
1327 pdbzip = zipfile.ZipFile(path, 'w')
1328 for f in glob.glob1(os.path.join(srcdir, PCBUILD), "*.pdb"):
1329 if f not in pdbexclude and not f.endswith('_d.pdb'):
1330 pdbzip.write(os.path.join(srcdir, PCBUILD, f), f)
1331 pdbzip.close()
1332
Martin v. Löwis0077b652010-03-16 18:53:33 +00001333db,msiname = build_database()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001334try:
1335 add_features(db)
1336 add_ui(db)
1337 add_files(db)
1338 add_registry(db)
1339 remove_old_versions(db)
1340 db.Commit()
1341finally:
1342 del db
Martin v. Löwis0077b652010-03-16 18:53:33 +00001343
1344# Merge CRT into MSI file. This requires the database to be closed.
1345mod_dir = os.path.join(os.environ["ProgramFiles"], "Common Files", "Merge Modules")
1346if msilib.Win64:
Brian Curtin401f9f32012-05-13 11:19:23 -05001347 modules = ["Microsoft_VC100_CRT_x64.msm"]
Martin v. Löwis0077b652010-03-16 18:53:33 +00001348else:
Brian Curtin401f9f32012-05-13 11:19:23 -05001349 modules = ["Microsoft_VC100_CRT_x86.msm"]
Martin v. Löwis0077b652010-03-16 18:53:33 +00001350
1351for i, n in enumerate(modules):
1352 modules[i] = os.path.join(mod_dir, n)
1353
1354def merge(msi, feature, rootdir, modules):
1355 cab_and_filecount = []
1356 # Step 1: Merge databases, extract cabfiles
1357 m = msilib.MakeMerge2()
1358 m.OpenLog("merge.log")
1359 m.OpenDatabase(msi)
1360 for module in modules:
1361 print module
1362 m.OpenModule(module,0)
1363 m.Merge(feature, rootdir)
1364 print "Errors:"
1365 for e in m.Errors:
1366 print e.Type, e.ModuleTable, e.DatabaseTable
1367 print " Modkeys:",
1368 for s in e.ModuleKeys: print s,
1369 print
1370 print " DBKeys:",
1371 for s in e.DatabaseKeys: print s,
1372 print
1373 cabname = tempfile.mktemp(suffix=".cab")
1374 m.ExtractCAB(cabname)
1375 cab_and_filecount.append((cabname, len(m.ModuleFiles)))
1376 m.CloseModule()
1377 m.CloseDatabase(True)
1378 m.CloseLog()
1379
1380 # Step 2: Add CAB files
1381 i = msilib.MakeInstaller()
1382 db = i.OpenDatabase(msi, constants.msiOpenDatabaseModeTransact)
1383
1384 v = db.OpenView("SELECT LastSequence FROM Media")
1385 v.Execute(None)
1386 maxmedia = -1
1387 while 1:
1388 r = v.Fetch()
1389 if not r: break
1390 seq = r.IntegerData(1)
1391 if seq > maxmedia:
1392 maxmedia = seq
1393 print "Start of Media", maxmedia
1394
1395 for cabname, count in cab_and_filecount:
1396 stream = "merged%d" % maxmedia
1397 msilib.add_data(db, "Media",
1398 [(maxmedia+1, maxmedia+count, None, "#"+stream, None, None)])
1399 msilib.add_stream(db, stream, cabname)
1400 os.unlink(cabname)
1401 maxmedia += count
1402 # The merge module sets ALLUSERS to 1 in the property table.
1403 # This is undesired; delete that
1404 v = db.OpenView("DELETE FROM Property WHERE Property='ALLUSERS'")
1405 v.Execute(None)
1406 v.Close()
1407 db.Commit()
1408
1409merge(msiname, "SharedCRT", "TARGETDIR", modules)
1410
1411# certname (from config.py) should be (a substring of)
1412# the certificate subject, e.g. "Python Software Foundation"
1413if certname:
1414 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 +00001415
1416if pdbzip:
1417 build_pdbzip()