support/package-builder/PackageUtils.py
2820c61a
 from CommandUtils import CommandUtils
 from Logger import Logger
 import os
 import shutil
 from constants import constants
518d6a6f
 import re
75a2daa5
 from time import sleep
3cc43c92
 import PullSources
90d8acae
 import json
 import collections
2820c61a
 
 class PackageUtils(object):
97a9151c
 
2820c61a
     def __init__(self,logName=None,logPath=None):
         if logName is None:
             self.logName = "PackageUtils"
         if logPath is None:
             logPath = constants.logPath
         self.logName=logName
         self.logPath=logPath
         self.logger=Logger.getLogger(logName,logPath)
542dc63c
         self.runInChrootCommand="./run-in-chroot.sh " + constants.sourcePath + " " + constants.rpmPath;
518d6a6f
         self.rpmBinary = "rpm"
         self.installRPMPackageOptions = "-Uvh"
         self.nodepsRPMPackageOptions = "--nodeps"
97a9151c
 
518d6a6f
         self.rpmbuildBinary = "rpmbuild"
45e37dfb
         self.rpmbuildBuildallOption = "-ba --clean"
518d6a6f
         self.rpmbuildNocheckOption = "--nocheck"
b5e09fac
         self.rpmbuildCheckOption ="-bi --clean"
4c54f74b
         self.rpmbuildDistOption = '--define \\\"dist %s\\\"' % constants.dist
518d6a6f
         self.queryRpmPackageOptions = "-qa"
         self.forceRpmPackageOptions = "--force"
75a2daa5
         self.adjustGCCSpecScript="adjust-gcc-specs.sh"
542dc63c
         self.rpmFilesToInstallInAOneShot=""
         self.packagesToInstallInAOneShot=""
         self.noDepsRPMFilesToInstallInAOneShot=""
         self.noDepsPackagesToInstallInAOneShot=""
97a9151c
 
2cfb758d
     def getRPMArch(self,rpmName):
2820c61a
         arch=""
         if rpmName.find("x86_64") != -1:
2cfb758d
             arch="x86_64"
2820c61a
         elif rpmName.find("noarch") != -1:
             arch="noarch"
2cfb758d
         return arch
 
     def getRPMDestDir(self,rpmName,rpmDir):
         arch = self.getRPMArch(rpmName)
2820c61a
         rpmDestDir=rpmDir+"/"+arch
         return rpmDestDir
97a9151c
 
2820c61a
     def copyRPM(self,rpmFile,destDir):
         cmdUtils = CommandUtils()
         rpmName=os.path.basename(rpmFile)
         rpmDestDir=self.getRPMDestDir(rpmName,destDir)
         rpmDestPath=rpmDestDir+"/"+rpmName
542dc63c
         if os.geteuid()==0:
             if not os.path.isdir(rpmDestDir):
                 cmdUtils.runCommandInShell("mkdir -p "+rpmDestDir)
             shutil.copyfile(rpmFile,  rpmDestPath)
2820c61a
         return rpmDestPath
97a9151c
 
2820c61a
     def installRPM(self,package,chrootID,noDeps=False,destLogPath=None):
542dc63c
 #        self.logger.info("Installing rpm for package:"+package)
 #        self.logger.debug("No deps:"+str(noDeps))
97a9151c
 
2820c61a
         rpmfile=self.findRPMFileForGivenPackage(package)
         if rpmfile is None:
518d6a6f
             self.logger.error("No rpm file found for package:"+package)
b5e09fac
             raise Exception("Missing rpm file: "+package)
2820c61a
 
         rpmDestFile = self.copyRPM(rpmfile, chrootID+constants.topDirPath+"/RPMS")
         rpmFile=rpmDestFile.replace(chrootID,"")
542dc63c
         if noDeps:
             self.noDepsRPMFilesToInstallInAOneShot += " " + rpmFile
             self.noDepsPackagesToInstallInAOneShot += " " + package
         else:
             self.rpmFilesToInstallInAOneShot += " " + rpmFile
             self.packagesToInstallInAOneShot += " " + package
97a9151c
 
542dc63c
     def installRPMSInAOneShot(self,chrootID,destLogPath):
2820c61a
         chrootCmd=self.runInChrootCommand+" "+chrootID
518d6a6f
         rpmInstallcmd=self.rpmBinary+" "+ self.installRPMPackageOptions
542dc63c
         if self.noDepsRPMFilesToInstallInAOneShot != "":
             self.logger.info("Installing nodeps rpms: " + self.noDepsPackagesToInstallInAOneShot)
             logFile=chrootID+constants.topDirPath+"/LOGS/install_rpms_nodeps.log"
             cmdUtils = CommandUtils()
             cmd = rpmInstallcmd+" "+self.nodepsRPMPackageOptions + " " + self.noDepsRPMFilesToInstallInAOneShot
             returnVal = cmdUtils.runCommandInShell(cmd, logFile, chrootCmd)
             if destLogPath is not None:
                 shutil.copy2(logFile, destLogPath)
             if not returnVal:
                 self.logger.error("Unable to install rpms")
                 raise Exception("RPM installation failed")
         if self.rpmFilesToInstallInAOneShot != "":
             self.logger.info("Installing rpms: " + self.packagesToInstallInAOneShot)
             logFile=chrootID+constants.topDirPath+"/LOGS/install_rpms.log"
             cmdUtils = CommandUtils()
             cmd=rpmInstallcmd+" "+self.rpmFilesToInstallInAOneShot
             returnVal = cmdUtils.runCommandInShell(cmd, logFile, chrootCmd)
             if destLogPath is not None:
                 shutil.copy2(logFile, destLogPath)
             if not returnVal:
                 self.logger.error("Unable to install rpms")
                 raise Exception("RPM installation failed")
97a9151c
 
 
2820c61a
     def copySourcesTobuildroot(self,listSourceFiles,package,destDir):
         cmdUtils = CommandUtils()
         for source in listSourceFiles:
3cc43c92
             # Fetch/verify sources if sha1 not None.
             sha1 = constants.specData.getSHA1(package, source)
             if sha1 is not None:
                 PullSources.get(source, sha1, constants.sourcePath, constants.pullsourcesConfig)
 
518d6a6f
             sourcePath = cmdUtils.findFile(source,constants.sourcePath)
2820c61a
             if sourcePath is None or len(sourcePath) == 0:
518d6a6f
                 sourcePath = cmdUtils.findFile(source,constants.specPath)
7fba6943
                 if sourcePath is None or len(sourcePath) == 0:
                     if sha1 is None:
                         self.logger.error("No sha1 found or missing source for "+source)
8d560b23
                         raise Exception("No sha1 found or missing source for "+source)
7fba6943
                     else:
                         self.logger.error("Missing source: "+source+". Cannot find sources for package: "+package)
                         raise Exception("Missing source")
             else:
                 if sha1 is None:
                     self.logger.error("No sha1 found for "+source)
                     raise Exception("No sha1 found")
2820c61a
             if len(sourcePath) > 1:
518d6a6f
                 self.logger.error("Multiple sources found for source:"+source+"\n"+ ",".join(sourcePath) +"\nUnable to determine one.")
                 raise Exception("Multiple sources found")
2689a7f2
             self.logger.info("Copying... Source path :" + source + " Source filename: " + sourcePath[0])
90d8acae
             shutil.copy2(sourcePath[0], destDir)
97a9151c
 
1cf11562
     def copyAdditionalBuildFiles(self,listAdditionalFiles,chrootID):
90d8acae
         cmdUtils = CommandUtils()
1cf11562
         for additionalFile in listAdditionalFiles:
             source = additionalFile["src"].encode('utf-8')
             destDir = chrootID + additionalFile["dst"].encode('utf-8')
90d8acae
             if os.path.exists(source):
1cf11562
                 if os.path.isfile(source):
                     shutil.copy(source, destDir)
                 else:
                     shutil.copytree(source, destDir)
97a9151c
 
90d8acae
     def buildRPMSForGivenPackage(self,package,chrootID,listBuildOptionPackages,pkgBuildOptionFile,destLogPath=None):
518d6a6f
         self.logger.info("Building rpm's for package:"+package)
2820c61a
 
         listSourcesFiles = constants.specData.getSources(package)
         listPatchFiles =  constants.specData.getPatches(package)
         specFile = constants.specData.getSpecFile(package)
         specName = constants.specData.getSpecName(package) + ".spec"
97a9151c
 
2820c61a
         chrootSourcePath=chrootID+constants.topDirPath+"/SOURCES/"
         chrootSpecPath=constants.topDirPath+"/SPECS/"
         chrootLogsFilePath=chrootID+constants.topDirPath+"/LOGS/"+package+".log"
         chrootCmd=self.runInChrootCommand+" "+chrootID
         shutil.copyfile(specFile, chrootID+chrootSpecPath+specName )
97a9151c
 
e8435c63
 # FIXME: some sources are located in SPECS/.. how to mount?
 #        if os.geteuid()==0:
         self.copySourcesTobuildroot(listSourcesFiles,package,chrootSourcePath)
2820c61a
         self.copySourcesTobuildroot(listPatchFiles,package,chrootSourcePath)
90d8acae
 
         listAdditionalFiles = []
         macros = []
         if package in listBuildOptionPackages:
             jsonData = open(pkgBuildOptionFile)
             pkg_build_option_json = json.load(jsonData, object_pairs_hook=collections.OrderedDict)
             jsonData.close()
             pkgs_sorted = pkg_build_option_json.items()
             for pkg in pkgs_sorted:
                 p = str(pkg[0].encode('utf-8'))
                 if p == package:
                     filelist = pkg[1]["files"]
                     for f in filelist:
1cf11562
                         listAdditionalFiles.append(f)
90d8acae
                     macrolist = pkg[1]["macros"]
                     for macro in macrolist:
                         macros.append(str(macro.encode('utf-8')))
97a9151c
 
1cf11562
             self.copyAdditionalBuildFiles(listAdditionalFiles,chrootID)
90d8acae
 
9b2f8b85
         #Adding rpm macros
         listRPMMacros = constants.specData.getRPMMacros()
         for macroName in listRPMMacros.keys():
             macros.append(macroName+" "+listRPMMacros[macroName])
 
3ad2cb4c
         listRPMFiles=[]
d2526915
         listSRPMFiles=[]
3ad2cb4c
         try:
90d8acae
             listRPMFiles,listSRPMFiles = self.buildRPM(chrootSpecPath+"/"+specName,chrootLogsFilePath,chrootCmd,package,macros)
3ad2cb4c
         except Exception as e:
             self.logger.error("Failed while building rpm:"+package)
             raise e
         finally:
             if destLogPath is not None:
b5e09fac
                 if constants.rpmCheck and package in constants.testForceRPMS and constants.specData.isCheckAvailable(package):
                     cmd="sed -i '/^Executing(%check):/,/^Processing files:/{//!b};d' "+ chrootLogsFilePath
                     logFile = destLogPath+"/adjustTestFile.log"
                     returnVal = CommandUtils().runCommandInShell(cmd, logFile)
                     testLogFile = destLogPath+"/"+package+"-test.log"
                     shutil.copyfile(chrootLogsFilePath, testLogFile)
                 else:
                     shutil.copy2(chrootLogsFilePath, destLogPath)
2cfb758d
         self.logger.info("RPM build is successful")
b5e09fac
 
2820c61a
         for rpmFile in listRPMFiles:
             self.copyRPM(chrootID+"/"+rpmFile, constants.rpmPath)
97a9151c
 
d2526915
         for srpmFile in listSRPMFiles:
97a9151c
             srpmDestFile = self.copyRPM(chrootID+"/"+srpmFile, constants.sourceRpmPath)
d2526915
 
90d8acae
     def buildRPM(self,specFile,logFile,chrootCmd,package,macros):
97a9151c
 
b5e09fac
         rpmBuildcmd=self.rpmbuildBinary+" "+self.rpmbuildBuildallOption+" "+self.rpmbuildDistOption
 
         if constants.rpmCheck and package in constants.testForceRPMS:
             self.logger.info("#"*(68+2*len(package)))
             if not constants.specData.isCheckAvailable(package):
                 self.logger.info("####### "+package+" MakeCheck is not available. Skipping MakeCheck TEST for "+package+ " #######")
                 rpmBuildcmd=self.rpmbuildBinary+" --clean"
             else:
                 self.logger.info("####### "+package+" MakeCheck is available. Running MakeCheck TEST for "+package+ " #######")
                 rpmBuildcmd=self.rpmbuildBinary+" "+self.rpmbuildCheckOption
             self.logger.info("#"*(68+2*len(package)))
         else:
            rpmBuildcmd+=" "+self.rpmbuildNocheckOption
 
90d8acae
         for macro in macros:
             rpmBuildcmd+=' --define \\\"%s\\\"' % macro
518d6a6f
         rpmBuildcmd+=" "+specFile
97a9151c
 
2820c61a
         cmdUtils = CommandUtils()
42ffccb5
         self.logger.info("Building rpm....")
2c153d29
         self.logger.info(rpmBuildcmd)
518d6a6f
         returnVal = cmdUtils.runCommandInShell(rpmBuildcmd, logFile, chrootCmd)
b5e09fac
         if constants.rpmCheck and package in constants.testForceRPMS:
             if not constants.specData.isCheckAvailable(package):
                 constants.testLogger.info(package+" : N/A")
             elif returnVal:
                 constants.testLogger.info(package+" : PASS")
             else:
                 constants.testLogger.error(package+" : FAIL" )
 
         if constants.rpmCheck:
             if not returnVal and constants.rpmCheckStopOnError:
                 self.logger.error("Checking rpm is failed "+specFile)
                 raise Exception("RPM check failed")
         else:
             if not returnVal:
                 self.logger.error("Building rpm is failed "+specFile)
                 raise Exception("RPM build failed")
 
518d6a6f
         #Extracting rpms created from log file
         logfile=open(logFile,'r')
         fileContents=logfile.readlines()
         logfile.close()
         listRPMFiles=[]
d2526915
         listSRPMFiles=[]
518d6a6f
         for i in range(0,len(fileContents)):
             if re.search("^Wrote:",fileContents[i]):
                 listcontents=fileContents[i].split()
                 if (len(listcontents) == 2) and listcontents[1].strip()[-4:] == ".rpm" and listcontents[1].find("/RPMS/") != -1:
                     listRPMFiles.append(listcontents[1])
d2526915
                 if (len(listcontents) == 2) and listcontents[1].strip()[-8:] == ".src.rpm" and listcontents[1].find("/SRPMS/") != -1:
                     listSRPMFiles.append(listcontents[1])
97a9151c
         return listRPMFiles,listSRPMFiles
 
2820c61a
     def findRPMFileForGivenPackage(self,package):
         cmdUtils = CommandUtils()
         version = constants.specData.getVersion(package)
         release = constants.specData.getRelease(package)
cd022cc1
         listFoundRPMFiles = sum([cmdUtils.findFile(package+"-"+version+"-"+release+".x86_64.rpm",constants.rpmPath),
                             cmdUtils.findFile(package+"-"+version+"-"+release+".noarch.rpm",constants.rpmPath)], [])
42ffccb5
         if constants.inputRPMSPath is not None:
             listFoundRPMFiles = sum([cmdUtils.findFile(package+"-"+version+"-"+release+".x86_64.rpm",constants.inputRPMSPath),
97a9151c
                             cmdUtils.findFile(package+"-"+version+"-"+release+".noarch.rpm",constants.inputRPMSPath)], listFoundRPMFiles)
2820c61a
         if len(listFoundRPMFiles) == 1 :
             return listFoundRPMFiles[0]
         if len(listFoundRPMFiles) == 0 :
             return None
         if len(listFoundRPMFiles) > 1 :
518d6a6f
             self.logger.error("Found multiple rpm files for given package in rpm directory.Unable to determine the rpm file for package:"+package)
             raise Exception("Multiple rpm files found")
97a9151c
 
2820c61a
     def findPackageNameFromRPMFile(self,rpmfile):
         rpmfile=os.path.basename(rpmfile)
         releaseindex=rpmfile.rfind("-")
         if releaseindex == -1:
             self.logger.error("Invalid rpm file:"+rpmfile)
518d6a6f
             raise Exception("Invalid RPM")
2820c61a
         versionindex=rpmfile[0:releaseindex].rfind("-")
         if versionindex == -1:
             self.logger.error("Invalid rpm file:"+rpmfile)
518d6a6f
             raise Exception("Invalid RPM")
2820c61a
         packageName=rpmfile[0:versionindex]
97a9151c
         return packageName
af3575c9
 
     def findPackageInfoFromRPMFile(self,rpmfile):
         rpmfile=os.path.basename(rpmfile)
         rpmfile=rpmfile.replace(".x86_64.rpm","")
         rpmfile=rpmfile.replace(".noarch.rpm","")
         releaseindex=rpmfile.rfind("-")
         if releaseindex == -1:
             self.logger.error("Invalid rpm file:"+rpmfile)
             raise Exception("Invalid RPM")
         versionindex=rpmfile[0:releaseindex].rfind("-")
         if versionindex == -1:
             self.logger.error("Invalid rpm file:"+rpmfile)
             raise Exception("Invalid RPM")
         packageName=rpmfile[0:versionindex]
         version=rpmfile[versionindex+1:releaseindex]
         release=rpmfile[releaseindex+1:]
         return packageName,version,release
2cfb758d
 
518d6a6f
     def findInstalledRPMPackages(self, chrootID):
         cmd = self.rpmBinary+" "+self.queryRpmPackageOptions
         chrootCmd=self.runInChrootCommand+" "+chrootID
         cmdUtils=CommandUtils()
         result=cmdUtils.runCommandInShell2(cmd, chrootCmd)
610ab83e
         if result is not None:
             return result.split()
518d6a6f
         return result
75a2daa5
 
     def adjustGCCSpecs(self, package, chrootID, logPath):
         opt = " " + constants.specData.getSecurityHardeningOption(package)
         cmdUtils=CommandUtils()
8d0a7e93
         cpcmd="cp "+ self.adjustGCCSpecScript+" "+chrootID+"/tmp/"+self.adjustGCCSpecScript
75a2daa5
         cmd = "/tmp/"+self.adjustGCCSpecScript+opt
         logFile = logPath+"/adjustGCCSpecScript.log"
         chrootCmd=self.runInChrootCommand+" "+chrootID
8d0a7e93
         returnVal = cmdUtils.runCommandInShell(cpcmd, logFile)
         if not returnVal:
42ffccb5
             self.logger.error("Error during copying the file adjust gcc spec")
36c2f510
             raise Exception("Failed while copying adjust gcc spec file")
610ab83e
         returnVal = cmdUtils.runCommandInShell(cmd, logFile, chrootCmd)
         if returnVal:
             return
 
         self.logger.debug(cmdUtils.runCommandInShell2("ls -la " + chrootID + "/tmp/" + self.adjustGCCSpecScript))
         self.logger.debug(cmdUtils.runCommandInShell2("lsof " + chrootID + "/tmp/" + self.adjustGCCSpecScript))
         self.logger.debug(cmdUtils.runCommandInShell2("ps ax"))
 
         self.logger.error("Failed while adjusting gcc specs")
36c2f510
         raise Exception("Failed while adjusting gcc specs")