diff options
Diffstat (limited to 'Tools/msi/msi.py')
-rw-r--r-- | Tools/msi/msi.py | 137 |
1 files changed, 117 insertions, 20 deletions
diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py index b668c7a..53e652d 100644 --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -7,6 +7,7 @@ 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,6 +29,8 @@ have_tcl = True PCBUILD="PCbuild" # msvcrt version MSVCR = "90" +# Name of certificate in default store to sign MSI with +certname = None # Make a zip file containing the PDB files for this build? pdbzip = True @@ -115,6 +118,7 @@ pythondll_uuid = { "27":"{4fe21c76-1760-437b-a2f2-99909130a175}", "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}", "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}", + "32":"{3ff95315-1096-4d31-bd86-601d5438ad5e}", } [major+minor] # Compute the name that Sphinx gives to the docfile @@ -221,7 +225,8 @@ def build_database(): # schema represents the installer 2.0 database schema. # sequence is the set of standard sequences # (ui/execute, admin/advt/install) - db = msilib.init_database("python-%s%s.msi" % (full_current_version, msilib.arch_ext), + msiname = "python-%s%s.msi" % (full_current_version, msilib.arch_ext) + db = msilib.init_database(msiname, schema, ProductName="Python "+full_current_version+productsuffix, ProductCode=product_code, ProductVersion=current_version, @@ -244,7 +249,7 @@ def build_database(): ("ProductLine", "Python%s%s" % (major, minor)), ]) db.Commit() - return db + return db, msiname def remove_old_versions(db): "Fill the upgrade table." @@ -876,7 +881,6 @@ def generate_license(): shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out) shutil.copyfileobj(open("crtlicense.txt"), out) for name, pat, file in (("bzip2","bzip2-*", "LICENSE"), - ("Berkeley DB", "db-*", "LICENSE"), ("openssl", "openssl-*", "LICENSE"), ("Tcl", "tcl8*", "license.terms"), ("Tk", "tk8*", "license.terms"), @@ -900,6 +904,13 @@ 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 + # See "File Table", "Component Table", "Directory Table", # "FeatureComponents Table" def add_files(db): @@ -963,13 +974,13 @@ def add_files(db): extensions.remove("_ctypes.pyd") # Add all .py files in Lib, except tkinter, test - dirs={} + dirs = [] pydirs = [(root,"Lib")] while pydirs: # Commit every now and then, or else installer will complain db.Commit() parent, dir = pydirs.pop() - if dir == ".svn" or dir.startswith("plat-"): + if dir == ".svn" or dir == '__pycache__' or dir.startswith("plat-"): continue elif dir in ["tkinter", "idlelib", "Icons"]: if not have_tcl: @@ -987,7 +998,7 @@ def add_files(db): default_feature.set_current() lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir)) # Add additional files - dirs[dir]=lib + dirs.append(lib) lib.glob("*.txt") if dir=='site-packages': lib.add_file("README.txt", src="README") @@ -997,19 +1008,14 @@ def add_files(db): if files: # Add an entry to the RemoveFile table to remove bytecode files. lib.remove_pyc() - if dir.endswith('.egg-info'): - lib.add_file('entry_points.txt') - lib.add_file('PKG-INFO') - lib.add_file('top_level.txt') - lib.add_file('zip-safe') - continue + # 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("cfgparser.1") lib.add_file("sgml_input.html") - lib.add_file("test.xml") - lib.add_file("test.xml.out") lib.add_file("testtar.tar") lib.add_file("test_difflib_expect.html") lib.add_file("check_soundcard.vbs") @@ -1018,26 +1024,41 @@ def add_files(db): 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") - if dir=="setuptools": - lib.add_file("cli.exe") - lib.add_file("gui.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): @@ -1049,6 +1070,8 @@ def add_files(db): 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() # Add DLLs default_feature.set_current() lib = DLLs @@ -1064,6 +1087,7 @@ def add_files(db): continue dlls.append(f) lib.add_file(f) + lib.add_file('python3.dll') # Add sqlite if msilib.msi_type=="Intel64;1033": sqlite_arch = "/ia64" @@ -1100,6 +1124,7 @@ def add_files(db): for f in dlls: lib.add_file(f.replace('pyd','lib')) lib.add_file('python%s%s.lib' % (major, minor)) + lib.add_file('python3.lib') # Add the mingw-format library if have_mingw: lib.add_file('libpython%s%s.a' % (major, minor)) @@ -1120,7 +1145,7 @@ def add_files(db): # Add tools tools.set_current() tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools") - for f in ['i18n', 'pynche', 'Scripts', 'webchecker']: + for f in ['i18n', 'pynche', 'Scripts']: lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f)) lib.glob("*.py") lib.glob("*.pyw", exclude=['pydocgui.pyw']) @@ -1307,7 +1332,7 @@ def build_pdbzip(): pdbzip.write(os.path.join(srcdir, PCBUILD, f), f) pdbzip.close() -db = build_database() +db,msiname = build_database() try: add_features(db) add_ui(db) @@ -1318,5 +1343,77 @@ try: finally: del db +# 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"] +else: + modules = ["Microsoft_VC90_CRT_x86.msm","policy_9_0_Microsoft_VC90_CRT_x86.msm"] + +for i, n in enumerate(modules): + modules[i] = os.path.join(mod_dir, n) + +def merge(msi, feature, rootdir, modules): + cab_and_filecount = [] + # Step 1: Merge databases, extract cabfiles + m = msilib.MakeMerge2() + m.OpenLog("merge.log") + m.OpenDatabase(msi) + for module in modules: + print module + m.OpenModule(module,0) + m.Merge(feature, rootdir) + print "Errors:" + for e in m.Errors: + print e.Type, e.ModuleTable, e.DatabaseTable + print " Modkeys:", + for s in e.ModuleKeys: print s, + print + print " DBKeys:", + for s in e.DatabaseKeys: print s, + print + cabname = tempfile.mktemp(suffix=".cab") + m.ExtractCAB(cabname) + cab_and_filecount.append((cabname, len(m.ModuleFiles))) + m.CloseModule() + m.CloseDatabase(True) + m.CloseLog() + + # Step 2: Add CAB files + i = msilib.MakeInstaller() + db = i.OpenDatabase(msi, constants.msiOpenDatabaseModeTransact) + + v = db.OpenView("SELECT LastSequence FROM Media") + v.Execute(None) + maxmedia = -1 + while 1: + r = v.Fetch() + if not r: break + seq = r.IntegerData(1) + if seq > maxmedia: + maxmedia = seq + print "Start of Media", maxmedia + + for cabname, count in cab_and_filecount: + stream = "merged%d" % maxmedia + msilib.add_data(db, "Media", + [(maxmedia+1, maxmedia+count, None, "#"+stream, None, None)]) + msilib.add_stream(db, stream, cabname) + os.unlink(cabname) + maxmedia += count + # The merge module sets ALLUSERS to 1 in the property table. + # This is undesired; delete that + v = db.OpenView("DELETE FROM Property WHERE Property='ALLUSERS'") + v.Execute(None) + v.Close() + db.Commit() + +merge(msiname, "SharedCRT", "TARGETDIR", modules) + +# certname (from config.py) should be (a substring of) +# the certificate subject, e.g. "Python Software Foundation" +if certname: + os.system('signtool sign /n "%s" /t http://timestamp.verisign.com/scripts/timestamp.dll %s' % (certname, msiname)) + if pdbzip: build_pdbzip() |