blob: 66457fbb1a4bdd3e9a4ed3d8cd8b4e3e7f211ad4 [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.
Christian Heimes81ca7c72007-11-18 18:18:41 +00004import msilib, schema, sequence, os, glob, time, re, shutil
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öwis8ffe9ab2004-08-22 13:34:34 +000031
32try:
33 from config import *
34except ImportError:
35 pass
36
37# Extract current version from Include/patchlevel.h
38lines = open(srcdir + "/Include/patchlevel.h").readlines()
39major = minor = micro = level = serial = None
40levels = {
41 'PY_RELEASE_LEVEL_ALPHA':0xA,
42 'PY_RELEASE_LEVEL_BETA': 0xB,
43 'PY_RELEASE_LEVEL_GAMMA':0xC,
44 'PY_RELEASE_LEVEL_FINAL':0xF
45 }
46for l in lines:
47 if not l.startswith("#define"):
48 continue
49 l = l.split()
50 if len(l) != 3:
51 continue
52 _, name, value = l
53 if name == 'PY_MAJOR_VERSION': major = value
54 if name == 'PY_MINOR_VERSION': minor = value
55 if name == 'PY_MICRO_VERSION': micro = value
56 if name == 'PY_RELEASE_LEVEL': level = levels[value]
57 if name == 'PY_RELEASE_SERIAL': serial = value
58
59short_version = major+"."+minor
60# See PC/make_versioninfo.c
61FIELD3 = 1000*int(micro) + 10*level + int(serial)
62current_version = "%s.%d" % (short_version, FIELD3)
63
64# This should never change. The UpgradeCode of this package can be
65# used in the Upgrade table of future packages to make the future
66# package replace this one. See "UpgradeCode Property".
67upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}'
68upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}'
69
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000070if snapshot:
71 current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24))
72 product_code = msilib.gen_uuid()
73else:
74 product_code = product_codes[current_version]
75
76if full_current_version is None:
77 full_current_version = current_version
78
79extensions = [
80 'bz2.pyd',
81 'pyexpat.pyd',
82 'select.pyd',
83 'unicodedata.pyd',
84 'winsound.pyd',
Trent Micke97e5a72005-12-15 22:08:46 +000085 '_elementtree.pyd',
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000086 '_bsddb.pyd',
87 '_socket.pyd',
88 '_ssl.pyd',
89 '_testcapi.pyd',
90 '_tkinter.pyd',
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +000091 '_msi.pyd',
Martin v. Löwisa09655e2006-03-10 15:36:28 +000092 '_ctypes.pyd',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000093 '_ctypes_test.pyd',
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000094 '_sqlite3.pyd',
Martin v. Löwis9aa04c42008-06-30 07:03:57 +000095 '_hashlib.pyd',
96 '_multiprocessing.pyd'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000097]
98
Martin v. Löwis141f41a2005-03-15 00:39:40 +000099# Well-known component UUIDs
100# These are needed for SharedDLLs reference counter; if
101# a different UUID was used for each incarnation of, say,
102# python24.dll, an upgrade would set the reference counter
103# from 1 to 2 (due to what I consider a bug in MSI)
104# Using the same UUID is fine since these files are versioned,
105# so Installer will always keep the newest version.
Christian Heimesd0764e22007-12-04 15:00:33 +0000106# NOTE: All uuids are self generated.
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000107pythondll_uuid = {
108 "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000109 "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}",
Guido van Rossumaf554a02007-08-16 23:48:43 +0000110 "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}",
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000111 "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}",
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000112 } [major+minor]
Tim Peterseba28be2005-03-28 01:08:02 +0000113
Alexandre Vassalotti6461e102008-05-15 22:09:29 +0000114# Compute the name that Sphinx gives to the docfile
115docfile = ""
116if level < 0xf:
117 docfile = '%x%s' % (level, serial)
118docfile = 'python%s%s%s.chm' % (major, minor, docfile)
119
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000120# Build the mingw import library, libpythonXY.a
121# This requires 'nm' and 'dlltool' executables on your PATH
122def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib):
123 warning = "WARNING: %s - libpythonXX.a not built"
124 nm = find_executable('nm')
125 dlltool = find_executable('dlltool')
126
127 if not nm or not dlltool:
Collin Winter6afaeb72007-08-03 17:06:41 +0000128 print(warning % "nm and/or dlltool were not found")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000129 return False
130
131 nm_command = '%s -Cs %s' % (nm, lib_file)
132 dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \
133 (dlltool, dll_file, def_file, mingw_lib)
134 export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match
135
136 f = open(def_file,'w')
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000137 f.write("LIBRARY %s\n" % dll_file)
138 f.write("EXPORTS\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000139
140 nm_pipe = os.popen(nm_command)
141 for line in nm_pipe.readlines():
142 m = export_match(line)
143 if m:
Martin v. Löwis4c6c7ca2007-08-30 15:23:04 +0000144 f.write(m.group(1)+"\n")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000145 f.close()
146 exit = nm_pipe.close()
147
148 if exit:
Collin Winter6afaeb72007-08-03 17:06:41 +0000149 print(warning % "nm did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000150 return False
151
152 if os.system(dlltool_command) != 0:
Collin Winter6afaeb72007-08-03 17:06:41 +0000153 print(warning % "dlltool did not run successfully")
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000154 return False
155
156 return True
157
158# Target files (.def and .a) go in PCBuild directory
Christian Heimes81ca7c72007-11-18 18:18:41 +0000159lib_file = os.path.join(srcdir, PCBUILD, "python%s%s.lib" % (major, minor))
160def_file = os.path.join(srcdir, PCBUILD, "python%s%s.def" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000161dll_file = "python%s%s.dll" % (major, minor)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000162mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000163
164have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib)
165
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000166# Determine the target architechture
Christian Heimes81ca7c72007-11-18 18:18:41 +0000167dll_path = os.path.join(srcdir, PCBUILD, dll_file)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000168msilib.set_arch_from_file(dll_path)
169if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"):
Collin Wintera817e582007-08-22 23:05:06 +0000170 raise SystemError("msisupport.dll for incorrect architecture")
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000171
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000172if testpackage:
173 ext = 'px'
174 testprefix = 'x'
175else:
176 ext = 'py'
177 testprefix = ''
178
179if msilib.Win64:
Martin v. Löwis47cc2a02007-08-30 18:27:06 +0000180 SystemFolderName = "[System64Folder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000181 registry_component = 4|256
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000182else:
183 SystemFolderName = "[SystemFolder]"
Martin v. Löwis283e35f2007-08-31 09:59:29 +0000184 registry_component = 4
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000185
186msilib.reset()
187
188# condition in which to install pythonxy.dll in system32:
189# a) it is Windows 9x or
190# b) it is NT, the user is privileged, and has chosen per-machine installation
191sys32cond = "(Windows9x or (Privileged and ALLUSERS))"
192
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000193def build_database():
194 """Generate an empty database, with just the schema and the
195 Summary information stream."""
196 if snapshot:
197 uc = upgrade_code_snapshot
198 else:
199 uc = upgrade_code
200 # schema represents the installer 2.0 database schema.
201 # sequence is the set of standard sequences
202 # (ui/execute, admin/advt/install)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000203 db = msilib.init_database("python-%s%s.msi" % (full_current_version, msilib.arch_ext),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000204 schema, ProductName="Python "+full_current_version,
205 ProductCode=product_code,
206 ProductVersion=current_version,
Martin v. Löwis3b6cc0952008-07-18 18:40:42 +0000207 Manufacturer=u"Python Software Foundation")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000208 # The default sequencing of the RemoveExistingProducts action causes
209 # removal of files that got just installed. Place it after
210 # InstallInitialize, so we first uninstall everything, but still roll
211 # back in case the installation is interrupted
212 msilib.change_sequence(sequence.InstallExecuteSequence,
213 "RemoveExistingProducts", 1510)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000214 msilib.add_tables(db, sequence)
215 # We cannot set ALLUSERS in the property table, as this cannot be
216 # reset if the user choses a per-user installation. Instead, we
217 # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages
218 # this property, and when the execution starts, ALLUSERS is set
219 # accordingly.
220 add_data(db, "Property", [("UpgradeCode", uc),
221 ("WhichUsers", "ALL"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000222 ("ProductLine", "Python%s%s" % (major, minor)),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000223 ])
224 db.Commit()
225 return db
226
227def remove_old_versions(db):
228 "Fill the upgrade table."
229 start = "%s.%s.0" % (major, minor)
230 # This requests that feature selection states of an older
231 # installation should be forwarded into this one. Upgrading
232 # requires that both the old and the new installation are
233 # either both per-machine or per-user.
234 migrate_features = 1
235 # See "Upgrade Table". We remove releases with the same major and
236 # minor version. For an snapshot, we remove all earlier snapshots. For
237 # a release, we remove all snapshots, and all earlier releases.
238 if snapshot:
239 add_data(db, "Upgrade",
Tim Peters66cb0182004-08-26 05:23:19 +0000240 [(upgrade_code_snapshot, start,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000241 current_version,
242 None, # Ignore language
Tim Peters66cb0182004-08-26 05:23:19 +0000243 migrate_features,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000244 None, # Migrate ALL features
245 "REMOVEOLDSNAPSHOT")])
246 props = "REMOVEOLDSNAPSHOT"
247 else:
248 add_data(db, "Upgrade",
249 [(upgrade_code, start, current_version,
250 None, migrate_features, None, "REMOVEOLDVERSION"),
251 (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1),
252 None, migrate_features, None, "REMOVEOLDSNAPSHOT")])
253 props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION"
Martin v. Löwis1c4c3062008-09-08 16:27:54 +0000254
255 props += ";TARGETDIR;DLLDIR"
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000256 # Installer collects the product codes of the earlier releases in
257 # these properties. In order to allow modification of the properties,
258 # they must be declared as secure. See "SecureCustomProperties Property"
259 add_data(db, "Property", [("SecureCustomProperties", props)])
260
261class PyDialog(Dialog):
262 """Dialog class with a fixed layout: controls at the top, then a ruler,
263 then a list of buttons: back, next, cancel. Optionally a bitmap at the
264 left."""
265 def __init__(self, *args, **kw):
266 """Dialog(database, name, x, y, w, h, attributes, title, first,
267 default, cancel, bitmap=true)"""
268 Dialog.__init__(self, *args)
269 ruler = self.h - 36
270 bmwidth = 152*ruler/328
271 if kw.get("bitmap", True):
272 self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin")
273 self.line("BottomLine", 0, ruler, self.w, 0)
274
275 def title(self, title):
276 "Set the title text of the dialog at the top."
277 # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
278 # text, in VerdanaBold10
279 self.text("Title", 135, 10, 220, 60, 0x30003,
280 r"{\VerdanaBold10}%s" % title)
281
282 def back(self, title, next, name = "Back", active = 1):
283 """Add a back button with a given title, the tab-next button,
284 its name in the Control table, possibly initially disabled.
285
286 Return the button, so that events can be associated"""
287 if active:
288 flags = 3 # Visible|Enabled
289 else:
290 flags = 1 # Visible
291 return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next)
292
293 def cancel(self, title, next, name = "Cancel", active = 1):
294 """Add a cancel button with a given title, the tab-next button,
295 its name in the Control table, possibly initially disabled.
296
297 Return the button, so that events can be associated"""
298 if active:
299 flags = 3 # Visible|Enabled
300 else:
301 flags = 1 # Visible
302 return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next)
303
304 def next(self, title, next, name = "Next", active = 1):
305 """Add a Next 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, 236, self.h-27, 56, 17, flags, title, next)
314
315 def xbutton(self, name, title, next, xpos):
316 """Add a button with a given title, the tab-next button,
317 its name in the Control table, giving its x position; the
318 y-position is aligned with the other buttons.
319
320 Return the button, so that events can be associated"""
321 return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next)
322
323def add_ui(db):
324 x = y = 50
325 w = 370
326 h = 300
327 title = "[ProductName] Setup"
328
329 # see "Dialog Style Bits"
330 modal = 3 # visible | modal
331 modeless = 1 # visible
332 track_disk_space = 32
333
334 add_data(db, 'ActionText', uisample.ActionText)
335 add_data(db, 'UIText', uisample.UIText)
336
337 # Bitmaps
338 if not os.path.exists(srcdir+r"\PC\python_icon.exe"):
Georg Brandlbf82e372008-05-16 17:02:34 +0000339 raise RuntimeError("Run icons.mak in PC directory")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000340 add_data(db, "Binary",
Christian Heimesd9a4d1d2008-01-01 14:42:15 +0000341 [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000342 ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")),
343 ])
344 add_data(db, "Icon",
345 [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))])
346
347 # Scripts
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000348 # CheckDir sets TargetExists if TARGETDIR exists.
349 # UpdateEditIDLE sets the REGISTRY.tcl component into
350 # the installed/uninstalled state according to both the
351 # Extensions and TclTk features.
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000352 if os.system("nmake /nologo /c /f msisupport.mak") != 0:
Georg Brandlbf82e372008-05-16 17:02:34 +0000353 raise RuntimeError("'nmake /f msisupport.mak' failed")
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000354 add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))])
355 # See "Custom Action Type 1"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000356 if msilib.Win64:
357 CheckDir = "CheckDir"
Martin v. Löwisdf40ce32006-02-16 14:38:30 +0000358 UpdateEditIDLE = "UpdateEditIDLE"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000359 else:
360 CheckDir = "_CheckDir@4"
361 UpdateEditIDLE = "_UpdateEditIDLE@4"
Tim Peters0e9980f2004-09-12 03:49:31 +0000362 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000363 [("CheckDir", 1, "Script", CheckDir)])
Martin v. Löwiseac02e62004-11-18 08:00:33 +0000364 if have_tcl:
365 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000366 [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)])
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000367
368 # UI customization properties
369 add_data(db, "Property",
370 # See "DefaultUIFont Property"
371 [("DefaultUIFont", "DlgFont8"),
372 # See "ErrorDialog Style Bit"
373 ("ErrorDialog", "ErrorDlg"),
374 ("Progress1", "Install"), # modified in maintenance type dlg
375 ("Progress2", "installs"),
376 ("MaintenanceForm_Action", "Repair")])
377
378 # Fonts, see "TextStyle Table"
379 add_data(db, "TextStyle",
380 [("DlgFont8", "Tahoma", 9, None, 0),
381 ("DlgFontBold8", "Tahoma", 8, None, 1), #bold
382 ("VerdanaBold10", "Verdana", 10, None, 1),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000383 ("VerdanaRed9", "Verdana", 9, 255, 0),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000384 ])
385
Martin v. Löwis37475a82008-04-08 17:17:46 +0000386 compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x bad_coding|badsyntax|site-packages|py2_ "[TARGETDIR]Lib"'
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000387 lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000388 # See "CustomAction Table"
389 add_data(db, "CustomAction", [
390 # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty
391 # See "Custom Action Type 51",
392 # "Custom Action Execution Scheduling Options"
393 ("InitialTargetDir", 307, "TARGETDIR",
394 "[WindowsVolume]Python%s%s" % (major, minor)),
395 ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
396 ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
397 # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
398 # See "Custom Action Type 18"
Martin v. Löwis7b2563b2004-11-02 22:59:56 +0000399 ("CompilePyc", 18, "python.exe", compileargs),
400 ("CompilePyo", 18, "python.exe", "-O "+compileargs),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000401 ("CompileGrammar", 18, "python.exe", lib2to3args),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000402 ])
403
404 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
405 # Numbers indicate sequence; see sequence.py for how these action integrate
406 add_data(db, "InstallUISequence",
407 [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
408 ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141),
409 ("InitialTargetDir", 'TARGETDIR=""', 750),
410 # In the user interface, assume all-users installation if privileged.
411 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
412 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
413 ("SelectDirectoryDlg", "Not Installed", 1230),
414 # XXX no support for resume installations yet
415 #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
416 ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250),
417 ("ProgressDlg", None, 1280)])
418 add_data(db, "AdminUISequence",
419 [("InitialTargetDir", 'TARGETDIR=""', 750),
420 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
421 ])
422
423 # Execute Sequences
424 add_data(db, "InstallExecuteSequence",
425 [("InitialTargetDir", 'TARGETDIR=""', 750),
426 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
427 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000428 ("UpdateEditIDLE", None, 1050),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000429 ("CompilePyc", "COMPILEALL", 6800),
430 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000431 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000432 ])
433 add_data(db, "AdminExecuteSequence",
434 [("InitialTargetDir", 'TARGETDIR=""', 750),
435 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
436 ("CompilePyc", "COMPILEALL", 6800),
437 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000438 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000439 ])
440
441 #####################################################################
442 # Standard dialogs: FatalError, UserExit, ExitDialog
443 fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title,
444 "Finish", "Finish", "Finish")
445 fatal.title("[ProductName] Installer ended prematurely")
446 fatal.back("< Back", "Finish", active = 0)
447 fatal.cancel("Cancel", "Back", active = 0)
448 fatal.text("Description1", 135, 70, 220, 80, 0x30003,
449 "[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.")
450 fatal.text("Description2", 135, 155, 220, 20, 0x30003,
451 "Click the Finish button to exit the Installer.")
452 c=fatal.next("Finish", "Cancel", name="Finish")
453 # See "ControlEvent Table". Parameters are the event, the parameter
454 # to the action, and optionally the condition for the event, and the order
455 # of events.
456 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000457
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000458 user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title,
459 "Finish", "Finish", "Finish")
460 user_exit.title("[ProductName] Installer was interrupted")
461 user_exit.back("< Back", "Finish", active = 0)
462 user_exit.cancel("Cancel", "Back", active = 0)
463 user_exit.text("Description1", 135, 70, 220, 80, 0x30003,
464 "[ProductName] setup was interrupted. Your system has not been modified. "
465 "To install this program at a later time, please run the installation again.")
466 user_exit.text("Description2", 135, 155, 220, 20, 0x30003,
467 "Click the Finish button to exit the Installer.")
468 c = user_exit.next("Finish", "Cancel", name="Finish")
469 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000470
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000471 exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title,
472 "Finish", "Finish", "Finish")
473 exit_dialog.title("Completing the [ProductName] Installer")
474 exit_dialog.back("< Back", "Finish", active = 0)
475 exit_dialog.cancel("Cancel", "Back", active = 0)
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000476 exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003,
477 "Special Windows thanks to:\n"
Martin v. Löwisd3f61a22004-08-30 09:22:30 +0000478 " Mark Hammond, without whose years of freely \n"
479 " shared Windows expertise, Python for Windows \n"
480 " would still be Python for DOS.")
Tim Peters66cb0182004-08-26 05:23:19 +0000481
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000482 c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003,
483 "{\\VerdanaRed9}Warning: Python 2.5.x is the last "
484 "Python release for Windows 9x.")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000485 c.condition("Hide", "NOT Version9X")
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000486
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000487 exit_dialog.text("Description", 135, 235, 220, 20, 0x30003,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000488 "Click the Finish button to exit the Installer.")
489 c = exit_dialog.next("Finish", "Cancel", name="Finish")
490 c.event("EndDialog", "Return")
491
492 #####################################################################
493 # Required dialog: FilesInUse, ErrorDlg
494 inuse = PyDialog(db, "FilesInUse",
495 x, y, w, h,
496 19, # KeepModeless|Modal|Visible
497 title,
498 "Retry", "Retry", "Retry", bitmap=False)
499 inuse.text("Title", 15, 6, 200, 15, 0x30003,
500 r"{\DlgFontBold8}Files in Use")
501 inuse.text("Description", 20, 23, 280, 20, 0x30003,
502 "Some files that need to be updated are currently in use.")
503 inuse.text("Text", 20, 55, 330, 50, 3,
504 "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.")
505 inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess",
506 None, None, None)
507 c=inuse.back("Exit", "Ignore", name="Exit")
508 c.event("EndDialog", "Exit")
509 c=inuse.next("Ignore", "Retry", name="Ignore")
510 c.event("EndDialog", "Ignore")
511 c=inuse.cancel("Retry", "Exit", name="Retry")
512 c.event("EndDialog","Retry")
513
514
515 # See "Error Dialog". See "ICE20" for the required names of the controls.
516 error = Dialog(db, "ErrorDlg",
517 50, 10, 330, 101,
518 65543, # Error|Minimize|Modal|Visible
519 title,
520 "ErrorText", None, None)
521 error.text("ErrorText", 50,9,280,48,3, "")
522 error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
523 error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo")
524 error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes")
525 error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort")
526 error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel")
527 error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore")
528 error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk")
529 error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry")
530
531 #####################################################################
532 # Global "Query Cancel" dialog
533 cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title,
534 "No", "No", "No")
Tim Peters66cb0182004-08-26 05:23:19 +0000535 cancel.text("Text", 48, 15, 194, 30, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000536 "Are you sure you want to cancel [ProductName] installation?")
537 cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
538 "py.ico", None, None)
539 c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
540 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000541
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000542 c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
543 c.event("EndDialog", "Return")
544
545 #####################################################################
546 # Global "Wait for costing" dialog
547 costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title,
548 "Return", "Return", "Return")
549 costing.text("Text", 48, 15, 194, 30, 3,
550 "Please wait while the installer finishes determining your disk space requirements.")
551 costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
552 "py.ico", None, None)
553 c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
554 c.event("EndDialog", "Exit")
555
556 #####################################################################
557 # Preparation dialog: no user input except cancellation
558 prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title,
559 "Cancel", "Cancel", "Cancel")
560 prep.text("Description", 135, 70, 220, 40, 0x30003,
561 "Please wait while the Installer prepares to guide you through the installation.")
562 prep.title("Welcome to the [ProductName] Installer")
563 c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...")
564 c.mapping("ActionText", "Text")
565 c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None)
566 c.mapping("ActionData", "Text")
567 prep.back("Back", None, active=0)
568 prep.next("Next", None, active=0)
569 c=prep.cancel("Cancel", None)
570 c.event("SpawnDialog", "CancelDlg")
571
572 #####################################################################
573 # Target directory selection
574 seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title,
575 "Next", "Next", "Cancel")
576 seldlg.title("Select Destination Directory")
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000577 c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003,
578 "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.")
579 c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000580 seldlg.text("Description", 135, 50, 220, 40, 0x30003,
581 "Please select a directory for the [ProductName] files.")
582
583 seldlg.back("< Back", None, active=0)
584 c = seldlg.next("Next >", "Cancel")
585 c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1)
586 # If the target exists, but we found that we are going to remove old versions, don't bother
587 # confirming that the target directory exists. Strictly speaking, we should determine that
588 # the target directory is indeed the target of the product that we are going to remove, but
589 # I don't know how to do that.
590 c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2)
591 c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3)
592 c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4)
593 c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5)
594
595 c = seldlg.cancel("Cancel", "DirectoryCombo")
596 c.event("SpawnDialog", "CancelDlg")
597
598 seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219,
599 "TARGETDIR", None, "DirectoryList", None)
600 seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR",
601 None, "PathEdit", None)
602 seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None)
603 c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
604 c.event("DirectoryListUp", "0")
605 c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
606 c.event("DirectoryListNew", "0")
607
608 #####################################################################
609 # SelectFeaturesDlg
610 features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space,
611 title, "Tree", "Next", "Cancel")
612 features.title("Customize [ProductName]")
613 features.text("Description", 135, 35, 220, 15, 0x30003,
614 "Select the way you want features to be installed.")
615 features.text("Text", 135,45,220,30, 3,
616 "Click on the icons in the tree below to change the way features will be installed.")
617
618 c=features.back("< Back", "Next")
619 c.event("NewDialog", "SelectDirectoryDlg")
620
621 c=features.next("Next >", "Cancel")
622 c.mapping("SelectionNoItems", "Enabled")
623 c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1)
624 c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2)
625
626 c=features.cancel("Cancel", "Tree")
627 c.event("SpawnDialog", "CancelDlg")
628
Tim Peters66cb0182004-08-26 05:23:19 +0000629 # 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 +0000630 features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty",
631 "Tree of selections", "Back", None)
632
633 #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost")
634 #c.mapping("SelectionNoItems", "Enabled")
635 #c.event("Reset", "0")
Tim Peters66cb0182004-08-26 05:23:19 +0000636
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000637 features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None)
638
639 c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10)
640 c.mapping("SelectionNoItems","Enabled")
641 c.event("SpawnDialog", "DiskCostDlg")
642
643 c=features.xbutton("Advanced", "Advanced", None, 0.30)
644 c.event("SpawnDialog", "AdvancedDlg")
645
646 c=features.text("ItemDescription", 140, 180, 210, 30, 3,
647 "Multiline description of the currently selected item.")
648 c.mapping("SelectionDescription","Text")
Tim Peters66cb0182004-08-26 05:23:19 +0000649
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000650 c=features.text("ItemSize", 140, 210, 210, 45, 3,
651 "The size of the currently selected item.")
652 c.mapping("SelectionSize", "Text")
653
654 #####################################################################
655 # Disk cost
656 cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title,
657 "OK", "OK", "OK", bitmap=False)
658 cost.text("Title", 15, 6, 200, 15, 0x30003,
659 "{\DlgFontBold8}Disk Space Requirements")
660 cost.text("Description", 20, 20, 280, 20, 0x30003,
661 "The disk space required for the installation of the selected features.")
662 cost.text("Text", 20, 53, 330, 60, 3,
663 "The highlighted volumes (if any) do not have enough disk space "
664 "available for the currently selected features. You can either "
665 "remove some files from the highlighted volumes, or choose to "
666 "install less features onto local drive(s), or select different "
667 "destination drive(s).")
668 cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223,
669 None, "{120}{70}{70}{70}{70}", None, None)
670 cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
671
672 #####################################################################
673 # WhichUsers Dialog. Only available on NT, and for privileged users.
674 # This must be run before FindRelatedProducts, because that will
675 # take into account whether the previous installation was per-user
676 # or per-machine. We currently don't support going back to this
677 # dialog after "Next" was selected; to support this, we would need to
678 # find how to reset the ALLUSERS property, and how to re-run
679 # FindRelatedProducts.
680 # On Windows9x, the ALLUSERS property is ignored on the command line
681 # and in the Property table, but installer fails according to the documentation
682 # if a dialog attempts to set ALLUSERS.
683 whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title,
684 "AdminInstall", "Next", "Cancel")
685 whichusers.title("Select whether to install [ProductName] for all users of this computer.")
686 # A radio group with two options: allusers, justme
687 g = whichusers.radiogroup("AdminInstall", 135, 60, 160, 50, 3,
688 "WhichUsers", "", "Next")
689 g.add("ALL", 0, 5, 150, 20, "Install for all users")
690 g.add("JUSTME", 0, 25, 150, 20, "Install just for me")
691
Tim Peters66cb0182004-08-26 05:23:19 +0000692 whichusers.back("Back", None, active=0)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000693
694 c = whichusers.next("Next >", "Cancel")
695 c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
696 c.event("EndDialog", "Return", order = 2)
697
698 c = whichusers.cancel("Cancel", "AdminInstall")
699 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000700
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000701 #####################################################################
702 # Advanced Dialog.
703 advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title,
704 "CompilePyc", "Next", "Cancel")
705 advanced.title("Advanced Options for [ProductName]")
706 # A radio group with two options: allusers, justme
707 advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3,
708 "COMPILEALL", "Compile .py files to byte code after installation", "Next")
709
710 c = advanced.next("Finish", "Cancel")
711 c.event("EndDialog", "Return")
712
713 c = advanced.cancel("Cancel", "CompilePyc")
714 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000715
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000716 #####################################################################
Tim Peters66cb0182004-08-26 05:23:19 +0000717 # Existing Directory dialog
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000718 dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title,
719 "No", "No", "No")
720 dlg.text("Title", 10, 20, 180, 40, 3,
721 "[TARGETDIR] exists. Are you sure you want to overwrite existing files?")
722 c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No")
723 c.event("[TargetExists]", "0", order=1)
724 c.event("[TargetExistsOk]", "1", order=2)
725 c.event("EndDialog", "Return", order=3)
726 c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes")
727 c.event("EndDialog", "Return")
728
729 #####################################################################
730 # Installation Progress dialog (modeless)
731 progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title,
732 "Cancel", "Cancel", "Cancel", bitmap=False)
733 progress.text("Title", 20, 15, 200, 15, 0x30003,
734 "{\DlgFontBold8}[Progress1] [ProductName]")
735 progress.text("Text", 35, 65, 300, 30, 3,
736 "Please wait while the Installer [Progress2] [ProductName]. "
737 "This may take several minutes.")
738 progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
739
740 c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...")
741 c.mapping("ActionText", "Text")
742
743 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
744 #c.mapping("ActionData", "Text")
745
746 c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537,
747 None, "Progress done", None, None)
748 c.mapping("SetProgress", "Progress")
749
750 progress.back("< Back", "Next", active=False)
751 progress.next("Next >", "Cancel", active=False)
752 progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
753
754 # Maintenance type: repair/uninstall
755 maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title,
756 "Next", "Next", "Cancel")
757 maint.title("Welcome to the [ProductName] Setup Wizard")
758 maint.text("BodyText", 135, 63, 230, 42, 3,
759 "Select whether you want to repair or remove [ProductName].")
760 g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3,
761 "MaintenanceForm_Action", "", "Next")
762 g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
763 g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
764 g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
Tim Peters66cb0182004-08-26 05:23:19 +0000765
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000766 maint.back("< Back", None, active=False)
767 c=maint.next("Finish", "Cancel")
768 # Change installation: Change progress dialog to "Change", then ask
769 # for feature selection
770 c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
771 c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
772
773 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
774 # Also set list of reinstalled features to "ALL"
775 c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
776 c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
Raymond Hettinger72f08012004-11-07 07:08:25 +0000777 c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000778 c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
779
780 # Uninstall: Change progress to "Remove", then invoke uninstall
781 # Also set list of removed features to "ALL"
782 c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
783 c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
784 c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
785 c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
786
Tim Peters66cb0182004-08-26 05:23:19 +0000787 # Close dialog when maintenance action scheduled
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000788 c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
789 c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
Tim Peters66cb0182004-08-26 05:23:19 +0000790
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000791 maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000792
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000793
794# See "Feature Table". The feature level is 1 for all features,
795# and the feature attributes are 0 for the DefaultFeature, and
796# FollowParent for all other features. The numbers are the Display
797# column.
798def add_features(db):
799 # feature attributes:
800 # msidbFeatureAttributesFollowParent == 2
801 # msidbFeatureAttributesDisallowAdvertise == 8
802 # Features that need to be installed with together with the main feature
803 # (i.e. additional Python libraries) need to follow the parent feature.
804 # Features that have no advertisement trigger (e.g. the test suite)
805 # must not support advertisement
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000806 global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000807 default_feature = Feature(db, "DefaultFeature", "Python",
808 "Python Interpreter and Libraries",
809 1, directory = "TARGETDIR")
Martin v. Löwis2a241ca2008-04-05 18:58:09 +0000810 shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0,
811 level=0)
812 private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0,
813 level=0)
814 add_data(db, "Condition", [("SharedCRT", 1, sys32cond),
815 ("PrivateCRT", 1, "not "+sys32cond)])
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000816 # We don't support advertisement of extensions
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000817 ext_feature = Feature(db, "Extensions", "Register Extensions",
818 "Make this Python installation the default Python installation", 3,
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000819 parent = default_feature, attributes=2|8)
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000820 if have_tcl:
821 tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000822 parent = default_feature, attributes=2)
823 htmlfiles = Feature(db, "Documentation", "Documentation",
824 "Python HTMLHelp File", 7, parent = default_feature)
825 tools = Feature(db, "Tools", "Utility Scripts",
Tim Peters66cb0182004-08-26 05:23:19 +0000826 "Python utility scripts (Tools/", 9,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000827 parent = default_feature, attributes=2)
828 testsuite = Feature(db, "Testsuite", "Test suite",
829 "Python test suite (Lib/test/)", 11,
830 parent = default_feature, attributes=2|8)
Tim Peters66cb0182004-08-26 05:23:19 +0000831
Christian Heimes81ca7c72007-11-18 18:18:41 +0000832def extract_msvcr90():
Martin v. Löwisee7498e2008-02-28 23:01:33 +0000833 # Find the redistributable files
834 dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\x86\Microsoft.VC90.CRT")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000835
Christian Heimese1feb2e2008-02-28 20:52:40 +0000836 result = []
Christian Heimes81ca7c72007-11-18 18:18:41 +0000837 installer = msilib.MakeInstaller()
Christian Heimese1feb2e2008-02-28 20:52:40 +0000838 # omit msvcm90 and msvcp90, as they aren't really needed
839 files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"]
840 for f in files:
841 path = os.path.join(dir, f)
842 kw = {'src':path}
843 if f.endswith('.dll'):
844 kw['version'] = installer.FileVersion(path, 0)
845 kw['language'] = installer.FileVersion(path, 1)
846 result.append((f, kw))
847 return result
Christian Heimes81ca7c72007-11-18 18:18:41 +0000848
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000849def generate_license():
850 import shutil, glob
851 out = open("LICENSE.txt", "w")
852 shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out)
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000853 for name, pat, file in (("bzip2","bzip2-*", "LICENSE"),
854 ("Berkeley DB", "db-*", "LICENSE"),
855 ("openssl", "openssl-*", "LICENSE"),
856 ("Tcl", "tcl8*", "license.terms"),
857 ("Tk", "tk8*", "license.terms"),
858 ("Tix", "tix-*", "license.terms")):
859 out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name)
860 dirs = glob.glob(srcdir+"/../"+pat)
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000861 if not dirs:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000862 raise ValueError, "Could not find "+srcdir+"/../"+pat
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000863 if len(dirs) > 2:
Martin v. Löwisf38e0d02008-06-13 14:11:59 +0000864 raise ValueError, "Multiple copies of "+pat
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000865 dir = dirs[0]
866 shutil.copyfileobj(open(os.path.join(dir, file)), out)
867 out.close()
868
869
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000870class PyDirectory(Directory):
871 """By default, all components in the Python installer
872 can run from source."""
873 def __init__(self, *args, **kw):
Georg Brandlbf82e372008-05-16 17:02:34 +0000874 if "componentflags" not in kw:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000875 kw['componentflags'] = 2 #msidbComponentAttributesOptional
876 Directory.__init__(self, *args, **kw)
877
878# See "File Table", "Component Table", "Directory Table",
879# "FeatureComponents Table"
880def add_files(db):
881 cab = CAB("python")
882 tmpfiles = []
883 # Add all executables, icons, text files into the TARGETDIR component
884 root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir")
885 default_feature.set_current()
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000886 if not msilib.Win64:
Christian Heimes81ca7c72007-11-18 18:18:41 +0000887 root.add_file("%s/w9xpopen.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000888 root.add_file("README.txt", src="README")
889 root.add_file("NEWS.txt", src="Misc/NEWS")
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +0000890 generate_license()
891 root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000892 root.start_component("python.exe", keyfile="python.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000893 root.add_file("%s/python.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000894 root.start_component("pythonw.exe", keyfile="pythonw.exe")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000895 root.add_file("%s/pythonw.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000896
897 # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
Christian Heimese1feb2e2008-02-28 20:52:40 +0000898 #dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
899 #install python30.dll into root dir for now
900 dlldir = root
901
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000902 pydll = "python%s%s.dll" % (major, minor)
Christian Heimes81ca7c72007-11-18 18:18:41 +0000903 pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000904 dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000905 installer = msilib.MakeInstaller()
906 pyversion = installer.FileVersion(pydllsrc, 0)
907 if not snapshot:
908 # For releases, the Python DLL has the same version as the
909 # installer package.
910 assert pyversion.split(".")[:3] == current_version.split(".")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000911 dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000912 version=pyversion,
913 language=installer.FileVersion(pydllsrc, 1))
Christian Heimese1feb2e2008-02-28 20:52:40 +0000914 DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs")
Christian Heimes81ca7c72007-11-18 18:18:41 +0000915
Martin v. Löwis21c80f22008-04-07 21:14:19 +0000916 # msvcr90.dll: Need to place the DLL and the manifest into the root directory,
917 # plus another copy of the manifest in the DLLs directory, with the manifest
918 # pointing to the root directory
919 root.start_component("msvcr90", feature=private_crt)
920 # Results are ID,keyword pairs
921 manifest, crtdll = extract_msvcr90()
922 root.add_file(manifest[0], **manifest[1])
923 root.add_file(crtdll[0], **crtdll[1])
924 # Copy the manifest
925 manifest_dlls = manifest[0]+".root"
926 open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr"))
927 DLLs.start_component("msvcr90_dlls", feature=private_crt)
928 DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls))
929
930 # Now start the main component for the DLLs directory;
931 # no regular files have been added to the directory yet.
932 DLLs.start_component()
Tim Peters66cb0182004-08-26 05:23:19 +0000933
Thomas Wouters89f507f2006-12-13 04:49:30 +0000934 # Check if _ctypes.pyd exists
Christian Heimes81ca7c72007-11-18 18:18:41 +0000935 have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000936 if not have_ctypes:
Collin Winter6afaeb72007-08-03 17:06:41 +0000937 print("WARNING: _ctypes.pyd not found, ctypes will not be included")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000938 extensions.remove("_ctypes.pyd")
939
Georg Brandl6e47a332008-05-17 19:15:58 +0000940 # Add all .py files in Lib, except tkinter, test
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000941 dirs={}
942 pydirs = [(root,"Lib")]
943 while pydirs:
Martin v. Löwis94b8b822008-06-13 19:00:35 +0000944 # Commit every now and then, or else installer will complain
945 db.Commit()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000946 parent, dir = pydirs.pop()
Martin v. Löwis9ca9f562006-01-03 06:29:53 +0000947 if dir == ".svn" or dir.startswith("plat-"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000948 continue
Georg Brandl6e47a332008-05-17 19:15:58 +0000949 elif dir in ["tkinter", "idlelib", "Icons"]:
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000950 if not have_tcl:
951 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000952 tcltk.set_current()
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +0000953 elif dir in ['test', 'tests', 'data', 'output']:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000954 # test: Lib, Lib/email, Lib/bsddb, Lib/ctypes, Lib/sqlite3
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +0000955 # tests: Lib/distutils
956 # data: Lib/email/test
957 # output: Lib/test
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000958 testsuite.set_current()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000959 elif not have_ctypes and dir == "ctypes":
960 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000961 else:
962 default_feature.set_current()
963 lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
964 # Add additional files
965 dirs[dir]=lib
966 lib.glob("*.txt")
967 if dir=='site-packages':
Martin v. Löwis6d60c092004-11-21 10:16:26 +0000968 lib.add_file("README.txt", src="README")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000969 continue
970 files = lib.glob("*.py")
971 files += lib.glob("*.pyw")
972 if files:
973 # Add an entry to the RemoveFile table to remove bytecode files.
974 lib.remove_pyc()
Thomas Wouters3fc2ca32006-04-21 11:28:17 +0000975 if dir.endswith('.egg-info'):
976 lib.add_file('entry_points.txt')
977 lib.add_file('PKG-INFO')
978 lib.add_file('top_level.txt')
979 lib.add_file('zip-safe')
980 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000981 if dir=='test' and parent.physical=='Lib':
982 lib.add_file("185test.db")
983 lib.add_file("audiotest.au")
984 lib.add_file("cfgparser.1")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000985 lib.add_file("sgml_input.html")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000986 lib.add_file("test.xml")
987 lib.add_file("test.xml.out")
988 lib.add_file("testtar.tar")
Martin v. Löwis7d3755d2004-09-06 06:31:12 +0000989 lib.add_file("test_difflib_expect.html")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000990 lib.add_file("check_soundcard.vbs")
991 lib.add_file("empty.vbs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000992 lib.glob("*.uue")
Christian Heimes5d14c2b2007-11-20 23:38:09 +0000993 lib.glob("*.pem")
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000994 lib.glob("*.pck")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000995 lib.add_file("readme.txt", src="README")
996 if dir=='decimaltestdata':
997 lib.glob("*.decTest")
998 if dir=='output':
999 lib.glob("test_*")
1000 if dir=='idlelib':
1001 lib.glob("*.def")
1002 lib.add_file("idle.bat")
1003 if dir=="Icons":
1004 lib.glob("*.gif")
1005 lib.add_file("idle.icns")
Thomas Wouters3fc2ca32006-04-21 11:28:17 +00001006 if dir=="command" and parent.physical=="distutils":
Martin v. Löwis5680d0c2008-04-10 03:06:53 +00001007 lib.glob("wininst*.exe")
Thomas Wouters3fc2ca32006-04-21 11:28:17 +00001008 if dir=="setuptools":
1009 lib.add_file("cli.exe")
1010 lib.add_file("gui.exe")
Martin v. Löwis90cc5ab2008-06-02 10:04:16 +00001011 if dir=="lib2to3":
1012 lib.removefile("pickle", "*.pickle")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001013 if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email":
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001014 # This should contain all non-.svn files listed in subversion
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001015 for f in os.listdir(lib.absolute):
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001016 if f.endswith(".txt") or f==".svn":continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001017 if f.endswith(".au") or f.endswith(".gif"):
1018 lib.add_file(f)
1019 else:
Collin Winter6afaeb72007-08-03 17:06:41 +00001020 print("WARNING: New file %s in email/test/data" % f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001021 for f in os.listdir(lib.absolute):
1022 if os.path.isdir(os.path.join(lib.absolute, f)):
1023 pydirs.append((lib, f))
1024 # Add DLLs
1025 default_feature.set_current()
Christian Heimese1feb2e2008-02-28 20:52:40 +00001026 lib = DLLs
Christian Heimesd9a4d1d2008-01-01 14:42:15 +00001027 lib.add_file("py.ico", src=srcdir+"/PC/py.ico")
1028 lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001029 dlls = []
1030 tclfiles = []
1031 for f in extensions:
1032 if f=="_tkinter.pyd":
1033 continue
Christian Heimes81ca7c72007-11-18 18:18:41 +00001034 if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f):
Collin Winter6afaeb72007-08-03 17:06:41 +00001035 print("WARNING: Missing extension", f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001036 continue
1037 dlls.append(f)
1038 lib.add_file(f)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001039 # Add sqlite
1040 if msilib.msi_type=="Intel64;1033":
1041 sqlite_arch = "/ia64"
1042 elif msilib.msi_type=="x64;1033":
1043 sqlite_arch = "/amd64"
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001044 tclsuffix = "64"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001045 else:
1046 sqlite_arch = ""
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001047 tclsuffix = ""
Martin v. Löwis94b8b822008-06-13 19:00:35 +00001048 lib.add_file("sqlite3.dll")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001049 if have_tcl:
Christian Heimes81ca7c72007-11-18 18:18:41 +00001050 if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)):
Collin Winter6afaeb72007-08-03 17:06:41 +00001051 print("WARNING: Missing _tkinter.pyd")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001052 else:
1053 lib.start_component("TkDLLs", tcltk)
1054 lib.add_file("_tkinter.pyd")
1055 dlls.append("_tkinter.pyd")
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001056 tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001057 for f in glob.glob1(tcldir, "*.dll"):
1058 lib.add_file(f, src=os.path.join(tcldir, f))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001059 # check whether there are any unknown extensions
Christian Heimes81ca7c72007-11-18 18:18:41 +00001060 for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001061 if f.endswith("_d.pyd"): continue # debug version
1062 if f in dlls: continue
Collin Winter6afaeb72007-08-03 17:06:41 +00001063 print("WARNING: Unknown extension", f)
Tim Peters66cb0182004-08-26 05:23:19 +00001064
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001065 # Add headers
1066 default_feature.set_current()
1067 lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include")
1068 lib.glob("*.h")
1069 lib.add_file("pyconfig.h", src="../PC/pyconfig.h")
1070 # Add import libraries
Christian Heimes81ca7c72007-11-18 18:18:41 +00001071 lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001072 for f in dlls:
1073 lib.add_file(f.replace('pyd','lib'))
1074 lib.add_file('python%s%s.lib' % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +00001075 # Add the mingw-format library
1076 if have_mingw:
Tim Peters5a9fb3c2005-01-07 16:01:32 +00001077 lib.add_file('libpython%s%s.a' % (major, minor))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001078 if have_tcl:
1079 # Add Tcl/Tk
Martin v. Löwis20c892d2008-02-29 21:03:38 +00001080 tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')]
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001081 tcltk.set_current()
1082 while tcldirs:
1083 parent, phys, dir = tcldirs.pop()
1084 lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir))
1085 if not os.path.exists(lib.absolute):
1086 continue
1087 for f in os.listdir(lib.absolute):
1088 if os.path.isdir(os.path.join(lib.absolute, f)):
1089 tcldirs.append((lib, f, f))
1090 else:
1091 lib.add_file(f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001092 # Add tools
1093 tools.set_current()
1094 tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools")
Martin v. Löwisf8bba8e2008-03-24 00:52:58 +00001095 for f in ['i18n', 'pynche', 'Scripts', 'versioncheck', 'webchecker']:
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001096 lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f))
1097 lib.glob("*.py")
1098 lib.glob("*.pyw", exclude=['pydocgui.pyw'])
1099 lib.remove_pyc()
1100 lib.glob("*.txt")
1101 if f == "pynche":
1102 x = PyDirectory(db, cab, lib, "X", "X", "X|X")
1103 x.glob("*.txt")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001104 if os.path.exists(os.path.join(lib.absolute, "README")):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001105 lib.add_file("README.txt", src="README")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001106 if f == 'Scripts':
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001107 if have_tcl:
1108 lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
1109 lib.add_file("pydocgui.pyw")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001110 # Add documentation
1111 htmlfiles.set_current()
1112 lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc")
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001113 lib.start_component("documentation", keyfile=docfile)
1114 lib.add_file(docfile, src="build/htmlhelp/"+docfile)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001115
1116 cab.commit(db)
1117
1118 for f in tmpfiles:
1119 os.unlink(f)
1120
1121# See "Registry Table", "Component Table"
1122def add_registry(db):
1123 # File extensions, associated with the REGISTRY.def component
1124 # IDLE verbs depend on the tcltk feature.
1125 # msidbComponentAttributesRegistryKeyPath = 4
1126 # -1 for Root specifies "dependent on ALLUSERS property"
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001127 tcldata = []
1128 if have_tcl:
1129 tcldata = [
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001130 ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001131 "py.IDLE")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001132 add_data(db, "Component",
1133 # msidbComponentAttributesRegistryKeyPath = 4
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001134 [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001135 "InstallPath"),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001136 ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001137 "Documentation"),
Martin v. Löwis283e35f2007-08-31 09:59:29 +00001138 ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001139 None, None)] + tcldata)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001140 # See "FeatureComponents Table".
1141 # The association between TclTk and pythonw.exe is necessary to make ICE59
1142 # happy, because the installer otherwise believes that the IDLE and PyDoc
1143 # shortcuts might get installed without pythonw.exe being install. This
1144 # is not true, since installing TclTk will install the default feature, which
1145 # will cause pythonw.exe to be installed.
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001146 # REGISTRY.tcl is not associated with any feature, as it will be requested
1147 # through a custom action
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001148 tcldata = []
1149 if have_tcl:
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001150 tcldata = [(tcltk.id, "pythonw.exe")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001151 add_data(db, "FeatureComponents",
1152 [(default_feature.id, "REGISTRY"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001153 (htmlfiles.id, "REGISTRY.doc"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001154 (ext_feature.id, "REGISTRY.def")] +
1155 tcldata
1156 )
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001157 # Extensions are not advertised. For advertised extensions,
1158 # we would need separate binaries that install along with the
1159 # extension.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001160 pat = r"Software\Classes\%sPython.%sFile\shell\%s\command"
1161 ewi = "Edit with IDLE"
1162 pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon"
1163 pat3 = r"Software\Classes\%sPython.%sFile"
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001164 tcl_verbs = []
1165 if have_tcl:
1166 tcl_verbs=[
1167 ("py.IDLE", -1, pat % (testprefix, "", ewi), "",
1168 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"',
1169 "REGISTRY.tcl"),
1170 ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "",
1171 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"',
1172 "REGISTRY.tcl"),
1173 ]
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001174 add_data(db, "Registry",
1175 [# Extensions
1176 ("py.ext", -1, r"Software\Classes\."+ext, "",
1177 "Python.File", "REGISTRY.def"),
1178 ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "",
1179 "Python.NoConFile", "REGISTRY.def"),
1180 ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "",
1181 "Python.CompiledFile", "REGISTRY.def"),
1182 ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "",
1183 "Python.CompiledFile", "REGISTRY.def"),
1184 # MIME types
1185 ("py.mime", -1, r"Software\Classes\."+ext, "Content Type",
1186 "text/plain", "REGISTRY.def"),
1187 ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type",
1188 "text/plain", "REGISTRY.def"),
1189 #Verbs
1190 ("py.open", -1, pat % (testprefix, "", "open"), "",
1191 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
1192 ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
1193 r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"),
1194 ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
1195 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001196 ] + tcl_verbs + [
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001197 #Icons
1198 ("py.icon", -1, pat2 % (testprefix, ""), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001199 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001200 ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001201 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001202 ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001203 r'[DLLs]pyc.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001204 # Descriptions
1205 ("py.txt", -1, pat3 % (testprefix, ""), "",
1206 "Python File", "REGISTRY.def"),
1207 ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "",
1208 "Python File (no console)", "REGISTRY.def"),
1209 ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "",
1210 "Compiled Python File", "REGISTRY.def"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001211 ])
Tim Peters66cb0182004-08-26 05:23:19 +00001212
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001213 # Registry keys
1214 prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version)
1215 add_data(db, "Registry",
1216 [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"),
1217 ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "",
1218 "Python %s" % short_version, "REGISTRY"),
1219 ("PythonPath", -1, prefix+r"\PythonPath", "",
Georg Brandl6e47a332008-05-17 19:15:58 +00001220 r"[TARGETDIR]Lib;[TARGETDIR]DLLs", "REGISTRY"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001221 ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001222 "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001223 ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"),
1224 ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe",
1225 "", r"[TARGETDIR]Python.exe", "REGISTRY.def")
1226 ])
1227 # Shortcuts, see "Shortcut Table"
1228 add_data(db, "Directory",
1229 [("ProgramMenuFolder", "TARGETDIR", "."),
1230 ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))])
1231 add_data(db, "RemoveFile",
1232 [("MenuDir", "TARGETDIR", None, "MenuDir", 2)])
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001233 tcltkshortcuts = []
1234 if have_tcl:
1235 tcltkshortcuts = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001236 ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001237 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 +00001238 ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001239 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 +00001240 ]
1241 add_data(db, "Shortcut",
1242 tcltkshortcuts +
1243 [# Advertised shortcuts: targets are features, not files
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001244 ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe",
1245 default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001246 # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an
1247 # icon first.
1248 #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation",
1249 # htmlfiles.id, None, None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001250 ## Non-advertised shortcuts: must be associated with a registry component
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001251 ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc",
Alexandre Vassalotti6461e102008-05-15 22:09:29 +00001252 "[#%s]" % docfile, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001253 None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001254 ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY",
1255 SystemFolderName+"msiexec", "/x%s" % product_code,
1256 None, None, None, None, None, None),
1257 ])
1258 db.Commit()
1259
1260db = build_database()
1261try:
1262 add_features(db)
1263 add_ui(db)
1264 add_files(db)
1265 add_registry(db)
1266 remove_old_versions(db)
1267 db.Commit()
1268finally:
1269 del db