blob: 65ce5c153cfff86b9bc46d1ece6d26c025b99766 [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
Serhiy Storchaka9a118f12016-04-17 09:37:36 +0300262 # minor version. For a snapshot, we remove all earlier snapshots. For
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000263 # 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"))])
Steve Dower0ca4b6f2016-09-01 11:21:56 -0700379 add_data(db, "Binary", [("WixCA", msilib.Binary("WixCA.blob"))])
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000380 # See "Custom Action Type 1"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000381 if msilib.Win64:
382 CheckDir = "CheckDir"
Martin v. Löwisdf40ce32006-02-16 14:38:30 +0000383 UpdateEditIDLE = "UpdateEditIDLE"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000384 else:
385 CheckDir = "_CheckDir@4"
386 UpdateEditIDLE = "_UpdateEditIDLE@4"
Tim Peters0e9980f2004-09-12 03:49:31 +0000387 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000388 [("CheckDir", 1, "Script", CheckDir)])
Martin v. Löwiseac02e62004-11-18 08:00:33 +0000389 if have_tcl:
390 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000391 [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)])
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000392
393 # UI customization properties
394 add_data(db, "Property",
395 # See "DefaultUIFont Property"
396 [("DefaultUIFont", "DlgFont8"),
397 # See "ErrorDialog Style Bit"
398 ("ErrorDialog", "ErrorDlg"),
399 ("Progress1", "Install"), # modified in maintenance type dlg
400 ("Progress2", "installs"),
401 ("MaintenanceForm_Action", "Repair")])
402
403 # Fonts, see "TextStyle Table"
404 add_data(db, "TextStyle",
405 [("DlgFont8", "Tahoma", 9, None, 0),
406 ("DlgFontBold8", "Tahoma", 8, None, 1), #bold
407 ("VerdanaBold10", "Verdana", 10, None, 1),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000408 ("VerdanaRed9", "Verdana", 9, 255, 0),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000409 ])
410
Steve Dower0ca4b6f2016-09-01 11:21:56 -0700411 compileargs = r'"[#python.exe]" -Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py3_" "[TARGETDIR]Lib"'
412 compileoargs = r'"[#python.exe]" -O -Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py3_" "[TARGETDIR]Lib"'
413 lib2to3args = r'"[#python.exe]" -c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
414 updatepipargs = r'"[#python.exe]" -m ensurepip -U --default-pip'
415 removepipargs = r'"[#python.exe]" -B -m ensurepip._uninstall'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000416 # See "CustomAction Table"
417 add_data(db, "CustomAction", [
418 # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty
419 # See "Custom Action Type 51",
420 # "Custom Action Execution Scheduling Options"
421 ("InitialTargetDir", 307, "TARGETDIR",
422 "[WindowsVolume]Python%s%s" % (major, minor)),
423 ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
424 ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
425 # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
426 # See "Custom Action Type 18"
Steve Dower2d142702014-11-12 19:02:20 -0800427 # msidbCustomActionTypeInScript (1024); run during actual installation
428 # msidbCustomActionTypeNoImpersonate (2048); run action in system account, not user account
Steve Dower0ca4b6f2016-09-01 11:21:56 -0700429 ("SetCompilePycCommandLine", 51, "CompilePyc", compileargs),
430 ("SetCompilePyoCommandLine", 51, "CompilePyo", compileoargs),
431 ("SetCompileGrammarCommandLine", 51, "CompileGrammar", lib2to3args),
432 ("CompilePyc", 1+64+1024, "WixCA", "CAQuietExec"),
433 ("CompilePyo", 1+64+1024, "WixCA", "CAQuietExec"),
434 ("CompileGrammar", 1+64+1024, "WixCA", "CAQuietExec"),
435 ("SetUpdatePipCommandLine", 51, "UpdatePip", updatepipargs),
436 ("UpdatePip", 1+64+1024, "WixCA", "CAQuietExec"),
437 ("SetRemovePipCommandLine", 51, "RemovePip", removepipargs),
438 ("RemovePip", 1+64+1024, "WixCA", "CAQuietExec"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000439 ])
440
441 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
442 # Numbers indicate sequence; see sequence.py for how these action integrate
443 add_data(db, "InstallUISequence",
444 [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
445 ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141),
446 ("InitialTargetDir", 'TARGETDIR=""', 750),
447 # In the user interface, assume all-users installation if privileged.
448 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
449 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
450 ("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),
458 ])
459
Brian Curtind67c0b82014-05-10 12:52:59 -0500460 # Prepend TARGETDIR to the system path, and remove it on uninstall.
461 add_data(db, "Environment",
Steve Dower2d142702014-11-12 19:02:20 -0800462 [("PathAddition", "=-*Path", "[TARGETDIR];[TARGETDIR]Scripts;[~]", "REGISTRY.path")])
Brian Curtind67c0b82014-05-10 12:52:59 -0500463
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000464 # Execute Sequences
465 add_data(db, "InstallExecuteSequence",
466 [("InitialTargetDir", 'TARGETDIR=""', 750),
467 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
468 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000469 ("UpdateEditIDLE", None, 1050),
Steve Dower2d142702014-11-12 19:02:20 -0800470 # remove pip when state changes to INSTALLSTATE_ABSENT
471 # run before RemoveFiles
Steve Dower0ca4b6f2016-09-01 11:21:56 -0700472 ("SetRemovePipCommandLine", "&pip_feature=2 and !pip_feature=3", 3498),
473 ("RemovePip", "RemovePip", 3499),
474 # run command if install state of pip changes to INSTALLSTATE_LOCAL
475 # run after InstallFiles
476 ("SetUpdatePipCommandLine", "&pip_feature=3 and not !pip_feature=3", 4001),
477 ("UpdatePip", "UpdatePip", 4002),
478 ("SetCompilePycCommandLine", "COMPILEALL", 4003),
479 ("SetCompilePyoCommandLine", "COMPILEALL", 4004),
480 ("SetCompileGrammarCommandLine", "COMPILEALL", 4005),
481 ("CompilePyc", "CompilePyc", 4006),
482 ("CompilePyo", "CompilePyo", 4007),
483 ("CompileGrammar", "CompileGrammar", 4008),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000484 ])
485 add_data(db, "AdminExecuteSequence",
486 [("InitialTargetDir", 'TARGETDIR=""', 750),
487 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000488 ])
489
490 #####################################################################
491 # Standard dialogs: FatalError, UserExit, ExitDialog
492 fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title,
493 "Finish", "Finish", "Finish")
494 fatal.title("[ProductName] Installer ended prematurely")
495 fatal.back("< Back", "Finish", active = 0)
496 fatal.cancel("Cancel", "Back", active = 0)
497 fatal.text("Description1", 135, 70, 220, 80, 0x30003,
498 "[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.")
499 fatal.text("Description2", 135, 155, 220, 20, 0x30003,
500 "Click the Finish button to exit the Installer.")
501 c=fatal.next("Finish", "Cancel", name="Finish")
502 # See "ControlEvent Table". Parameters are the event, the parameter
503 # to the action, and optionally the condition for the event, and the order
504 # of events.
505 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000506
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000507 user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title,
508 "Finish", "Finish", "Finish")
509 user_exit.title("[ProductName] Installer was interrupted")
510 user_exit.back("< Back", "Finish", active = 0)
511 user_exit.cancel("Cancel", "Back", active = 0)
512 user_exit.text("Description1", 135, 70, 220, 80, 0x30003,
513 "[ProductName] setup was interrupted. Your system has not been modified. "
514 "To install this program at a later time, please run the installation again.")
515 user_exit.text("Description2", 135, 155, 220, 20, 0x30003,
516 "Click the Finish button to exit the Installer.")
517 c = user_exit.next("Finish", "Cancel", name="Finish")
518 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000519
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000520 exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title,
521 "Finish", "Finish", "Finish")
Martin v. Löwisef281bd2012-02-21 17:07:32 +0100522 exit_dialog.title("Complete the [ProductName] Installer")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000523 exit_dialog.back("< Back", "Finish", active = 0)
524 exit_dialog.cancel("Cancel", "Back", active = 0)
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000525 exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003,
526 "Special Windows thanks to:\n"
Martin v. Löwisd3f61a22004-08-30 09:22:30 +0000527 " Mark Hammond, without whose years of freely \n"
528 " shared Windows expertise, Python for Windows \n"
529 " would still be Python for DOS.")
Tim Peters66cb0182004-08-26 05:23:19 +0000530
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000531 c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003,
Brian Curtin611cfd22011-05-03 13:36:34 -0500532 "{\\VerdanaRed9}Warning: Python 3.3.0 is the last "
Martin v. Löwis16b2a5e2010-06-04 19:15:32 +0000533 "Python release for Windows 2000.")
534 c.condition("Hide", "VersionNT > 500")
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000535
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000536 exit_dialog.text("Description", 135, 235, 220, 20, 0x30003,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000537 "Click the Finish button to exit the Installer.")
538 c = exit_dialog.next("Finish", "Cancel", name="Finish")
539 c.event("EndDialog", "Return")
540
541 #####################################################################
542 # Required dialog: FilesInUse, ErrorDlg
543 inuse = PyDialog(db, "FilesInUse",
544 x, y, w, h,
545 19, # KeepModeless|Modal|Visible
546 title,
547 "Retry", "Retry", "Retry", bitmap=False)
548 inuse.text("Title", 15, 6, 200, 15, 0x30003,
549 r"{\DlgFontBold8}Files in Use")
550 inuse.text("Description", 20, 23, 280, 20, 0x30003,
551 "Some files that need to be updated are currently in use.")
552 inuse.text("Text", 20, 55, 330, 50, 3,
553 "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.")
554 inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess",
555 None, None, None)
556 c=inuse.back("Exit", "Ignore", name="Exit")
557 c.event("EndDialog", "Exit")
558 c=inuse.next("Ignore", "Retry", name="Ignore")
559 c.event("EndDialog", "Ignore")
560 c=inuse.cancel("Retry", "Exit", name="Retry")
561 c.event("EndDialog","Retry")
562
563
564 # See "Error Dialog". See "ICE20" for the required names of the controls.
565 error = Dialog(db, "ErrorDlg",
566 50, 10, 330, 101,
567 65543, # Error|Minimize|Modal|Visible
568 title,
569 "ErrorText", None, None)
570 error.text("ErrorText", 50,9,280,48,3, "")
571 error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
572 error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo")
573 error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes")
574 error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort")
575 error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel")
576 error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore")
577 error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk")
578 error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry")
579
580 #####################################################################
581 # Global "Query Cancel" dialog
582 cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title,
583 "No", "No", "No")
Tim Peters66cb0182004-08-26 05:23:19 +0000584 cancel.text("Text", 48, 15, 194, 30, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000585 "Are you sure you want to cancel [ProductName] installation?")
586 cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
587 "py.ico", None, None)
588 c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
589 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000590
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000591 c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
592 c.event("EndDialog", "Return")
593
594 #####################################################################
595 # Global "Wait for costing" dialog
596 costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title,
597 "Return", "Return", "Return")
598 costing.text("Text", 48, 15, 194, 30, 3,
599 "Please wait while the installer finishes determining your disk space requirements.")
600 costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
601 "py.ico", None, None)
602 c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
603 c.event("EndDialog", "Exit")
604
605 #####################################################################
606 # Preparation dialog: no user input except cancellation
607 prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title,
608 "Cancel", "Cancel", "Cancel")
609 prep.text("Description", 135, 70, 220, 40, 0x30003,
610 "Please wait while the Installer prepares to guide you through the installation.")
611 prep.title("Welcome to the [ProductName] Installer")
612 c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...")
613 c.mapping("ActionText", "Text")
614 c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None)
615 c.mapping("ActionData", "Text")
616 prep.back("Back", None, active=0)
617 prep.next("Next", None, active=0)
618 c=prep.cancel("Cancel", None)
619 c.event("SpawnDialog", "CancelDlg")
620
621 #####################################################################
622 # Target directory selection
623 seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title,
624 "Next", "Next", "Cancel")
625 seldlg.title("Select Destination Directory")
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000626 c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003,
627 "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.")
628 c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000629 seldlg.text("Description", 135, 50, 220, 40, 0x30003,
630 "Please select a directory for the [ProductName] files.")
631
632 seldlg.back("< Back", None, active=0)
633 c = seldlg.next("Next >", "Cancel")
634 c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1)
635 # If the target exists, but we found that we are going to remove old versions, don't bother
636 # confirming that the target directory exists. Strictly speaking, we should determine that
637 # the target directory is indeed the target of the product that we are going to remove, but
638 # I don't know how to do that.
639 c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2)
640 c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3)
641 c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4)
642 c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5)
643
644 c = seldlg.cancel("Cancel", "DirectoryCombo")
645 c.event("SpawnDialog", "CancelDlg")
646
647 seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219,
648 "TARGETDIR", None, "DirectoryList", None)
649 seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR",
650 None, "PathEdit", None)
651 seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None)
652 c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
653 c.event("DirectoryListUp", "0")
654 c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
655 c.event("DirectoryListNew", "0")
656
657 #####################################################################
658 # SelectFeaturesDlg
659 features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space,
660 title, "Tree", "Next", "Cancel")
661 features.title("Customize [ProductName]")
662 features.text("Description", 135, 35, 220, 15, 0x30003,
663 "Select the way you want features to be installed.")
664 features.text("Text", 135,45,220,30, 3,
665 "Click on the icons in the tree below to change the way features will be installed.")
666
667 c=features.back("< Back", "Next")
668 c.event("NewDialog", "SelectDirectoryDlg")
669
670 c=features.next("Next >", "Cancel")
671 c.mapping("SelectionNoItems", "Enabled")
672 c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1)
673 c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2)
674
675 c=features.cancel("Cancel", "Tree")
676 c.event("SpawnDialog", "CancelDlg")
677
Tim Peters66cb0182004-08-26 05:23:19 +0000678 # 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 +0000679 features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty",
680 "Tree of selections", "Back", None)
681
682 #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost")
683 #c.mapping("SelectionNoItems", "Enabled")
684 #c.event("Reset", "0")
Tim Peters66cb0182004-08-26 05:23:19 +0000685
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000686 features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None)
687
688 c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10)
689 c.mapping("SelectionNoItems","Enabled")
690 c.event("SpawnDialog", "DiskCostDlg")
691
692 c=features.xbutton("Advanced", "Advanced", None, 0.30)
693 c.event("SpawnDialog", "AdvancedDlg")
694
Brian Curtind67c0b82014-05-10 12:52:59 -0500695 c=features.text("ItemDescription", 140, 180, 210, 40, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000696 "Multiline description of the currently selected item.")
697 c.mapping("SelectionDescription","Text")
Tim Peters66cb0182004-08-26 05:23:19 +0000698
Brian Curtind67c0b82014-05-10 12:52:59 -0500699 c=features.text("ItemSize", 140, 225, 210, 33, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000700 "The size of the currently selected item.")
701 c.mapping("SelectionSize", "Text")
702
703 #####################################################################
704 # Disk cost
705 cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title,
706 "OK", "OK", "OK", bitmap=False)
707 cost.text("Title", 15, 6, 200, 15, 0x30003,
708 "{\DlgFontBold8}Disk Space Requirements")
709 cost.text("Description", 20, 20, 280, 20, 0x30003,
710 "The disk space required for the installation of the selected features.")
711 cost.text("Text", 20, 53, 330, 60, 3,
712 "The highlighted volumes (if any) do not have enough disk space "
713 "available for the currently selected features. You can either "
714 "remove some files from the highlighted volumes, or choose to "
715 "install less features onto local drive(s), or select different "
716 "destination drive(s).")
717 cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223,
718 None, "{120}{70}{70}{70}{70}", None, None)
719 cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
720
721 #####################################################################
722 # WhichUsers Dialog. Only available on NT, and for privileged users.
723 # This must be run before FindRelatedProducts, because that will
724 # take into account whether the previous installation was per-user
725 # or per-machine. We currently don't support going back to this
726 # dialog after "Next" was selected; to support this, we would need to
727 # find how to reset the ALLUSERS property, and how to re-run
728 # FindRelatedProducts.
729 # On Windows9x, the ALLUSERS property is ignored on the command line
730 # and in the Property table, but installer fails according to the documentation
731 # if a dialog attempts to set ALLUSERS.
732 whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title,
733 "AdminInstall", "Next", "Cancel")
734 whichusers.title("Select whether to install [ProductName] for all users of this computer.")
735 # A radio group with two options: allusers, justme
Martin v. Löwiseba774b2008-10-13 11:23:35 +0000736 g = whichusers.radiogroup("AdminInstall", 135, 60, 235, 80, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000737 "WhichUsers", "", "Next")
Martin v. Löwiseba774b2008-10-13 11:23:35 +0000738 g.condition("Disable", "VersionNT=600") # Not available on Vista and Windows 2008
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000739 g.add("ALL", 0, 5, 150, 20, "Install for all users")
Martin v. Löwiseba774b2008-10-13 11:23:35 +0000740 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 +0000741
Tim Peters66cb0182004-08-26 05:23:19 +0000742 whichusers.back("Back", None, active=0)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000743
744 c = whichusers.next("Next >", "Cancel")
745 c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
746 c.event("EndDialog", "Return", order = 2)
747
748 c = whichusers.cancel("Cancel", "AdminInstall")
749 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000750
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000751 #####################################################################
752 # Advanced Dialog.
753 advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title,
Martin v. Löwis63470982008-11-19 13:51:44 +0000754 "CompilePyc", "Ok", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000755 advanced.title("Advanced Options for [ProductName]")
756 # A radio group with two options: allusers, justme
757 advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3,
Martin v. Löwis63470982008-11-19 13:51:44 +0000758 "COMPILEALL", "Compile .py files to byte code after installation", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000759
Martin v. Löwis63470982008-11-19 13:51:44 +0000760 c = advanced.cancel("Ok", "CompilePyc", name="Ok") # Button just has location of cancel button.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000761 c.event("EndDialog", "Return")
762
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000763 #####################################################################
Tim Peters66cb0182004-08-26 05:23:19 +0000764 # Existing Directory dialog
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000765 dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title,
766 "No", "No", "No")
767 dlg.text("Title", 10, 20, 180, 40, 3,
768 "[TARGETDIR] exists. Are you sure you want to overwrite existing files?")
769 c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No")
770 c.event("[TargetExists]", "0", order=1)
771 c.event("[TargetExistsOk]", "1", order=2)
772 c.event("EndDialog", "Return", order=3)
773 c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes")
774 c.event("EndDialog", "Return")
775
776 #####################################################################
777 # Installation Progress dialog (modeless)
778 progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title,
779 "Cancel", "Cancel", "Cancel", bitmap=False)
780 progress.text("Title", 20, 15, 200, 15, 0x30003,
781 "{\DlgFontBold8}[Progress1] [ProductName]")
782 progress.text("Text", 35, 65, 300, 30, 3,
783 "Please wait while the Installer [Progress2] [ProductName]. "
784 "This may take several minutes.")
785 progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
786
787 c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...")
788 c.mapping("ActionText", "Text")
789
790 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
791 #c.mapping("ActionData", "Text")
792
793 c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537,
794 None, "Progress done", None, None)
795 c.mapping("SetProgress", "Progress")
796
797 progress.back("< Back", "Next", active=False)
798 progress.next("Next >", "Cancel", active=False)
799 progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
800
801 # Maintenance type: repair/uninstall
802 maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title,
803 "Next", "Next", "Cancel")
804 maint.title("Welcome to the [ProductName] Setup Wizard")
805 maint.text("BodyText", 135, 63, 230, 42, 3,
806 "Select whether you want to repair or remove [ProductName].")
807 g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3,
808 "MaintenanceForm_Action", "", "Next")
809 g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
810 g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
811 g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
Tim Peters66cb0182004-08-26 05:23:19 +0000812
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000813 maint.back("< Back", None, active=False)
814 c=maint.next("Finish", "Cancel")
815 # Change installation: Change progress dialog to "Change", then ask
816 # for feature selection
817 c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
818 c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
819
820 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
821 # Also set list of reinstalled features to "ALL"
822 c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
823 c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
Raymond Hettinger72f08012004-11-07 07:08:25 +0000824 c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000825 c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
826
827 # Uninstall: Change progress to "Remove", then invoke uninstall
828 # Also set list of removed features to "ALL"
829 c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
830 c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
831 c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
832 c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
833
Tim Peters66cb0182004-08-26 05:23:19 +0000834 # Close dialog when maintenance action scheduled
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000835 c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
836 c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
Tim Peters66cb0182004-08-26 05:23:19 +0000837
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000838 maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000839
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000840
841# See "Feature Table". The feature level is 1 for all features,
842# and the feature attributes are 0 for the DefaultFeature, and
843# FollowParent for all other features. The numbers are the Display
844# column.
845def add_features(db):
846 # feature attributes:
847 # msidbFeatureAttributesFollowParent == 2
848 # msidbFeatureAttributesDisallowAdvertise == 8
849 # Features that need to be installed with together with the main feature
850 # (i.e. additional Python libraries) need to follow the parent feature.
851 # Features that have no advertisement trigger (e.g. the test suite)
852 # must not support advertisement
Steve Dower2d142702014-11-12 19:02:20 -0800853 global default_feature, tcltk, htmlfiles, tools, testsuite
854 global ext_feature, private_crt, prepend_path, pip_feature
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000855 default_feature = Feature(db, "DefaultFeature", "Python",
856 "Python Interpreter and Libraries",
857 1, directory = "TARGETDIR")
Martin v. Löwis4dc34152008-04-05 15:48:36 +0000858 shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0,
859 level=0)
860 private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0,
861 level=0)
862 add_data(db, "Condition", [("SharedCRT", 1, sys32cond),
863 ("PrivateCRT", 1, "not "+sys32cond)])
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000864 # We don't support advertisement of extensions
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000865 ext_feature = Feature(db, "Extensions", "Register Extensions",
866 "Make this Python installation the default Python installation", 3,
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000867 parent = default_feature, attributes=2|8)
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000868 if have_tcl:
869 tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000870 parent = default_feature, attributes=2)
871 htmlfiles = Feature(db, "Documentation", "Documentation",
872 "Python HTMLHelp File", 7, parent = default_feature)
873 tools = Feature(db, "Tools", "Utility Scripts",
Tim Peters66cb0182004-08-26 05:23:19 +0000874 "Python utility scripts (Tools/", 9,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000875 parent = default_feature, attributes=2)
Steve Dower2d142702014-11-12 19:02:20 -0800876 pip_feature = Feature(db, "pip_feature", "pip",
877 "Install or upgrade pip, a tool for installing and managing "
878 "Python packages.", 11,
879 parent = default_feature, attributes=2|8)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000880 testsuite = Feature(db, "Testsuite", "Test suite",
Steve Dower2d142702014-11-12 19:02:20 -0800881 "Python test suite (Lib/test/)", 13,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000882 parent = default_feature, attributes=2|8)
Brian Curtind67c0b82014-05-10 12:52:59 -0500883 # prepend_path is an additional feature which is to be off by default.
884 # Since the default level for the above features is 1, this needs to be
885 # at least level higher.
886 prepend_path = Feature(db, "PrependPath", "Add python.exe to Path",
887 "Prepend [TARGETDIR] to the system Path variable. "
888 "This allows you to type 'python' into a command "
Steve Dower2d142702014-11-12 19:02:20 -0800889 "prompt without needing the full path.", 15,
Brian Curtind67c0b82014-05-10 12:52:59 -0500890 parent = default_feature, attributes=2|8,
891 level=2)
Tim Peters66cb0182004-08-26 05:23:19 +0000892
Christian Heimes9acba042007-12-04 14:57:30 +0000893def extract_msvcr90():
Martin v. Löwis03dc56c2008-02-28 22:20:50 +0000894 # Find the redistributable files
Martin v. Löwise1d9dca2008-09-19 19:20:03 +0000895 if msilib.Win64:
896 arch = "amd64"
897 else:
898 arch = "x86"
899 dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC90.CRT" % arch)
Christian Heimes9acba042007-12-04 14:57:30 +0000900
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000901 result = []
Christian Heimes9acba042007-12-04 14:57:30 +0000902 installer = msilib.MakeInstaller()
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000903 # omit msvcm90 and msvcp90, as they aren't really needed
904 files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"]
905 for f in files:
906 path = os.path.join(dir, f)
907 kw = {'src':path}
908 if f.endswith('.dll'):
909 kw['version'] = installer.FileVersion(path, 0)
910 kw['language'] = installer.FileVersion(path, 1)
911 result.append((f, kw))
912 return result
Christian Heimes9acba042007-12-04 14:57:30 +0000913
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000914def generate_license():
915 import shutil, glob
916 out = open("LICENSE.txt", "w")
917 shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out)
Martin v. Löwis4eb18f92008-09-14 20:22:39 +0000918 shutil.copyfileobj(open("crtlicense.txt"), out)
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000919 for name, pat, file in (("bzip2","bzip2-*", "LICENSE"),
920 ("Berkeley DB", "db-*", "LICENSE"),
921 ("openssl", "openssl-*", "LICENSE"),
Steve Dower144de312014-09-12 11:48:13 -0700922 ("Tcl", "tcl-8*", "license.terms"),
923 ("Tk", "tk-8*", "license.terms"),
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000924 ("Tix", "tix-*", "license.terms")):
925 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 -0800926 dirs = glob.glob(srcdir+"/externals/"+pat)
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000927 if not dirs:
Steve Dowera6e6d0a2014-11-25 22:43:06 -0800928 raise ValueError, "Could not find "+srcdir+"/externals/"+pat
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000929 if len(dirs) > 2:
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000930 raise ValueError, "Multiple copies of "+pat
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000931 dir = dirs[0]
932 shutil.copyfileobj(open(os.path.join(dir, file)), out)
933 out.close()
934
935
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000936class PyDirectory(Directory):
937 """By default, all components in the Python installer
938 can run from source."""
939 def __init__(self, *args, **kw):
940 if not kw.has_key("componentflags"):
941 kw['componentflags'] = 2 #msidbComponentAttributesOptional
942 Directory.__init__(self, *args, **kw)
943
944# See "File Table", "Component Table", "Directory Table",
945# "FeatureComponents Table"
946def add_files(db):
947 cab = CAB("python")
948 tmpfiles = []
949 # Add all executables, icons, text files into the TARGETDIR component
950 root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir")
951 default_feature.set_current()
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000952 if not msilib.Win64:
Christian Heimes9acba042007-12-04 14:57:30 +0000953 root.add_file("%s/w9xpopen.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000954 root.add_file("README.txt", src="README")
955 root.add_file("NEWS.txt", src="Misc/NEWS")
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000956 generate_license()
957 root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000958 root.start_component("python.exe", keyfile="python.exe")
Christian Heimes9acba042007-12-04 14:57:30 +0000959 root.add_file("%s/python.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000960 root.start_component("pythonw.exe", keyfile="pythonw.exe")
Christian Heimes9acba042007-12-04 14:57:30 +0000961 root.add_file("%s/pythonw.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000962
963 # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
Martin v. Löwis0f3e7692008-10-17 13:43:01 +0000964 dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000965
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000966 pydll = "python%s%s.dll" % (major, minor)
Christian Heimes9acba042007-12-04 14:57:30 +0000967 pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000968 dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000969 installer = msilib.MakeInstaller()
970 pyversion = installer.FileVersion(pydllsrc, 0)
971 if not snapshot:
972 # For releases, the Python DLL has the same version as the
973 # installer package.
Steve Dower144de312014-09-12 11:48:13 -0700974 assert pyversion.split(".")[:3] == current_version.split("."), "%s != %s" % (pyversion, current_version)
Christian Heimes9acba042007-12-04 14:57:30 +0000975 dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000976 version=pyversion,
977 language=installer.FileVersion(pydllsrc, 1))
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000978 DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs")
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000979
980 # msvcr90.dll: Need to place the DLL and the manifest into the root directory,
981 # plus another copy of the manifest in the DLLs directory, with the manifest
982 # pointing to the root directory
Martin v. Löwis46a8be72008-04-07 14:55:53 +0000983 root.start_component("msvcr90", feature=private_crt)
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000984 # Results are ID,keyword pairs
985 manifest, crtdll = extract_msvcr90()
986 root.add_file(manifest[0], **manifest[1])
987 root.add_file(crtdll[0], **crtdll[1])
988 # Copy the manifest
Martin v. Löwisddd82632008-11-06 19:46:03 +0000989 # Actually, don't do that anymore - no DLL in DLLs should have a manifest
990 # dependency on msvcr90.dll anymore, so this should not be necessary
991 #manifest_dlls = manifest[0]+".root"
992 #open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr"))
993 #DLLs.start_component("msvcr90_dlls", feature=private_crt)
994 #DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls))
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000995
996 # Now start the main component for the DLLs directory;
997 # no regular files have been added to the directory yet.
998 DLLs.start_component()
Tim Peters66cb0182004-08-26 05:23:19 +0000999
Martin v. Löwis38325b72006-08-25 00:03:34 +00001000 # Check if _ctypes.pyd exists
Christian Heimes9acba042007-12-04 14:57:30 +00001001 have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD)
Martin v. Löwis38325b72006-08-25 00:03:34 +00001002 if not have_ctypes:
1003 print "WARNING: _ctypes.pyd not found, ctypes will not be included"
1004 extensions.remove("_ctypes.pyd")
Tim Peters147f9ae2006-08-25 22:05:39 +00001005
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001006 # Add all .py files in Lib, except lib-tk, test
1007 dirs={}
1008 pydirs = [(root,"Lib")]
1009 while pydirs:
Martin v. Löwisc9798fc2008-06-13 18:58:47 +00001010 # Commit every now and then, or else installer will complain
1011 db.Commit()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001012 parent, dir = pydirs.pop()
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001013 if dir == ".svn" or dir.startswith("plat-"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001014 continue
Georg Brandl6634bf22008-05-20 07:13:37 +00001015 elif dir in ["lib-tk", "idlelib", "Icons"]:
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001016 if not have_tcl:
1017 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001018 tcltk.set_current()
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +00001019 elif dir in ['test', 'tests', 'data', 'output']:
Martin v. Löwis59c3acc2006-04-03 12:07:46 +00001020 # test: Lib, Lib/email, Lib/bsddb, Lib/ctypes, Lib/sqlite3
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +00001021 # tests: Lib/distutils
1022 # data: Lib/email/test
1023 # output: Lib/test
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001024 testsuite.set_current()
Martin v. Löwis38325b72006-08-25 00:03:34 +00001025 elif not have_ctypes and dir == "ctypes":
1026 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001027 else:
1028 default_feature.set_current()
1029 lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
1030 # Add additional files
1031 dirs[dir]=lib
1032 lib.glob("*.txt")
Steve Dower25b61202014-11-26 09:20:00 -08001033 lib.glob("*.whl")
1034 lib.glob("*.0")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001035 if dir=='site-packages':
Martin v. Löwis6d60c092004-11-21 10:16:26 +00001036 lib.add_file("README.txt", src="README")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001037 continue
1038 files = lib.glob("*.py")
1039 files += lib.glob("*.pyw")
1040 if files:
1041 # Add an entry to the RemoveFile table to remove bytecode files.
1042 lib.remove_pyc()
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001043 if dir.endswith('.egg-info'):
1044 lib.add_file('entry_points.txt')
1045 lib.add_file('PKG-INFO')
1046 lib.add_file('top_level.txt')
1047 lib.add_file('zip-safe')
1048 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001049 if dir=='test' and parent.physical=='Lib':
1050 lib.add_file("185test.db")
1051 lib.add_file("audiotest.au")
1052 lib.add_file("cfgparser.1")
Martin v. Löwisc0fdb182006-09-12 19:49:20 +00001053 lib.add_file("sgml_input.html")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001054 lib.add_file("testtar.tar")
Martin v. Löwis7d3755d2004-09-06 06:31:12 +00001055 lib.add_file("test_difflib_expect.html")
Thomas Heller3bd33152006-04-04 18:41:13 +00001056 lib.add_file("empty.vbs")
Martin v. Löwisea598b62009-06-01 04:10:03 +00001057 lib.add_file("Sine-1000Hz-300ms.aif")
Steve Dower0c3708a2014-11-26 09:32:41 -08001058 lib.add_file("revocation.crl")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001059 lib.glob("*.uue")
Martin v. Löwis0ffdacd2007-11-20 02:46:02 +00001060 lib.glob("*.pem")
Martin v. Löwis6b449f42007-12-03 19:20:02 +00001061 lib.glob("*.pck")
Martin v. Löwis91a1a072009-04-04 18:44:44 +00001062 lib.add_file("zipdir.zip")
Brian Curtin69a106a2010-11-22 02:08:49 +00001063 if dir=='tests' and parent.physical=='distutils':
1064 lib.add_file("Setup.sample")
Benjamin Peterson672b0432014-05-18 16:32:22 -07001065 if dir=='audiodata':
1066 lib.glob("*.*")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001067 if dir=='decimaltestdata':
1068 lib.glob("*.decTest")
Benjamin Peterson672b0432014-05-18 16:32:22 -07001069 if dir=='imghdrdata':
1070 lib.glob("*.*")
Florent Xicluna13ba1a12010-03-13 11:18:49 +00001071 if dir=='xmltestdata':
1072 lib.glob("*.xml")
1073 lib.add_file("test.xml.out")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001074 if dir=='output':
1075 lib.glob("test_*")
1076 if dir=='idlelib':
1077 lib.glob("*.def")
1078 lib.add_file("idle.bat")
Terry Jan Reedy30b51c92016-11-11 12:03:09 -05001079 lib.add_file("help.html")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001080 if dir=="Icons":
1081 lib.glob("*.gif")
Steve Dowerbd2ab522014-05-10 21:25:54 -07001082 lib.glob("*.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001083 lib.add_file("idle.icns")
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001084 if dir=="command" and parent.physical=="distutils":
Martin v. Löwis023b9f92008-04-09 18:56:20 +00001085 lib.glob("wininst*.exe")
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001086 if dir=="setuptools":
1087 lib.add_file("cli.exe")
1088 lib.add_file("gui.exe")
Martin v. Löwis367c79a2008-05-25 16:37:34 +00001089 if dir=="lib2to3":
1090 lib.removefile("pickle", "*.pickle")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001091 if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email":
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001092 # This should contain all non-.svn files listed in subversion
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001093 for f in os.listdir(lib.absolute):
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001094 if f.endswith(".txt") or f==".svn":continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001095 if f.endswith(".au") or f.endswith(".gif"):
1096 lib.add_file(f)
1097 else:
1098 print "WARNING: New file %s in email/test/data" % f
1099 for f in os.listdir(lib.absolute):
1100 if os.path.isdir(os.path.join(lib.absolute, f)):
1101 pydirs.append((lib, f))
1102 # Add DLLs
1103 default_feature.set_current()
Martin v. Löwisd9759c42008-02-28 19:57:34 +00001104 lib = DLLs
Christian Heimes7e28e492008-01-01 13:52:57 +00001105 lib.add_file("py.ico", src=srcdir+"/PC/py.ico")
Christian Heimese1c6af02008-01-01 13:58:16 +00001106 lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001107 dlls = []
1108 tclfiles = []
1109 for f in extensions:
1110 if f=="_tkinter.pyd":
1111 continue
Christian Heimes9acba042007-12-04 14:57:30 +00001112 if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001113 print "WARNING: Missing extension", f
1114 continue
1115 dlls.append(f)
1116 lib.add_file(f)
Martin v. Löwis88ef6372006-07-06 06:55:58 +00001117 # Add sqlite
1118 if msilib.msi_type=="Intel64;1033":
1119 sqlite_arch = "/ia64"
1120 elif msilib.msi_type=="x64;1033":
1121 sqlite_arch = "/amd64"
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001122 tclsuffix = "64"
Martin v. Löwis88ef6372006-07-06 06:55:58 +00001123 else:
1124 sqlite_arch = ""
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001125 tclsuffix = ""
Martin v. Löwisc9798fc2008-06-13 18:58:47 +00001126 lib.add_file("sqlite3.dll")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001127 if have_tcl:
Christian Heimes9acba042007-12-04 14:57:30 +00001128 if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)):
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001129 print "WARNING: Missing _tkinter.pyd"
1130 else:
1131 lib.start_component("TkDLLs", tcltk)
1132 lib.add_file("_tkinter.pyd")
1133 dlls.append("_tkinter.pyd")
Steve Dowera6e6d0a2014-11-25 22:43:06 -08001134 tcldir = os.path.normpath(srcdir+("/externals/tcltk%s/bin" % tclsuffix))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001135 for f in glob.glob1(tcldir, "*.dll"):
1136 lib.add_file(f, src=os.path.join(tcldir, f))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001137 # check whether there are any unknown extensions
Christian Heimes9acba042007-12-04 14:57:30 +00001138 for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001139 if f.endswith("_d.pyd"): continue # debug version
1140 if f in dlls: continue
1141 print "WARNING: Unknown extension", f
Tim Peters66cb0182004-08-26 05:23:19 +00001142
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001143 # Add headers
1144 default_feature.set_current()
1145 lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include")
1146 lib.glob("*.h")
1147 lib.add_file("pyconfig.h", src="../PC/pyconfig.h")
1148 # Add import libraries
Christian Heimes9acba042007-12-04 14:57:30 +00001149 lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001150 for f in dlls:
1151 lib.add_file(f.replace('pyd','lib'))
1152 lib.add_file('python%s%s.lib' % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +00001153 # Add the mingw-format library
1154 if have_mingw:
Tim Peters5a9fb3c2005-01-07 16:01:32 +00001155 lib.add_file('libpython%s%s.a' % (major, minor))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001156 if have_tcl:
1157 # Add Tcl/Tk
Steve Dowera6e6d0a2014-11-25 22:43:06 -08001158 tcldirs = [(root, 'externals/tcltk%s/lib' % tclsuffix, 'tcl')]
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001159 tcltk.set_current()
1160 while tcldirs:
1161 parent, phys, dir = tcldirs.pop()
1162 lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir))
1163 if not os.path.exists(lib.absolute):
1164 continue
1165 for f in os.listdir(lib.absolute):
1166 if os.path.isdir(os.path.join(lib.absolute, f)):
1167 tcldirs.append((lib, f, f))
1168 else:
1169 lib.add_file(f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001170 # Add tools
1171 tools.set_current()
1172 tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools")
1173 for f in ['i18n', 'pynche', 'Scripts', 'versioncheck', 'webchecker']:
1174 lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f))
1175 lib.glob("*.py")
1176 lib.glob("*.pyw", exclude=['pydocgui.pyw'])
1177 lib.remove_pyc()
1178 lib.glob("*.txt")
1179 if f == "pynche":
1180 x = PyDirectory(db, cab, lib, "X", "X", "X|X")
1181 x.glob("*.txt")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001182 if os.path.exists(os.path.join(lib.absolute, "README")):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001183 lib.add_file("README.txt", src="README")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001184 if f == 'Scripts':
Martin v. Löwisd69c9042008-10-01 11:19:50 +00001185 lib.add_file("2to3.py", src="2to3")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001186 if have_tcl:
1187 lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
1188 lib.add_file("pydocgui.pyw")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001189 # Add documentation
1190 htmlfiles.set_current()
1191 lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc")
Martin v. Löwis344d0662008-05-09 18:21:55 +00001192 lib.start_component("documentation", keyfile=docfile)
1193 lib.add_file(docfile, src="build/htmlhelp/"+docfile)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001194
1195 cab.commit(db)
1196
1197 for f in tmpfiles:
1198 os.unlink(f)
1199
1200# See "Registry Table", "Component Table"
1201def add_registry(db):
1202 # File extensions, associated with the REGISTRY.def component
1203 # IDLE verbs depend on the tcltk feature.
1204 # msidbComponentAttributesRegistryKeyPath = 4
1205 # -1 for Root specifies "dependent on ALLUSERS property"
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001206 tcldata = []
1207 if have_tcl:
1208 tcldata = [
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001209 ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001210 "py.IDLE")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001211 add_data(db, "Component",
1212 # msidbComponentAttributesRegistryKeyPath = 4
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001213 [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001214 "InstallPath"),
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001215 ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001216 "Documentation"),
Brian Curtind67c0b82014-05-10 12:52:59 -05001217 ("REGISTRY.path", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
1218 None),
Steve Dower2d142702014-11-12 19:02:20 -08001219 ("REGISTRY.ensurepip", msilib.gen_uuid(), "TARGETDIR", registry_component, "EnsurePipRun",
1220 None),
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001221 ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001222 None, None)] + tcldata)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001223 # See "FeatureComponents Table".
1224 # The association between TclTk and pythonw.exe is necessary to make ICE59
1225 # happy, because the installer otherwise believes that the IDLE and PyDoc
1226 # shortcuts might get installed without pythonw.exe being install. This
1227 # is not true, since installing TclTk will install the default feature, which
1228 # will cause pythonw.exe to be installed.
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001229 # REGISTRY.tcl is not associated with any feature, as it will be requested
1230 # through a custom action
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001231 tcldata = []
1232 if have_tcl:
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001233 tcldata = [(tcltk.id, "pythonw.exe")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001234 add_data(db, "FeatureComponents",
1235 [(default_feature.id, "REGISTRY"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001236 (htmlfiles.id, "REGISTRY.doc"),
Brian Curtind67c0b82014-05-10 12:52:59 -05001237 (prepend_path.id, "REGISTRY.path"),
Steve Dower2d142702014-11-12 19:02:20 -08001238 (pip_feature.id, "REGISTRY.ensurepip"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001239 (ext_feature.id, "REGISTRY.def")] +
1240 tcldata
1241 )
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001242 # Extensions are not advertised. For advertised extensions,
1243 # we would need separate binaries that install along with the
1244 # extension.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001245 pat = r"Software\Classes\%sPython.%sFile\shell\%s\command"
1246 ewi = "Edit with IDLE"
1247 pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon"
1248 pat3 = r"Software\Classes\%sPython.%sFile"
Martin v. Löwis3d6f8ff2008-11-07 18:51:50 +00001249 pat4 = r"Software\Classes\%sPython.%sFile\shellex\DropHandler"
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001250 tcl_verbs = []
1251 if have_tcl:
1252 tcl_verbs=[
1253 ("py.IDLE", -1, pat % (testprefix, "", ewi), "",
Martin v. Löwis588b54b2009-05-05 16:10:16 +00001254 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001255 "REGISTRY.tcl"),
1256 ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "",
Martin v. Löwis588b54b2009-05-05 16:10:16 +00001257 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001258 "REGISTRY.tcl"),
1259 ]
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001260 add_data(db, "Registry",
1261 [# Extensions
1262 ("py.ext", -1, r"Software\Classes\."+ext, "",
1263 "Python.File", "REGISTRY.def"),
1264 ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "",
1265 "Python.NoConFile", "REGISTRY.def"),
1266 ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "",
1267 "Python.CompiledFile", "REGISTRY.def"),
1268 ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "",
1269 "Python.CompiledFile", "REGISTRY.def"),
1270 # MIME types
1271 ("py.mime", -1, r"Software\Classes\."+ext, "Content Type",
1272 "text/plain", "REGISTRY.def"),
1273 ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type",
1274 "text/plain", "REGISTRY.def"),
1275 #Verbs
1276 ("py.open", -1, pat % (testprefix, "", "open"), "",
1277 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
1278 ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
1279 r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"),
1280 ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
1281 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001282 ] + tcl_verbs + [
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001283 #Icons
1284 ("py.icon", -1, pat2 % (testprefix, ""), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001285 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001286 ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001287 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001288 ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001289 r'[DLLs]pyc.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001290 # Descriptions
1291 ("py.txt", -1, pat3 % (testprefix, ""), "",
1292 "Python File", "REGISTRY.def"),
1293 ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "",
1294 "Python File (no console)", "REGISTRY.def"),
1295 ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "",
1296 "Compiled Python File", "REGISTRY.def"),
Martin v. Löwis3d6f8ff2008-11-07 18:51:50 +00001297 # Drop Handler
1298 ("py.drop", -1, pat4 % (testprefix, ""), "",
1299 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1300 ("pyw.drop", -1, pat4 % (testprefix, "NoCon"), "",
1301 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1302 ("pyc.drop", -1, pat4 % (testprefix, "Compiled"), "",
1303 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001304 ])
Tim Peters66cb0182004-08-26 05:23:19 +00001305
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001306 # Registry keys
1307 prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version)
1308 add_data(db, "Registry",
1309 [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"),
1310 ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "",
1311 "Python %s" % short_version, "REGISTRY"),
1312 ("PythonPath", -1, prefix+r"\PythonPath", "",
Martin v. Löwisf13337d2004-09-19 18:36:45 +00001313 r"[TARGETDIR]Lib;[TARGETDIR]DLLs;[TARGETDIR]Lib\lib-tk", "REGISTRY"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001314 ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "",
Martin v. Löwis344d0662008-05-09 18:21:55 +00001315 "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001316 ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"),
1317 ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe",
Martin v. Löwiscb6c3592008-11-30 11:08:26 +00001318 "", r"[TARGETDIR]Python.exe", "REGISTRY.def"),
1319 ("DisplayIcon", -1,
1320 r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code,
Steve Dower2d142702014-11-12 19:02:20 -08001321 "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY"),
1322 # Fake registry entry to allow installer to track whether ensurepip has been run
1323 ("EnsurePipRun", -1, prefix+r"\EnsurePipRun", "", "#1", "REGISTRY.ensurepip"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001324 ])
1325 # Shortcuts, see "Shortcut Table"
1326 add_data(db, "Directory",
1327 [("ProgramMenuFolder", "TARGETDIR", "."),
1328 ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))])
1329 add_data(db, "RemoveFile",
1330 [("MenuDir", "TARGETDIR", None, "MenuDir", 2)])
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001331 tcltkshortcuts = []
1332 if have_tcl:
1333 tcltkshortcuts = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001334 ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001335 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 +00001336 ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001337 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 +00001338 ]
1339 add_data(db, "Shortcut",
1340 tcltkshortcuts +
1341 [# Advertised shortcuts: targets are features, not files
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001342 ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe",
1343 default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001344 # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an
1345 # icon first.
1346 #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation",
1347 # htmlfiles.id, None, None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001348 ## Non-advertised shortcuts: must be associated with a registry component
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001349 ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc",
Martin v. Löwis344d0662008-05-09 18:21:55 +00001350 "[#%s]" % docfile, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001351 None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001352 ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY",
1353 SystemFolderName+"msiexec", "/x%s" % product_code,
1354 None, None, None, None, None, None),
1355 ])
1356 db.Commit()
1357
Martin v. Löwiseebd0172010-11-14 18:17:39 +00001358def build_pdbzip():
1359 pdbexclude = ['kill_python.pdb', 'make_buildinfo.pdb',
1360 'make_versioninfo.pdb']
1361 path = "python-%s%s-pdb.zip" % (full_current_version, msilib.arch_ext)
1362 pdbzip = zipfile.ZipFile(path, 'w')
1363 for f in glob.glob1(os.path.join(srcdir, PCBUILD), "*.pdb"):
1364 if f not in pdbexclude and not f.endswith('_d.pdb'):
1365 pdbzip.write(os.path.join(srcdir, PCBUILD, f), f)
1366 pdbzip.close()
1367
Martin v. Löwis34360642010-03-16 18:49:28 +00001368db,msiname = build_database()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001369try:
1370 add_features(db)
1371 add_ui(db)
1372 add_files(db)
1373 add_registry(db)
1374 remove_old_versions(db)
1375 db.Commit()
1376finally:
1377 del db
Martin v. Löwis34360642010-03-16 18:49:28 +00001378
1379# Merge CRT into MSI file. This requires the database to be closed.
1380mod_dir = os.path.join(os.environ["ProgramFiles"], "Common Files", "Merge Modules")
1381if msilib.Win64:
1382 modules = ["Microsoft_VC90_CRT_x86_x64.msm", "policy_9_0_Microsoft_VC90_CRT_x86_x64.msm"]
1383else:
1384 modules = ["Microsoft_VC90_CRT_x86.msm","policy_9_0_Microsoft_VC90_CRT_x86.msm"]
1385
1386for i, n in enumerate(modules):
1387 modules[i] = os.path.join(mod_dir, n)
1388
1389def merge(msi, feature, rootdir, modules):
1390 cab_and_filecount = []
1391 # Step 1: Merge databases, extract cabfiles
1392 m = msilib.MakeMerge2()
1393 m.OpenLog("merge.log")
1394 m.OpenDatabase(msi)
1395 for module in modules:
1396 print module
1397 m.OpenModule(module,0)
1398 m.Merge(feature, rootdir)
1399 print "Errors:"
1400 for e in m.Errors:
1401 print e.Type, e.ModuleTable, e.DatabaseTable
1402 print " Modkeys:",
1403 for s in e.ModuleKeys: print s,
1404 print
1405 print " DBKeys:",
1406 for s in e.DatabaseKeys: print s,
1407 print
1408 cabname = tempfile.mktemp(suffix=".cab")
1409 m.ExtractCAB(cabname)
1410 cab_and_filecount.append((cabname, len(m.ModuleFiles)))
1411 m.CloseModule()
1412 m.CloseDatabase(True)
1413 m.CloseLog()
1414
1415 # Step 2: Add CAB files
1416 i = msilib.MakeInstaller()
1417 db = i.OpenDatabase(msi, constants.msiOpenDatabaseModeTransact)
1418
1419 v = db.OpenView("SELECT LastSequence FROM Media")
1420 v.Execute(None)
1421 maxmedia = -1
1422 while 1:
1423 r = v.Fetch()
1424 if not r: break
1425 seq = r.IntegerData(1)
1426 if seq > maxmedia:
1427 maxmedia = seq
1428 print "Start of Media", maxmedia
1429
1430 for cabname, count in cab_and_filecount:
1431 stream = "merged%d" % maxmedia
1432 msilib.add_data(db, "Media",
1433 [(maxmedia+1, maxmedia+count, None, "#"+stream, None, None)])
1434 msilib.add_stream(db, stream, cabname)
1435 os.unlink(cabname)
1436 maxmedia += count
1437 # The merge module sets ALLUSERS to 1 in the property table.
1438 # This is undesired; delete that
1439 v = db.OpenView("DELETE FROM Property WHERE Property='ALLUSERS'")
1440 v.Execute(None)
1441 v.Close()
1442 db.Commit()
1443
1444merge(msiname, "SharedCRT", "TARGETDIR", modules)
1445
1446# certname (from config.py) should be (a substring of)
1447# the certificate subject, e.g. "Python Software Foundation"
1448if certname:
Martin v. Löwisd5375df2013-08-03 20:24:00 +02001449 os.system('signtool sign /n "%s" '
1450 '/t http://timestamp.verisign.com/scripts/timestamp.dll '
Steve Dowerdb287182016-02-08 09:26:25 -08001451 '/fd SHA256 '
Martin v. Löwisd5375df2013-08-03 20:24:00 +02001452 '/d "Python %s" '
1453 '%s' % (certname, full_current_version, msiname))
Martin v. Löwiseebd0172010-11-14 18:17:39 +00001454
1455if pdbzip:
1456 build_pdbzip()