summaryrefslogtreecommitdiffstats
path: root/Tools/msi
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/msi')
-rw-r--r--Tools/msi/msi.py270
-rw-r--r--Tools/msi/msilib.py18
-rw-r--r--Tools/msi/uuids.py99
3 files changed, 143 insertions, 244 deletions
diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py
index 508816d..2ec6951 100644
--- a/Tools/msi/msi.py
+++ b/Tools/msi/msi.py
@@ -2,12 +2,11 @@
# (C) 2003 Martin v. Loewis
# See "FOO" in comments refers to MSDN sections with the title FOO.
import msilib, schema, sequence, os, glob, time, re, shutil, zipfile
+import subprocess, tempfile
from msilib import Feature, CAB, Directory, Dialog, Binary, add_data
import uisample
from win32com.client import constants
from distutils.spawn import find_executable
-from uuids import product_codes
-import tempfile
# Settings can be overridden in config.py below
# 0 for official python.org releases
@@ -28,7 +27,7 @@ have_tcl = True
# path to PCbuild directory
PCBUILD="PCbuild"
# msvcrt version
-MSVCR = "90"
+MSVCR = "100"
# Name of certificate in default store to sign MSI with
certname = None
# Make a zip file containing the PDB files for this build?
@@ -77,19 +76,16 @@ upgrade_code_64='{6A965A0C-6EE6-4E3A-9983-3263F56311EC}'
if snapshot:
current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24))
- product_code = msilib.gen_uuid()
-else:
- product_code = product_codes[current_version]
if full_current_version is None:
full_current_version = current_version
extensions = [
- 'bz2.pyd',
'pyexpat.pyd',
'select.pyd',
'unicodedata.pyd',
'winsound.pyd',
+ '_bz2.pyd',
'_elementtree.pyd',
'_socket.pyd',
'_ssl.pyd',
@@ -100,7 +96,10 @@ extensions = [
'_ctypes_test.pyd',
'_sqlite3.pyd',
'_hashlib.pyd',
- '_multiprocessing.pyd'
+ '_multiprocessing.pyd',
+ '_lzma.pyd',
+ '_decimal.pyd',
+ '_testbuffer.pyd'
]
# Well-known component UUIDs
@@ -119,12 +118,11 @@ pythondll_uuid = {
"30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}",
"31":"{4afcba0b-13e4-47c3-bebe-477428b46913}",
"32":"{3ff95315-1096-4d31-bd86-601d5438ad5e}",
+ "33":"{f7581ca4-d368-4eea-8f82-d48c64c4f047}",
} [major+minor]
# Compute the name that Sphinx gives to the docfile
-docfile = ""
-if int(micro):
- docfile = micro
+docfile = micro
if level < 0xf:
if level == 0xC:
docfile += "rc%s" % (serial,)
@@ -185,12 +183,19 @@ dll_path = os.path.join(srcdir, PCBUILD, dll_file)
msilib.set_arch_from_file(dll_path)
if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"):
raise SystemError("msisupport.dll for incorrect architecture")
+
if msilib.Win64:
upgrade_code = upgrade_code_64
- # Bump the last digit of the code by one, so that 32-bit and 64-bit
- # releases get separate product codes
- digit = hex((int(product_code[-2],16)+1)%16)[-1]
- product_code = product_code[:-2] + digit + '}'
+
+if snapshot:
+ product_code = msilib.gen_uuid()
+else:
+ # official release: generate UUID from the download link that the file will have
+ import uuid
+ product_code = uuid.uuid3(uuid.NAMESPACE_URL,
+ 'http://www.python.org/ftp/python/%s.%s.%s/python-%s%s.msi' %
+ (major, minor, micro, full_current_version, msilib.arch_ext))
+ product_code = '{%s}' % product_code
if testpackage:
ext = 'px'
@@ -281,7 +286,7 @@ def remove_old_versions(db):
None, migrate_features, None, "REMOVEOLDSNAPSHOT")])
props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION"
- props += ";TARGETDIR;DLLDIR"
+ props += ";TARGETDIR;DLLDIR;LAUNCHERDIR"
# Installer collects the product codes of the earlier releases in
# these properties. In order to allow modification of the properties,
# they must be declared as secure. See "SecureCustomProperties Property"
@@ -410,7 +415,7 @@ def add_ui(db):
("VerdanaRed9", "Verdana", 9, 255, 0),
])
- compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests" "[TARGETDIR]Lib"'
+ compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TARGETDIR]Lib"'
lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"'
# See "CustomAction Table"
add_data(db, "CustomAction", [
@@ -421,6 +426,8 @@ def add_ui(db):
"[WindowsVolume]Python%s%s" % (major, minor)),
("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"),
("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName),
+ ("SetLauncherDirToTarget", 307, "LAUNCHERDIR", "[TARGETDIR]"),
+ ("SetLauncherDirToWindows", 307, "LAUNCHERDIR", "[WindowsFolder]"),
# msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile
# See "Custom Action Type 18"
("CompilePyc", 18, "python.exe", compileargs),
@@ -437,6 +444,8 @@ def add_ui(db):
# In the user interface, assume all-users installation if privileged.
("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
+ ("SetLauncherDirToWindows", 'LAUNCHERDIR="" and ' + sys32cond, 753),
+ ("SetLauncherDirToTarget", 'LAUNCHERDIR="" and not ' + sys32cond, 754),
("SelectDirectoryDlg", "Not Installed", 1230),
# XXX no support for resume installations yet
#("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
@@ -445,13 +454,20 @@ def add_ui(db):
add_data(db, "AdminUISequence",
[("InitialTargetDir", 'TARGETDIR=""', 750),
("SetDLLDirToTarget", 'DLLDIR=""', 751),
+ ("SetLauncherDirToTarget", 'LAUNCHERDIR=""', 752),
])
+ # Prepend TARGETDIR to the system path, and remove it on uninstall.
+ add_data(db, "Environment",
+ [("PathAddition", "=-*Path", "[TARGETDIR];[~]", "REGISTRY.path")])
+
# Execute Sequences
add_data(db, "InstallExecuteSequence",
[("InitialTargetDir", 'TARGETDIR=""', 750),
("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751),
("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752),
+ ("SetLauncherDirToWindows", 'LAUNCHERDIR="" and ' + sys32cond, 753),
+ ("SetLauncherDirToTarget", 'LAUNCHERDIR="" and not ' + sys32cond, 754),
("UpdateEditIDLE", None, 1050),
("CompilePyc", "COMPILEALL", 6800),
("CompilePyo", "COMPILEALL", 6801),
@@ -460,6 +476,7 @@ def add_ui(db):
add_data(db, "AdminExecuteSequence",
[("InitialTargetDir", 'TARGETDIR=""', 750),
("SetDLLDirToTarget", 'DLLDIR=""', 751),
+ ("SetLauncherDirToTarget", 'LAUNCHERDIR=""', 752),
("CompilePyc", "COMPILEALL", 6800),
("CompilePyo", "COMPILEALL", 6801),
("CompileGrammar", "COMPILEALL", 6802),
@@ -670,11 +687,11 @@ def add_ui(db):
c=features.xbutton("Advanced", "Advanced", None, 0.30)
c.event("SpawnDialog", "AdvancedDlg")
- c=features.text("ItemDescription", 140, 180, 210, 30, 3,
+ c=features.text("ItemDescription", 140, 180, 210, 40, 3,
"Multiline description of the currently selected item.")
c.mapping("SelectionDescription","Text")
- c=features.text("ItemSize", 140, 210, 210, 45, 3,
+ c=features.text("ItemSize", 140, 225, 210, 33, 3,
"The size of the currently selected item.")
c.mapping("SelectionSize", "Text")
@@ -828,7 +845,7 @@ def add_features(db):
# (i.e. additional Python libraries) need to follow the parent feature.
# Features that have no advertisement trigger (e.g. the test suite)
# must not support advertisement
- global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt
+ global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt, prepend_path
default_feature = Feature(db, "DefaultFeature", "Python",
"Python Interpreter and Libraries",
1, directory = "TARGETDIR")
@@ -848,32 +865,38 @@ def add_features(db):
htmlfiles = Feature(db, "Documentation", "Documentation",
"Python HTMLHelp File", 7, parent = default_feature)
tools = Feature(db, "Tools", "Utility Scripts",
- "Python utility scripts (Tools/", 9,
+ "Python utility scripts (Tools/)", 9,
parent = default_feature, attributes=2)
testsuite = Feature(db, "Testsuite", "Test suite",
"Python test suite (Lib/test/)", 11,
parent = default_feature, attributes=2|8)
-
-def extract_msvcr90():
+ # prepend_path is an additional feature which is to be off by default.
+ # Since the default level for the above features is 1, this needs to be
+ # at least level higher.
+ prepend_path = Feature(db, "PrependPath", "Add python.exe to Path",
+ "Prepend [TARGETDIR] to the system Path variable. "
+ "This allows you to type 'python' into a command "
+ "prompt without needing the full path.", 13,
+ parent = default_feature, attributes=2|8,
+ level=2)
+
+def extract_msvcr100():
# Find the redistributable files
if msilib.Win64:
- arch = "amd64"
+ arch = "x64"
else:
arch = "x86"
- dir = os.path.join(os.environ['VS90COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC90.CRT" % arch)
+ dir = os.path.join(os.environ['VS100COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC100.CRT" % arch)
result = []
installer = msilib.MakeInstaller()
- # omit msvcm90 and msvcp90, as they aren't really needed
- files = ["Microsoft.VC90.CRT.manifest", "msvcr90.dll"]
- for f in files:
- path = os.path.join(dir, f)
- kw = {'src':path}
- if f.endswith('.dll'):
- kw['version'] = installer.FileVersion(path, 0)
- kw['language'] = installer.FileVersion(path, 1)
- result.append((f, kw))
- return result
+ # At least for VS2010, manifests are no longer provided
+ name = "msvcr100.dll"
+ path = os.path.join(dir, name)
+ kw = {'src':path}
+ kw['version'] = installer.FileVersion(path, 0)
+ kw['language'] = installer.FileVersion(path, 1)
+ return name, kw
def generate_license():
import shutil, glob
@@ -889,7 +912,7 @@ def generate_license():
dirs = glob.glob(srcdir+"/../"+pat)
if not dirs:
raise ValueError, "Could not find "+srcdir+"/../"+pat
- if len(dirs) > 2:
+ if len(dirs) > 2 and not snapshot:
raise ValueError, "Multiple copies of "+pat
dir = dirs[0]
shutil.copyfileobj(open(os.path.join(dir, file)), out)
@@ -904,16 +927,28 @@ class PyDirectory(Directory):
kw['componentflags'] = 2 #msidbComponentAttributesOptional
Directory.__init__(self, *args, **kw)
- def check_unpackaged(self):
- self.unpackaged_files.discard('__pycache__')
- self.unpackaged_files.discard('.svn')
- if self.unpackaged_files:
- print "Warning: Unpackaged files in %s" % self.absolute
- print self.unpackaged_files
+def hgmanifest():
+ # Fetch file list from Mercurial
+ process = subprocess.Popen(['hg', 'manifest'], stdout=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ # Create nested directories for file tree
+ result = {}
+ for line in stdout.splitlines():
+ components = line.split('/')
+ d = result
+ while len(components) > 1:
+ d1 = d.setdefault(components[0], {})
+ d = d1
+ del components[0]
+ d[components[0]] = None
+ return result
+
# See "File Table", "Component Table", "Directory Table",
# "FeatureComponents Table"
def add_files(db):
+ installer = msilib.MakeInstaller()
+ hgfiles = hgmanifest()
cab = CAB("python")
tmpfiles = []
# Add all executables, icons, text files into the TARGETDIR component
@@ -932,11 +967,32 @@ def add_files(db):
# msidbComponentAttributesSharedDllRefCount = 8, see "Component Table"
dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".")
+ launcherdir = PyDirectory(db, cab, root, srcdir, "LAUNCHERDIR", ".")
+
+ # msidbComponentAttributes64bit = 256; this disables registry redirection
+ # to allow setting the SharedDLLs key in the 64-bit portion even for a
+ # 32-bit installer.
+ # XXX does this still allow to install the component on a 32-bit system?
+ # Pick up 32-bit binary always
+ launchersrc = PCBUILD
+ if launchersrc.lower() == 'pcbuild\\x64-pgo':
+ launchersrc = 'PCBuild\\win32-pgo'
+ if launchersrc.lower() == 'pcbuild\\amd64':
+ launchersrc = 'PCBuild'
+ launcher = os.path.join(srcdir, launchersrc, "py.exe")
+ launcherdir.start_component("launcher", flags = 8+256, keyfile="py.exe")
+ launcherdir.add_file(launcher,
+ version=installer.FileVersion(launcher, 0),
+ language=installer.FileVersion(launcher, 1))
+ launcherw = os.path.join(srcdir, launchersrc, "pyw.exe")
+ launcherdir.start_component("launcherw", flags = 8+256, keyfile="pyw.exe")
+ launcherdir.add_file(launcherw,
+ version=installer.FileVersion(launcherw, 0),
+ language=installer.FileVersion(launcherw, 1))
pydll = "python%s%s.dll" % (major, minor)
pydllsrc = os.path.join(srcdir, PCBUILD, pydll)
dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid)
- installer = msilib.MakeInstaller()
pyversion = installer.FileVersion(pydllsrc, 0)
if not snapshot:
# For releases, the Python DLL has the same version as the
@@ -952,9 +1008,8 @@ def add_files(db):
# pointing to the root directory
root.start_component("msvcr90", feature=private_crt)
# Results are ID,keyword pairs
- manifest, crtdll = extract_msvcr90()
- root.add_file(manifest[0], **manifest[1])
- root.add_file(crtdll[0], **crtdll[1])
+ crtdll, kwds = extract_msvcr100()
+ root.add_file(crtdll, **kwds)
# Copy the manifest
# Actually, don't do that anymore - no DLL in DLLs should have a manifest
# dependency on msvcr90.dll anymore, so this should not be necessary
@@ -975,104 +1030,40 @@ def add_files(db):
# Add all .py files in Lib, except tkinter, test
dirs = []
- pydirs = [(root,"Lib")]
+ pydirs = [(root, "Lib", hgfiles["Lib"], default_feature)]
while pydirs:
# Commit every now and then, or else installer will complain
db.Commit()
- parent, dir = pydirs.pop()
- if dir == ".svn" or dir == '__pycache__' or dir.startswith("plat-"):
+ parent, dir, files, feature = pydirs.pop()
+ if dir.startswith("plat-"):
continue
- elif dir in ["tkinter", "idlelib", "Icons"]:
+ if dir in ["tkinter", "idlelib", "turtledemo"]:
if not have_tcl:
continue
+ feature = tcltk
tcltk.set_current()
- elif dir in ['test', 'tests', 'data', 'output']:
- # test: Lib, Lib/email, Lib/ctypes, Lib/sqlite3
- # tests: Lib/distutils
- # data: Lib/email/test
- # output: Lib/test
- testsuite.set_current()
+ elif dir in ('test', 'tests'):
+ feature = testsuite
elif not have_ctypes and dir == "ctypes":
continue
- else:
- default_feature.set_current()
+ feature.set_current()
lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir))
- # Add additional files
dirs.append(lib)
- lib.glob("*.txt")
- if dir=='site-packages':
- lib.add_file("README.txt", src="README")
- continue
- files = lib.glob("*.py")
- files += lib.glob("*.pyw")
- if files:
- # Add an entry to the RemoveFile table to remove bytecode files.
- lib.remove_pyc()
- # package READMEs if present
- lib.glob("README")
- if dir=='Lib':
- lib.add_file('wsgiref.egg-info')
- if dir=='test' and parent.physical=='Lib':
- lib.add_file("185test.db")
- lib.add_file("audiotest.au")
- lib.add_file("sgml_input.html")
- lib.add_file("testtar.tar")
- lib.add_file("test_difflib_expect.html")
- lib.add_file("check_soundcard.vbs")
- lib.add_file("empty.vbs")
- lib.add_file("Sine-1000Hz-300ms.aif")
- lib.add_file("mime.types")
- lib.glob("*.uue")
- lib.glob("*.pem")
- lib.glob("*.pck")
- lib.glob("cfgparser.*")
- lib.add_file("zip_cp437_header.zip")
- lib.add_file("zipdir.zip")
- if dir=='capath':
- lib.glob("*.0")
- if dir=='tests' and parent.physical=='distutils':
- lib.add_file("Setup.sample")
- if dir=='decimaltestdata':
- lib.glob("*.decTest")
- if dir=='xmltestdata':
- lib.glob("*.xml")
- lib.add_file("test.xml.out")
- if dir=='output':
- lib.glob("test_*")
- if dir=='sndhdrdata':
- lib.glob("sndhdr.*")
- if dir=='idlelib':
- lib.glob("*.def")
- lib.add_file("idle.bat")
- lib.add_file("ChangeLog")
- if dir=="Icons":
- lib.glob("*.gif")
- lib.add_file("idle.icns")
- if dir=="command" and parent.physical=="distutils":
- lib.glob("wininst*.exe")
- lib.add_file("command_template")
- if dir=="lib2to3":
- lib.removefile("pickle", "*.pickle")
- if dir=="macholib":
- lib.add_file("README.ctypes")
- lib.glob("fetch_macholib*")
- if dir=='turtledemo':
- lib.add_file("turtle.cfg")
- if dir=="pydoc_data":
- lib.add_file("_pydoc.css")
- if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email":
- # This should contain all non-.svn files listed in subversion
- for f in os.listdir(lib.absolute):
- if f.endswith(".txt") or f==".svn":continue
- if f.endswith(".au") or f.endswith(".gif"):
- lib.add_file(f)
+ has_py = False
+ for name, subdir in files.items():
+ if subdir is None:
+ assert os.path.isfile(os.path.join(lib.absolute, name))
+ if name == 'README':
+ lib.add_file("README.txt", src="README")
else:
- print("WARNING: New file %s in email/test/data" % f)
- for f in os.listdir(lib.absolute):
- if os.path.isdir(os.path.join(lib.absolute, f)):
- pydirs.append((lib, f))
- for d in dirs:
- d.check_unpackaged()
+ lib.add_file(name)
+ has_py = has_py or name.endswith(".py") or name.endswith(".pyw")
+ else:
+ assert os.path.isdir(os.path.join(lib.absolute, name))
+ pydirs.append((lib, name, subdir, feature))
+
+ if has_py:
+ lib.remove_pyc()
# Add DLLs
default_feature.set_current()
lib = DLLs
@@ -1159,6 +1150,8 @@ def add_files(db):
lib.add_file("README.txt", src="README")
if f == 'Scripts':
lib.add_file("2to3.py", src="2to3")
+ lib.add_file("pydoc3.py", src="pydoc3")
+ lib.add_file("pyvenv.py", src="pyvenv")
if have_tcl:
lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw")
lib.add_file("pydocgui.pyw")
@@ -1190,6 +1183,8 @@ def add_registry(db):
"InstallPath"),
("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
"Documentation"),
+ ("REGISTRY.path", msilib.gen_uuid(), "TARGETDIR", registry_component, None,
+ None),
("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component,
None, None)] + tcldata)
# See "FeatureComponents Table".
@@ -1206,6 +1201,7 @@ def add_registry(db):
add_data(db, "FeatureComponents",
[(default_feature.id, "REGISTRY"),
(htmlfiles.id, "REGISTRY.doc"),
+ (prepend_path.id, "REGISTRY.path"),
(ext_feature.id, "REGISTRY.def")] +
tcldata
)
@@ -1244,11 +1240,11 @@ def add_registry(db):
"text/plain", "REGISTRY.def"),
#Verbs
("py.open", -1, pat % (testprefix, "", "open"), "",
- r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
+ r'"[LAUNCHERDIR]py.exe" "%1" %*', "REGISTRY.def"),
("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "",
- r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"),
+ r'"[LAUNCHERDIR]pyw.exe" "%1" %*', "REGISTRY.def"),
("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "",
- r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"),
+ r'"[LAUNCHERDIR]py.exe" "%1" %*', "REGISTRY.def"),
] + tcl_verbs + [
#Icons
("py.icon", -1, pat2 % (testprefix, ""), "",
@@ -1347,9 +1343,9 @@ finally:
# Merge CRT into MSI file. This requires the database to be closed.
mod_dir = os.path.join(os.environ["ProgramFiles"], "Common Files", "Merge Modules")
if msilib.Win64:
- modules = ["Microsoft_VC90_CRT_x86_x64.msm", "policy_9_0_Microsoft_VC90_CRT_x86_x64.msm"]
+ modules = ["Microsoft_VC100_CRT_x64.msm"]
else:
- modules = ["Microsoft_VC90_CRT_x86.msm","policy_9_0_Microsoft_VC90_CRT_x86.msm"]
+ modules = ["Microsoft_VC100_CRT_x86.msm"]
for i, n in enumerate(modules):
modules[i] = os.path.join(mod_dir, n)
diff --git a/Tools/msi/msilib.py b/Tools/msi/msilib.py
index 5795d0e..472d9d4 100644
--- a/Tools/msi/msilib.py
+++ b/Tools/msi/msilib.py
@@ -408,7 +408,7 @@ class Directory:
self.physical = physical
self.logical = logical
self.component = None
- self.short_names = sets.Set()
+ self.short_names = {}
self.ids = sets.Set()
self.keyfiles = {}
self.componentflags = componentflags
@@ -456,23 +456,25 @@ class Directory:
[(feature.id, component)])
def make_short(self, file):
+ long = file
file = re.sub(r'[\?|><:/*"+,;=\[\]]', '_', file) # restrictions on short names
- parts = file.split(".")
+ parts = file.split(".", 1)
if len(parts)>1:
- suffix = parts[-1].upper()
+ suffix = parts[1].upper()
else:
- suffix = None
+ suffix = ''
prefix = parts[0].upper()
- if len(prefix) <= 8 and (not suffix or len(suffix)<=3):
+ if len(prefix) <= 8 and '.' not in suffix and len(suffix) <= 3:
if suffix:
file = prefix+"."+suffix
else:
file = prefix
- assert file not in self.short_names
+ assert file not in self.short_names, (file, self.short_names[file])
else:
prefix = prefix[:6]
if suffix:
- suffix = suffix[:3]
+ # last three characters of last suffix
+ suffix = suffix.rsplit('.')[-1][:3]
pos = 1
while 1:
if suffix:
@@ -484,7 +486,7 @@ class Directory:
assert pos < 10000
if pos in (10, 100, 1000):
prefix = prefix[:-1]
- self.short_names.add(file)
+ self.short_names[file] = long
return file
def add_file(self, file, src=None, version=None, language=None):
diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py
deleted file mode 100644
index 80d17ad..0000000
--- a/Tools/msi/uuids.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# This should be extended for each Python release.
-# The product code must change whenever the name of the MSI file
-# changes, and when new component codes are issued for existing
-# components. See "Changing the Product Code". As we change the
-# component codes with every build, we need a new product code
-# each time. For intermediate (snapshot) releases, they are automatically
-# generated. For official releases, we record the product codes,
-# so people can refer to them.
-product_codes = {
- '2.5.101': '{bc14ce3e-5e72-4a64-ac1f-bf59a571898c}', # 2.5a1
- '2.5.102': '{5eed51c1-8e9d-4071-94c5-b40de5d49ba5}', # 2.5a2
- '2.5.103': '{73dcd966-ffec-415f-bb39-8342c1f47017}', # 2.5a3
- '2.5.111': '{c797ecf8-a8e6-4fec-bb99-526b65f28626}', # 2.5b1
- '2.5.112': '{32beb774-f625-439d-b587-7187487baf15}', # 2.5b2
- '2.5.113': '{89f23918-11cf-4f08-be13-b9b2e6463fd9}', # 2.5b3
- '2.5.121': '{8e9321bc-6b24-48a3-8fd4-c95f8e531e5f}', # 2.5c1
- '2.5.122': '{a6cd508d-9599-45da-a441-cbffa9f7e070}', # 2.5c2
- '2.5.150': '{0a2c5854-557e-48c8-835a-3b9f074bdcaa}', # 2.5.0
- '2.5.1121':'{0378b43e-6184-4c2f-be1a-4a367781cd54}', # 2.5.1c1
- '2.5.1150':'{31800004-6386-4999-a519-518f2d78d8f0}', # 2.5.1
- '2.5.2150':'{6304a7da-1132-4e91-a343-a296269eab8a}', # 2.5.2c1
- '2.5.2150':'{6b976adf-8ae8-434e-b282-a06c7f624d2f}', # 2.5.2
- '2.6.101': '{0ba82e1b-52fd-4e03-8610-a6c76238e8a8}', # 2.6a1
- '2.6.102': '{3b27e16c-56db-4570-a2d3-e9a26180c60b}', # 2.6a2
- '2.6.103': '{cd06a9c5-bde5-4bd7-9874-48933997122a}', # 2.6a3
- '2.6.104': '{dc6ed634-474a-4a50-a547-8de4b7491e53}', # 2.6a4
- '2.6.111': '{3f82079a-5bee-4c4a-8a41-8292389e24ae}', # 2.6b1
- '2.6.112': '{8a0e5970-f3e6-4737-9a2b-bc5ff0f15fb5}', # 2.6b2
- '2.6.113': '{df4f5c21-6fcc-4540-95de-85feba634e76}', # 2.6b3
- '2.6.121': '{bbd34464-ddeb-4028-99e5-f16c4a8fbdb3}', # 2.6c1
- '2.6.122': '{8f64787e-a023-4c60-bfee-25d3a3f592c6}', # 2.6c2
- '2.6.150': '{110eb5c4-e995-4cfb-ab80-a5f315bea9e8}', # 2.6.0
- '2.6.1150':'{9cc89170-000b-457d-91f1-53691f85b223}', # 2.6.1
- '2.6.2121':'{adac412b-b209-4c15-b6ab-dca1b6e47144}', # 2.6.2c1
- '2.6.2150':'{24aab420-4e30-4496-9739-3e216f3de6ae}', # 2.6.2
- '2.6.3121':'{a73e0254-dcda-4fe4-bf37-c7e1c4f4ebb6}', # 2.6.3c1
- '2.6.3150':'{3d9ac095-e115-4e94-bdef-7f7edf17697d}', # 2.6.3
- '2.6.4121':'{727de605-0359-4606-a94b-c2033652379b}', # 2.6.4c1
- '2.6.4122':'{4f7603c6-6352-4299-a398-150a31b19acc}', # 2.6.4c2
- '2.6.4150':'{e7394a0f-3f80-45b1-87fc-abcd51893246}', # 2.6.4
- '2.6.5121':'{e0e273d7-7598-4701-8325-c90c069fd5ff}', # 2.6.5c1
- '2.6.5122':'{fa227b76-0671-4dc6-b826-c2ff2a70dfd5}', # 2.6.5c2
- '2.6.5150':'{4723f199-fa64-4233-8e6e-9fccc95a18ee}', # 2.6.5
- '2.7.101': '{eca1bbef-432c-49ae-a667-c213cc7bbf22}', # 2.7a1
- '2.7.102': '{21ce16ed-73c4-460d-9b11-522f417b2090}', # 2.7a2
- '2.7.103': '{6e7dbd55-ba4a-48ac-a688-6c75db4d7500}', # 2.7a3
- '2.7.104': '{ee774ba3-74a5-48d9-b425-b35a287260c8}', # 2.7a4
- '2.7.111': '{9cfd9ec7-a9c7-4980-a1c6-054fc6493eb3}', # 2.7b1
- '2.7.112': '{9a72faf6-c304-4165-8595-9291ff30cac6}', # 2.7b2
- '2.7.121': '{f530c94a-dd53-4de9-948e-b632b9cb48d2}', # 2.7c1
- '2.7.122': '{f80905d2-dd8d-4b8e-8a40-c23c93dca07d}', # 2.7c2
- '2.7.150': '{20c31435-2a0a-4580-be8b-ac06fc243ca4}', # 2.7.0
- '3.0.101': '{8554263a-3242-4857-9359-aa87bc2c58c2}', # 3.0a1
- '3.0.102': '{692d6e2c-f0ac-40b8-a133-7191aeeb67f9}', # 3.0a2
- '3.0.103': '{49cb2995-751a-4753-be7a-d0b1bb585e06}', # 3.0a3
- '3.0.104': '{87cb019e-19fd-4238-b1c7-85751437d646}', # 3.0a4
- '3.0.105': '{cf2659af-19ec-43d2-8c35-0f6a09439d42}', # 3.0a5
- '3.0.111': '{36c26f55-837d-45cf-848c-5f5c0fb47a28}', # 3.0b1
- '3.0.112': '{056a0fbc-c8fe-4c61-aade-c4411b70c998}', # 3.0b2
- '3.0.113': '{2b2e89a9-83af-43f9-b7d5-96e80c5a3f26}', # 3.0b3
- '3.0.114': '{e95c31af-69be-4dd7-96e6-e5fc85e660e6}', # 3.0b4
- '3.0.121': '{d0979c5e-cd3c-42ec-be4c-e294da793573}', # 3.0c1
- '3.0.122': '{f707b8e9-a257-4045-818e-4923fc20fbb6}', # 3.0c2
- '3.0.123': '{5e7208f1-8643-4ea2-ab5e-4644887112e3}', # 3.0c3
- '3.0.150': '{e0e56e21-55de-4f77-a109-1baa72348743}', # 3.0.0
- '3.0.1121':'{d35b1ea5-3d70-4872-bf7e-cd066a77a9c9}', # 3.0.1c1
- '3.0.1150':'{de2f2d9c-53e2-40ee-8209-74da63cb060e}', # 3.0.1
- '3.0.2121':'{cef79e7f-9809-49e2-afd2-e24148d7c855}', # 3.0.2c1
- '3.0.2150':'{0cf3b95a-8382-4607-9779-c36407ff362c}', # 3.0.2
- '3.1.101': '{c423eada-c498-4d51-9eb4-bfeae647e0a0}', # 3.1a1
- '3.1.102': '{f6e199bf-dc64-42f3-87d4-1525991a013e}', # 3.1a2
- '3.1.111': '{c3c82893-69b2-4676-8554-1b6ee6c191e9}', # 3.1b1
- '3.1.121': '{da2b5170-12f3-4d99-8a1f-54926cca7acd}', # 3.1c1
- '3.1.122': '{bceb5133-e2ee-4109-951f-ac7e941a1692}', # 3.1c2
- '3.1.150': '{3ad61ee5-81d2-4d7e-adef-da1dd37277d1}', # 3.1.0
- '3.1.1121':'{5782f957-6d49-41d4-bad0-668715dfd638}', # 3.1.1c1
- '3.1.1150':'{7ff90460-89b7-435b-b583-b37b2815ccc7}', # 3.1.1
- '3.1.2121':'{ec45624a-378c-43be-91f3-3f7a59b0d90c}', # 3.1.2c1
- '3.1.2150':'{d40af016-506c-43fb-a738-bd54fa8c1e85}', # 3.1.2
- '3.2.101' :'{b411f168-7a36-4fff-902c-a554d1c78a4f}', # 3.2a1
- '3.2.102' :'{79ff73b7-8359-410f-b9c5-152d2026f8c8}', # 3.2a2
- '3.2.103' :'{e7635c65-c221-4b9b-b70a-5611b8369d77}', # 3.2a3
- '3.2.104' :'{748cd139-75b8-4ca8-98a7-58262298181e}', # 3.2a4
- '3.2.111' :'{20bfc16f-c7cd-4fc0-8f96-9914614a3c50}', # 3.2b1
- '3.2.112' :'{0e350c98-8d73-4993-b686-cfe87160046e}', # 3.2b2
- '3.2.121' :'{2094968d-7583-47f6-a7fd-22304532e09f}', # 3.2rc1
- '3.2.122' :'{4f3edfa6-cf70-469a-825f-e1206aa7f412}', # 3.2rc2
- '3.2.123' :'{90c673d7-8cfd-4969-9816-f7d70bad87f3}', # 3.2rc3
- '3.2.150' :'{b2042d5e-986d-44ec-aee3-afe4108ccc93}', # 3.2.0
- '3.2.1121':'{4f90de4a-83dd-4443-b625-ca130ff361dd}', # 3.2.1rc1
- '3.2.1122':'{dc5eb04d-ff8a-4bed-8f96-23942fd59e5f}', # 3.2.1rc2
- '3.2.1150':'{34b2530c-6349-4292-9dc3-60bda4aed93c}', # 3.2.1
- '3.2.2121':'{DFB29A53-ACC4-44e6-85A6-D0DA26FE8E4E}', # 3.2.2rc1
- '3.2.2150':'{4CDE3168-D060-4b7c-BC74-4D8F9BB01AFD}', # 3.2.2
- '3.2.3121':'{B8E8CFF7-E4C6-4a7c-9F06-BB3A8B75DDA8}', # 3.2.3rc1
- '3.2.3122':'{E8DCD3E0-12B6-4fb7-9DB5-543C2E67372E}', # 3.2.3rc2
- '3.2.3150':'{789C9644-9F82-44d3-B4CA-AC31F46F5882}', # 3.2.3
-
-}