def merge(msi, feature, rootdir, modules): cab_and_filecount = [] # Step 1: Merge databases, extract cabfiles m = msilib.MakeMerge2() m.OpenLog("merge.log") print "Opened Log" m.OpenDatabase(msi) print "Opened DB" for module in modules: print module m.OpenModule(module, 0) print "Opened Module", module 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, win32com.client.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()
def generate_MSI(self): shutil.copy(self.template, self.msifile.path) #1 Add exe and ini file to cab filelist = [(self.exefile.path, "ExeFile"), (self.inifile.path, "IniFile")] cabfile = os.path.join(self.tempdir, "files.cab") msilib.FCICreate(cabfile, filelist) #2 Open the MSI database #database = msilib.init_database(self.msifile.path, msilib.schema, self.msifile.name, self.productcode, self.productversion, self.manufacturer) #print self.msifile.path #msilib.add_tables(database, msilib.schema) database = msilib.OpenDatabase(self.msifile.path, msilib.MSIDBOPEN_DIRECT) msilib.add_stream(database, "Wpkg_GP.cab", cabfile) # Update Product Code summaryinformation = database.GetSummaryInformation(1) summaryinformation.SetProperty(msilib.PID_REVNUMBER, self.package_GUID) summaryinformation.Persist() # Add information to Media # DiskId | LastSequence | DiskPrompt | Cabinet | VolumeLabel | Source table = "Media" records = [(1, 2, None, "#Wpkg_GP.cab", None, None)] msilib.add_data(database, table, records) #CAB = msilib.CAB("Wpkg_GP.cab") #CAB.append(self.exefile.path, "ExeFile", "ExeFile") #CAB.append(self.inifile.path, "IniFile", "IniFile") #CAB.commit(database) # Add information to File # File | Component_ | FileName | FileSize| Version | Language | Attributes | Sequence table = "File" records = [("ExeFile", "Installer", self.exefile.name, self.exefile.size, None, None, 512, 1), ("IniFile", "Installer", self.inifile.name, self.inifile.size, None, None, 512, 2)] msilib.add_data(database, table, records) # Add information to CustomAction # Action | Type | Source | Target # For Type, see: http://msdn.microsoft.com/en-us/library/aa372048%28v=VS.85%29.aspx # Add information to Property # Property | Value # Update version view = database.OpenView( "UPDATE Property SET Value='%s' WHERE Property='ProductVersion'" % self.exefile.get_fileversion_as_string()) view.Execute(None) view = database.OpenView( "UPDATE Property Set Value='%s' WHERE Property='ProductCode'" % self.product_GUID) view.Execute(None) database.Commit()
def commit(self, db): filename = tempfile.mktemp() msilib.FCICreate(filename, self.files) print filename, os.path.getsize(filename) sys.stderr.write(str((self.diskId, self.index, None, "#"+self.name, None, None)) + "\n") msilib.add_data(db, "Media", [(self.diskId, self.index, None, "#"+self.name, None, None)]) msilib.add_stream(db, self.name, filename) self.diskId += 1 db.Commit() os.unlink(filename)
def generate_MSI(self): shutil.copy(self.template, self.msifile.path) #1 Add exe and ini file to cab filelist = [(self.exefile.path, "ExeFile"), (self.inifile.path, "IniFile")] cabfile = os.path.join(self.tempdir, "files.cab") msilib.FCICreate(cabfile, filelist) #2 Open the MSI database #database = msilib.init_database(self.msifile.path, msilib.schema, self.msifile.name, self.productcode, self.productversion, self.manufacturer) #print self.msifile.path #msilib.add_tables(database, msilib.schema) database = msilib.OpenDatabase(self.msifile.path, msilib.MSIDBOPEN_DIRECT) msilib.add_stream(database, "Wpkg_GP.cab", cabfile) # Update Product Code summaryinformation = database.GetSummaryInformation(1) summaryinformation.SetProperty(msilib.PID_REVNUMBER, self.package_GUID) summaryinformation.Persist() # Add information to Media # DiskId | LastSequence | DiskPrompt | Cabinet | VolumeLabel | Source table = "Media" records = [(1, 2, None, "#Wpkg_GP.cab", None, None)] msilib.add_data(database, table, records) #CAB = msilib.CAB("Wpkg_GP.cab") #CAB.append(self.exefile.path, "ExeFile", "ExeFile") #CAB.append(self.inifile.path, "IniFile", "IniFile") #CAB.commit(database) # Add information to File # File | Component_ | FileName | FileSize| Version | Language | Attributes | Sequence table = "File" records = [ ("ExeFile", "Installer", self.exefile.name, self.exefile.size, None, None, 512, 1), ("IniFile", "Installer", self.inifile.name, self.inifile.size, None, None, 512, 2) ] msilib.add_data(database, table, records) # Add information to CustomAction # Action | Type | Source | Target # For Type, see: http://msdn.microsoft.com/en-us/library/aa372048%28v=VS.85%29.aspx # Add information to Property # Property | Value # Update version view = database.OpenView("UPDATE Property SET Value='%s' WHERE Property='ProductVersion'" % self.exefile.get_fileversion_as_string()) view.Execute(None) view = database.OpenView("UPDATE Property Set Value='%s' WHERE Property='ProductCode'" % self.product_GUID) view.Execute(None) database.Commit()
def merge(msi, feature, rootdir, modules): cab_and_filecount = [] # Step 1: Merge databases, extract cabfiles m = msilib.MakeMerge2() m.OpenLog("merge.log") print "Opened Log" m.OpenDatabase(msi) print "Opened DB" for module in modules: print module m.OpenModule(module, 0) print "Opened Module", module 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, win32com.client.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()