blob: ae3b01892cc27f996499a09c74aee70675805339 [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öwis3a72b252010-11-14 18:13:49 +00004import msilib, schema, sequence, os, glob, time, re, shutil, zipfile
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00005from msilib import Feature, CAB, Directory, Dialog, Binary, add_data
6import uisample
7from win32com.client import constants
Martin v. Löwis9fda9312004-12-22 13:41:49 +00008from distutils.spawn import find_executable
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00009from uuids import product_codes
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000010
11# Settings can be overridden in config.py below
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000012# 0 for official python.org releases
13# 1 for intermediate releases by anybody, with
14# a new product code for every package.
15snapshot = 1
16# 1 means that file extension is px, not py,
17# and binaries start with x
18testpackage = 0
19# Location of build tree
20srcdir = os.path.abspath("../..")
21# Text to be displayed as the version in dialogs etc.
22# goes into file name and ProductCode. Defaults to
23# current_version.day for Snapshot, current_version otherwise
24full_current_version = None
Martin v. Löwise0f780d2004-09-01 14:51:06 +000025# Is Tcl available at all?
26have_tcl = True
Christian Heimes81ca7c72007-11-18 18:18:41 +000027# path to PCbuild directory
Christian Heimesfaf2f632008-01-06 16:59:19 +000028PCBUILD="PCbuild"
Christian Heimes81ca7c72007-11-18 18:18:41 +000029# msvcrt version
Christian Heimesfaf2f632008-01-06 16:59:19 +000030MSVCR = "90"
Martin v. Löwis3a72b252010-11-14 18:13:49 +000031# Make a zip file containing the PDB files for this build?
32pdbzip = True
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000033
34try:
35 from config import *
36except ImportError:
37 pass
38
39# Extract current version from Include/patchlevel.h
40lines = open(srcdir + "/Include/patchlevel.h").readlines()
41major = minor = micro = level = serial = None
42levels = {
43 'PY_RELEASE_LEVEL_ALPHA':0xA,
44 'PY_RELEASE_LEVEL_BETA': 0xB,
45 'PY_RELEASE_LEVEL_GAMMA':0xC,
46 'PY_RELEASE_LEVEL_FINAL':0xF
47 }
48for l in lines:
49 if not l.startswith("#define"):
50 continue
51 l = l.split()
52 if len(l) != 3:
53 continue
54 _, name, value = l
55 if name == 'PY_MAJOR_VERSION': major = value
56 if name == 'PY_MINOR_VERSION': minor = value
57 if name == 'PY_MICRO_VERSION': micro = value
58 if name == 'PY_RELEASE_LEVEL': level = levels[value]
59 if name == 'PY_RELEASE_SERIAL': serial = value
60
61short_version = major+"."+minor
62# See PC/make_versioninfo.c
63FIELD3 = 1000*int(micro) + 10*level + int(serial)
64current_version = "%s.%d" % (short_version, FIELD3)
65
66# This should never change. The UpgradeCode of this package can be
67# used in the Upgrade table of future packages to make the future
68# package replace this one. See "UpgradeCode Property".
Martin v. Löwisf27f8a12008-09-13 08:14:01 +000069# upgrade_code gets set to upgrade_code_64 when we have determined
70# that the target is Win64.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000071upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}'
72upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}'
Martin v. Löwisf27f8a12008-09-13 08:14:01 +000073upgrade_code_64='{6A965A0C-6EE6-4E3A-9983-3263F56311EC}'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000074
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000075if snapshot:
76 current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24))
77 product_code = msilib.gen_uuid()
78else:
79 product_code = product_codes[current_version]
80
81if full_current_version is None:
82 full_current_version = current_version
83
84extensions = [
85 'bz2.pyd',
86 'pyexpat.pyd',
87 'select.pyd',
88 'unicodedata.pyd',
89 'winsound.pyd',
Trent Micke97e5a72005-12-15 22:08:46 +000090 '_elementtree.pyd',
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000091 '_socket.pyd',
92 '_ssl.pyd',
93 '_testcapi.pyd',
94 '_tkinter.pyd',
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +000095 '_msi.pyd',
Martin v. Löwisa09655e2006-03-10 15:36:28 +000096 '_ctypes.pyd',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000097 '_ctypes_test.pyd',
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000098 '_sqlite3.pyd',
Martin v. Löwis9aa04c42008-06-30 07:03:57 +000099 '_hashlib.pyd',
100 '_multiprocessing.pyd'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000101]
102
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000103# Well-known component UUIDs
104# These are needed for SharedDLLs reference counter; if
105# a different UUID was used for each incarnation of, say,
106# python24.dll, an upgrade would set the reference counter
107# from 1 to 2 (due to what I consider a bug in MSI)
108# Using the same UUID is fine since these files are versioned,
109# so Installer will always keep the newest version.
Christian Heimesd0764e22007-12-04 15:00:33 +0000110# NOTE: All uuids are self generated.
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000111pythondll_uuid = {
112 "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000113 "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}",
Guido van Rossumaf554a02007-08-16 23:48:43 +0000114 "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}",
Martin v. Löwis7a63fc42008-10-02 20:09:01 +0000115 "27":"{4fe21c76-1760-437b-a2f2-99909130a175}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000116 "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}",
Martin v. Löwisfc972492008-10-02 20:09:47 +0000117 "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}",
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000118 } [major+minor]
Tim Peterseba28be2005-03-28 01:08:02 +0000119
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000120# Compute the name that Sphinx gives to the docfile
121docfile = ""
Martin v. Löwisa01bd622009-06-28 12:29:40 +0000122if int(micro):
123 docfile = micro
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000124if level < 0xf:
Benjamin Petersonb48f6342009-06-22 19:36:31 +0000125 if level == 0xC:
Martin v. Löwisa01bd622009-06-28 12:29:40 +0000126 docfile += "rc%s" % (serial,)
Benjamin Petersonb48f6342009-06-22 19:36:31 +0000127 else:
Martin v. Löwisa01bd622009-06-28 12:29:40 +0000128 docfile += '%x%s' % (level, serial)
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000129docfile = 'python%s%s%s.chm' % (major, minor, docfile)
130
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000131# Build the mingw import library, libpythonXY.a
132# This requires 'nm' and 'dlltool' executables on your PATH
133def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib):
134 warning = "WARNING: %s - libpythonXX.a not built"
135 nm = find_executable('nm')
136 dlltool = find_executable('dlltool')
137
138 if not nm or not dlltool:
Collin Winter6afaeb72007-08-03 17:06:41 +0000139 print(warning % "nm and/or dlltool were not found")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000140 return False
141
142 nm_command = '%s -Cs %s' % (nm, lib_file)
143 dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \
144 (dlltool, dll_file, def_file, mingw_lib)
145 export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match
146
147 f = open(def_file,'w')
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000148 f.write("LIBRARY %s\n" % dll_file)
149 f.write("EXPORTS\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000150
151 nm_pipe = os.popen(nm_command)
152 for line in nm_pipe.readlines():
153 m = export_match(line)
154 if m:
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000155 f.write(m.group(1)+"\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000156 f.close()
157 exit = nm_pipe.close()
158
159 if exit:
Collin Winter6afaeb72007-08-03 17:06:41 +0000160 print(warning % "nm did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000161 return False
162
163 if os.system(dlltool_command) != 0:
Collin Winter6afaeb72007-08-03 17:06:41 +0000164 print(warning % "dlltool did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000165 return False
166
167 return True
168
169# Target files (.def and .a) go in PCBuild directory
Christian Heimes81ca7c72007-11-18 18:18:41 +0000170lib_file = os.path.join(srcdir, PCBUILD, "python%s%s.lib" % (major, minor))
171def_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 Heimes81ca7c72007-11-18 18:18:41 +0000173mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000174
175have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib)
176
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000177# Determine the target architechture
Christian Heimes81ca7c72007-11-18 18:18:41 +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"):
Collin Wintera817e582007-08-22 23:05:06 +0000181 raise SystemError("msisupport.dll for incorrect architecture")
Martin v. Löwisf27f8a12008-09-13 08:14:01 +0000182if msilib.Win64:
183 upgrade_code = upgrade_code_64
Martin v. Löwise40a2132008-09-13 08:37:17 +0000184 # Bump the last digit of the code by one, so that 32-bit and 64-bit
185 # releases get separate product codes
186 digit = hex((int(product_code[-2],16)+1)%16)[-1]
187 product_code = product_code[:-2] + digit + '}'
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000188
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000189if testpackage:
190 ext = 'px'
191 testprefix = 'x'
192else:
193 ext = 'py'
194 testprefix = ''
195
196if msilib.Win64:
Martin v. Löwis47cc2a02007-08-30 18:27:06 +0000197 SystemFolderName = "[System64Folder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000198 registry_component = 4|256
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000199else:
200 SystemFolderName = "[SystemFolder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000201 registry_component = 4
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000202
203msilib.reset()
204
205# condition in which to install pythonxy.dll in system32:
206# a) it is Windows 9x or
207# b) it is NT, the user is privileged, and has chosen per-machine installation
208sys32cond = "(Windows9x or (Privileged and ALLUSERS))"
209
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000210def build_database():
211 """Generate an empty database, with just the schema and the
212 Summary information stream."""
213 if snapshot:
214 uc = upgrade_code_snapshot
215 else:
216 uc = upgrade_code
Martin v. Löwise40a2132008-09-13 08:37:17 +0000217 if msilib.Win64:
218 productsuffix = " (64-bit)"
219 else:
220 productsuffix = ""
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000221 # schema represents the installer 2.0 database schema.
222 # sequence is the set of standard sequences
223 # (ui/execute, admin/advt/install)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000224 db = msilib.init_database("python-%s%s.msi" % (full_current_version, msilib.arch_ext),
Martin v. Löwise40a2132008-09-13 08:37:17 +0000225 schema, ProductName="Python "+full_current_version+productsuffix,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000226 ProductCode=product_code,
227 ProductVersion=current_version,
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000228 Manufacturer=u"Python Software Foundation",
229 request_uac = True)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000230 # The default sequencing of the RemoveExistingProducts action causes
231 # removal of files that got just installed. Place it after
232 # InstallInitialize, so we first uninstall everything, but still roll
233 # back in case the installation is interrupted
234 msilib.change_sequence(sequence.InstallExecuteSequence,
235 "RemoveExistingProducts", 1510)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000236 msilib.add_tables(db, sequence)
237 # We cannot set ALLUSERS in the property table, as this cannot be
238 # reset if the user choses a per-user installation. Instead, we
239 # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages
240 # this property, and when the execution starts, ALLUSERS is set
241 # accordingly.
242 add_data(db, "Property", [("UpgradeCode", uc),
243 ("WhichUsers", "ALL"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000244 ("ProductLine", "Python%s%s" % (major, minor)),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000245 ])
246 db.Commit()
247 return db
248
249def remove_old_versions(db):
250 "Fill the upgrade table."
251 start = "%s.%s.0" % (major, minor)
252 # This requests that feature selection states of an older
253 # installation should be forwarded into this one. Upgrading
254 # requires that both the old and the new installation are
255 # either both per-machine or per-user.
256 migrate_features = 1
257 # See "Upgrade Table". We remove releases with the same major and
258 # minor version. For an snapshot, we remove all earlier snapshots. For
259 # a release, we remove all snapshots, and all earlier releases.
260 if snapshot:
261 add_data(db, "Upgrade",
Tim Peters66cb0182004-08-26 05:23:19 +0000262 [(upgrade_code_snapshot, start,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000263 current_version,
264 None, # Ignore language
Tim Peters66cb0182004-08-26 05:23:19 +0000265 migrate_features,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000266 None, # Migrate ALL features
267 "REMOVEOLDSNAPSHOT")])
268 props = "REMOVEOLDSNAPSHOT"
269 else:
270 add_data(db, "Upgrade",
271 [(upgrade_code, start, current_version,
272 None, migrate_features, None, "REMOVEOLDVERSION"),
273 (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1),
274 None, migrate_features, None, "REMOVEOLDSNAPSHOT")])
275 props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION"
Martin v. Löwis1c4c3062008-09-08 16:27:54 +0000276
277 props += ";TARGETDIR;DLLDIR"
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000278 # Installer collects the product codes of the earlier releases in
279 # these properties. In order to allow modification of the properties,
280 # they must be declared as secure. See "SecureCustomProperties Property"
281 add_data(db, "Property", [("SecureCustomProperties", props)])
282
283class PyDialog(Dialog):
284 """Dialog class with a fixed layout: controls at the top, then a ruler,
285 then a list of buttons: back, next, cancel. Optionally a bitmap at the
286 left."""
287 def __init__(self, *args, **kw):
288 """Dialog(database, name, x, y, w, h, attributes, title, first,
289 default, cancel, bitmap=true)"""
290 Dialog.__init__(self, *args)
291 ruler = self.h - 36
292 bmwidth = 152*ruler/328
293 if kw.get("bitmap", True):
294 self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin")
295 self.line("BottomLine", 0, ruler, self.w, 0)
296
297 def title(self, title):
298 "Set the title text of the dialog at the top."
299 # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
300 # text, in VerdanaBold10
301 self.text("Title", 135, 10, 220, 60, 0x30003,
302 r"{\VerdanaBold10}%s" % title)
303
304 def back(self, title, next, name = "Back", active = 1):
305 """Add a back button with a given title, the tab-next button,
306 its name in the Control table, possibly initially disabled.
307
308 Return the button, so that events can be associated"""
309 if active:
310 flags = 3 # Visible|Enabled
311 else:
312 flags = 1 # Visible
313 return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next)
314
315 def cancel(self, title, next, name = "Cancel", active = 1):
316 """Add a cancel button with a given title, the tab-next button,
317 its name in the Control table, possibly initially disabled.
318
319 Return the button, so that events can be associated"""
320 if active:
321 flags = 3 # Visible|Enabled
322 else:
323 flags = 1 # Visible
324 return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next)
325
326 def next(self, title, next, name = "Next", active = 1):
327 """Add a Next button with a given title, the tab-next button,
328 its name in the Control table, possibly initially disabled.
329
330 Return the button, so that events can be associated"""
331 if active:
332 flags = 3 # Visible|Enabled
333 else:
334 flags = 1 # Visible
335 return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next)
336
337 def xbutton(self, name, title, next, xpos):
338 """Add a button with a given title, the tab-next button,
339 its name in the Control table, giving its x position; the
340 y-position is aligned with the other buttons.
341
342 Return the button, so that events can be associated"""
343 return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next)
344
345def add_ui(db):
346 x = y = 50
347 w = 370
348 h = 300
349 title = "[ProductName] Setup"
350
351 # see "Dialog Style Bits"
352 modal = 3 # visible | modal
353 modeless = 1 # visible
354 track_disk_space = 32
355
356 add_data(db, 'ActionText', uisample.ActionText)
357 add_data(db, 'UIText', uisample.UIText)
358
359 # Bitmaps
360 if not os.path.exists(srcdir+r"\PC\python_icon.exe"):
Georg Brandlbf82e372008-05-16 17:02:34 +0000361 raise RuntimeError("Run icons.mak in PC directory")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000362 add_data(db, "Binary",
Christian Heimesd9a4d1d2008-01-01 14:42:15 +0000363 [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000364 ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")),
365 ])
366 add_data(db, "Icon",
367 [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))])
368
369 # Scripts
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000370 # CheckDir sets TargetExists if TARGETDIR exists.
371 # UpdateEditIDLE sets the REGISTRY.tcl component into
372 # the installed/uninstalled state according to both the
373 # Extensions and TclTk features.
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000374 if os.system("nmake /nologo /c /f msisupport.mak") != 0:
Georg Brandlbf82e372008-05-16 17:02:34 +0000375 raise RuntimeError("'nmake /f msisupport.mak' failed")
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000376 add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))])
377 # See "Custom Action Type 1"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000378 if msilib.Win64:
379 CheckDir = "CheckDir"
Martin v. Löwisdf40ce32006-02-16 14:38:30 +0000380 UpdateEditIDLE = "UpdateEditIDLE"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000381 else:
382 CheckDir = "_CheckDir@4"
383 UpdateEditIDLE = "_UpdateEditIDLE@4"
Tim Peters0e9980f2004-09-12 03:49:31 +0000384 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000385 [("CheckDir", 1, "Script", CheckDir)])
Martin v. Löwiseac02e62004-11-18 08:00:33 +0000386 if have_tcl:
387 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000388 [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)])
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000389
390 # UI customization properties
391 add_data(db, "Property",
392 # See "DefaultUIFont Property"
393 [("DefaultUIFont", "DlgFont8"),
394 # See "ErrorDialog Style Bit"
395 ("ErrorDialog", "ErrorDlg"),
396 ("Progress1", "Install"), # modified in maintenance type dlg
397 ("Progress2", "installs"),
398 ("MaintenanceForm_Action", "Repair")])
399
400 # Fonts, see "TextStyle Table"
401 add_data(db, "TextStyle",
402 [("DlgFont8", "Tahoma", 9, None, 0),
403 ("DlgFontBold8", "Tahoma", 8, None, 1), #bold
404 ("VerdanaBold10", "Verdana", 10, None, 1),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000405 ("VerdanaRed9", "Verdana", 9, 255, 0),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000406 ])
407
Martin v. Löwise96ac3a2010-03-21 22:02:42 +0000408 compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests" "[TARGETDIR]Lib"'
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000409 lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000410 # See "CustomAction Table"
411 add_data(db, "CustomAction", [
412 # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty
413 # See "Custom Action Type 51",
414 # "Custom Action Execution Scheduling Options"
415 ("InitialTargetDir", 307, "TARGETDIR",
416 "[WindowsVolume]Python%s%s" % (major, minor)),
417 ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
418 ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
419 # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
420 # See "Custom Action Type 18"
Martin v. Löwis7b2563b2004-11-02 22:59:56 +0000421 ("CompilePyc", 18, "python.exe", compileargs),
422 ("CompilePyo", 18, "python.exe", "-O "+compileargs),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000423 ("CompileGrammar", 18, "python.exe", lib2to3args),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000424 ])
425
426 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
427 # Numbers indicate sequence; see sequence.py for how these action integrate
428 add_data(db, "InstallUISequence",
429 [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
430 ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141),
431 ("InitialTargetDir", 'TARGETDIR=""', 750),
432 # In the user interface, assume all-users installation if privileged.
433 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
434 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
435 ("SelectDirectoryDlg", "Not Installed", 1230),
436 # XXX no support for resume installations yet
437 #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
438 ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250),
439 ("ProgressDlg", None, 1280)])
440 add_data(db, "AdminUISequence",
441 [("InitialTargetDir", 'TARGETDIR=""', 750),
442 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
443 ])
444
445 # Execute Sequences
446 add_data(db, "InstallExecuteSequence",
447 [("InitialTargetDir", 'TARGETDIR=""', 750),
448 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
449 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000450 ("UpdateEditIDLE", None, 1050),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000451 ("CompilePyc", "COMPILEALL", 6800),
452 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000453 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000454 ])
455 add_data(db, "AdminExecuteSequence",
456 [("InitialTargetDir", 'TARGETDIR=""', 750),
457 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
458 ("CompilePyc", "COMPILEALL", 6800),
459 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000460 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000461 ])
462
463 #####################################################################
464 # Standard dialogs: FatalError, UserExit, ExitDialog
465 fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title,
466 "Finish", "Finish", "Finish")
467 fatal.title("[ProductName] Installer ended prematurely")
468 fatal.back("< Back", "Finish", active = 0)
469 fatal.cancel("Cancel", "Back", active = 0)
470 fatal.text("Description1", 135, 70, 220, 80, 0x30003,
471 "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.")
472 fatal.text("Description2", 135, 155, 220, 20, 0x30003,
473 "Click the Finish button to exit the Installer.")
474 c=fatal.next("Finish", "Cancel", name="Finish")
475 # See "ControlEvent Table". Parameters are the event, the parameter
476 # to the action, and optionally the condition for the event, and the order
477 # of events.
478 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000479
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000480 user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title,
481 "Finish", "Finish", "Finish")
482 user_exit.title("[ProductName] Installer was interrupted")
483 user_exit.back("< Back", "Finish", active = 0)
484 user_exit.cancel("Cancel", "Back", active = 0)
485 user_exit.text("Description1", 135, 70, 220, 80, 0x30003,
486 "[ProductName] setup was interrupted. Your system has not been modified. "
487 "To install this program at a later time, please run the installation again.")
488 user_exit.text("Description2", 135, 155, 220, 20, 0x30003,
489 "Click the Finish button to exit the Installer.")
490 c = user_exit.next("Finish", "Cancel", name="Finish")
491 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000492
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000493 exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title,
494 "Finish", "Finish", "Finish")
495 exit_dialog.title("Completing the [ProductName] Installer")
496 exit_dialog.back("< Back", "Finish", active = 0)
497 exit_dialog.cancel("Cancel", "Back", active = 0)
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000498 exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003,
499 "Special Windows thanks to:\n"
Martin v. Löwisd3f61a22004-08-30 09:22:30 +0000500 " Mark Hammond, without whose years of freely \n"
501 " shared Windows expertise, Python for Windows \n"
502 " would still be Python for DOS.")
Tim Peters66cb0182004-08-26 05:23:19 +0000503
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000504 c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003,
505 "{\\VerdanaRed9}Warning: Python 2.5.x is the last "
506 "Python release for Windows 9x.")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000507 c.condition("Hide", "NOT Version9X")
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000508
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000509 exit_dialog.text("Description", 135, 235, 220, 20, 0x30003,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000510 "Click the Finish button to exit the Installer.")
511 c = exit_dialog.next("Finish", "Cancel", name="Finish")
512 c.event("EndDialog", "Return")
513
514 #####################################################################
515 # Required dialog: FilesInUse, ErrorDlg
516 inuse = PyDialog(db, "FilesInUse",
517 x, y, w, h,
518 19, # KeepModeless|Modal|Visible
519 title,
520 "Retry", "Retry", "Retry", bitmap=False)
521 inuse.text("Title", 15, 6, 200, 15, 0x30003,
522 r"{\DlgFontBold8}Files in Use")
523 inuse.text("Description", 20, 23, 280, 20, 0x30003,
524 "Some files that need to be updated are currently in use.")
525 inuse.text("Text", 20, 55, 330, 50, 3,
526 "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.")
527 inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess",
528 None, None, None)
529 c=inuse.back("Exit", "Ignore", name="Exit")
530 c.event("EndDialog", "Exit")
531 c=inuse.next("Ignore", "Retry", name="Ignore")
532 c.event("EndDialog", "Ignore")
533 c=inuse.cancel("Retry", "Exit", name="Retry")
534 c.event("EndDialog","Retry")
535
536
537 # See "Error Dialog". See "ICE20" for the required names of the controls.
538 error = Dialog(db, "ErrorDlg",
539 50, 10, 330, 101,
540 65543, # Error|Minimize|Modal|Visible
541 title,
542 "ErrorText", None, None)
543 error.text("ErrorText", 50,9,280,48,3, "")
544 error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
545 error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo")
546 error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes")
547 error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort")
548 error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel")
549 error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore")
550 error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk")
551 error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry")
552
553 #####################################################################
554 # Global "Query Cancel" dialog
555 cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title,
556 "No", "No", "No")
Tim Peters66cb0182004-08-26 05:23:19 +0000557 cancel.text("Text", 48, 15, 194, 30, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000558 "Are you sure you want to cancel [ProductName] installation?")
559 cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
560 "py.ico", None, None)
561 c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
562 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000563
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000564 c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
565 c.event("EndDialog", "Return")
566
567 #####################################################################
568 # Global "Wait for costing" dialog
569 costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title,
570 "Return", "Return", "Return")
571 costing.text("Text", 48, 15, 194, 30, 3,
572 "Please wait while the installer finishes determining your disk space requirements.")
573 costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
574 "py.ico", None, None)
575 c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
576 c.event("EndDialog", "Exit")
577
578 #####################################################################
579 # Preparation dialog: no user input except cancellation
580 prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title,
581 "Cancel", "Cancel", "Cancel")
582 prep.text("Description", 135, 70, 220, 40, 0x30003,
583 "Please wait while the Installer prepares to guide you through the installation.")
584 prep.title("Welcome to the [ProductName] Installer")
585 c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...")
586 c.mapping("ActionText", "Text")
587 c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None)
588 c.mapping("ActionData", "Text")
589 prep.back("Back", None, active=0)
590 prep.next("Next", None, active=0)
591 c=prep.cancel("Cancel", None)
592 c.event("SpawnDialog", "CancelDlg")
593
594 #####################################################################
595 # Target directory selection
596 seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title,
597 "Next", "Next", "Cancel")
598 seldlg.title("Select Destination Directory")
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000599 c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003,
600 "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.")
601 c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000602 seldlg.text("Description", 135, 50, 220, 40, 0x30003,
603 "Please select a directory for the [ProductName] files.")
604
605 seldlg.back("< Back", None, active=0)
606 c = seldlg.next("Next >", "Cancel")
607 c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1)
608 # If the target exists, but we found that we are going to remove old versions, don't bother
609 # confirming that the target directory exists. Strictly speaking, we should determine that
610 # the target directory is indeed the target of the product that we are going to remove, but
611 # I don't know how to do that.
612 c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2)
613 c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3)
614 c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4)
615 c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5)
616
617 c = seldlg.cancel("Cancel", "DirectoryCombo")
618 c.event("SpawnDialog", "CancelDlg")
619
620 seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219,
621 "TARGETDIR", None, "DirectoryList", None)
622 seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR",
623 None, "PathEdit", None)
624 seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None)
625 c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
626 c.event("DirectoryListUp", "0")
627 c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
628 c.event("DirectoryListNew", "0")
629
630 #####################################################################
631 # SelectFeaturesDlg
632 features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space,
633 title, "Tree", "Next", "Cancel")
634 features.title("Customize [ProductName]")
635 features.text("Description", 135, 35, 220, 15, 0x30003,
636 "Select the way you want features to be installed.")
637 features.text("Text", 135,45,220,30, 3,
638 "Click on the icons in the tree below to change the way features will be installed.")
639
640 c=features.back("< Back", "Next")
641 c.event("NewDialog", "SelectDirectoryDlg")
642
643 c=features.next("Next >", "Cancel")
644 c.mapping("SelectionNoItems", "Enabled")
645 c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1)
646 c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2)
647
648 c=features.cancel("Cancel", "Tree")
649 c.event("SpawnDialog", "CancelDlg")
650
Tim Peters66cb0182004-08-26 05:23:19 +0000651 # 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 +0000652 features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty",
653 "Tree of selections", "Back", None)
654
655 #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost")
656 #c.mapping("SelectionNoItems", "Enabled")
657 #c.event("Reset", "0")
Tim Peters66cb0182004-08-26 05:23:19 +0000658
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000659 features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None)
660
661 c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10)
662 c.mapping("SelectionNoItems","Enabled")
663 c.event("SpawnDialog", "DiskCostDlg")
664
665 c=features.xbutton("Advanced", "Advanced", None, 0.30)
666 c.event("SpawnDialog", "AdvancedDlg")
667
668 c=features.text("ItemDescription", 140, 180, 210, 30, 3,
669 "Multiline description of the currently selected item.")
670 c.mapping("SelectionDescription","Text")
Tim Peters66cb0182004-08-26 05:23:19 +0000671
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000672 c=features.text("ItemSize", 140, 210, 210, 45, 3,
673 "The size of the currently selected item.")
674 c.mapping("SelectionSize", "Text")
675
676 #####################################################################
677 # Disk cost
678 cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title,
679 "OK", "OK", "OK", bitmap=False)
680 cost.text("Title", 15, 6, 200, 15, 0x30003,
681 "{\DlgFontBold8}Disk Space Requirements")
682 cost.text("Description", 20, 20, 280, 20, 0x30003,
683 "The disk space required for the installation of the selected features.")
684 cost.text("Text", 20, 53, 330, 60, 3,
685 "The highlighted volumes (if any) do not have enough disk space "
686 "available for the currently selected features. You can either "
687 "remove some files from the highlighted volumes, or choose to "
688 "install less features onto local drive(s), or select different "
689 "destination drive(s).")
690 cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223,
691 None, "{120}{70}{70}{70}{70}", None, None)
692 cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
693
694 #####################################################################
695 # WhichUsers Dialog. Only available on NT, and for privileged users.
696 # This must be run before FindRelatedProducts, because that will
697 # take into account whether the previous installation was per-user
698 # or per-machine. We currently don't support going back to this
699 # dialog after "Next" was selected; to support this, we would need to
700 # find how to reset the ALLUSERS property, and how to re-run
701 # FindRelatedProducts.
702 # On Windows9x, the ALLUSERS property is ignored on the command line
703 # and in the Property table, but installer fails according to the documentation
704 # if a dialog attempts to set ALLUSERS.
705 whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title,
706 "AdminInstall", "Next", "Cancel")
707 whichusers.title("Select whether to install [ProductName] for all users of this computer.")
708 # A radio group with two options: allusers, justme
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000709 g = whichusers.radiogroup("AdminInstall", 135, 60, 235, 80, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000710 "WhichUsers", "", "Next")
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000711 g.condition("Disable", "VersionNT=600") # Not available on Vista and Windows 2008
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000712 g.add("ALL", 0, 5, 150, 20, "Install for all users")
Martin v. Löwisf63921f2008-10-13 11:30:30 +0000713 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 +0000714
Tim Peters66cb0182004-08-26 05:23:19 +0000715 whichusers.back("Back", None, active=0)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000716
717 c = whichusers.next("Next >", "Cancel")
718 c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
719 c.event("EndDialog", "Return", order = 2)
720
721 c = whichusers.cancel("Cancel", "AdminInstall")
722 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000723
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000724 #####################################################################
725 # Advanced Dialog.
726 advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title,
Martin v. Löwisa632a752008-11-19 13:55:07 +0000727 "CompilePyc", "Ok", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000728 advanced.title("Advanced Options for [ProductName]")
729 # A radio group with two options: allusers, justme
730 advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3,
Martin v. Löwisa632a752008-11-19 13:55:07 +0000731 "COMPILEALL", "Compile .py files to byte code after installation", "Ok")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000732
Martin v. Löwisa632a752008-11-19 13:55:07 +0000733 c = advanced.cancel("Ok", "CompilePyc", name="Ok") # Button just has location of cancel button.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000734 c.event("EndDialog", "Return")
735
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000736 #####################################################################
Tim Peters66cb0182004-08-26 05:23:19 +0000737 # Existing Directory dialog
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000738 dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title,
739 "No", "No", "No")
740 dlg.text("Title", 10, 20, 180, 40, 3,
741 "[TARGETDIR] exists. Are you sure you want to overwrite existing files?")
742 c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No")
743 c.event("[TargetExists]", "0", order=1)
744 c.event("[TargetExistsOk]", "1", order=2)
745 c.event("EndDialog", "Return", order=3)
746 c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes")
747 c.event("EndDialog", "Return")
748
749 #####################################################################
750 # Installation Progress dialog (modeless)
751 progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title,
752 "Cancel", "Cancel", "Cancel", bitmap=False)
753 progress.text("Title", 20, 15, 200, 15, 0x30003,
754 "{\DlgFontBold8}[Progress1] [ProductName]")
755 progress.text("Text", 35, 65, 300, 30, 3,
756 "Please wait while the Installer [Progress2] [ProductName]. "
757 "This may take several minutes.")
758 progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
759
760 c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...")
761 c.mapping("ActionText", "Text")
762
763 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
764 #c.mapping("ActionData", "Text")
765
766 c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537,
767 None, "Progress done", None, None)
768 c.mapping("SetProgress", "Progress")
769
770 progress.back("< Back", "Next", active=False)
771 progress.next("Next >", "Cancel", active=False)
772 progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
773
774 # Maintenance type: repair/uninstall
775 maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title,
776 "Next", "Next", "Cancel")
777 maint.title("Welcome to the [ProductName] Setup Wizard")
778 maint.text("BodyText", 135, 63, 230, 42, 3,
779 "Select whether you want to repair or remove [ProductName].")
780 g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3,
781 "MaintenanceForm_Action", "", "Next")
782 g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
783 g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
784 g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
Tim Peters66cb0182004-08-26 05:23:19 +0000785
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000786 maint.back("< Back", None, active=False)
787 c=maint.next("Finish", "Cancel")
788 # Change installation: Change progress dialog to "Change", then ask
789 # for feature selection
790 c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
791 c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
792
793 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
794 # Also set list of reinstalled features to "ALL"
795 c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
796 c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
Raymond Hettinger72f08012004-11-07 07:08:25 +0000797 c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000798 c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
799
800 # Uninstall: Change progress to "Remove", then invoke uninstall
801 # Also set list of removed features to "ALL"
802 c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
803 c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
804 c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
805 c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
806
Tim Peters66cb0182004-08-26 05:23:19 +0000807 # Close dialog when maintenance action scheduled
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000808 c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
809 c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
Tim Peters66cb0182004-08-26 05:23:19 +0000810
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000811 maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000812
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000813
814# See "Feature Table". The feature level is 1 for all features,
815# and the feature attributes are 0 for the DefaultFeature, and
816# FollowParent for all other features. The numbers are the Display
817# column.
818def add_features(db):
819 # feature attributes:
820 # msidbFeatureAttributesFollowParent == 2
821 # msidbFeatureAttributesDisallowAdvertise == 8
822 # Features that need to be installed with together with the main feature
823 # (i.e. additional Python libraries) need to follow the parent feature.
824 # Features that have no advertisement trigger (e.g. the test suite)
825 # must not support advertisement
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000826 global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000827 default_feature = Feature(db, "DefaultFeature", "Python",
828 "Python Interpreter and Libraries",
829 1, directory = "TARGETDIR")
Martin v. Löwis2a241ca2008-04-05 18:58:09 +0000830 shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0,
831 level=0)
832 private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0,
833 level=0)
834 add_data(db, "Condition", [("SharedCRT", 1, sys32cond),
835 ("PrivateCRT", 1, "not "+sys32cond)])
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000836 # We don't support advertisement of extensions
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000837 ext_feature = Feature(db, "Extensions", "Register Extensions",
838 "Make this Python installation the default Python installation", 3,
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000839 parent = default_feature, attributes=2|8)
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000840 if have_tcl:
841 tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000842 parent = default_feature, attributes=2)
843 htmlfiles = Feature(db, "Documentation", "Documentation",
844 "Python HTMLHelp File", 7, parent = default_feature)
845 tools = Feature(db, "Tools", "Utility Scripts",
Tim Peters66cb0182004-08-26 05:23:19 +0000846 "Python utility scripts (Tools/", 9,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000847 parent = default_feature, attributes=2)
848 testsuite = Feature(db, "Testsuite", "Test suite",
849 "Python test suite (Lib/test/)", 11,
850 parent = default_feature, attributes=2|8)
Tim Peters66cb0182004-08-26 05:23:19 +0000851
Christian Heimes81ca7c72007-11-18 18:18:41 +0000852def extract_msvcr90():
Martin v. Löwisee7498e2008-02-28 23:01:33 +0000853 # Find the redistributable files
Martin v. Löwis8a2e90e2008-09-19 19:21:20 +0000854 if msilib.Win64:
855 arch = "amd64"
856 else:
857 arch = "x86"
858 dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC90.CRT" % arch)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000859
Christian Heimese1feb2e2008-02-28 20:52:40 +0000860 result = []
Christian Heimes81ca7c72007-11-18 18:18:41 +0000861 installer = msilib.MakeInstaller()
Christian Heimese1feb2e2008-02-28 20:52:40 +0000862 # omit msvcm90 and msvcp90, as they aren't really needed
863 files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"]
864 for f in files:
865 path = os.path.join(dir, f)
866 kw = {'src':path}
867 if f.endswith('.dll'):
868 kw['version'] = installer.FileVersion(path, 0)
869 kw['language'] = installer.FileVersion(path, 1)
870 result.append((f, kw))
871 return result
Christian Heimes81ca7c72007-11-18 18:18:41 +0000872
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000873def generate_license():
874 import shutil, glob
875 out = open("LICENSE.txt", "w")
876 shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out)
Martin v. Löwisb29f2d72008-09-14 20:27:52 +0000877 shutil.copyfileobj(open("crtlicense.txt"), out)
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000878 for name, pat, file in (("bzip2","bzip2-*", "LICENSE"),
879 ("Berkeley DB", "db-*", "LICENSE"),
880 ("openssl", "openssl-*", "LICENSE"),
881 ("Tcl", "tcl8*", "license.terms"),
882 ("Tk", "tk8*", "license.terms"),
883 ("Tix", "tix-*", "license.terms")):
884 out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name)
885 dirs = glob.glob(srcdir+"/../"+pat)
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000886 if not dirs:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000887 raise ValueError, "Could not find "+srcdir+"/../"+pat
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000888 if len(dirs) > 2:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000889 raise ValueError, "Multiple copies of "+pat
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000890 dir = dirs[0]
891 shutil.copyfileobj(open(os.path.join(dir, file)), out)
892 out.close()
893
894
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000895class PyDirectory(Directory):
896 """By default, all components in the Python installer
897 can run from source."""
898 def __init__(self, *args, **kw):
Georg Brandlbf82e372008-05-16 17:02:34 +0000899 if "componentflags" not in kw:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000900 kw['componentflags'] = 2 #msidbComponentAttributesOptional
901 Directory.__init__(self, *args, **kw)
902
903# See "File Table", "Component Table", "Directory Table",
904# "FeatureComponents Table"
905def add_files(db):
906 cab = CAB("python")
907 tmpfiles = []
908 # Add all executables, icons, text files into the TARGETDIR component
909 root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir")
910 default_feature.set_current()
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000911 if not msilib.Win64:
Christian Heimes81ca7c72007-11-18 18:18:41 +0000912 root.add_file("%s/w9xpopen.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000913 root.add_file("README.txt", src="README")
914 root.add_file("NEWS.txt", src="Misc/NEWS")
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000915 generate_license()
916 root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000917 root.start_component("python.exe", keyfile="python.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000918 root.add_file("%s/python.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000919 root.start_component("pythonw.exe", keyfile="pythonw.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000920 root.add_file("%s/pythonw.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000921
922 # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
Martin v. Löwisc820eaf2008-10-17 13:47:20 +0000923 dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
Christian Heimese1feb2e2008-02-28 20:52:40 +0000924
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000925 pydll = "python%s%s.dll" % (major, minor)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000926 pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000927 dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000928 installer = msilib.MakeInstaller()
929 pyversion = installer.FileVersion(pydllsrc, 0)
930 if not snapshot:
931 # For releases, the Python DLL has the same version as the
932 # installer package.
933 assert pyversion.split(".")[:3] == current_version.split(".")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000934 dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000935 version=pyversion,
936 language=installer.FileVersion(pydllsrc, 1))
Christian Heimese1feb2e2008-02-28 20:52:40 +0000937 DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000938
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000939 # msvcr90.dll: Need to place the DLL and the manifest into the root directory,
940 # plus another copy of the manifest in the DLLs directory, with the manifest
941 # pointing to the root directory
942 root.start_component("msvcr90", feature=private_crt)
943 # Results are ID,keyword pairs
944 manifest, crtdll = extract_msvcr90()
945 root.add_file(manifest[0], **manifest[1])
946 root.add_file(crtdll[0], **crtdll[1])
947 # Copy the manifest
Martin v. Löwis91845562008-11-06 19:46:56 +0000948 # Actually, don't do that anymore - no DLL in DLLs should have a manifest
949 # dependency on msvcr90.dll anymore, so this should not be necessary
950 #manifest_dlls = manifest[0]+".root"
951 #open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr"))
952 #DLLs.start_component("msvcr90_dlls", feature=private_crt)
953 #DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls))
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000954
955 # Now start the main component for the DLLs directory;
956 # no regular files have been added to the directory yet.
957 DLLs.start_component()
Tim Peters66cb0182004-08-26 05:23:19 +0000958
Thomas Wouters89f507f2006-12-13 04:49:30 +0000959 # Check if _ctypes.pyd exists
Christian Heimes81ca7c72007-11-18 18:18:41 +0000960 have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000961 if not have_ctypes:
Collin Winter6afaeb72007-08-03 17:06:41 +0000962 print("WARNING: _ctypes.pyd not found, ctypes will not be included")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000963 extensions.remove("_ctypes.pyd")
964
Georg Brandl6e47a332008-05-17 19:15:58 +0000965 # Add all .py files in Lib, except tkinter, test
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000966 dirs={}
967 pydirs = [(root,"Lib")]
968 while pydirs:
Martin v. Löwis94b8b822008-06-13 19:00:35 +0000969 # Commit every now and then, or else installer will complain
970 db.Commit()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000971 parent, dir = pydirs.pop()
Martin v. Löwis9ca9f562006-01-03 06:29:53 +0000972 if dir == ".svn" or dir.startswith("plat-"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000973 continue
Georg Brandl6e47a332008-05-17 19:15:58 +0000974 elif dir in ["tkinter", "idlelib", "Icons"]:
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000975 if not have_tcl:
976 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000977 tcltk.set_current()
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +0000978 elif dir in ['test', 'tests', 'data', 'output']:
Amaury Forgeot d'Arcf7bfcfb2008-09-09 06:42:00 +0000979 # test: Lib, Lib/email, Lib/ctypes, Lib/sqlite3
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +0000980 # tests: Lib/distutils
981 # data: Lib/email/test
982 # output: Lib/test
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000983 testsuite.set_current()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000984 elif not have_ctypes and dir == "ctypes":
985 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000986 else:
987 default_feature.set_current()
988 lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
989 # Add additional files
990 dirs[dir]=lib
991 lib.glob("*.txt")
992 if dir=='site-packages':
Martin v. Löwis6d60c092004-11-21 10:16:26 +0000993 lib.add_file("README.txt", src="README")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000994 continue
995 files = lib.glob("*.py")
996 files += lib.glob("*.pyw")
997 if files:
998 # Add an entry to the RemoveFile table to remove bytecode files.
999 lib.remove_pyc()
Thomas Wouters3fc2ca32006-04-21 11:28:17 +00001000 if dir.endswith('.egg-info'):
1001 lib.add_file('entry_points.txt')
1002 lib.add_file('PKG-INFO')
1003 lib.add_file('top_level.txt')
1004 lib.add_file('zip-safe')
1005 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001006 if dir=='test' and parent.physical=='Lib':
1007 lib.add_file("185test.db")
1008 lib.add_file("audiotest.au")
1009 lib.add_file("cfgparser.1")
Thomas Wouters89f507f2006-12-13 04:49:30 +00001010 lib.add_file("sgml_input.html")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001011 lib.add_file("test.xml")
1012 lib.add_file("test.xml.out")
1013 lib.add_file("testtar.tar")
Martin v. Löwis7d3755d2004-09-06 06:31:12 +00001014 lib.add_file("test_difflib_expect.html")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001015 lib.add_file("check_soundcard.vbs")
1016 lib.add_file("empty.vbs")
Martin v. Löwisbb6db342009-06-01 04:12:01 +00001017 lib.add_file("Sine-1000Hz-300ms.aif")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001018 lib.glob("*.uue")
Christian Heimes5d14c2b2007-11-20 23:38:09 +00001019 lib.glob("*.pem")
Christian Heimescbf3b5c2007-12-03 21:02:03 +00001020 lib.glob("*.pck")
Martin v. Löwis270a9ce2009-04-04 18:48:39 +00001021 lib.add_file("zipdir.zip")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001022 if dir=='decimaltestdata':
1023 lib.glob("*.decTest")
1024 if dir=='output':
1025 lib.glob("test_*")
1026 if dir=='idlelib':
1027 lib.glob("*.def")
1028 lib.add_file("idle.bat")
1029 if dir=="Icons":
1030 lib.glob("*.gif")
1031 lib.add_file("idle.icns")
Thomas Wouters3fc2ca32006-04-21 11:28:17 +00001032 if dir=="command" and parent.physical=="distutils":
Martin v. Löwis5680d0c2008-04-10 03:06:53 +00001033 lib.glob("wininst*.exe")
Thomas Wouters3fc2ca32006-04-21 11:28:17 +00001034 if dir=="setuptools":
1035 lib.add_file("cli.exe")
1036 lib.add_file("gui.exe")
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +00001037 if dir=="lib2to3":
1038 lib.removefile("pickle", "*.pickle")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001039 if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email":
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001040 # This should contain all non-.svn files listed in subversion
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001041 for f in os.listdir(lib.absolute):
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001042 if f.endswith(".txt") or f==".svn":continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001043 if f.endswith(".au") or f.endswith(".gif"):
1044 lib.add_file(f)
1045 else:
Collin Winter6afaeb72007-08-03 17:06:41 +00001046 print("WARNING: New file %s in email/test/data" % f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001047 for f in os.listdir(lib.absolute):
1048 if os.path.isdir(os.path.join(lib.absolute, f)):
1049 pydirs.append((lib, f))
1050 # Add DLLs
1051 default_feature.set_current()
Christian Heimese1feb2e2008-02-28 20:52:40 +00001052 lib = DLLs
Christian Heimesd9a4d1d2008-01-01 14:42:15 +00001053 lib.add_file("py.ico", src=srcdir+"/PC/py.ico")
1054 lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001055 dlls = []
1056 tclfiles = []
1057 for f in extensions:
1058 if f=="_tkinter.pyd":
1059 continue
Christian Heimes81ca7c72007-11-18 18:18:41 +00001060 if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f):
Collin Winter6afaeb72007-08-03 17:06:41 +00001061 print("WARNING: Missing extension", f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001062 continue
1063 dlls.append(f)
1064 lib.add_file(f)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001065 # Add sqlite
1066 if msilib.msi_type=="Intel64;1033":
1067 sqlite_arch = "/ia64"
1068 elif msilib.msi_type=="x64;1033":
1069 sqlite_arch = "/amd64"
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001070 tclsuffix = "64"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001071 else:
1072 sqlite_arch = ""
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001073 tclsuffix = ""
Martin v. Löwis94b8b822008-06-13 19:00:35 +00001074 lib.add_file("sqlite3.dll")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001075 if have_tcl:
Christian Heimes81ca7c72007-11-18 18:18:41 +00001076 if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)):
Collin Winter6afaeb72007-08-03 17:06:41 +00001077 print("WARNING: Missing _tkinter.pyd")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001078 else:
1079 lib.start_component("TkDLLs", tcltk)
1080 lib.add_file("_tkinter.pyd")
1081 dlls.append("_tkinter.pyd")
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001082 tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001083 for f in glob.glob1(tcldir, "*.dll"):
1084 lib.add_file(f, src=os.path.join(tcldir, f))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001085 # check whether there are any unknown extensions
Christian Heimes81ca7c72007-11-18 18:18:41 +00001086 for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001087 if f.endswith("_d.pyd"): continue # debug version
1088 if f in dlls: continue
Collin Winter6afaeb72007-08-03 17:06:41 +00001089 print("WARNING: Unknown extension", f)
Tim Peters66cb0182004-08-26 05:23:19 +00001090
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001091 # Add headers
1092 default_feature.set_current()
1093 lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include")
1094 lib.glob("*.h")
1095 lib.add_file("pyconfig.h", src="../PC/pyconfig.h")
1096 # Add import libraries
Christian Heimes81ca7c72007-11-18 18:18:41 +00001097 lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001098 for f in dlls:
1099 lib.add_file(f.replace('pyd','lib'))
1100 lib.add_file('python%s%s.lib' % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +00001101 # Add the mingw-format library
1102 if have_mingw:
Tim Peters5a9fb3c2005-01-07 16:01:32 +00001103 lib.add_file('libpython%s%s.a' % (major, minor))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001104 if have_tcl:
1105 # Add Tcl/Tk
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001106 tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')]
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001107 tcltk.set_current()
1108 while tcldirs:
1109 parent, phys, dir = tcldirs.pop()
1110 lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir))
1111 if not os.path.exists(lib.absolute):
1112 continue
1113 for f in os.listdir(lib.absolute):
1114 if os.path.isdir(os.path.join(lib.absolute, f)):
1115 tcldirs.append((lib, f, f))
1116 else:
1117 lib.add_file(f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001118 # Add tools
1119 tools.set_current()
1120 tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools")
Martin v. Löwis3a72b252010-11-14 18:13:49 +00001121 for f in ['i18n', 'pynche', 'Scripts', 'webchecker']:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001122 lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f))
1123 lib.glob("*.py")
1124 lib.glob("*.pyw", exclude=['pydocgui.pyw'])
1125 lib.remove_pyc()
1126 lib.glob("*.txt")
1127 if f == "pynche":
1128 x = PyDirectory(db, cab, lib, "X", "X", "X|X")
1129 x.glob("*.txt")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001130 if os.path.exists(os.path.join(lib.absolute, "README")):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001131 lib.add_file("README.txt", src="README")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001132 if f == 'Scripts':
Martin v. Löwisfe218842008-10-01 11:22:32 +00001133 lib.add_file("2to3.py", src="2to3")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001134 if have_tcl:
1135 lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
1136 lib.add_file("pydocgui.pyw")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001137 # Add documentation
1138 htmlfiles.set_current()
1139 lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc")
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001140 lib.start_component("documentation", keyfile=docfile)
1141 lib.add_file(docfile, src="build/htmlhelp/"+docfile)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001142
1143 cab.commit(db)
1144
1145 for f in tmpfiles:
1146 os.unlink(f)
1147
1148# See "Registry Table", "Component Table"
1149def add_registry(db):
1150 # File extensions, associated with the REGISTRY.def component
1151 # IDLE verbs depend on the tcltk feature.
1152 # msidbComponentAttributesRegistryKeyPath = 4
1153 # -1 for Root specifies "dependent on ALLUSERS property"
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001154 tcldata = []
1155 if have_tcl:
1156 tcldata = [
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001157 ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001158 "py.IDLE")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001159 add_data(db, "Component",
1160 # msidbComponentAttributesRegistryKeyPath = 4
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001161 [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001162 "InstallPath"),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001163 ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001164 "Documentation"),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001165 ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001166 None, None)] + tcldata)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001167 # See "FeatureComponents Table".
1168 # The association between TclTk and pythonw.exe is necessary to make ICE59
1169 # happy, because the installer otherwise believes that the IDLE and PyDoc
1170 # shortcuts might get installed without pythonw.exe being install. This
1171 # is not true, since installing TclTk will install the default feature, which
1172 # will cause pythonw.exe to be installed.
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001173 # REGISTRY.tcl is not associated with any feature, as it will be requested
1174 # through a custom action
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001175 tcldata = []
1176 if have_tcl:
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001177 tcldata = [(tcltk.id, "pythonw.exe")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001178 add_data(db, "FeatureComponents",
1179 [(default_feature.id, "REGISTRY"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001180 (htmlfiles.id, "REGISTRY.doc"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001181 (ext_feature.id, "REGISTRY.def")] +
1182 tcldata
1183 )
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001184 # Extensions are not advertised. For advertised extensions,
1185 # we would need separate binaries that install along with the
1186 # extension.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001187 pat = r"Software\Classes\%sPython.%sFile\shell\%s\command"
1188 ewi = "Edit with IDLE"
1189 pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon"
1190 pat3 = r"Software\Classes\%sPython.%sFile"
Martin v. Löwisbfda5442008-11-07 18:54:51 +00001191 pat4 = r"Software\Classes\%sPython.%sFile\shellex\DropHandler"
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001192 tcl_verbs = []
1193 if have_tcl:
1194 tcl_verbs=[
1195 ("py.IDLE", -1, pat % (testprefix, "", ewi), "",
Martin v. Löwis8482ef92009-05-05 16:14:30 +00001196 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001197 "REGISTRY.tcl"),
1198 ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "",
Martin v. Löwis8482ef92009-05-05 16:14:30 +00001199 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"',
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001200 "REGISTRY.tcl"),
1201 ]
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001202 add_data(db, "Registry",
1203 [# Extensions
1204 ("py.ext", -1, r"Software\Classes\."+ext, "",
1205 "Python.File", "REGISTRY.def"),
1206 ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "",
1207 "Python.NoConFile", "REGISTRY.def"),
1208 ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "",
1209 "Python.CompiledFile", "REGISTRY.def"),
1210 ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "",
1211 "Python.CompiledFile", "REGISTRY.def"),
1212 # MIME types
1213 ("py.mime", -1, r"Software\Classes\."+ext, "Content Type",
1214 "text/plain", "REGISTRY.def"),
1215 ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type",
1216 "text/plain", "REGISTRY.def"),
1217 #Verbs
1218 ("py.open", -1, pat % (testprefix, "", "open"), "",
1219 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
1220 ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
1221 r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"),
1222 ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
1223 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001224 ] + tcl_verbs + [
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001225 #Icons
1226 ("py.icon", -1, pat2 % (testprefix, ""), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001227 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001228 ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001229 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001230 ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001231 r'[DLLs]pyc.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001232 # Descriptions
1233 ("py.txt", -1, pat3 % (testprefix, ""), "",
1234 "Python File", "REGISTRY.def"),
1235 ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "",
1236 "Python File (no console)", "REGISTRY.def"),
1237 ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "",
1238 "Compiled Python File", "REGISTRY.def"),
Martin v. Löwisbfda5442008-11-07 18:54:51 +00001239 # Drop Handler
1240 ("py.drop", -1, pat4 % (testprefix, ""), "",
1241 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1242 ("pyw.drop", -1, pat4 % (testprefix, "NoCon"), "",
1243 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
1244 ("pyc.drop", -1, pat4 % (testprefix, "Compiled"), "",
1245 "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001246 ])
Tim Peters66cb0182004-08-26 05:23:19 +00001247
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001248 # Registry keys
1249 prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version)
1250 add_data(db, "Registry",
1251 [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"),
1252 ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "",
1253 "Python %s" % short_version, "REGISTRY"),
1254 ("PythonPath", -1, prefix+r"\PythonPath", "",
Georg Brandl6e47a332008-05-17 19:15:58 +00001255 r"[TARGETDIR]Lib;[TARGETDIR]DLLs", "REGISTRY"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001256 ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001257 "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001258 ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"),
1259 ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe",
Martin v. Löwis45a6b9f2008-11-30 11:12:00 +00001260 "", r"[TARGETDIR]Python.exe", "REGISTRY.def"),
1261 ("DisplayIcon", -1,
1262 r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code,
Martin v. Löwis9d49c1d2009-06-28 09:40:34 +00001263 "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001264 ])
1265 # Shortcuts, see "Shortcut Table"
1266 add_data(db, "Directory",
1267 [("ProgramMenuFolder", "TARGETDIR", "."),
1268 ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))])
1269 add_data(db, "RemoveFile",
1270 [("MenuDir", "TARGETDIR", None, "MenuDir", 2)])
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001271 tcltkshortcuts = []
1272 if have_tcl:
1273 tcltkshortcuts = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001274 ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001275 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 +00001276 ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001277 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 +00001278 ]
1279 add_data(db, "Shortcut",
1280 tcltkshortcuts +
1281 [# Advertised shortcuts: targets are features, not files
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001282 ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe",
1283 default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001284 # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an
1285 # icon first.
1286 #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation",
1287 # htmlfiles.id, None, None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001288 ## Non-advertised shortcuts: must be associated with a registry component
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001289 ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001290 "[#%s]" % docfile, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001291 None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001292 ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY",
1293 SystemFolderName+"msiexec", "/x%s" % product_code,
1294 None, None, None, None, None, None),
1295 ])
1296 db.Commit()
1297
Martin v. Löwis3a72b252010-11-14 18:13:49 +00001298def build_pdbzip():
1299 pdbexclude = ['kill_python.pdb', 'make_buildinfo.pdb',
1300 'make_versioninfo.pdb']
1301 path = "python-%s%s-pdb.zip" % (full_current_version, msilib.arch_ext)
1302 pdbzip = zipfile.ZipFile(path, 'w')
1303 for f in glob.glob1(os.path.join(srcdir, PCBUILD), "*.pdb"):
1304 if f not in pdbexclude and not f.endswith('_d.pdb'):
1305 pdbzip.write(os.path.join(srcdir, PCBUILD, f), f)
1306 pdbzip.close()
1307
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001308db = build_database()
1309try:
1310 add_features(db)
1311 add_ui(db)
1312 add_files(db)
1313 add_registry(db)
1314 remove_old_versions(db)
1315 db.Commit()
1316finally:
1317 del db
Martin v. Löwis3a72b252010-11-14 18:13:49 +00001318
1319if pdbzip:
1320 build_pdbzip()