blob: dff0e2de6d3f3032b53e15cf9b4c51b6aa4a943a [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 Heimes9acba042007-12-04 14:57:30 +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
Martin v. Löwis1d278fc2006-03-28 18:30:05 +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 Heimes9acba042007-12-04 14:57:30 +000027# path to PCbuild directory
Martin v. Löwise7a434e2008-01-06 11:03:43 +000028PCBUILD="PCbuild"
Christian Heimes9acba042007-12-04 14:57:30 +000029# msvcrt version
Martin v. Löwise7a434e2008-01-06 11:03:43 +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".
Martin v. Löwisab0b29b2008-09-13 08:11:57 +000067# upgrade_code gets set to upgrade_code_64 when we have determined
68# that the target is Win64.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000069upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}'
70upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}'
Martin v. Löwisab0b29b2008-09-13 08:11:57 +000071upgrade_code_64='{6A965A0C-6EE6-4E3A-9983-3263F56311EC}'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000072
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000073if snapshot:
74 current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24))
75 product_code = msilib.gen_uuid()
76else:
77 product_code = product_codes[current_version]
78
79if full_current_version is None:
80 full_current_version = current_version
81
82extensions = [
83 'bz2.pyd',
84 'pyexpat.pyd',
85 'select.pyd',
86 'unicodedata.pyd',
87 'winsound.pyd',
Trent Micke97e5a72005-12-15 22:08:46 +000088 '_elementtree.pyd',
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +000089 '_bsddb.pyd',
90 '_socket.pyd',
91 '_ssl.pyd',
92 '_testcapi.pyd',
93 '_tkinter.pyd',
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +000094 '_msi.pyd',
Martin v. Löwisa09655e2006-03-10 15:36:28 +000095 '_ctypes.pyd',
Martin v. Löwis1a494bd2006-04-04 07:10:59 +000096 '_ctypes_test.pyd',
Martin v. Löwisa09fd6e2006-08-16 12:55:10 +000097 '_sqlite3.pyd',
Martin v. Löwis1d2ce452008-06-30 07:01:09 +000098 '_hashlib.pyd',
99 '_multiprocessing.pyd'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000100]
101
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000102# Well-known component UUIDs
103# These are needed for SharedDLLs reference counter; if
104# a different UUID was used for each incarnation of, say,
105# python24.dll, an upgrade would set the reference counter
106# from 1 to 2 (due to what I consider a bug in MSI)
107# Using the same UUID is fine since these files are versioned,
108# so Installer will always keep the newest version.
Christian Heimes9acba042007-12-04 14:57:30 +0000109# NOTE: All uuids are self generated.
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000110pythondll_uuid = {
111 "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}",
Martin v. Löwis5409c8d2007-08-30 18:15:22 +0000112 "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}",
Martin v. Löwisbe7abbb2007-08-14 05:01:50 +0000113 "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}",
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000114 } [major+minor]
Tim Peterseba28be2005-03-28 01:08:02 +0000115
Martin v. Löwis344d0662008-05-09 18:21:55 +0000116# Compute the name that Sphinx gives to the docfile
117docfile = ""
118if level < 0xf:
119 docfile = '%x%s' % (level, serial)
120docfile = 'python%s%s%s.chm' % (major, minor, docfile)
121
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000122# Build the mingw import library, libpythonXY.a
123# This requires 'nm' and 'dlltool' executables on your PATH
124def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib):
125 warning = "WARNING: %s - libpythonXX.a not built"
126 nm = find_executable('nm')
127 dlltool = find_executable('dlltool')
128
129 if not nm or not dlltool:
130 print warning % "nm and/or dlltool were not found"
131 return False
132
133 nm_command = '%s -Cs %s' % (nm, lib_file)
134 dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \
135 (dlltool, dll_file, def_file, mingw_lib)
136 export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match
137
138 f = open(def_file,'w')
139 print >>f, "LIBRARY %s" % dll_file
140 print >>f, "EXPORTS"
141
142 nm_pipe = os.popen(nm_command)
143 for line in nm_pipe.readlines():
144 m = export_match(line)
145 if m:
146 print >>f, m.group(1)
147 f.close()
148 exit = nm_pipe.close()
149
150 if exit:
151 print warning % "nm did not run successfully"
152 return False
153
154 if os.system(dlltool_command) != 0:
155 print warning % "dlltool did not run successfully"
156 return False
157
158 return True
159
160# Target files (.def and .a) go in PCBuild directory
Christian Heimes9acba042007-12-04 14:57:30 +0000161lib_file = os.path.join(srcdir, PCBUILD, "python%s%s.lib" % (major, minor))
162def_file = os.path.join(srcdir, PCBUILD, "python%s%s.def" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000163dll_file = "python%s%s.dll" % (major, minor)
Christian Heimes9acba042007-12-04 14:57:30 +0000164mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +0000165
166have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib)
167
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000168# Determine the target architechture
Christian Heimes9acba042007-12-04 14:57:30 +0000169dll_path = os.path.join(srcdir, PCBUILD, dll_file)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000170msilib.set_arch_from_file(dll_path)
171if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"):
172 raise SystemError, "msisupport.dll for incorrect architecture"
Martin v. Löwisab0b29b2008-09-13 08:11:57 +0000173if msilib.Win64:
174 upgrade_code = upgrade_code_64
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000175
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000176if testpackage:
177 ext = 'px'
178 testprefix = 'x'
179else:
180 ext = 'py'
181 testprefix = ''
182
183if msilib.Win64:
Martin v. Löwis75c23bd2007-08-30 18:25:47 +0000184 SystemFolderName = "[System64Folder]"
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +0000185 registry_component = 4|256
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000186else:
187 SystemFolderName = "[SystemFolder]"
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +0000188 registry_component = 4
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000189
190msilib.reset()
191
192# condition in which to install pythonxy.dll in system32:
193# a) it is Windows 9x or
194# b) it is NT, the user is privileged, and has chosen per-machine installation
195sys32cond = "(Windows9x or (Privileged and ALLUSERS))"
196
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000197def build_database():
198 """Generate an empty database, with just the schema and the
199 Summary information stream."""
200 if snapshot:
201 uc = upgrade_code_snapshot
202 else:
203 uc = upgrade_code
204 # schema represents the installer 2.0 database schema.
205 # sequence is the set of standard sequences
206 # (ui/execute, admin/advt/install)
Martin v. Löwis856bf9a2006-02-14 20:42:55 +0000207 db = msilib.init_database("python-%s%s.msi" % (full_current_version, msilib.arch_ext),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000208 schema, ProductName="Python "+full_current_version,
209 ProductCode=product_code,
210 ProductVersion=current_version,
Martin v. Löwis8bc77e42007-09-01 06:36:03 +0000211 Manufacturer=u"Python Software Foundation")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000212 # The default sequencing of the RemoveExistingProducts action causes
213 # removal of files that got just installed. Place it after
214 # InstallInitialize, so we first uninstall everything, but still roll
215 # back in case the installation is interrupted
216 msilib.change_sequence(sequence.InstallExecuteSequence,
217 "RemoveExistingProducts", 1510)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000218 msilib.add_tables(db, sequence)
219 # We cannot set ALLUSERS in the property table, as this cannot be
220 # reset if the user choses a per-user installation. Instead, we
221 # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages
222 # this property, and when the execution starts, ALLUSERS is set
223 # accordingly.
224 add_data(db, "Property", [("UpgradeCode", uc),
225 ("WhichUsers", "ALL"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000226 ("ProductLine", "Python%s%s" % (major, minor)),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000227 ])
228 db.Commit()
229 return db
230
231def remove_old_versions(db):
232 "Fill the upgrade table."
233 start = "%s.%s.0" % (major, minor)
234 # This requests that feature selection states of an older
235 # installation should be forwarded into this one. Upgrading
236 # requires that both the old and the new installation are
237 # either both per-machine or per-user.
238 migrate_features = 1
239 # See "Upgrade Table". We remove releases with the same major and
240 # minor version. For an snapshot, we remove all earlier snapshots. For
241 # a release, we remove all snapshots, and all earlier releases.
242 if snapshot:
243 add_data(db, "Upgrade",
Tim Peters66cb0182004-08-26 05:23:19 +0000244 [(upgrade_code_snapshot, start,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000245 current_version,
246 None, # Ignore language
Tim Peters66cb0182004-08-26 05:23:19 +0000247 migrate_features,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000248 None, # Migrate ALL features
249 "REMOVEOLDSNAPSHOT")])
250 props = "REMOVEOLDSNAPSHOT"
251 else:
252 add_data(db, "Upgrade",
253 [(upgrade_code, start, current_version,
254 None, migrate_features, None, "REMOVEOLDVERSION"),
255 (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1),
256 None, migrate_features, None, "REMOVEOLDSNAPSHOT")])
257 props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION"
Martin v. Löwis3f5fda82008-09-08 13:50:10 +0000258
259 props += ";TARGETDIR;DLLDIR"
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000260 # Installer collects the product codes of the earlier releases in
261 # these properties. In order to allow modification of the properties,
262 # they must be declared as secure. See "SecureCustomProperties Property"
263 add_data(db, "Property", [("SecureCustomProperties", props)])
264
265class PyDialog(Dialog):
266 """Dialog class with a fixed layout: controls at the top, then a ruler,
267 then a list of buttons: back, next, cancel. Optionally a bitmap at the
268 left."""
269 def __init__(self, *args, **kw):
270 """Dialog(database, name, x, y, w, h, attributes, title, first,
271 default, cancel, bitmap=true)"""
272 Dialog.__init__(self, *args)
273 ruler = self.h - 36
274 bmwidth = 152*ruler/328
275 if kw.get("bitmap", True):
276 self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin")
277 self.line("BottomLine", 0, ruler, self.w, 0)
278
279 def title(self, title):
280 "Set the title text of the dialog at the top."
281 # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
282 # text, in VerdanaBold10
283 self.text("Title", 135, 10, 220, 60, 0x30003,
284 r"{\VerdanaBold10}%s" % title)
285
286 def back(self, title, next, name = "Back", active = 1):
287 """Add a back button with a given title, the tab-next button,
288 its name in the Control table, possibly initially disabled.
289
290 Return the button, so that events can be associated"""
291 if active:
292 flags = 3 # Visible|Enabled
293 else:
294 flags = 1 # Visible
295 return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next)
296
297 def cancel(self, title, next, name = "Cancel", active = 1):
298 """Add a cancel button with a given title, the tab-next button,
299 its name in the Control table, possibly initially disabled.
300
301 Return the button, so that events can be associated"""
302 if active:
303 flags = 3 # Visible|Enabled
304 else:
305 flags = 1 # Visible
306 return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next)
307
308 def next(self, title, next, name = "Next", active = 1):
309 """Add a Next button with a given title, the tab-next button,
310 its name in the Control table, possibly initially disabled.
311
312 Return the button, so that events can be associated"""
313 if active:
314 flags = 3 # Visible|Enabled
315 else:
316 flags = 1 # Visible
317 return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next)
318
319 def xbutton(self, name, title, next, xpos):
320 """Add a button with a given title, the tab-next button,
321 its name in the Control table, giving its x position; the
322 y-position is aligned with the other buttons.
323
324 Return the button, so that events can be associated"""
325 return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next)
326
327def add_ui(db):
328 x = y = 50
329 w = 370
330 h = 300
331 title = "[ProductName] Setup"
332
333 # see "Dialog Style Bits"
334 modal = 3 # visible | modal
335 modeless = 1 # visible
336 track_disk_space = 32
337
338 add_data(db, 'ActionText', uisample.ActionText)
339 add_data(db, 'UIText', uisample.UIText)
340
341 # Bitmaps
342 if not os.path.exists(srcdir+r"\PC\python_icon.exe"):
343 raise "Run icons.mak in PC directory"
344 add_data(db, "Binary",
Christian Heimes7e28e492008-01-01 13:52:57 +0000345 [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000346 ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")),
347 ])
348 add_data(db, "Icon",
349 [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))])
350
351 # Scripts
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000352 # CheckDir sets TargetExists if TARGETDIR exists.
353 # UpdateEditIDLE sets the REGISTRY.tcl component into
354 # the installed/uninstalled state according to both the
355 # Extensions and TclTk features.
Martin v. Löwiseb68be42004-12-12 15:29:21 +0000356 if os.system("nmake /nologo /c /f msisupport.mak") != 0:
357 raise "'nmake /f msisupport.mak' failed"
358 add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))])
359 # See "Custom Action Type 1"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000360 if msilib.Win64:
361 CheckDir = "CheckDir"
Martin v. Löwisdf40ce32006-02-16 14:38:30 +0000362 UpdateEditIDLE = "UpdateEditIDLE"
Martin v. Löwis3390d332005-03-14 17:20:13 +0000363 else:
364 CheckDir = "_CheckDir@4"
365 UpdateEditIDLE = "_UpdateEditIDLE@4"
Tim Peters0e9980f2004-09-12 03:49:31 +0000366 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000367 [("CheckDir", 1, "Script", CheckDir)])
Martin v. Löwiseac02e62004-11-18 08:00:33 +0000368 if have_tcl:
369 add_data(db, "CustomAction",
Martin v. Löwis3390d332005-03-14 17:20:13 +0000370 [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)])
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000371
372 # UI customization properties
373 add_data(db, "Property",
374 # See "DefaultUIFont Property"
375 [("DefaultUIFont", "DlgFont8"),
376 # See "ErrorDialog Style Bit"
377 ("ErrorDialog", "ErrorDlg"),
378 ("Progress1", "Install"), # modified in maintenance type dlg
379 ("Progress2", "installs"),
380 ("MaintenanceForm_Action", "Repair")])
381
382 # Fonts, see "TextStyle Table"
383 add_data(db, "TextStyle",
384 [("DlgFont8", "Tahoma", 9, None, 0),
385 ("DlgFontBold8", "Tahoma", 8, None, 1), #bold
386 ("VerdanaBold10", "Verdana", 10, None, 1),
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000387 ("VerdanaRed9", "Verdana", 9, 255, 0),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000388 ])
389
Martin v. Löwis775e10d2008-04-08 16:48:35 +0000390 compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x bad_coding|badsyntax|site-packages|py3_ "[TARGETDIR]Lib"'
Martin v. Löwis367c79a2008-05-25 16:37:34 +0000391 lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000392 # See "CustomAction Table"
393 add_data(db, "CustomAction", [
394 # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty
395 # See "Custom Action Type 51",
396 # "Custom Action Execution Scheduling Options"
397 ("InitialTargetDir", 307, "TARGETDIR",
398 "[WindowsVolume]Python%s%s" % (major, minor)),
399 ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
400 ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
401 # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
402 # See "Custom Action Type 18"
Martin v. Löwis7b2563b2004-11-02 22:59:56 +0000403 ("CompilePyc", 18, "python.exe", compileargs),
404 ("CompilePyo", 18, "python.exe", "-O "+compileargs),
Martin v. Löwis367c79a2008-05-25 16:37:34 +0000405 ("CompileGrammar", 18, "python.exe", lib2to3args),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000406 ])
407
408 # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
409 # Numbers indicate sequence; see sequence.py for how these action integrate
410 add_data(db, "InstallUISequence",
411 [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
412 ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141),
413 ("InitialTargetDir", 'TARGETDIR=""', 750),
414 # In the user interface, assume all-users installation if privileged.
415 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
416 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
417 ("SelectDirectoryDlg", "Not Installed", 1230),
418 # XXX no support for resume installations yet
419 #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
420 ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250),
421 ("ProgressDlg", None, 1280)])
422 add_data(db, "AdminUISequence",
423 [("InitialTargetDir", 'TARGETDIR=""', 750),
424 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
425 ])
426
427 # Execute Sequences
428 add_data(db, "InstallExecuteSequence",
429 [("InitialTargetDir", 'TARGETDIR=""', 750),
430 ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
431 ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000432 ("UpdateEditIDLE", None, 1050),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000433 ("CompilePyc", "COMPILEALL", 6800),
434 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis367c79a2008-05-25 16:37:34 +0000435 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000436 ])
437 add_data(db, "AdminExecuteSequence",
438 [("InitialTargetDir", 'TARGETDIR=""', 750),
439 ("SetDLLDirToTarget", 'DLLDIR=""', 751),
440 ("CompilePyc", "COMPILEALL", 6800),
441 ("CompilePyo", "COMPILEALL", 6801),
Martin v. Löwis367c79a2008-05-25 16:37:34 +0000442 ("CompileGrammar", "COMPILEALL", 6802),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000443 ])
444
445 #####################################################################
446 # Standard dialogs: FatalError, UserExit, ExitDialog
447 fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title,
448 "Finish", "Finish", "Finish")
449 fatal.title("[ProductName] Installer ended prematurely")
450 fatal.back("< Back", "Finish", active = 0)
451 fatal.cancel("Cancel", "Back", active = 0)
452 fatal.text("Description1", 135, 70, 220, 80, 0x30003,
453 "[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.")
454 fatal.text("Description2", 135, 155, 220, 20, 0x30003,
455 "Click the Finish button to exit the Installer.")
456 c=fatal.next("Finish", "Cancel", name="Finish")
457 # See "ControlEvent Table". Parameters are the event, the parameter
458 # to the action, and optionally the condition for the event, and the order
459 # of events.
460 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000461
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000462 user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title,
463 "Finish", "Finish", "Finish")
464 user_exit.title("[ProductName] Installer was interrupted")
465 user_exit.back("< Back", "Finish", active = 0)
466 user_exit.cancel("Cancel", "Back", active = 0)
467 user_exit.text("Description1", 135, 70, 220, 80, 0x30003,
468 "[ProductName] setup was interrupted. Your system has not been modified. "
469 "To install this program at a later time, please run the installation again.")
470 user_exit.text("Description2", 135, 155, 220, 20, 0x30003,
471 "Click the Finish button to exit the Installer.")
472 c = user_exit.next("Finish", "Cancel", name="Finish")
473 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000474
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000475 exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title,
476 "Finish", "Finish", "Finish")
477 exit_dialog.title("Completing the [ProductName] Installer")
478 exit_dialog.back("< Back", "Finish", active = 0)
479 exit_dialog.cancel("Cancel", "Back", active = 0)
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000480 exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003,
481 "Special Windows thanks to:\n"
Martin v. Löwisd3f61a22004-08-30 09:22:30 +0000482 " Mark Hammond, without whose years of freely \n"
483 " shared Windows expertise, Python for Windows \n"
484 " would still be Python for DOS.")
Tim Peters66cb0182004-08-26 05:23:19 +0000485
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000486 c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003,
487 "{\\VerdanaRed9}Warning: Python 2.5.x is the last "
488 "Python release for Windows 9x.")
Martin v. Löwisdf511792006-03-28 07:51:51 +0000489 c.condition("Hide", "NOT Version9X")
Martin v. Löwis8c7c56e2006-03-05 14:04:26 +0000490
Martin v. Löwis2dd2a282004-08-22 17:10:12 +0000491 exit_dialog.text("Description", 135, 235, 220, 20, 0x30003,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000492 "Click the Finish button to exit the Installer.")
493 c = exit_dialog.next("Finish", "Cancel", name="Finish")
494 c.event("EndDialog", "Return")
495
496 #####################################################################
497 # Required dialog: FilesInUse, ErrorDlg
498 inuse = PyDialog(db, "FilesInUse",
499 x, y, w, h,
500 19, # KeepModeless|Modal|Visible
501 title,
502 "Retry", "Retry", "Retry", bitmap=False)
503 inuse.text("Title", 15, 6, 200, 15, 0x30003,
504 r"{\DlgFontBold8}Files in Use")
505 inuse.text("Description", 20, 23, 280, 20, 0x30003,
506 "Some files that need to be updated are currently in use.")
507 inuse.text("Text", 20, 55, 330, 50, 3,
508 "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.")
509 inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess",
510 None, None, None)
511 c=inuse.back("Exit", "Ignore", name="Exit")
512 c.event("EndDialog", "Exit")
513 c=inuse.next("Ignore", "Retry", name="Ignore")
514 c.event("EndDialog", "Ignore")
515 c=inuse.cancel("Retry", "Exit", name="Retry")
516 c.event("EndDialog","Retry")
517
518
519 # See "Error Dialog". See "ICE20" for the required names of the controls.
520 error = Dialog(db, "ErrorDlg",
521 50, 10, 330, 101,
522 65543, # Error|Minimize|Modal|Visible
523 title,
524 "ErrorText", None, None)
525 error.text("ErrorText", 50,9,280,48,3, "")
526 error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None)
527 error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo")
528 error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes")
529 error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort")
530 error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel")
531 error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore")
532 error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk")
533 error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry")
534
535 #####################################################################
536 # Global "Query Cancel" dialog
537 cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title,
538 "No", "No", "No")
Tim Peters66cb0182004-08-26 05:23:19 +0000539 cancel.text("Text", 48, 15, 194, 30, 3,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000540 "Are you sure you want to cancel [ProductName] installation?")
541 cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
542 "py.ico", None, None)
543 c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
544 c.event("EndDialog", "Exit")
Tim Peters66cb0182004-08-26 05:23:19 +0000545
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000546 c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
547 c.event("EndDialog", "Return")
548
549 #####################################################################
550 # Global "Wait for costing" dialog
551 costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title,
552 "Return", "Return", "Return")
553 costing.text("Text", 48, 15, 194, 30, 3,
554 "Please wait while the installer finishes determining your disk space requirements.")
555 costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
556 "py.ico", None, None)
557 c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
558 c.event("EndDialog", "Exit")
559
560 #####################################################################
561 # Preparation dialog: no user input except cancellation
562 prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title,
563 "Cancel", "Cancel", "Cancel")
564 prep.text("Description", 135, 70, 220, 40, 0x30003,
565 "Please wait while the Installer prepares to guide you through the installation.")
566 prep.title("Welcome to the [ProductName] Installer")
567 c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...")
568 c.mapping("ActionText", "Text")
569 c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None)
570 c.mapping("ActionData", "Text")
571 prep.back("Back", None, active=0)
572 prep.next("Next", None, active=0)
573 c=prep.cancel("Cancel", None)
574 c.event("SpawnDialog", "CancelDlg")
575
576 #####################################################################
577 # Target directory selection
578 seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title,
579 "Next", "Next", "Cancel")
580 seldlg.title("Select Destination Directory")
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000581 c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003,
582 "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.")
583 c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""')
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000584 seldlg.text("Description", 135, 50, 220, 40, 0x30003,
585 "Please select a directory for the [ProductName] files.")
586
587 seldlg.back("< Back", None, active=0)
588 c = seldlg.next("Next >", "Cancel")
589 c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1)
590 # If the target exists, but we found that we are going to remove old versions, don't bother
591 # confirming that the target directory exists. Strictly speaking, we should determine that
592 # the target directory is indeed the target of the product that we are going to remove, but
593 # I don't know how to do that.
594 c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2)
595 c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3)
596 c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4)
597 c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5)
598
599 c = seldlg.cancel("Cancel", "DirectoryCombo")
600 c.event("SpawnDialog", "CancelDlg")
601
602 seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219,
603 "TARGETDIR", None, "DirectoryList", None)
604 seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR",
605 None, "PathEdit", None)
606 seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None)
607 c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
608 c.event("DirectoryListUp", "0")
609 c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
610 c.event("DirectoryListNew", "0")
611
612 #####################################################################
613 # SelectFeaturesDlg
614 features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space,
615 title, "Tree", "Next", "Cancel")
616 features.title("Customize [ProductName]")
617 features.text("Description", 135, 35, 220, 15, 0x30003,
618 "Select the way you want features to be installed.")
619 features.text("Text", 135,45,220,30, 3,
620 "Click on the icons in the tree below to change the way features will be installed.")
621
622 c=features.back("< Back", "Next")
623 c.event("NewDialog", "SelectDirectoryDlg")
624
625 c=features.next("Next >", "Cancel")
626 c.mapping("SelectionNoItems", "Enabled")
627 c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1)
628 c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2)
629
630 c=features.cancel("Cancel", "Tree")
631 c.event("SpawnDialog", "CancelDlg")
632
Tim Peters66cb0182004-08-26 05:23:19 +0000633 # 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 +0000634 features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty",
635 "Tree of selections", "Back", None)
636
637 #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost")
638 #c.mapping("SelectionNoItems", "Enabled")
639 #c.event("Reset", "0")
Tim Peters66cb0182004-08-26 05:23:19 +0000640
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000641 features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None)
642
643 c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10)
644 c.mapping("SelectionNoItems","Enabled")
645 c.event("SpawnDialog", "DiskCostDlg")
646
647 c=features.xbutton("Advanced", "Advanced", None, 0.30)
648 c.event("SpawnDialog", "AdvancedDlg")
649
650 c=features.text("ItemDescription", 140, 180, 210, 30, 3,
651 "Multiline description of the currently selected item.")
652 c.mapping("SelectionDescription","Text")
Tim Peters66cb0182004-08-26 05:23:19 +0000653
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000654 c=features.text("ItemSize", 140, 210, 210, 45, 3,
655 "The size of the currently selected item.")
656 c.mapping("SelectionSize", "Text")
657
658 #####################################################################
659 # Disk cost
660 cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title,
661 "OK", "OK", "OK", bitmap=False)
662 cost.text("Title", 15, 6, 200, 15, 0x30003,
663 "{\DlgFontBold8}Disk Space Requirements")
664 cost.text("Description", 20, 20, 280, 20, 0x30003,
665 "The disk space required for the installation of the selected features.")
666 cost.text("Text", 20, 53, 330, 60, 3,
667 "The highlighted volumes (if any) do not have enough disk space "
668 "available for the currently selected features. You can either "
669 "remove some files from the highlighted volumes, or choose to "
670 "install less features onto local drive(s), or select different "
671 "destination drive(s).")
672 cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223,
673 None, "{120}{70}{70}{70}{70}", None, None)
674 cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
675
676 #####################################################################
677 # WhichUsers Dialog. Only available on NT, and for privileged users.
678 # This must be run before FindRelatedProducts, because that will
679 # take into account whether the previous installation was per-user
680 # or per-machine. We currently don't support going back to this
681 # dialog after "Next" was selected; to support this, we would need to
682 # find how to reset the ALLUSERS property, and how to re-run
683 # FindRelatedProducts.
684 # On Windows9x, the ALLUSERS property is ignored on the command line
685 # and in the Property table, but installer fails according to the documentation
686 # if a dialog attempts to set ALLUSERS.
687 whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title,
688 "AdminInstall", "Next", "Cancel")
689 whichusers.title("Select whether to install [ProductName] for all users of this computer.")
690 # A radio group with two options: allusers, justme
691 g = whichusers.radiogroup("AdminInstall", 135, 60, 160, 50, 3,
692 "WhichUsers", "", "Next")
693 g.add("ALL", 0, 5, 150, 20, "Install for all users")
694 g.add("JUSTME", 0, 25, 150, 20, "Install just for me")
695
Tim Peters66cb0182004-08-26 05:23:19 +0000696 whichusers.back("Back", None, active=0)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000697
698 c = whichusers.next("Next >", "Cancel")
699 c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
700 c.event("EndDialog", "Return", order = 2)
701
702 c = whichusers.cancel("Cancel", "AdminInstall")
703 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000704
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000705 #####################################################################
706 # Advanced Dialog.
707 advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title,
708 "CompilePyc", "Next", "Cancel")
709 advanced.title("Advanced Options for [ProductName]")
710 # A radio group with two options: allusers, justme
711 advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3,
712 "COMPILEALL", "Compile .py files to byte code after installation", "Next")
713
714 c = advanced.next("Finish", "Cancel")
715 c.event("EndDialog", "Return")
716
717 c = advanced.cancel("Cancel", "CompilePyc")
718 c.event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000719
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000720 #####################################################################
Tim Peters66cb0182004-08-26 05:23:19 +0000721 # Existing Directory dialog
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000722 dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title,
723 "No", "No", "No")
724 dlg.text("Title", 10, 20, 180, 40, 3,
725 "[TARGETDIR] exists. Are you sure you want to overwrite existing files?")
726 c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No")
727 c.event("[TargetExists]", "0", order=1)
728 c.event("[TargetExistsOk]", "1", order=2)
729 c.event("EndDialog", "Return", order=3)
730 c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes")
731 c.event("EndDialog", "Return")
732
733 #####################################################################
734 # Installation Progress dialog (modeless)
735 progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title,
736 "Cancel", "Cancel", "Cancel", bitmap=False)
737 progress.text("Title", 20, 15, 200, 15, 0x30003,
738 "{\DlgFontBold8}[Progress1] [ProductName]")
739 progress.text("Text", 35, 65, 300, 30, 3,
740 "Please wait while the Installer [Progress2] [ProductName]. "
741 "This may take several minutes.")
742 progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
743
744 c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...")
745 c.mapping("ActionText", "Text")
746
747 #c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
748 #c.mapping("ActionData", "Text")
749
750 c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537,
751 None, "Progress done", None, None)
752 c.mapping("SetProgress", "Progress")
753
754 progress.back("< Back", "Next", active=False)
755 progress.next("Next >", "Cancel", active=False)
756 progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
757
758 # Maintenance type: repair/uninstall
759 maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title,
760 "Next", "Next", "Cancel")
761 maint.title("Welcome to the [ProductName] Setup Wizard")
762 maint.text("BodyText", 135, 63, 230, 42, 3,
763 "Select whether you want to repair or remove [ProductName].")
764 g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3,
765 "MaintenanceForm_Action", "", "Next")
766 g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
767 g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
768 g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
Tim Peters66cb0182004-08-26 05:23:19 +0000769
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000770 maint.back("< Back", None, active=False)
771 c=maint.next("Finish", "Cancel")
772 # Change installation: Change progress dialog to "Change", then ask
773 # for feature selection
774 c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
775 c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
776
777 # Reinstall: Change progress dialog to "Repair", then invoke reinstall
778 # Also set list of reinstalled features to "ALL"
779 c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
780 c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
Raymond Hettinger72f08012004-11-07 07:08:25 +0000781 c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000782 c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
783
784 # Uninstall: Change progress to "Remove", then invoke uninstall
785 # Also set list of removed features to "ALL"
786 c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
787 c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
788 c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
789 c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
790
Tim Peters66cb0182004-08-26 05:23:19 +0000791 # Close dialog when maintenance action scheduled
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000792 c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
793 c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21)
Tim Peters66cb0182004-08-26 05:23:19 +0000794
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000795 maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
Tim Peters66cb0182004-08-26 05:23:19 +0000796
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000797
798# See "Feature Table". The feature level is 1 for all features,
799# and the feature attributes are 0 for the DefaultFeature, and
800# FollowParent for all other features. The numbers are the Display
801# column.
802def add_features(db):
803 # feature attributes:
804 # msidbFeatureAttributesFollowParent == 2
805 # msidbFeatureAttributesDisallowAdvertise == 8
806 # Features that need to be installed with together with the main feature
807 # (i.e. additional Python libraries) need to follow the parent feature.
808 # Features that have no advertisement trigger (e.g. the test suite)
809 # must not support advertisement
Martin v. Löwise411f892008-04-07 14:54:16 +0000810 global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000811 default_feature = Feature(db, "DefaultFeature", "Python",
812 "Python Interpreter and Libraries",
813 1, directory = "TARGETDIR")
Martin v. Löwis4dc34152008-04-05 15:48:36 +0000814 shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0,
815 level=0)
816 private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0,
817 level=0)
818 add_data(db, "Condition", [("SharedCRT", 1, sys32cond),
819 ("PrivateCRT", 1, "not "+sys32cond)])
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000820 # We don't support advertisement of extensions
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000821 ext_feature = Feature(db, "Extensions", "Register Extensions",
822 "Make this Python installation the default Python installation", 3,
Martin v. Löwisdff68d02004-09-10 09:20:10 +0000823 parent = default_feature, attributes=2|8)
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000824 if have_tcl:
825 tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000826 parent = default_feature, attributes=2)
827 htmlfiles = Feature(db, "Documentation", "Documentation",
828 "Python HTMLHelp File", 7, parent = default_feature)
829 tools = Feature(db, "Tools", "Utility Scripts",
Tim Peters66cb0182004-08-26 05:23:19 +0000830 "Python utility scripts (Tools/", 9,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000831 parent = default_feature, attributes=2)
832 testsuite = Feature(db, "Testsuite", "Test suite",
833 "Python test suite (Lib/test/)", 11,
834 parent = default_feature, attributes=2|8)
Tim Peters66cb0182004-08-26 05:23:19 +0000835
Christian Heimes9acba042007-12-04 14:57:30 +0000836def extract_msvcr90():
Martin v. Löwis03dc56c2008-02-28 22:20:50 +0000837 # Find the redistributable files
838 dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\x86\Microsoft.VC90.CRT")
Christian Heimes9acba042007-12-04 14:57:30 +0000839
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000840 result = []
Christian Heimes9acba042007-12-04 14:57:30 +0000841 installer = msilib.MakeInstaller()
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000842 # omit msvcm90 and msvcp90, as they aren't really needed
843 files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"]
844 for f in files:
845 path = os.path.join(dir, f)
846 kw = {'src':path}
847 if f.endswith('.dll'):
848 kw['version'] = installer.FileVersion(path, 0)
849 kw['language'] = installer.FileVersion(path, 1)
850 result.append((f, kw))
851 return result
Christian Heimes9acba042007-12-04 14:57:30 +0000852
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000853def generate_license():
854 import shutil, glob
855 out = open("LICENSE.txt", "w")
856 shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out)
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000857 for name, pat, file in (("bzip2","bzip2-*", "LICENSE"),
858 ("Berkeley DB", "db-*", "LICENSE"),
859 ("openssl", "openssl-*", "LICENSE"),
860 ("Tcl", "tcl8*", "license.terms"),
861 ("Tk", "tk8*", "license.terms"),
862 ("Tix", "tix-*", "license.terms")):
863 out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name)
864 dirs = glob.glob(srcdir+"/../"+pat)
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000865 if not dirs:
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000866 raise ValueError, "Could not find "+srcdir+"/../"+pat
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000867 if len(dirs) > 2:
Martin v. Löwisb8a18ea2008-06-12 20:07:53 +0000868 raise ValueError, "Multiple copies of "+pat
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000869 dir = dirs[0]
870 shutil.copyfileobj(open(os.path.join(dir, file)), out)
871 out.close()
872
873
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000874class PyDirectory(Directory):
875 """By default, all components in the Python installer
876 can run from source."""
877 def __init__(self, *args, **kw):
878 if not kw.has_key("componentflags"):
879 kw['componentflags'] = 2 #msidbComponentAttributesOptional
880 Directory.__init__(self, *args, **kw)
881
882# See "File Table", "Component Table", "Directory Table",
883# "FeatureComponents Table"
884def add_files(db):
885 cab = CAB("python")
886 tmpfiles = []
887 # Add all executables, icons, text files into the TARGETDIR component
888 root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir")
889 default_feature.set_current()
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000890 if not msilib.Win64:
Christian Heimes9acba042007-12-04 14:57:30 +0000891 root.add_file("%s/w9xpopen.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000892 root.add_file("README.txt", src="README")
893 root.add_file("NEWS.txt", src="Misc/NEWS")
Martin v. Löwisdcc86202008-05-25 11:56:23 +0000894 generate_license()
895 root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt"))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000896 root.start_component("python.exe", keyfile="python.exe")
Christian Heimes9acba042007-12-04 14:57:30 +0000897 root.add_file("%s/python.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000898 root.start_component("pythonw.exe", keyfile="pythonw.exe")
Christian Heimes9acba042007-12-04 14:57:30 +0000899 root.add_file("%s/pythonw.exe" % PCBUILD)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000900
901 # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000902 #dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
903 #install python30.dll into root dir for now
904 dlldir = root
905
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000906 pydll = "python%s%s.dll" % (major, minor)
Christian Heimes9acba042007-12-04 14:57:30 +0000907 pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
Martin v. Löwis141f41a2005-03-15 00:39:40 +0000908 dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000909 installer = msilib.MakeInstaller()
910 pyversion = installer.FileVersion(pydllsrc, 0)
911 if not snapshot:
912 # For releases, the Python DLL has the same version as the
913 # installer package.
914 assert pyversion.split(".")[:3] == current_version.split(".")
Christian Heimes9acba042007-12-04 14:57:30 +0000915 dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000916 version=pyversion,
917 language=installer.FileVersion(pydllsrc, 1))
Martin v. Löwisd9759c42008-02-28 19:57:34 +0000918 DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs")
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000919
920 # msvcr90.dll: Need to place the DLL and the manifest into the root directory,
921 # plus another copy of the manifest in the DLLs directory, with the manifest
922 # pointing to the root directory
Martin v. Löwis46a8be72008-04-07 14:55:53 +0000923 root.start_component("msvcr90", feature=private_crt)
Martin v. Löwis1e72fec2008-04-07 16:34:04 +0000924 # Results are ID,keyword pairs
925 manifest, crtdll = extract_msvcr90()
926 root.add_file(manifest[0], **manifest[1])
927 root.add_file(crtdll[0], **crtdll[1])
928 # Copy the manifest
929 manifest_dlls = manifest[0]+".root"
930 open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr"))
931 DLLs.start_component("msvcr90_dlls", feature=private_crt)
932 DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls))
933
934 # Now start the main component for the DLLs directory;
935 # no regular files have been added to the directory yet.
936 DLLs.start_component()
Tim Peters66cb0182004-08-26 05:23:19 +0000937
Martin v. Löwis38325b72006-08-25 00:03:34 +0000938 # Check if _ctypes.pyd exists
Christian Heimes9acba042007-12-04 14:57:30 +0000939 have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD)
Martin v. Löwis38325b72006-08-25 00:03:34 +0000940 if not have_ctypes:
941 print "WARNING: _ctypes.pyd not found, ctypes will not be included"
942 extensions.remove("_ctypes.pyd")
Tim Peters147f9ae2006-08-25 22:05:39 +0000943
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000944 # Add all .py files in Lib, except lib-tk, test
945 dirs={}
946 pydirs = [(root,"Lib")]
947 while pydirs:
Martin v. Löwisc9798fc2008-06-13 18:58:47 +0000948 # Commit every now and then, or else installer will complain
949 db.Commit()
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000950 parent, dir = pydirs.pop()
Martin v. Löwis9ca9f562006-01-03 06:29:53 +0000951 if dir == ".svn" or dir.startswith("plat-"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000952 continue
Georg Brandl6634bf22008-05-20 07:13:37 +0000953 elif dir in ["lib-tk", "idlelib", "Icons"]:
Martin v. Löwise0f780d2004-09-01 14:51:06 +0000954 if not have_tcl:
955 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000956 tcltk.set_current()
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +0000957 elif dir in ['test', 'tests', 'data', 'output']:
Martin v. Löwis59c3acc2006-04-03 12:07:46 +0000958 # test: Lib, Lib/email, Lib/bsddb, Lib/ctypes, Lib/sqlite3
Martin v. Löwis5c9e55e2004-12-30 14:08:18 +0000959 # tests: Lib/distutils
960 # data: Lib/email/test
961 # output: Lib/test
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000962 testsuite.set_current()
Martin v. Löwis38325b72006-08-25 00:03:34 +0000963 elif not have_ctypes and dir == "ctypes":
964 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000965 else:
966 default_feature.set_current()
967 lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
968 # Add additional files
969 dirs[dir]=lib
970 lib.glob("*.txt")
971 if dir=='site-packages':
Martin v. Löwis6d60c092004-11-21 10:16:26 +0000972 lib.add_file("README.txt", src="README")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000973 continue
974 files = lib.glob("*.py")
975 files += lib.glob("*.pyw")
976 if files:
977 # Add an entry to the RemoveFile table to remove bytecode files.
978 lib.remove_pyc()
Martin v. Löwis64ed0432006-04-21 10:00:46 +0000979 if dir.endswith('.egg-info'):
980 lib.add_file('entry_points.txt')
981 lib.add_file('PKG-INFO')
982 lib.add_file('top_level.txt')
983 lib.add_file('zip-safe')
984 continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000985 if dir=='test' and parent.physical=='Lib':
986 lib.add_file("185test.db")
987 lib.add_file("audiotest.au")
988 lib.add_file("cfgparser.1")
Martin v. Löwisc0fdb182006-09-12 19:49:20 +0000989 lib.add_file("sgml_input.html")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000990 lib.add_file("test.xml")
991 lib.add_file("test.xml.out")
992 lib.add_file("testtar.tar")
Martin v. Löwis7d3755d2004-09-06 06:31:12 +0000993 lib.add_file("test_difflib_expect.html")
Martin v. Löwis59c3acc2006-04-03 12:07:46 +0000994 lib.add_file("check_soundcard.vbs")
Thomas Heller3bd33152006-04-04 18:41:13 +0000995 lib.add_file("empty.vbs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000996 lib.glob("*.uue")
Martin v. Löwis0ffdacd2007-11-20 02:46:02 +0000997 lib.glob("*.pem")
Martin v. Löwis6b449f42007-12-03 19:20:02 +0000998 lib.glob("*.pck")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +0000999 lib.add_file("readme.txt", src="README")
1000 if dir=='decimaltestdata':
1001 lib.glob("*.decTest")
1002 if dir=='output':
1003 lib.glob("test_*")
1004 if dir=='idlelib':
1005 lib.glob("*.def")
1006 lib.add_file("idle.bat")
1007 if dir=="Icons":
1008 lib.glob("*.gif")
1009 lib.add_file("idle.icns")
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001010 if dir=="command" and parent.physical=="distutils":
Martin v. Löwis023b9f92008-04-09 18:56:20 +00001011 lib.glob("wininst*.exe")
Martin v. Löwis64ed0432006-04-21 10:00:46 +00001012 if dir=="setuptools":
1013 lib.add_file("cli.exe")
1014 lib.add_file("gui.exe")
Martin v. Löwis367c79a2008-05-25 16:37:34 +00001015 if dir=="lib2to3":
1016 lib.removefile("pickle", "*.pickle")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001017 if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email":
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001018 # This should contain all non-.svn files listed in subversion
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001019 for f in os.listdir(lib.absolute):
Martin v. Löwis9ca9f562006-01-03 06:29:53 +00001020 if f.endswith(".txt") or f==".svn":continue
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001021 if f.endswith(".au") or f.endswith(".gif"):
1022 lib.add_file(f)
1023 else:
1024 print "WARNING: New file %s in email/test/data" % f
1025 for f in os.listdir(lib.absolute):
1026 if os.path.isdir(os.path.join(lib.absolute, f)):
1027 pydirs.append((lib, f))
1028 # Add DLLs
1029 default_feature.set_current()
Martin v. Löwisd9759c42008-02-28 19:57:34 +00001030 lib = DLLs
Christian Heimes7e28e492008-01-01 13:52:57 +00001031 lib.add_file("py.ico", src=srcdir+"/PC/py.ico")
Christian Heimese1c6af02008-01-01 13:58:16 +00001032 lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001033 dlls = []
1034 tclfiles = []
1035 for f in extensions:
1036 if f=="_tkinter.pyd":
1037 continue
Christian Heimes9acba042007-12-04 14:57:30 +00001038 if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001039 print "WARNING: Missing extension", f
1040 continue
1041 dlls.append(f)
1042 lib.add_file(f)
Martin v. Löwis88ef6372006-07-06 06:55:58 +00001043 # Add sqlite
1044 if msilib.msi_type=="Intel64;1033":
1045 sqlite_arch = "/ia64"
1046 elif msilib.msi_type=="x64;1033":
1047 sqlite_arch = "/amd64"
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001048 tclsuffix = "64"
Martin v. Löwis88ef6372006-07-06 06:55:58 +00001049 else:
1050 sqlite_arch = ""
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001051 tclsuffix = ""
Martin v. Löwisc9798fc2008-06-13 18:58:47 +00001052 lib.add_file("sqlite3.dll")
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001053 if have_tcl:
Christian Heimes9acba042007-12-04 14:57:30 +00001054 if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)):
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001055 print "WARNING: Missing _tkinter.pyd"
1056 else:
1057 lib.start_component("TkDLLs", tcltk)
1058 lib.add_file("_tkinter.pyd")
1059 dlls.append("_tkinter.pyd")
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001060 tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001061 for f in glob.glob1(tcldir, "*.dll"):
1062 lib.add_file(f, src=os.path.join(tcldir, f))
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001063 # check whether there are any unknown extensions
Christian Heimes9acba042007-12-04 14:57:30 +00001064 for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001065 if f.endswith("_d.pyd"): continue # debug version
1066 if f in dlls: continue
1067 print "WARNING: Unknown extension", f
Tim Peters66cb0182004-08-26 05:23:19 +00001068
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001069 # Add headers
1070 default_feature.set_current()
1071 lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include")
1072 lib.glob("*.h")
1073 lib.add_file("pyconfig.h", src="../PC/pyconfig.h")
1074 # Add import libraries
Christian Heimes9acba042007-12-04 14:57:30 +00001075 lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001076 for f in dlls:
1077 lib.add_file(f.replace('pyd','lib'))
1078 lib.add_file('python%s%s.lib' % (major, minor))
Martin v. Löwis9fda9312004-12-22 13:41:49 +00001079 # Add the mingw-format library
1080 if have_mingw:
Tim Peters5a9fb3c2005-01-07 16:01:32 +00001081 lib.add_file('libpython%s%s.a' % (major, minor))
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001082 if have_tcl:
1083 # Add Tcl/Tk
Martin v. Löwis0e795e72008-02-29 20:54:44 +00001084 tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')]
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001085 tcltk.set_current()
1086 while tcldirs:
1087 parent, phys, dir = tcldirs.pop()
1088 lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir))
1089 if not os.path.exists(lib.absolute):
1090 continue
1091 for f in os.listdir(lib.absolute):
1092 if os.path.isdir(os.path.join(lib.absolute, f)):
1093 tcldirs.append((lib, f, f))
1094 else:
1095 lib.add_file(f)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001096 # Add tools
1097 tools.set_current()
1098 tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools")
1099 for f in ['i18n', 'pynche', 'Scripts', 'versioncheck', 'webchecker']:
1100 lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f))
1101 lib.glob("*.py")
1102 lib.glob("*.pyw", exclude=['pydocgui.pyw'])
1103 lib.remove_pyc()
1104 lib.glob("*.txt")
1105 if f == "pynche":
1106 x = PyDirectory(db, cab, lib, "X", "X", "X|X")
1107 x.glob("*.txt")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001108 if os.path.exists(os.path.join(lib.absolute, "README")):
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001109 lib.add_file("README.txt", src="README")
Martin v. Löwis4d930be2004-12-01 21:46:35 +00001110 if f == 'Scripts':
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001111 if have_tcl:
1112 lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
1113 lib.add_file("pydocgui.pyw")
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001114 # Add documentation
1115 htmlfiles.set_current()
1116 lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc")
Martin v. Löwis344d0662008-05-09 18:21:55 +00001117 lib.start_component("documentation", keyfile=docfile)
1118 lib.add_file(docfile, src="build/htmlhelp/"+docfile)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001119
1120 cab.commit(db)
1121
1122 for f in tmpfiles:
1123 os.unlink(f)
1124
1125# See "Registry Table", "Component Table"
1126def add_registry(db):
1127 # File extensions, associated with the REGISTRY.def component
1128 # IDLE verbs depend on the tcltk feature.
1129 # msidbComponentAttributesRegistryKeyPath = 4
1130 # -1 for Root specifies "dependent on ALLUSERS property"
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001131 tcldata = []
1132 if have_tcl:
1133 tcldata = [
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001134 ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001135 "py.IDLE")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001136 add_data(db, "Component",
1137 # msidbComponentAttributesRegistryKeyPath = 4
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001138 [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001139 "InstallPath"),
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001140 ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001141 "Documentation"),
Martin v. Löwis1ab4a1f2007-08-31 10:01:07 +00001142 ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001143 None, None)] + tcldata)
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001144 # See "FeatureComponents Table".
1145 # The association between TclTk and pythonw.exe is necessary to make ICE59
1146 # happy, because the installer otherwise believes that the IDLE and PyDoc
1147 # shortcuts might get installed without pythonw.exe being install. This
1148 # is not true, since installing TclTk will install the default feature, which
1149 # will cause pythonw.exe to be installed.
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001150 # REGISTRY.tcl is not associated with any feature, as it will be requested
1151 # through a custom action
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001152 tcldata = []
1153 if have_tcl:
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001154 tcldata = [(tcltk.id, "pythonw.exe")]
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001155 add_data(db, "FeatureComponents",
1156 [(default_feature.id, "REGISTRY"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001157 (htmlfiles.id, "REGISTRY.doc"),
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001158 (ext_feature.id, "REGISTRY.def")] +
1159 tcldata
1160 )
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001161 # Extensions are not advertised. For advertised extensions,
1162 # we would need separate binaries that install along with the
1163 # extension.
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001164 pat = r"Software\Classes\%sPython.%sFile\shell\%s\command"
1165 ewi = "Edit with IDLE"
1166 pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon"
1167 pat3 = r"Software\Classes\%sPython.%sFile"
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001168 tcl_verbs = []
1169 if have_tcl:
1170 tcl_verbs=[
1171 ("py.IDLE", -1, pat % (testprefix, "", ewi), "",
1172 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"',
1173 "REGISTRY.tcl"),
1174 ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "",
1175 r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"',
1176 "REGISTRY.tcl"),
1177 ]
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001178 add_data(db, "Registry",
1179 [# Extensions
1180 ("py.ext", -1, r"Software\Classes\."+ext, "",
1181 "Python.File", "REGISTRY.def"),
1182 ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "",
1183 "Python.NoConFile", "REGISTRY.def"),
1184 ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "",
1185 "Python.CompiledFile", "REGISTRY.def"),
1186 ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "",
1187 "Python.CompiledFile", "REGISTRY.def"),
1188 # MIME types
1189 ("py.mime", -1, r"Software\Classes\."+ext, "Content Type",
1190 "text/plain", "REGISTRY.def"),
1191 ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type",
1192 "text/plain", "REGISTRY.def"),
1193 #Verbs
1194 ("py.open", -1, pat % (testprefix, "", "open"), "",
1195 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
1196 ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
1197 r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"),
1198 ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
1199 r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
Martin v. Löwiseac02e62004-11-18 08:00:33 +00001200 ] + tcl_verbs + [
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001201 #Icons
1202 ("py.icon", -1, pat2 % (testprefix, ""), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001203 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001204 ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001205 r'[DLLs]py.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001206 ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "",
Martin v. Löwis1319bb12006-05-12 13:57:36 +00001207 r'[DLLs]pyc.ico', "REGISTRY.def"),
Martin v. Löwisdff68d02004-09-10 09:20:10 +00001208 # Descriptions
1209 ("py.txt", -1, pat3 % (testprefix, ""), "",
1210 "Python File", "REGISTRY.def"),
1211 ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "",
1212 "Python File (no console)", "REGISTRY.def"),
1213 ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "",
1214 "Compiled Python File", "REGISTRY.def"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001215 ])
Tim Peters66cb0182004-08-26 05:23:19 +00001216
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001217 # Registry keys
1218 prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version)
1219 add_data(db, "Registry",
1220 [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"),
1221 ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "",
1222 "Python %s" % short_version, "REGISTRY"),
1223 ("PythonPath", -1, prefix+r"\PythonPath", "",
Martin v. Löwisf13337d2004-09-19 18:36:45 +00001224 r"[TARGETDIR]Lib;[TARGETDIR]DLLs;[TARGETDIR]Lib\lib-tk", "REGISTRY"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001225 ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "",
Martin v. Löwis344d0662008-05-09 18:21:55 +00001226 "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001227 ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"),
1228 ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe",
1229 "", r"[TARGETDIR]Python.exe", "REGISTRY.def")
1230 ])
1231 # Shortcuts, see "Shortcut Table"
1232 add_data(db, "Directory",
1233 [("ProgramMenuFolder", "TARGETDIR", "."),
1234 ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))])
1235 add_data(db, "RemoveFile",
1236 [("MenuDir", "TARGETDIR", None, "MenuDir", 2)])
Martin v. Löwise0f780d2004-09-01 14:51:06 +00001237 tcltkshortcuts = []
1238 if have_tcl:
1239 tcltkshortcuts = [
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001240 ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001241 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 +00001242 ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe",
Martin v. Löwisac191da2004-12-22 12:55:44 +00001243 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 +00001244 ]
1245 add_data(db, "Shortcut",
1246 tcltkshortcuts +
1247 [# Advertised shortcuts: targets are features, not files
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001248 ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe",
1249 default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"),
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001250 # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an
1251 # icon first.
1252 #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation",
1253 # htmlfiles.id, None, None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001254 ## Non-advertised shortcuts: must be associated with a registry component
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001255 ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc",
Martin v. Löwis344d0662008-05-09 18:21:55 +00001256 "[#%s]" % docfile, None,
Martin v. Löwis141f41a2005-03-15 00:39:40 +00001257 None, None, None, None, None, None),
Martin v. Löwis8ffe9ab2004-08-22 13:34:34 +00001258 ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY",
1259 SystemFolderName+"msiexec", "/x%s" % product_code,
1260 None, None, None, None, None, None),
1261 ])
1262 db.Commit()
1263
1264db = build_database()
1265try:
1266 add_features(db)
1267 add_ui(db)
1268 add_files(db)
1269 add_registry(db)
1270 remove_old_versions(db)
1271 db.Commit()
1272finally:
1273 del db