blob: 219c0edf78a54936670b81c5cfce85d28e0ae76d [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öwiseebd0172010-11-14 18:17:39 +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
Martin v. Löwis1d278fc2006-03-28 18:30:05 +00009from uuids import product_codes
Martin v. Löwis34360642010-03-16 18:49:28 +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.
Steve Dower144de312014-09-12 11:48:13 -070016snapshot = int(os.environ.get("SNAPSHOT", "1"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000017# 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
Steve Dower144de312014-09-12 11:48:13 -070025full_current_version = os.environ.get("CURRENT_VERSION")
Martin v. Löwise0f780d2004-09-01 14:51:06 +000026# Is Tcl available at all?
27have_tcl = True
Christian Heimes9acba042007-12-04 14:57:30 +000028# path to PCbuild directory
Steve Dower144de312014-09-12 11:48:13 -070029PCBUILD=os.environ.get("PCBUILD", "PCbuild")
Christian Heimes9acba042007-12-04 14:57:30 +000030# msvcrt version
Martin v. Löwise7a434e2008-01-06 11:03:43 +000031MSVCR = "90"
Martin v. Löwis34360642010-03-16 18:49:28 +000032# Name of certificate in default store to sign MSI with
Steve Dower144de312014-09-12 11:48:13 -070033certname = os.environ.get("CERTNAME", None)
Martin v. Löwiseebd0172010-11-14 18:17:39 +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öwisab0b29b2008-09-13 08:11:57 +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öwisab0b29b2008-09-13 08:11:57 +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 = [
88 'bz2.pyd',
89 'pyexpat.pyd',
90 'select.pyd',
91 'unicodedata.pyd',
92 'winsound.pyd',
Trent Micke97e5a72005-12-15 22:08:46 +000093 '_elementtree.pyd',
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000094 '_bsddb.pyd',
95 '_socket.pyd',
96 '_ssl.pyd',
97 '_testcapi.pyd',
98 '_tkinter.pyd',
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +000099 '_msi.pyd',
Martin v. Löwisa09655e2006-03-10 15:36:28 +0000100 '_ctypes.pyd',
Martin v. Löwis1a494bd2006-04-04 07:10:59 +0000101 '_ctypes_test.pyd',
Martin v. Löwisa09fd6e2006-08-16 12:55:10 +0000102 '_sqlite3.pyd',
Martin v. Löwis1d2ce452008-06-30 07:01:09 +0000103 '_hashlib.pyd',
104 '_multiprocessing.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 Heimes9acba042007-12-04 14:57:30 +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öwis5409c8d2007-08-30 18:15:22 +0000117 "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}",
Martin v. Löwisbe7abbb2007-08-14 05:01:50 +0000118 "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}",
Martin v. Löwis62d45382008-10-02 20:04:47 +0000119 "27":"{4fe21c76-1760-437b-a2f2-99909130a175}",
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000120 } [major+minor]
Tim Peterseba28be2005-03-28 01:08:02 +0000121
Martin v. Löwis344d0662008-05-09 18:21:55 +0000122# Compute the name that Sphinx gives to the docfile
123docfile = ""
Martin v. Löwis741e6992009-06-28 12:24:23 +0000124if int(micro):
125 docfile = micro
Martin v. Löwis344d0662008-05-09 18:21:55 +0000126if level < 0xf:
Benjamin Peterson0805b282009-06-13 15:48:04 +0000127 if level == 0xC:
Martin v. Löwis741e6992009-06-28 12:24:23 +0000128 docfile += "rc%s" % (serial,)
Benjamin Peterson0805b282009-06-13 15:48:04 +0000129 else:
Martin v. Löwis741e6992009-06-28 12:24:23 +0000130 docfile += '%x%s' % (level, serial)
Martin v. Löwis344d0662008-05-09 18:21:55 +0000131docfile = 'python%s%s%s.chm' % (major, minor, docfile)
132
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000133# Build the mingw import library, libpythonXY.a
134# This requires 'nm' and 'dlltool' executables on your PATH
Steve Dower7407f582015-01-31 12:15:13 -0800135def build_mingw_lib(dll_path, def_file, dll_file, mingw_lib):
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000136 warning = "WARNING: %s - libpythonXX.a not built"
Steve Dower7407f582015-01-31 12:15:13 -0800137 gendef = find_executable('gendef')
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000138 dlltool = find_executable('dlltool')
139
Steve Dower7407f582015-01-31 12:15:13 -0800140 if not gendef or not dlltool:
141 print warning % "gendef and/or dlltool were not found"
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000142 return False
143
Steve Dower7407f582015-01-31 12:15:13 -0800144 gendef_command = '%s - %s' % (gendef, dll_path)
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000145 dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \
146 (dlltool, dll_file, def_file, mingw_lib)
Steve Dower7407f582015-01-31 12:15:13 -0800147 if msilib.Win64:
148 dlltool_command += " -m i386:x86-64"
149 else:
Steve Dowere44cbe72015-06-08 09:57:04 -0700150 dlltool_command += " -m i386 --as-flags=--32"
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000151
152 f = open(def_file,'w')
Steve Dower7407f582015-01-31 12:15:13 -0800153 gendef_pipe = os.popen(gendef_command)
154 for line in gendef_pipe.readlines():
155 print >>f, line
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000156 f.close()
Steve Dower7407f582015-01-31 12:15:13 -0800157 exit = gendef_pipe.close()
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000158
159 if exit:
Steve Dower7407f582015-01-31 12:15:13 -0800160 print warning % "gendef did not run successfully"
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000161 return False
162
163 if os.system(dlltool_command) != 0:
164 print warning % "dlltool did not run successfully"
165 return False
166
167 return True
168
169# Target files (.def and .a) go in PCBuild directory
Steve Dower7407f582015-01-31 12:15:13 -0800170dll_path = os.path.join(srcdir, PCBUILD, "python%s%s.dll" % (major, minor))
Christian Heimes9acba042007-12-04 14:57:30 +0000171def_file = os.path.join(srcdir, PCBUILD, "python%s%s.def" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000172dll_file = "python%s%s.dll" % (major, minor)
Christian Heimes9acba042007-12-04 14:57:30 +0000173mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000174
Ezio Melotti24b07bc2011-03-15 18:55:01 +0200175# Determine the target architecture
Martin v. Löwisa1b2af82012-02-21 18:12:02 +0100176if os.system("nmake /nologo /c /f msisupport.mak") != 0:
177 raise RuntimeError("'nmake /f msisupport.mak' failed")
Christian Heimes9acba042007-12-04 14:57:30 +0000178dll_path = os.path.join(srcdir, PCBUILD, dll_file)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000179msilib.set_arch_from_file(dll_path)
180if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"):
181 raise SystemError, "msisupport.dll for incorrect architecture"
Steve Dower7407f582015-01-31 12:15:13 -0800182
Martin v. Löwisab0b29b2008-09-13 08:11:57 +0000183if msilib.Win64:
184 upgrade_code = upgrade_code_64
Martin v. Löwisa9aff012008-09-13 08:36:22 +0000185 # Bump the last digit of the code by one, so that 32-bit and 64-bit
186 # releases get separate product codes
187 digit = hex((int(product_code[-2],16)+1)%16)[-1]
188 product_code = product_code[:-2] + digit + '}'
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000189
Steve Dower7407f582015-01-31 12:15:13 -0800190have_mingw = build_mingw_lib(dll_path, def_file, dll_file, mingw_lib)
191
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000192if testpackage:
193 ext = 'px'
194 testprefix = 'x'
195else:
196 ext = 'py'
197 testprefix = ''
198
199if msilib.Win64:
Martin v. Löwis75c23bd2007-08-30 18:25:47 +0000200 SystemFolderName = "[System64Folder]"
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +0000201 registry_component = 4|256
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000202else:
203 SystemFolderName = "[SystemFolder]"
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +0000204 registry_component = 4
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000205
206msilib.reset()
207
208# condition in which to install pythonxy.dll in system32:
209# a) it is Windows 9x or
210# b) it is NT, the user is privileged, and has chosen per-machine installation
211sys32cond = "(Windows9x or (Privileged and ALLUSERS))"
212
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000213def build_database():
214 """Generate an empty database, with just the schema and the
215 Summary information stream."""
216 if snapshot:
217 uc = upgrade_code_snapshot
218 else:
219 uc = upgrade_code
Martin v. Löwisa9aff012008-09-13 08:36:22 +0000220 if msilib.Win64:
221 productsuffix = " (64-bit)"
222 else:
223 productsuffix = ""
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000224 # schema represents the installer 2.0 database schema.
225 # sequence is the set of standard sequences
226 # (ui/execute, admin/advt/install)
Martin v. Löwis34360642010-03-16 18:49:28 +0000227 msiname = "python-%s%s.msi" % (full_current_version, msilib.arch_ext)
228 db = msilib.init_database(msiname,
Martin v. Löwisa9aff012008-09-13 08:36:22 +0000229 schema, ProductName="Python "+full_current_version+productsuffix,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000230 ProductCode=product_code,
231 ProductVersion=current_version,
Martin v. Löwiseba774b2008-10-13 11:23:35 +0000232 Manufacturer=u"Python Software Foundation",
233 request_uac = True)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000234 # The default sequencing of the RemoveExistingProducts action causes
235 # removal of files that got just installed. Place it after
236 # InstallInitialize, so we first uninstall everything, but still roll
237 # back in case the installation is interrupted
238 msilib.change_sequence(sequence.InstallExecuteSequence,
239 "RemoveExistingProducts", 1510)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000240 msilib.add_tables(db, sequence)
241 # We cannot set ALLUSERS in the property table, as this cannot be
242 # reset if the user choses a per-user installation. Instead, we
243 # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages
244 # this property, and when the execution starts, ALLUSERS is set
245 # accordingly.
246 add_data(db, "Property", [("UpgradeCode", uc),
247 ("WhichUsers", "ALL"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000248 ("ProductLine", "Python%s%s" % (major, minor)),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000249 ])
250 db.Commit()
Martin v. Löwis34360642010-03-16 18:49:28 +0000251 return db, msiname
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000252
253def remove_old_versions(db):
254 "Fill the upgrade table."
255 start = "%s.%s.0" % (major, minor)
256 # This requests that feature selection states of an older
257 # installation should be forwarded into this one. Upgrading
258 # requires that both the old and the new installation are
259 # either both per-machine or per-user.
260 migrate_features = 1
261 # See "Upgrade Table". We remove releases with the same major and
262 # minor version. For an snapshot, we remove all earlier snapshots. For
263 # a release, we remove all snapshots, and all earlier releases.
264 if snapshot:
265 add_data(db, "Upgrade",
Tim Peters66cb0182004-08-26 05:23:19 +0000266 [(upgrade_code_snapshot, start,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000267 current_version,
268 None, # Ignore language
Tim Peters66cb0182004-08-26 05:23:19 +0000269 migrate_features,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000270 None, # Migrate ALL features
271 "REMOVEOLDSNAPSHOT")])
272 props = "REMOVEOLDSNAPSHOT"
273 else:
274 add_data(db, "Upgrade",
275 [(upgrade_code, start, current_version,
276 None, migrate_features, None, "REMOVEOLDVERSION"),
277 (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1),
278 None, migrate_features, None, "REMOVEOLDSNAPSHOT")])
279 props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION"
Martin v. Löwis3f5fda82008-09-08 13:50:10 +0000280
281 props += ";TARGETDIR;DLLDIR"
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000282 # Installer collects the product codes of the earlier releases in
283 # these properties. In order to allow modification of the properties,
284 # they must be declared as secure. See "SecureCustomProperties Property"
285 add_data(db, "Property", [("SecureCustomProperties", props)])
286
287class PyDialog(Dialog):
288 """Dialog class with a fixed layout: controls at the top, then a ruler,
289 then a list of buttons: back, next, cancel. Optionally a bitmap at the
290 left."""
291 def __init__(self, *args, **kw):
292 """Dialog(database, name, x, y, w, h, attributes, title, first,
293 default, cancel, bitmap=true)"""
294 Dialog.__init__(self, *args)
295 ruler = self.h - 36
296 bmwidth = 152*ruler/328
297 if kw.get("bitmap", True):
298 self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin")
299 self.line("BottomLine", 0, ruler, self.w, 0)
300
301 def title(self, title):
302 "Set the title text of the dialog at the top."
303 # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
304 # text, in VerdanaBold10
305 self.text("Title", 135, 10, 220, 60, 0x30003,
306 r"{\VerdanaBold10}%s" % title)
307
308 def back(self, title, next, name = "Back", active = 1):
309 """Add a back button with a given title, the tab-next button,
310 its name in the Control table, possibly initially disabled.
311
312 Return the button, so that events can be associated"""
313 if active:
314 flags = 3 # Visible|Enabled
315 else:
316 flags = 1 # Visible
317 return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next)
318
319 def cancel(self, title, next, name = "Cancel", active = 1):
320 """Add a cancel button with a given title, the tab-next button,
321 its name in the Control table, possibly initially disabled.
322
323 Return the button, so that events can be associated"""
324 if active:
325 flags = 3 # Visible|Enabled
326 else:
327 flags = 1 # Visible
328 return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next)
329
330 def next(self, title, next, name = "Next", active = 1):
331 """Add a Next button with a given title, the tab-next button,
332 its name in the Control table, possibly initially disabled.
333
334 Return the button, so that events can be associated"""
335 if active:
336 flags = 3 # Visible|Enabled
337 else:
338 flags = 1 # Visible
339 return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next)
340
341 def xbutton(self, name, title, next, xpos):
342 """Add a button with a given title, the tab-next button,
343 its name in the Control table, giving its x position; the
344 y-position is aligned with the other buttons.
345
346 Return the button, so that events can be associated"""
347 return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next)
348
349def add_ui(db):
350 x = y = 50
351 w = 370
352 h = 300
353 title = "[ProductName] Setup"
354
355 # see "Dialog Style Bits"
356 modal = 3 # visible | modal
357 modeless = 1 # visible
358 track_disk_space = 32
359
360 add_data(db, 'ActionText', uisample.ActionText)
361 add_data(db, 'UIText', uisample.UIText)
362
363 # Bitmaps
364 if not os.path.exists(srcdir+r"\PC\python_icon.exe"):
365 raise "Run icons.mak in PC directory"
366 add_data(db, "Binary",
Christian Heimes7e28e492008-01-01 13:52:57 +0000367 [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000368 ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")),
369 ])
370 add_data(db, "Icon",
371 [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))])
372
373 # Scripts
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000374 # CheckDir sets TargetExists if TARGETDIR exists.
375 # UpdateEditIDLE sets the REGISTRY.tcl component into
376 # the installed/uninstalled state according to both the
377 # Extensions and TclTk features.
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000378 add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))])
379 # See "Custom Action Type 1"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000380 if msilib.Win64:
381 CheckDir = "CheckDir"
Martin v. Löwisdf40ce32006-02-16 14:38:30 +0000382 UpdateEditIDLE = "UpdateEditIDLE"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000383 else:
384 CheckDir = "_CheckDir@4"
385 UpdateEditIDLE = "_UpdateEditIDLE@4"
Tim Peters0e9980f2004-09-12 03:49:31 +0000386 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000387 [("CheckDir", 1, "Script", CheckDir)])
Martin v. Löwiseac02e62004-11-18 08:00:33 +0000388 if have_tcl:
389 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000390 [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)])
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000391
392 # UI customization properties
393 add_data(db, "Property",
394 # See "DefaultUIFont Property"
395 [("DefaultUIFont", "DlgFont8"),
396 # See "ErrorDialog Style Bit"
397 ("ErrorDialog", "ErrorDlg"),
398 ("Progress1", "Install"), # modified in maintenance type dlg
399 ("Progress2", "installs"),
400 ("MaintenanceForm_Action", "Repair")])
401
402 # Fonts, see "TextStyle Table"
403 add_data(db, "TextStyle",
404 [("DlgFont8", "Tahoma", 9, None, 0),
405 ("DlgFontBold8", "Tahoma", 8, None, 1), #bold
406 ("VerdanaBold10", "Verdana", 10, None, 1),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000407 ("VerdanaRed9", "Verdana", 9, 255, 0),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000408 ])
409
Martin v. Löwis24e4e162010-03-15 13:00:17 +0000410 compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py3_" "[TARGETDIR]Lib"'
Martin v. Löwis367c79a2008-05-25 16:37:34 +0000411 lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
Steve Dower2d142702014-11-12 19:02:20 -0800412 updatepipargs = r'-m ensurepip -U --default-pip'
413 removepipargs = r'-B -m ensurepip._uninstall'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000414 # See "CustomAction Table"
415 add_data(db, "CustomAction", [
416 # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty
417 # See "Custom Action Type 51",
418 # "Custom Action Execution Scheduling Options"
419 ("InitialTargetDir", 307, "TARGETDIR",
420 "[WindowsVolume]Python%s%s" % (major, minor)),
421 ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
422 ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
423 # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
424 # See "Custom Action Type 18"
Steve Dower2d142702014-11-12 19:02:20 -0800425 # msidbCustomActionTypeInScript (1024); run during actual installation
426 # msidbCustomActionTypeNoImpersonate (2048); run action in system account, not user account
427 ("CompilePyc", 18+1024+2048, "python.exe", compileargs),
428 ("CompilePyo", 18+1024+2048, "python.exe", "-O "+compileargs),
429 ("CompileGrammar", 18+1024+2048, "python.exe", lib2to3args),
430 ("UpdatePip", 18+1024+2048, "python.exe", updatepipargs),
431 ("RemovePip", 18+1024+2048, "python.exe", removepipargs),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000432 ])
433
434 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
435 # Numbers indicate sequence; see sequence.py for how these action integrate
436 add_data(db, "InstallUISequence",
437 [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
438 ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141),
439 ("InitialTargetDir", 'TARGETDIR=""', 750),
440 # In the user interface, assume all-users installation if privileged.
441 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
442 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
443 ("SelectDirectoryDlg", "Not Installed", 1230),
444 # XXX no support for resume installations yet
445 #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
446 ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250),
447 ("ProgressDlg", None, 1280)])
448 add_data(db, "AdminUISequence",
449 [("InitialTargetDir", 'TARGETDIR=""', 750),
450 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
451 ])
452
Brian Curtind67c0b82014-05-10 12:52:59 -0500453 # Prepend TARGETDIR to the system path, and remove it on uninstall.
454 add_data(db, "Environment",
Steve Dower2d142702014-11-12 19:02:20 -0800455 [("PathAddition", "=-*Path", "[TARGETDIR];[TARGETDIR]Scripts;[~]", "REGISTRY.path")])
Brian Curtind67c0b82014-05-10 12:52:59 -0500456
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000457 # Execute Sequences
458 add_data(db, "InstallExecuteSequence",
459 [("InitialTargetDir", 'TARGETDIR=""', 750),
460 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
461 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000462 ("UpdateEditIDLE", None, 1050),
Steve Dower2d142702014-11-12 19:02:20 -0800463 # run command if install state of pip changes to INSTALLSTATE_LOCAL
464 # run after InstallFiles
465 ("UpdatePip", "&pip_feature=3", 4001),
466 # remove pip when state changes to INSTALLSTATE_ABSENT
467 # run before RemoveFiles
468 ("RemovePip", "&pip_feature=2", 3499),
469 ("CompilePyc", "COMPILEALL", 4002),
470 ("CompilePyo", "COMPILEALL", 4003),
471 ("CompileGrammar", "COMPILEALL", 4004),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000472 ])
473 add_data(db, "AdminExecuteSequence",
474 [("InitialTargetDir", 'TARGETDIR=""', 750),
475 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000476 ])
477
478 #####################################################################
479 # Standard dialogs: FatalError, UserExit, ExitDialog
480 fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title,
481 "Finish", "Finish", "Finish")
482 fatal.title("[ProductName] Installer ended prematurely")
483 fatal.back("< Back", "Finish", active = 0)
484 fatal.cancel("Cancel", "Back", active = 0)
485 fatal.text("Description1", 135, 70, 220, 80, 0x30003,
486 "[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.")
487 fatal.text("Description2", 135, 155, 220, 20, 0x30003,
488 "Click the Finish button to exit the Installer.")
489 c=fatal.next("Finish", "Cancel", name="Finish")
490 # See "ControlEvent Table". Parameters are the event, the parameter
491 # to the action, and optionally the condition for the event, and the order
492 # of events.
493 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000494
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000495 user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title,
496 "Finish", "Finish", "Finish")
497 user_exit.title("[ProductName] Installer was interrupted")
498 user_exit.back("< Back", "Finish", active = 0)
499 user_exit.cancel("Cancel", "Back", active = 0)
500 user_exit.text("Description1", 135, 70, 220, 80, 0x30003,
501 "[ProductName] setup was interrupted. Your system has not been modified. "
502 "To install this program at a later time, please run the installation again.")
503 user_exit.text("Description2", 135, 155, 220, 20, 0x30003,
504 "Click the Finish button to exit the Installer.")
505 c = user_exit.next("Finish", "Cancel", name="Finish")
506 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000507
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000508 exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title,
509 "Finish", "Finish", "Finish")
Martin v. Löwisef281bd2012-02-21 17:07:32 +0100510 exit_dialog.title("Complete the [ProductName] Installer")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000511 exit_dialog.back("< Back", "Finish", active = 0)
512 exit_dialog.cancel("Cancel", "Back", active = 0)
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000513 exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003,
514 "Special Windows thanks to:\n"
Martin v. Löwisd3f61a22004-08-30 09:22:30 +0000515 " Mark Hammond, without whose years of freely \n"
516 " shared Windows expertise, Python for Windows \n"
517 " would still be Python for DOS.")
Tim Peters66cb0182004-08-26 05:23:19 +0000518
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000519 c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003,
Brian Curtin611cfd22011-05-03 13:36:34 -0500520 "{\\VerdanaRed9}Warning: Python 3.3.0 is the last "
Martin v. Löwis16b2a5e2010-06-04 19:15:32 +0000521 "Python release for Windows 2000.")
522 c.condition("Hide", "VersionNT > 500")
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000523
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000524 exit_dialog.text("Description", 135, 235, 220, 20, 0x30003,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000525 "Click the Finish button to exit the Installer.")
526 c = exit_dialog.next("Finish", "Cancel", name="Finish")
527 c.event("EndDialog", "Return")
528
529 #####################################################################
530 # Required dialog: FilesInUse, ErrorDlg
531 inuse = PyDialog(db, "FilesInUse",
532 x, y, w, h,
533 19, # KeepModeless|Modal|Visible
534 title,
535 "Retry", "Retry", "Retry", bitmap=False)
536 inuse.text("Title", 15, 6, 200, 15, 0x30003,
537 r"{\DlgFontBold8}Files in Use")
538 inuse.text("Description", 20, 23, 280, 20, 0x30003,
539 "Some files that need to be updated are currently in use.")
540 inuse.text("Text", 20, 55, 330, 50, 3,
541 "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.")
542 inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess",
543 None, None, None)
544 c=inuse.back("Exit", "Ignore", name="Exit")
545 c.event("EndDialog", "Exit")
546 c=inuse.next("Ignore", "Retry", name="Ignore")
547 c.event("EndDialog", "Ignore")
548 c=inuse.cancel("Retry", "Exit", name="Retry")
549 c.event("EndDialog","Retry")
550
551
552 # See "Error Dialog". See "ICE20" for the required names of the controls.
553 error = Dialog(db, "ErrorDlg",
554 50, 10, 330, 101,
555 65543, # Error|Minimize|Modal|Visible
556 title,
557 "ErrorText", None, None)
558 error.text("ErrorText", 50,9,280,48,3, "")
559 error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
560 error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo")
561 error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes")
562 error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort")
563 error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel")
564 error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore")
565 error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk")
566 error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry")
567
568 #####################################################################
569 # Global "Query Cancel" dialog
570 cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title,
571 "No", "No", "No")
Tim Peters66cb0182004-08-26 05:23:19 +0000572 cancel.text("Text", 48, 15, 194, 30, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000573 "Are you sure you want to cancel [ProductName] installation?")
574 cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
575 "py.ico", None, None)
576 c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
577 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000578
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000579 c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
580 c.event("EndDialog", "Return")
581
582 #####################################################################
583 # Global "Wait for costing" dialog
584 costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title,
585 "Return", "Return", "Return")
586 costing.text("Text", 48, 15, 194, 30, 3,
587 "Please wait while the installer finishes determining your disk space requirements.")
588 costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
589 "py.ico", None, None)
590 c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
591 c.event("EndDialog", "Exit")
592
593 #####################################################################
594 # Preparation dialog: no user input except cancellation
595 prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title,
596 "Cancel", "Cancel", "Cancel")
597 prep.text("Description", 135, 70, 220, 40, 0x30003,
598 "Please wait while the Installer prepares to guide you through the installation.")
599 prep.title("Welcome to the [ProductName] Installer")
600 c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...")
601 c.mapping("ActionText", "Text")
602 c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None)
603 c.mapping("ActionData", "Text")
604 prep.back("Back", None, active=0)
605 prep.next("Next", None, active=0)
606 c=prep.cancel("Cancel", None)
607 c.event("SpawnDialog", "CancelDlg")
608
609 #####################################################################
610 # Target directory selection
611 seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title,
612 "Next", "Next", "Cancel")
613 seldlg.title("Select Destination Directory")
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000614 c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003,
615 "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.")
616 c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000617 seldlg.text("Description", 135, 50, 220, 40, 0x30003,
618 "Please select a directory for the [ProductName] files.")
619
620 seldlg.back("< Back", None, active=0)
621 c = seldlg.next("Next >", "Cancel")
622 c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1)
623 # If the target exists, but we found that we are going to remove old versions, don't bother
624 # confirming that the target directory exists. Strictly speaking, we should determine that
625 # the target directory is indeed the target of the product that we are going to remove, but
626 # I don't know how to do that.
627 c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2)
628 c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3)
629 c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4)
630 c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5)
631
632 c = seldlg.cancel("Cancel", "DirectoryCombo")
633 c.event("SpawnDialog", "CancelDlg")
634
635 seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219,
636 "TARGETDIR", None, "DirectoryList", None)
637 seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR",
638 None, "PathEdit", None)
639 seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None)
640 c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
641 c.event("DirectoryListUp", "0")
642 c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
643 c.event("DirectoryListNew", "0")
644
645 #####################################################################
646 # SelectFeaturesDlg
647 features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space,
648 title, "Tree", "Next", "Cancel")
649 features.title("Customize [ProductName]")
650 features.text("Description", 135, 35, 220, 15, 0x30003,
651 "Select the way you want features to be installed.")
652 features.text("Text", 135,45,220,30, 3,
653 "Click on the icons in the tree below to change the way features will be installed.")
654
655 c=features.back("< Back", "Next")
656 c.event("NewDialog", "SelectDirectoryDlg")
657
658 c=features.next("Next >", "Cancel")
659 c.mapping("SelectionNoItems", "Enabled")
660 c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1)
661 c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2)
662
663 c=features.cancel("Cancel", "Tree")
664 c.event("SpawnDialog", "CancelDlg")
665
Tim Peters66cb0182004-08-26 05:23:19 +0000666 # 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 +0000667 features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty",
668 "Tree of selections", "Back", None)
669
670 #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost")
671 #c.mapping("SelectionNoItems", "Enabled")
672 #c.event("Reset", "0")
Tim Peters66cb0182004-08-26 05:23:19 +0000673
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000674 features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None)
675
676 c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10)
677 c.mapping("SelectionNoItems","Enabled")
678 c.event("SpawnDialog", "DiskCostDlg")
679
680 c=features.xbutton("Advanced", "Advanced", None, 0.30)
681 c.event("SpawnDialog", "AdvancedDlg")
682
Brian Curtind67c0b82014-05-10 12:52:59 -0500683 c=features.text("ItemDescription", 140, 180, 210, 40, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000684 "Multiline description of the currently selected item.")
685 c.mapping("SelectionDescription","Text")
Tim Peters66cb0182004-08-26 05:23:19 +0000686
Brian Curtind67c0b82014-05-10 12:52:59 -0500687 c=features.text("ItemSize", 140, 225, 210, 33, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000688 "The size of the currently selected item.")
689 c.mapping("SelectionSize", "Text")
690
691 #####################################################################
692 # Disk cost
693 cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title,
694 "OK", "OK", "OK", bitmap=False)
695 cost.text("Title", 15, 6, 200, 15, 0x30003,
696 "{\DlgFontBold8}Disk Space Requirements")
697 cost.text("Description", 20, 20, 280, 20, 0x30003,
698 "The disk space required for the installation of the selected features.")
699 cost.text("Text", 20, 53, 330, 60, 3,
700 "The highlighted volumes (if any) do not have enough disk space "
701 "available for the currently selected features. You can either "
702 "remove some files from the highlighted volumes, or choose to "
703 "install less features onto local drive(s), or select different "
704 "destination drive(s).")
705 cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223,
706 None, "{120}{70}{70}{70}{70}", None, None)
707 cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
708
709 #####################################################################
710 # WhichUsers Dialog. Only available on NT, and for privileged users.
711 # This must be run before FindRelatedProducts, because that will
712 # take into account whether the previous installation was per-user
713 # or per-machine. We currently don't support going back to this
714 # dialog after "Next" was selected; to support this, we would need to
715 # find how to reset the ALLUSERS property, and how to re-run
716 # FindRelatedProducts.
717 # On Windows9x, the ALLUSERS property is ignored on the command line
718 # and in the Property table, but installer fails according to the documentation
719 # if a dialog attempts to set ALLUSERS.
720 whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title,
721 "AdminInstall", "Next", "Cancel")
722 whichusers.title("Select whether to install [ProductName] for all users of this computer.")
723 # A radio group with two options: allusers, justme
Martin v. Löwiseba774b2008-10-13 11:23:35 +0000724 g = whichusers.radiogroup("AdminInstall", 135, 60, 235, 80, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000725 "WhichUsers", "", "Next")
Martin v. Löwiseba774b2008-10-13 11:23:35 +0000726 g.condition("Disable", "VersionNT=600") # Not available on Vista and Windows 2008
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000727 g.add("ALL", 0, 5, 150, 20, "Install for all users")
Martin v. Löwiseba774b2008-10-13 11:23:35 +0000728 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 +0000729
Tim Peters66cb0182004-08-26 05:23:19 +0000730 whichusers.back("Back", None, active=0)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000731
732 c = whichusers.next("Next >", "Cancel")
733 c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
734 c.event("EndDialog", "Return", order = 2)
735
736 c = whichusers.cancel("Cancel", "AdminInstall")
737 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000738
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000739 #####################################################################
740 # Advanced Dialog.
741 advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title,
Martin v. Löwis63470982008-11-19 13:51:44 +0000742 "CompilePyc", "Ok", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000743 advanced.title("Advanced Options for [ProductName]")
744 # A radio group with two options: allusers, justme
745 advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3,
Martin v. Löwis63470982008-11-19 13:51:44 +0000746 "COMPILEALL", "Compile .py files to byte code after installation", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000747
Martin v. Löwis63470982008-11-19 13:51:44 +0000748 c = advanced.cancel("Ok", "CompilePyc", name="Ok") # Button just has location of cancel button.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000749 c.event("EndDialog", "Return")
750
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000751 #####################################################################
Tim Peters66cb0182004-08-26 05:23:19 +0000752 # Existing Directory dialog
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000753 dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title,
754 "No", "No", "No")
755 dlg.text("Title", 10, 20, 180, 40, 3,
756 "[TARGETDIR] exists. Are you sure you want to overwrite existing files?")
757 c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No")
758 c.event("[TargetExists]", "0", order=1)
759 c.event("[TargetExistsOk]", "1", order=2)
760 c.event("EndDialog", "Return", order=3)
761 c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes")
762 c.event("EndDialog", "Return")
763
764 #####################################################################
765 # Installation Progress dialog (modeless)
766 progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title,
767 "Cancel", "Cancel", "Cancel", bitmap=False)
768 progress.text("Title", 20, 15, 200, 15, 0x30003,
769 "{\DlgFontBold8}[Progress1] [ProductName]")
770 progress.text("Text", 35, 65, 300, 30, 3,
771 "Please wait while the Installer [Progress2] [ProductName]. "
772 "This may take several minutes.")
773 progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
774
775 c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...")
776 c.mapping("ActionText", "Text")
777
778 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
779 #c.mapping("ActionData", "Text")
780
781 c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537,
782 None, "Progress done", None, None)
783 c.mapping("SetProgress", "Progress")
784
785 progress.back("< Back", "Next", active=False)
786 progress.next("Next >", "Cancel", active=False)
787 progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
788
789 # Maintenance type: repair/uninstall
790 maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title,
791 "Next", "Next", "Cancel")
792 maint.title("Welcome to the [ProductName] Setup Wizard")
793 maint.text("BodyText", 135, 63, 230, 42, 3,
794 "Select whether you want to repair or remove [ProductName].")
795 g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3,
796 "MaintenanceForm_Action", "", "Next")
797 g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
798 g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
799 g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
Tim Peters66cb0182004-08-26 05:23:19 +0000800
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000801 maint.back("< Back", None, active=False)
802 c=maint.next("Finish", "Cancel")
803 # Change installation: Change progress dialog to "Change", then ask
804 # for feature selection
805 c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
806 c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
807
808 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
809 # Also set list of reinstalled features to "ALL"
810 c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
811 c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
Raymond Hettinger72f08012004-11-07 07:08:25 +0000812 c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000813 c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
814
815 # Uninstall: Change progress to "Remove", then invoke uninstall
816 # Also set list of removed features to "ALL"
817 c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
818 c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
819 c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
820 c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
821
Tim Peters66cb0182004-08-26 05:23:19 +0000822 # Close dialog when maintenance action scheduled
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000823 c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
824 c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
Tim Peters66cb0182004-08-26 05:23:19 +0000825
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000826 maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000827
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000828
829# See "Feature Table". The feature level is 1 for all features,
830# and the feature attributes are 0 for the DefaultFeature, and
831# FollowParent for all other features. The numbers are the Display
832# column.
833def add_features(db):
834 # feature attributes:
835 # msidbFeatureAttributesFollowParent == 2
836 # msidbFeatureAttributesDisallowAdvertise == 8
837 # Features that need to be installed with together with the main feature
838 # (i.e. additional Python libraries) need to follow the parent feature.
839 # Features that have no advertisement trigger (e.g. the test suite)
840 # must not support advertisement
Steve Dower2d142702014-11-12 19:02:20 -0800841 global default_feature, tcltk, htmlfiles, tools, testsuite
842 global ext_feature, private_crt, prepend_path, pip_feature
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000843 default_feature = Feature(db, "DefaultFeature", "Python",
844 "Python Interpreter and Libraries",
845 1, directory = "TARGETDIR")
Martin v. Löwis4dc34152008-04-05 15:48:36 +0000846 shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0,
847 level=0)
848 private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0,
849 level=0)
850 add_data(db, "Condition", [("SharedCRT", 1, sys32cond),
851 ("PrivateCRT", 1, "not "+sys32cond)])
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000852 # We don't support advertisement of extensions
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000853 ext_feature = Feature(db, "Extensions", "Register Extensions",
854 "Make this Python installation the default Python installation", 3,
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000855 parent = default_feature, attributes=2|8)
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000856 if have_tcl:
857 tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000858 parent = default_feature, attributes=2)
859 htmlfiles = Feature(db, "Documentation", "Documentation",
860 "Python HTMLHelp File", 7, parent = default_feature)
861 tools = Feature(db, "Tools", "Utility Scripts",
Tim Peters66cb0182004-08-26 05:23:19 +0000862 "Python utility scripts (Tools/", 9,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000863 parent = default_feature, attributes=2)
Steve Dower2d142702014-11-12 19:02:20 -0800864 pip_feature = Feature(db, "pip_feature", "pip",
865 "Install or upgrade pip, a tool for installing and managing "
866 "Python packages.", 11,
867 parent = default_feature, attributes=2|8)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000868 testsuite = Feature(db, "Testsuite", "Test suite",
Steve Dower2d142702014-11-12 19:02:20 -0800869 "Python test suite (Lib/test/)", 13,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000870 parent = default_feature, attributes=2|8)
Brian Curtind67c0b82014-05-10 12:52:59 -0500871 # prepend_path is an additional feature which is to be off by default.
872 # Since the default level for the above features is 1, this needs to be
873 # at least level higher.
874 prepend_path = Feature(db, "PrependPath", "Add python.exe to Path",
875 "Prepend [TARGETDIR] to the system Path variable. "
876 "This allows you to type 'python' into a command "
Steve Dower2d142702014-11-12 19:02:20 -0800877 "prompt without needing the full path.", 15,
Brian Curtind67c0b82014-05-10 12:52:59 -0500878 parent = default_feature, attributes=2|8,
879 level=2)
Tim Peters66cb0182004-08-26 05:23:19 +0000880
Christian Heimes9acba042007-12-04 14:57:30 +0000881def extract_msvcr90():
Martin v. Löwis03dc56c2008-02-28 22:20:50 +0000882 # Find the redistributable files
Martin v. Löwise1d9dca2008-09-19 19:20:03 +0000883 if msilib.Win64:
884 arch = "amd64"
885 else:
886 arch = "x86"
887 dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC90.CRT" % arch)
Christian Heimes9acba042007-12-04 14:57:30 +0000888
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000889 result = []
Christian Heimes9acba042007-12-04 14:57:30 +0000890 installer = msilib.MakeInstaller()
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000891 # omit msvcm90 and msvcp90, as they aren't really needed
892 files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"]
893 for f in files:
894 path = os.path.join(dir, f)
895 kw = {'src':path}
896 if f.endswith('.dll'):
897 kw['version'] = installer.FileVersion(path, 0)
898 kw['language'] = installer.FileVersion(path, 1)
899 result.append((f, kw))
900 return result
Christian Heimes9acba042007-12-04 14:57:30 +0000901
Martin v. Löwisdcc86202008-05-25 11:56:23 +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öwis4eb18f92008-09-14 20:22:39 +0000906 shutil.copyfileobj(open("crtlicense.txt"), out)
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000907 for name, pat, file in (("bzip2","bzip2-*", "LICENSE"),
908 ("Berkeley DB", "db-*", "LICENSE"),
909 ("openssl", "openssl-*", "LICENSE"),
Steve Dower144de312014-09-12 11:48:13 -0700910 ("Tcl", "tcl-8*", "license.terms"),
911 ("Tk", "tk-8*", "license.terms"),
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000912 ("Tix", "tix-*", "license.terms")):
913 out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name)
Steve Dowera6e6d0a2014-11-25 22:43:06 -0800914 dirs = glob.glob(srcdir+"/externals/"+pat)
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000915 if not dirs:
Steve Dowera6e6d0a2014-11-25 22:43:06 -0800916 raise ValueError, "Could not find "+srcdir+"/externals/"+pat
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000917 if len(dirs) > 2:
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000918 raise ValueError, "Multiple copies of "+pat
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000919 dir = dirs[0]
920 shutil.copyfileobj(open(os.path.join(dir, file)), out)
921 out.close()
922
923
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000924class PyDirectory(Directory):
925 """By default, all components in the Python installer
926 can run from source."""
927 def __init__(self, *args, **kw):
928 if not kw.has_key("componentflags"):
929 kw['componentflags'] = 2 #msidbComponentAttributesOptional
930 Directory.__init__(self, *args, **kw)
931
932# See "File Table", "Component Table", "Directory Table",
933# "FeatureComponents Table"
934def add_files(db):
935 cab = CAB("python")
936 tmpfiles = []
937 # Add all executables, icons, text files into the TARGETDIR component
938 root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir")
939 default_feature.set_current()
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000940 if not msilib.Win64:
Christian Heimes9acba042007-12-04 14:57:30 +0000941 root.add_file("%s/w9xpopen.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000942 root.add_file("README.txt", src="README")
943 root.add_file("NEWS.txt", src="Misc/NEWS")
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000944 generate_license()
945 root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000946 root.start_component("python.exe", keyfile="python.exe")
Christian Heimes9acba042007-12-04 14:57:30 +0000947 root.add_file("%s/python.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000948 root.start_component("pythonw.exe", keyfile="pythonw.exe")
Christian Heimes9acba042007-12-04 14:57:30 +0000949 root.add_file("%s/pythonw.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000950
951 # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
Martin v. Löwis0f3e7692008-10-17 13:43:01 +0000952 dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000953
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000954 pydll = "python%s%s.dll" % (major, minor)
Christian Heimes9acba042007-12-04 14:57:30 +0000955 pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000956 dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000957 installer = msilib.MakeInstaller()
958 pyversion = installer.FileVersion(pydllsrc, 0)
959 if not snapshot:
960 # For releases, the Python DLL has the same version as the
961 # installer package.
Steve Dower144de312014-09-12 11:48:13 -0700962 assert pyversion.split(".")[:3] == current_version.split("."), "%s != %s" % (pyversion, current_version)
Christian Heimes9acba042007-12-04 14:57:30 +0000963 dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000964 version=pyversion,
965 language=installer.FileVersion(pydllsrc, 1))
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000966 DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs")
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000967
968 # msvcr90.dll: Need to place the DLL and the manifest into the root directory,
969 # plus another copy of the manifest in the DLLs directory, with the manifest
970 # pointing to the root directory
Martin v. Löwis46a8be72008-04-07 14:55:53 +0000971 root.start_component("msvcr90", feature=private_crt)
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000972 # Results are ID,keyword pairs
973 manifest, crtdll = extract_msvcr90()
974 root.add_file(manifest[0], **manifest[1])
975 root.add_file(crtdll[0], **crtdll[1])
976 # Copy the manifest
Martin v. Löwisddd82632008-11-06 19:46:03 +0000977 # Actually, don't do that anymore - no DLL in DLLs should have a manifest
978 # dependency on msvcr90.dll anymore, so this should not be necessary
979 #manifest_dlls = manifest[0]+".root"
980 #open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr"))
981 #DLLs.start_component("msvcr90_dlls", feature=private_crt)
982 #DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls))
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000983
984 # Now start the main component for the DLLs directory;
985 # no regular files have been added to the directory yet.
986 DLLs.start_component()
Tim Peters66cb0182004-08-26 05:23:19 +0000987
Martin v. Löwis38325b72006-08-25 00:03:34 +0000988 # Check if _ctypes.pyd exists
Christian Heimes9acba042007-12-04 14:57:30 +0000989 have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD)
Martin v. Löwis38325b72006-08-25 00:03:34 +0000990 if not have_ctypes:
991 print "WARNING: _ctypes.pyd not found, ctypes will not be included"
992 extensions.remove("_ctypes.pyd")
Tim Peters147f9ae2006-08-25 22:05:39 +0000993
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000994 # Add all .py files in Lib, except lib-tk, test
995 dirs={}
996 pydirs = [(root,"Lib")]
997 while pydirs:
Martin v. Löwisc9798fc2008-06-13 18:58:47 +0000998 # Commit every now and then, or else installer will complain
999 db.Commit()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001000 parent, dir = pydirs.pop()
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001001 if dir == ".svn" or dir.startswith("plat-"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001002 continue
Georg Brandl6634bf22008-05-20 07:13:37 +00001003 elif dir in ["lib-tk", "idlelib", "Icons"]:
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001004 if not have_tcl:
1005 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001006 tcltk.set_current()
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +00001007 elif dir in ['test', 'tests', 'data', 'output']:
Martin v. Löwis59c3acc2006-04-03 12:07:46 +00001008 # test: Lib, Lib/email, Lib/bsddb, Lib/ctypes, Lib/sqlite3
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +00001009 # tests: Lib/distutils
1010 # data: Lib/email/test
1011 # output: Lib/test
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001012 testsuite.set_current()
Martin v. Löwis38325b72006-08-25 00:03:34 +00001013 elif not have_ctypes and dir == "ctypes":
1014 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001015 else:
1016 default_feature.set_current()
1017 lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
1018 # Add additional files
1019 dirs[dir]=lib
1020 lib.glob("*.txt")
Steve Dower25b61202014-11-26 09:20:00 -08001021 lib.glob("*.whl")
1022 lib.glob("*.0")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001023 if dir=='site-packages':
Martin v. Löwis6d60c092004-11-21 10:16:26 +00001024 lib.add_file("README.txt", src="README")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001025 continue
1026 files = lib.glob("*.py")
1027 files += lib.glob("*.pyw")
1028 if files:
1029 # Add an entry to the RemoveFile table to remove bytecode files.
1030 lib.remove_pyc()
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001031 if dir.endswith('.egg-info'):
1032 lib.add_file('entry_points.txt')
1033 lib.add_file('PKG-INFO')
1034 lib.add_file('top_level.txt')
1035 lib.add_file('zip-safe')
1036 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001037 if dir=='test' and parent.physical=='Lib':
1038 lib.add_file("185test.db")
1039 lib.add_file("audiotest.au")
1040 lib.add_file("cfgparser.1")
Martin v. Löwisc0fdb182006-09-12 19:49:20 +00001041 lib.add_file("sgml_input.html")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001042 lib.add_file("testtar.tar")
Martin v. Löwis7d3755d2004-09-06 06:31:12 +00001043 lib.add_file("test_difflib_expect.html")
Martin v. Löwis59c3acc2006-04-03 12:07:46 +00001044 lib.add_file("check_soundcard.vbs")
Thomas Heller3bd33152006-04-04 18:41:13 +00001045 lib.add_file("empty.vbs")
Martin v. Löwisea598b62009-06-01 04:10:03 +00001046 lib.add_file("Sine-1000Hz-300ms.aif")
Steve Dower0c3708a2014-11-26 09:32:41 -08001047 lib.add_file("revocation.crl")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001048 lib.glob("*.uue")
Martin v. Löwis0ffdacd2007-11-20 02:46:02 +00001049 lib.glob("*.pem")
Martin v. Löwis6b449f42007-12-03 19:20:02 +00001050 lib.glob("*.pck")
Martin v. Löwis91a1a072009-04-04 18:44:44 +00001051 lib.add_file("zipdir.zip")
Brian Curtin69a106a2010-11-22 02:08:49 +00001052 if dir=='tests' and parent.physical=='distutils':
1053 lib.add_file("Setup.sample")
Benjamin Peterson672b0432014-05-18 16:32:22 -07001054 if dir=='audiodata':
1055 lib.glob("*.*")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001056 if dir=='decimaltestdata':
1057 lib.glob("*.decTest")
Benjamin Peterson672b0432014-05-18 16:32:22 -07001058 if dir=='imghdrdata':
1059 lib.glob("*.*")
Florent Xicluna13ba1a12010-03-13 11:18:49 +00001060 if dir=='xmltestdata':
1061 lib.glob("*.xml")
1062 lib.add_file("test.xml.out")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001063 if dir=='output':
1064 lib.glob("test_*")
1065 if dir=='idlelib':
1066 lib.glob("*.def")
1067 lib.add_file("idle.bat")
1068 if dir=="Icons":
1069 lib.glob("*.gif")
Steve Dowerbd2ab522014-05-10 21:25:54 -07001070 lib.glob("*.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001071 lib.add_file("idle.icns")
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001072 if dir=="command" and parent.physical=="distutils":
Martin v. Löwis023b9f92008-04-09 18:56:20 +00001073 lib.glob("wininst*.exe")
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001074 if dir=="setuptools":
1075 lib.add_file("cli.exe")
1076 lib.add_file("gui.exe")
Martin v. Löwis367c79a2008-05-25 16:37:34 +00001077 if dir=="lib2to3":
1078 lib.removefile("pickle", "*.pickle")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001079 if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email":
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001080 # This should contain all non-.svn files listed in subversion
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001081 for f in os.listdir(lib.absolute):
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001082 if f.endswith(".txt") or f==".svn":continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001083 if f.endswith(".au") or f.endswith(".gif"):
1084 lib.add_file(f)
1085 else:
1086 print "WARNING: New file %s in email/test/data" % f
1087 for f in os.listdir(lib.absolute):
1088 if os.path.isdir(os.path.join(lib.absolute, f)):
1089 pydirs.append((lib, f))
1090 # Add DLLs
1091 default_feature.set_current()
Martin v. Löwisd9759c42008-02-28 19:57:34 +00001092 lib = DLLs
Christian Heimes7e28e492008-01-01 13:52:57 +00001093 lib.add_file("py.ico", src=srcdir+"/PC/py.ico")
Christian Heimese1c6af02008-01-01 13:58:16 +00001094 lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001095 dlls = []
1096 tclfiles = []
1097 for f in extensions:
1098 if f=="_tkinter.pyd":
1099 continue
Christian Heimes9acba042007-12-04 14:57:30 +00001100 if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001101 print "WARNING: Missing extension", f
1102 continue
1103 dlls.append(f)
1104 lib.add_file(f)
Martin v. Löwis88ef6372006-07-06 06:55:58 +00001105 # Add sqlite
1106 if msilib.msi_type=="Intel64;1033":
1107 sqlite_arch = "/ia64"
1108 elif msilib.msi_type=="x64;1033":
1109 sqlite_arch = "/amd64"
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001110 tclsuffix = "64"
Martin v. Löwis88ef6372006-07-06 06:55:58 +00001111 else:
1112 sqlite_arch = ""
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001113 tclsuffix = ""
Martin v. Löwisc9798fc2008-06-13 18:58:47 +00001114 lib.add_file("sqlite3.dll")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001115 if have_tcl:
Christian Heimes9acba042007-12-04 14:57:30 +00001116 if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)):
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001117 print "WARNING: Missing _tkinter.pyd"
1118 else:
1119 lib.start_component("TkDLLs", tcltk)
1120 lib.add_file("_tkinter.pyd")
1121 dlls.append("_tkinter.pyd")
Steve Dowera6e6d0a2014-11-25 22:43:06 -08001122 tcldir = os.path.normpath(srcdir+("/externals/tcltk%s/bin" % tclsuffix))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001123 for f in glob.glob1(tcldir, "*.dll"):
1124 lib.add_file(f, src=os.path.join(tcldir, f))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001125 # check whether there are any unknown extensions
Christian Heimes9acba042007-12-04 14:57:30 +00001126 for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001127 if f.endswith("_d.pyd"): continue # debug version
1128 if f in dlls: continue
1129 print "WARNING: Unknown extension", f
Tim Peters66cb0182004-08-26 05:23:19 +00001130
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001131 # Add headers
1132 default_feature.set_current()
1133 lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include")
1134 lib.glob("*.h")
1135 lib.add_file("pyconfig.h", src="../PC/pyconfig.h")
1136 # Add import libraries
Christian Heimes9acba042007-12-04 14:57:30 +00001137 lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001138 for f in dlls:
1139 lib.add_file(f.replace('pyd','lib'))
1140 lib.add_file('python%s%s.lib' % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +00001141 # Add the mingw-format library
1142 if have_mingw:
Tim Peters5a9fb3c2005-01-07 16:01:32 +00001143 lib.add_file('libpython%s%s.a' % (major, minor))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001144 if have_tcl:
1145 # Add Tcl/Tk
Steve Dowera6e6d0a2014-11-25 22:43:06 -08001146 tcldirs = [(root, 'externals/tcltk%s/lib' % tclsuffix, 'tcl')]
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001147 tcltk.set_current()
1148 while tcldirs:
1149 parent, phys, dir = tcldirs.pop()
1150 lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir))
1151 if not os.path.exists(lib.absolute):
1152 continue
1153 for f in os.listdir(lib.absolute):
1154 if os.path.isdir(os.path.join(lib.absolute, f)):
1155 tcldirs.append((lib, f, f))
1156 else:
1157 lib.add_file(f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001158 # Add tools
1159 tools.set_current()
1160 tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools")
1161 for f in ['i18n', 'pynche', 'Scripts', 'versioncheck', 'webchecker']:
1162 lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f))
1163 lib.glob("*.py")
1164 lib.glob("*.pyw", exclude=['pydocgui.pyw'])
1165 lib.remove_pyc()
1166 lib.glob("*.txt")
1167 if f == "pynche":
1168 x = PyDirectory(db, cab, lib, "X", "X", "X|X")
1169 x.glob("*.txt")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001170 if os.path.exists(os.path.join(lib.absolute, "README")):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001171 lib.add_file("README.txt", src="README")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001172 if f == 'Scripts':
Martin v. Löwisd69c9042008-10-01 11:19:50 +00001173 lib.add_file("2to3.py", src="2to3")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001174 if have_tcl:
1175 lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
1176 lib.add_file("pydocgui.pyw")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001177 # Add documentation
1178 htmlfiles.set_current()
1179 lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc")
Martin v. Löwis344d0662008-05-09 18:21:55 +00001180 lib.start_component("documentation", keyfile=docfile)
1181 lib.add_file(docfile, src="build/htmlhelp/"+docfile)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001182
1183 cab.commit(db)
1184
1185 for f in tmpfiles:
1186 os.unlink(f)
1187
1188# See "Registry Table", "Component Table"
1189def add_registry(db):
1190 # File extensions, associated with the REGISTRY.def component
1191 # IDLE verbs depend on the tcltk feature.
1192 # msidbComponentAttributesRegistryKeyPath = 4
1193 # -1 for Root specifies "dependent on ALLUSERS property"
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001194 tcldata = []
1195 if have_tcl:
1196 tcldata = [
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001197 ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001198 "py.IDLE")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001199 add_data(db, "Component",
1200 # msidbComponentAttributesRegistryKeyPath = 4
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001201 [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001202 "InstallPath"),
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001203 ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001204 "Documentation"),
Brian Curtind67c0b82014-05-10 12:52:59 -05001205 ("REGISTRY.path", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
1206 None),
Steve Dower2d142702014-11-12 19:02:20 -08001207 ("REGISTRY.ensurepip", msilib.gen_uuid(), "TARGETDIR", registry_component, "EnsurePipRun",
1208 None),
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001209 ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001210 None, None)] + tcldata)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001211 # See "FeatureComponents Table".
1212 # The association between TclTk and pythonw.exe is necessary to make ICE59
1213 # happy, because the installer otherwise believes that the IDLE and PyDoc
1214 # shortcuts might get installed without pythonw.exe being install. This
1215 # is not true, since installing TclTk will install the default feature, which
1216 # will cause pythonw.exe to be installed.
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001217 # REGISTRY.tcl is not associated with any feature, as it will be requested
1218 # through a custom action
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001219 tcldata = []
1220 if have_tcl:
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001221 tcldata = [(tcltk.id, "pythonw.exe")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001222 add_data(db, "FeatureComponents",
1223 [(default_feature.id, "REGISTRY"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001224 (htmlfiles.id, "REGISTRY.doc"),
Brian Curtind67c0b82014-05-10 12:52:59 -05001225 (prepend_path.id, "REGISTRY.path"),
Steve Dower2d142702014-11-12 19:02:20 -08001226 (pip_feature.id, "REGISTRY.ensurepip"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001227 (ext_feature.id, "REGISTRY.def")] +
1228 tcldata
1229 )
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001230 # Extensions are not advertised. For advertised extensions,
1231 # we would need separate binaries that install along with the
1232 # extension.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001233 pat = r"Software\Classes\%sPython.%sFile\shell\%s\command"
1234 ewi = "Edit with IDLE"
1235 pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon"
1236 pat3 = r"Software\Classes\%sPython.%sFile"
Martin v. Löwis3d6f8ff2008-11-07 18:51:50 +00001237 pat4 = r"Software\Classes\%sPython.%sFile\shellex\DropHandler"
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001238 tcl_verbs = []
1239 if have_tcl:
1240 tcl_verbs=[
1241 ("py.IDLE", -1, pat % (testprefix, "", ewi), "",
Martin v. Löwis588b54b2009-05-05 16:10:16 +00001242 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001243 "REGISTRY.tcl"),
1244 ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "",
Martin v. Löwis588b54b2009-05-05 16:10:16 +00001245 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001246 "REGISTRY.tcl"),
1247 ]
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001248 add_data(db, "Registry",
1249 [# Extensions
1250 ("py.ext", -1, r"Software\Classes\."+ext, "",
1251 "Python.File", "REGISTRY.def"),
1252 ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "",
1253 "Python.NoConFile", "REGISTRY.def"),
1254 ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "",
1255 "Python.CompiledFile", "REGISTRY.def"),
1256 ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "",
1257 "Python.CompiledFile", "REGISTRY.def"),
1258 # MIME types
1259 ("py.mime", -1, r"Software\Classes\."+ext, "Content Type",
1260 "text/plain", "REGISTRY.def"),
1261 ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type",
1262 "text/plain", "REGISTRY.def"),
1263 #Verbs
1264 ("py.open", -1, pat % (testprefix, "", "open"), "",
1265 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
1266 ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
1267 r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"),
1268 ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
1269 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001270 ] + tcl_verbs + [
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001271 #Icons
1272 ("py.icon", -1, pat2 % (testprefix, ""), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001273 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001274 ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001275 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001276 ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001277 r'[DLLs]pyc.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001278 # Descriptions
1279 ("py.txt", -1, pat3 % (testprefix, ""), "",
1280 "Python File", "REGISTRY.def"),
1281 ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "",
1282 "Python File (no console)", "REGISTRY.def"),
1283 ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "",
1284 "Compiled Python File", "REGISTRY.def"),
Martin v. Löwis3d6f8ff2008-11-07 18:51:50 +00001285 # Drop Handler
1286 ("py.drop", -1, pat4 % (testprefix, ""), "",
1287 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1288 ("pyw.drop", -1, pat4 % (testprefix, "NoCon"), "",
1289 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1290 ("pyc.drop", -1, pat4 % (testprefix, "Compiled"), "",
1291 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001292 ])
Tim Peters66cb0182004-08-26 05:23:19 +00001293
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001294 # Registry keys
1295 prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version)
1296 add_data(db, "Registry",
1297 [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"),
1298 ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "",
1299 "Python %s" % short_version, "REGISTRY"),
1300 ("PythonPath", -1, prefix+r"\PythonPath", "",
Martin v. Löwisf13337d2004-09-19 18:36:45 +00001301 r"[TARGETDIR]Lib;[TARGETDIR]DLLs;[TARGETDIR]Lib\lib-tk", "REGISTRY"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001302 ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "",
Martin v. Löwis344d0662008-05-09 18:21:55 +00001303 "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001304 ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"),
1305 ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe",
Martin v. Löwiscb6c3592008-11-30 11:08:26 +00001306 "", r"[TARGETDIR]Python.exe", "REGISTRY.def"),
1307 ("DisplayIcon", -1,
1308 r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code,
Steve Dower2d142702014-11-12 19:02:20 -08001309 "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY"),
1310 # Fake registry entry to allow installer to track whether ensurepip has been run
1311 ("EnsurePipRun", -1, prefix+r"\EnsurePipRun", "", "#1", "REGISTRY.ensurepip"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001312 ])
1313 # Shortcuts, see "Shortcut Table"
1314 add_data(db, "Directory",
1315 [("ProgramMenuFolder", "TARGETDIR", "."),
1316 ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))])
1317 add_data(db, "RemoveFile",
1318 [("MenuDir", "TARGETDIR", None, "MenuDir", 2)])
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001319 tcltkshortcuts = []
1320 if have_tcl:
1321 tcltkshortcuts = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001322 ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001323 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 +00001324 ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001325 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 +00001326 ]
1327 add_data(db, "Shortcut",
1328 tcltkshortcuts +
1329 [# Advertised shortcuts: targets are features, not files
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001330 ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe",
1331 default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001332 # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an
1333 # icon first.
1334 #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation",
1335 # htmlfiles.id, None, None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001336 ## Non-advertised shortcuts: must be associated with a registry component
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001337 ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc",
Martin v. Löwis344d0662008-05-09 18:21:55 +00001338 "[#%s]" % docfile, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001339 None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001340 ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY",
1341 SystemFolderName+"msiexec", "/x%s" % product_code,
1342 None, None, None, None, None, None),
1343 ])
1344 db.Commit()
1345
Martin v. Löwiseebd0172010-11-14 18:17:39 +00001346def build_pdbzip():
1347 pdbexclude = ['kill_python.pdb', 'make_buildinfo.pdb',
1348 'make_versioninfo.pdb']
1349 path = "python-%s%s-pdb.zip" % (full_current_version, msilib.arch_ext)
1350 pdbzip = zipfile.ZipFile(path, 'w')
1351 for f in glob.glob1(os.path.join(srcdir, PCBUILD), "*.pdb"):
1352 if f not in pdbexclude and not f.endswith('_d.pdb'):
1353 pdbzip.write(os.path.join(srcdir, PCBUILD, f), f)
1354 pdbzip.close()
1355
Martin v. Löwis34360642010-03-16 18:49:28 +00001356db,msiname = build_database()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001357try:
1358 add_features(db)
1359 add_ui(db)
1360 add_files(db)
1361 add_registry(db)
1362 remove_old_versions(db)
1363 db.Commit()
1364finally:
1365 del db
Martin v. Löwis34360642010-03-16 18:49:28 +00001366
1367# Merge CRT into MSI file. This requires the database to be closed.
1368mod_dir = os.path.join(os.environ["ProgramFiles"], "Common Files", "Merge Modules")
1369if msilib.Win64:
1370 modules = ["Microsoft_VC90_CRT_x86_x64.msm", "policy_9_0_Microsoft_VC90_CRT_x86_x64.msm"]
1371else:
1372 modules = ["Microsoft_VC90_CRT_x86.msm","policy_9_0_Microsoft_VC90_CRT_x86.msm"]
1373
1374for i, n in enumerate(modules):
1375 modules[i] = os.path.join(mod_dir, n)
1376
1377def merge(msi, feature, rootdir, modules):
1378 cab_and_filecount = []
1379 # Step 1: Merge databases, extract cabfiles
1380 m = msilib.MakeMerge2()
1381 m.OpenLog("merge.log")
1382 m.OpenDatabase(msi)
1383 for module in modules:
1384 print module
1385 m.OpenModule(module,0)
1386 m.Merge(feature, rootdir)
1387 print "Errors:"
1388 for e in m.Errors:
1389 print e.Type, e.ModuleTable, e.DatabaseTable
1390 print " Modkeys:",
1391 for s in e.ModuleKeys: print s,
1392 print
1393 print " DBKeys:",
1394 for s in e.DatabaseKeys: print s,
1395 print
1396 cabname = tempfile.mktemp(suffix=".cab")
1397 m.ExtractCAB(cabname)
1398 cab_and_filecount.append((cabname, len(m.ModuleFiles)))
1399 m.CloseModule()
1400 m.CloseDatabase(True)
1401 m.CloseLog()
1402
1403 # Step 2: Add CAB files
1404 i = msilib.MakeInstaller()
1405 db = i.OpenDatabase(msi, constants.msiOpenDatabaseModeTransact)
1406
1407 v = db.OpenView("SELECT LastSequence FROM Media")
1408 v.Execute(None)
1409 maxmedia = -1
1410 while 1:
1411 r = v.Fetch()
1412 if not r: break
1413 seq = r.IntegerData(1)
1414 if seq > maxmedia:
1415 maxmedia = seq
1416 print "Start of Media", maxmedia
1417
1418 for cabname, count in cab_and_filecount:
1419 stream = "merged%d" % maxmedia
1420 msilib.add_data(db, "Media",
1421 [(maxmedia+1, maxmedia+count, None, "#"+stream, None, None)])
1422 msilib.add_stream(db, stream, cabname)
1423 os.unlink(cabname)
1424 maxmedia += count
1425 # The merge module sets ALLUSERS to 1 in the property table.
1426 # This is undesired; delete that
1427 v = db.OpenView("DELETE FROM Property WHERE Property='ALLUSERS'")
1428 v.Execute(None)
1429 v.Close()
1430 db.Commit()
1431
1432merge(msiname, "SharedCRT", "TARGETDIR", modules)
1433
1434# certname (from config.py) should be (a substring of)
1435# the certificate subject, e.g. "Python Software Foundation"
1436if certname:
Martin v. Löwisd5375df2013-08-03 20:24:00 +02001437 os.system('signtool sign /n "%s" '
1438 '/t http://timestamp.verisign.com/scripts/timestamp.dll '
1439 '/d "Python %s" '
1440 '%s' % (certname, full_current_version, msiname))
Martin v. Löwiseebd0172010-11-14 18:17:39 +00001441
1442if pdbzip:
1443 build_pdbzip()