77from win32com .client import constants
88from distutils .spawn import find_executable
99from uuids import product_codes
10+ import tempfile
1011
1112# Settings can be overridden in config.py below
1213# 0 for official python.org releases
2829PCBUILD = "PCbuild"
2930# msvcrt version
3031MSVCR = "90"
32+ # Name of certificate in default store to sign MSI with
33+ certname = None
3134
3235try :
3336 from config import *
@@ -220,7 +223,8 @@ def build_database():
220223 # schema represents the installer 2.0 database schema.
221224 # sequence is the set of standard sequences
222225 # (ui/execute, admin/advt/install)
223- db = msilib .init_database ("python-%s%s.msi" % (full_current_version , msilib .arch_ext ),
226+ msiname = "python-%s%s.msi" % (full_current_version , msilib .arch_ext )
227+ db = msilib .init_database (msiname ,
224228 schema , ProductName = "Python " + full_current_version + productsuffix ,
225229 ProductCode = product_code ,
226230 ProductVersion = current_version ,
@@ -243,7 +247,7 @@ def build_database():
243247 ("ProductLine" , "Python%s%s" % (major , minor )),
244248 ])
245249 db .Commit ()
246- return db
250+ return db , msiname
247251
248252def remove_old_versions (db ):
249253 "Fill the upgrade table."
@@ -1295,7 +1299,7 @@ def add_registry(db):
12951299 ])
12961300 db .Commit ()
12971301
1298- db = build_database ()
1302+ db , msiname = build_database ()
12991303try :
13001304 add_features (db )
13011305 add_ui (db )
@@ -1305,3 +1309,75 @@ def add_registry(db):
13051309 db .Commit ()
13061310finally :
13071311 del db
1312+
1313+ # Merge CRT into MSI file. This requires the database to be closed.
1314+ mod_dir = os .path .join (os .environ ["ProgramFiles" ], "Common Files" , "Merge Modules" )
1315+ if msilib .Win64 :
1316+ modules = ["Microsoft_VC90_CRT_x86_x64.msm" , "policy_9_0_Microsoft_VC90_CRT_x86_x64.msm" ]
1317+ else :
1318+ modules = ["Microsoft_VC90_CRT_x86.msm" ,"policy_9_0_Microsoft_VC90_CRT_x86.msm" ]
1319+
1320+ for i , n in enumerate (modules ):
1321+ modules [i ] = os .path .join (mod_dir , n )
1322+
1323+ def merge (msi , feature , rootdir , modules ):
1324+ cab_and_filecount = []
1325+ # Step 1: Merge databases, extract cabfiles
1326+ m = msilib .MakeMerge2 ()
1327+ m .OpenLog ("merge.log" )
1328+ m .OpenDatabase (msi )
1329+ for module in modules :
1330+ print module
1331+ m .OpenModule (module ,0 )
1332+ m .Merge (feature , rootdir )
1333+ print "Errors:"
1334+ for e in m .Errors :
1335+ print e .Type , e .ModuleTable , e .DatabaseTable
1336+ print " Modkeys:" ,
1337+ for s in e .ModuleKeys : print s ,
1338+ print
1339+ print " DBKeys:" ,
1340+ for s in e .DatabaseKeys : print s ,
1341+ print
1342+ cabname = tempfile .mktemp (suffix = ".cab" )
1343+ m .ExtractCAB (cabname )
1344+ cab_and_filecount .append ((cabname , len (m .ModuleFiles )))
1345+ m .CloseModule ()
1346+ m .CloseDatabase (True )
1347+ m .CloseLog ()
1348+
1349+ # Step 2: Add CAB files
1350+ i = msilib .MakeInstaller ()
1351+ db = i .OpenDatabase (msi , constants .msiOpenDatabaseModeTransact )
1352+
1353+ v = db .OpenView ("SELECT LastSequence FROM Media" )
1354+ v .Execute (None )
1355+ maxmedia = - 1
1356+ while 1 :
1357+ r = v .Fetch ()
1358+ if not r : break
1359+ seq = r .IntegerData (1 )
1360+ if seq > maxmedia :
1361+ maxmedia = seq
1362+ print "Start of Media" , maxmedia
1363+
1364+ for cabname , count in cab_and_filecount :
1365+ stream = "merged%d" % maxmedia
1366+ msilib .add_data (db , "Media" ,
1367+ [(maxmedia + 1 , maxmedia + count , None , "#" + stream , None , None )])
1368+ msilib .add_stream (db , stream , cabname )
1369+ os .unlink (cabname )
1370+ maxmedia += count
1371+ # The merge module sets ALLUSERS to 1 in the property table.
1372+ # This is undesired; delete that
1373+ v = db .OpenView ("DELETE FROM Property WHERE Property='ALLUSERS'" )
1374+ v .Execute (None )
1375+ v .Close ()
1376+ db .Commit ()
1377+
1378+ merge (msiname , "SharedCRT" , "TARGETDIR" , modules )
1379+
1380+ # certname (from config.py) should be (a substring of)
1381+ # the certificate subject, e.g. "Python Software Foundation"
1382+ if certname :
1383+ os .system ('signtool sign /n "%s" /t http://timestamp.verisign.com/scripts/timestamp.dll %s' % (certname , msiname ))
0 commit comments