2820c61a |
from PackageUtils import PackageUtils
from Logger import Logger
from ChrootUtils import ChrootUtils
from ToolChainUtils import ToolChainUtils
from CommandUtils import CommandUtils
import os.path
from constants import constants |
387ea52d |
import shutil |
45c9260c |
from SpecData import SPECS |
56c77555 |
import docker
import sys |
2820c61a |
|
56c77555 |
class PackageBuilderBase(object):
def __init__(self,mapPackageToCycles,listAvailableCyclicPackages,listBuildOptionPackages,pkgBuildOptionFile, pkgBuildType): |
7f9d2e12 |
# will be initialized in buildPackageThreadAPI()
self.logName=None
self.logPath=None
self.logger=None
self.package=None |
2820c61a |
self.mapPackageToCycles = mapPackageToCycles
self.listAvailableCyclicPackages = listAvailableCyclicPackages
self.listNodepsPackages = ["glibc","gmp","zlib","file","binutils","mpfr","mpc","gcc","ncurses","util-linux","groff","perl","texinfo","rpm","openssl","go"] |
90d8acae |
self.listBuildOptionPackages=listBuildOptionPackages
self.pkgBuildOptionFile=pkgBuildOptionFile |
56c77555 |
self.pkgBuildType = pkgBuildType |
97a9151c |
|
56c77555 |
def buildPackageThreadAPIPrepare(self,package,outputMap, threadName):
self.package=package
self.logName="build-"+package
self.logPath=constants.logPath+"/build-"+package
if not os.path.isdir(self.logPath):
cmdUtils = CommandUtils()
cmdUtils.runCommandInShell("mkdir -p "+self.logPath)
self.logger=Logger.getLogger(self.logName,self.logPath) |
97a9151c |
|
2820c61a |
def findPackageNameFromRPMFile(self,rpmfile):
rpmfile=os.path.basename(rpmfile)
releaseindex=rpmfile.rfind("-")
if releaseindex == -1:
self.logger.error("Invalid rpm file:"+rpmfile)
return None
versionindex=rpmfile[0:releaseindex].rfind("-")
if versionindex == -1:
self.logger.error("Invalid rpm file:"+rpmfile)
return None
packageName=rpmfile[0:versionindex]
return packageName |
97a9151c |
|
56c77555 |
def findInstalledPackages(self, instanceID):
pkgUtils = PackageUtils(self.logName, self.logPath)
if self.pkgBuildType == "chroot":
listInstalledRPMs = pkgUtils.findInstalledRPMPackages(instanceID)
elif self.pkgBuildType == "container":
listInstalledRPMs = pkgUtils.findInstalledRPMPackagesInContainer(instanceID) |
2820c61a |
listInstalledPackages=[]
for installedRPM in listInstalledRPMs:
packageName=self.findPackageNameFromRPMFile(installedRPM)
if packageName is not None:
listInstalledPackages.append(packageName) |
56c77555 |
return listInstalledPackages, listInstalledRPMs |
adf248d5 |
|
7f9d2e12 |
def checkIfPackageIsAlreadyBuilt(self):
basePkg=SPECS.getData().getSpecName(self.package) |
45c9260c |
listRPMPackages=SPECS.getData().getRPMPackages(basePkg) |
adf248d5 |
packageIsAlreadyBuilt=True
pkgUtils = PackageUtils(self.logName,self.logPath)
for pkg in listRPMPackages:
if pkgUtils.findRPMFileForGivenPackage(pkg) is None:
packageIsAlreadyBuilt=False
break
return packageIsAlreadyBuilt
|
2820c61a |
def findRunTimeRequiredRPMPackages(self,rpmPackage): |
45c9260c |
listRequiredPackages=SPECS.getData().getRequiresForPackage(rpmPackage) |
518d6a6f |
return listRequiredPackages |
97a9151c |
|
7f9d2e12 |
def findBuildTimeRequiredPackages(self):
listRequiredPackages=SPECS.getData().getBuildRequiresForPackage(self.package) |
518d6a6f |
return listRequiredPackages |
97a9151c |
|
7f9d2e12 |
def findBuildTimeCheckRequiredPackages(self):
listRequiredPackages=SPECS.getData().getCheckBuildRequiresForPackage(self.package) |
5f40784b |
return listRequiredPackages
|
56c77555 |
def installPackage(self, pkgUtils, package, instanceID, destLogPath, listInstalledPackages, listInstalledRPMs):
latestRPM = os.path.basename(pkgUtils.findRPMFileForGivenPackage(package)).replace(".rpm", "")
if package in listInstalledPackages and latestRPM in listInstalledRPMs: |
518d6a6f |
return |
75cb675a |
# mark it as installed - to avoid cyclic recursion
listInstalledPackages.append(package) |
56c77555 |
listInstalledRPMs.append(latestRPM)
self.installDependentRunTimePackages(pkgUtils,package,instanceID,destLogPath,listInstalledPackages, listInstalledRPMs) |
2820c61a |
noDeps=False
if self.mapPackageToCycles.has_key(package):
noDeps = True
if package in self.listNodepsPackages:
noDeps=True |
a5e4be9f |
if package in constants.noDepsPackageList:
noDeps=True |
56c77555 |
if self.pkgBuildType == "chroot":
pkgUtils.installRPM(package,instanceID,noDeps,destLogPath)
elif self.pkgBuildType == "container":
pkgUtils.prepRPMforInstallInContainer(package, instanceID, noDeps, destLogPath) |
2820c61a |
|
56c77555 |
def installDependentRunTimePackages(self,pkgUtils,package,instanceID,destLogPath,listInstalledPackages, listInstalledRPMs): |
518d6a6f |
listRunTimeDependentPackages=self.findRunTimeRequiredRPMPackages(package) |
2820c61a |
if len(listRunTimeDependentPackages) != 0:
for pkg in listRunTimeDependentPackages:
if self.mapPackageToCycles.has_key(pkg) and pkg not in self.listAvailableCyclicPackages:
continue |
56c77555 |
latestPkgRPM = os.path.basename(pkgUtils.findRPMFileForGivenPackage(pkg)).replace(".rpm", "")
if pkg in listInstalledPackages and latestPkgRPM in listInstalledRPMs: |
2820c61a |
continue |
56c77555 |
self.installPackage(pkgUtils, pkg, instanceID, destLogPath, listInstalledPackages, listInstalledRPMs)
class PackageBuilderContainer(object):
def __init__(self, mapPackageToCycles, listAvailableCyclicPackages, listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType):
self.buildContainerImage = "photon_build_container:latest"
self.dockerClient = docker.from_env(version="auto")
self.base = PackageBuilderBase(mapPackageToCycles, listAvailableCyclicPackages,
listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType)
def buildPackageThreadAPI(self, package, outputMap, threadName):
self.base.buildPackageThreadAPIPrepare(package, outputMap, threadName)
try:
self.buildPackage()
outputMap[threadName]=True
except Exception as e:
# TODO: self.logger might be None |
b8ab7fb4 |
self.base.logger.exception(e) |
56c77555 |
outputMap[threadName]=False
raise e
def prepareBuildContainer(self, containerTaskName, packageName, isToolChainPackage=False):
# Prepare an empty chroot environment to let docker use the BUILD folder.
# This avoids docker using overlayFS which will cause make check failure.
chrootName="build-"+packageName
chrUtils = ChrootUtils(self.base.logName, self.base.logPath)
returnVal,chrootID = chrUtils.createChroot(chrootName)
if not returnVal:
raise Exception("Unable to prepare build root")
cmdUtils = CommandUtils()
cmdUtils.runCommandInShell("mkdir -p " + chrootID + constants.topDirPath)
cmdUtils.runCommandInShell("mkdir -p " + chrootID + constants.topDirPath + "/BUILD")
containerID = None
mountVols = {
constants.prevPublishRPMRepo: {'bind': '/publishrpms', 'mode': 'ro'},
constants.prevPublishXRPMRepo: {'bind': '/publishxrpms', 'mode': 'ro'},
constants.tmpDirPath: {'bind': '/tmp', 'mode': 'rw'},
constants.rpmPath: {'bind': constants.topDirPath + "/RPMS", 'mode': 'rw'},
constants.sourceRpmPath: {'bind': constants.topDirPath + "/SRPMS", 'mode': 'rw'},
constants.logPath + "/" + self.base.logName: {'bind': constants.topDirPath + "/LOGS", 'mode': 'rw'}, |
b572cf8e |
chrootID + constants.topDirPath + "/BUILD": {'bind': constants.topDirPath + "/BUILD", 'mode': 'rw'},
constants.dockerUnixSocket: {'bind': constants.dockerUnixSocket, 'mode': 'rw'} |
56c77555 |
}
containerName = containerTaskName
containerName = containerName.replace("+", "p")
try:
oldContainerID = self.dockerClient.containers.get(containerName)
if oldContainerID is not None:
oldContainerID.remove(force=True)
except docker.errors.NotFound:
sys.exc_clear()
try:
self.base.logger.info("BuildContainer-prepareBuildContainer: Starting build container: " + containerName)
#TODO: Is init=True equivalent of --sig-proxy?
privilegedDocker = False
cap_list = ['SYS_PTRACE']
if packageName in constants.listReqPrivilegedDockerForTest:
privilegedDocker = True
containerID = self.dockerClient.containers.run(self.buildContainerImage,
detach=True,
cap_add=cap_list,
privileged=privilegedDocker,
name=containerName,
network_mode="host",
volumes=mountVols,
command="/bin/bash -l -c /wait.sh")
self.base.logger.debug("Started Photon build container for task " + containerTaskName
+ " ID: " + containerID.short_id)
if not containerID:
raise Exception("Unable to start Photon build container for task " + containerTaskName)
except Exception as e:
self.base.logger.debug("Unable to start Photon build container for task " + containerTaskName)
raise e
return containerID, chrootID |
b5e09fac |
|
56c77555 |
def buildPackage(self):
#do not build if RPM is already built
#test only if the package is in the testForceRPMS with rpmCheck
#build only if the package is not in the testForceRPMS with rpmCheck
if self.base.checkIfPackageIsAlreadyBuilt():
if not constants.rpmCheck:
self.base.logger.info("Skipping building the package:" + self.base.package)
return
elif constants.rpmCheck and self.base.package not in constants.testForceRPMS:
self.base.logger.info("Skipping testing the package:" + self.base.package)
return
#should initialize a logger based on package name
containerTaskName = "build-" + self.base.package
containerID = None
chrootID = None
isToolChainPackage = False
if self.base.package in constants.listToolChainPackages:
isToolChainPackage = True
destLogPath = constants.logPath + "/build-" + self.base.package
try:
containerID, chrootID = self.prepareBuildContainer(containerTaskName, self.base.package, isToolChainPackage)
tcUtils = ToolChainUtils(self.base.logName, self.base.logPath)
if self.base.package in constants.perPackageToolChain:
self.base.logger.debug(constants.perPackageToolChain[self.base.package])
tcUtils.installCustomToolChainRPMSinContainer(containerID,
constants.perPackageToolChain[self.base.package],
self.base.package);
listInstalledPackages, listInstalledRPMs = self.base.findInstalledPackages(containerID)
self.base.logger.info(listInstalledPackages)
listDependentPackages = self.base.findBuildTimeRequiredPackages()
if constants.rpmCheck and self.base.package in constants.testForceRPMS:
listDependentPackages.extend(self.base.findBuildTimeCheckRequiredPackages())
testPackages=set(constants.listMakeCheckRPMPkgtoInstall)-set(listInstalledPackages)-set([self.base.package])
listDependentPackages.extend(testPackages)
listDependentPackages=list(set(listDependentPackages))
pkgUtils = PackageUtils(self.base.logName, self.base.logPath)
if len(listDependentPackages) != 0:
self.base.logger.info("BuildContainer-buildPackage: Installing dependent packages..")
self.base.logger.info(listDependentPackages)
for pkg in listDependentPackages:
self.base.installPackage(pkgUtils, pkg, containerID, destLogPath, listInstalledPackages, listInstalledRPMs)
pkgUtils.installRPMSInAOneShotInContainer(containerID, destLogPath)
self.base.logger.info("Finished installing the build time dependent packages......")
self.base.logger.info("BuildContainer-buildPackage: Start building the package: " + self.base.package)
pkgUtils.adjustGCCSpecsInContainer(self.base.package, containerID, destLogPath)
pkgUtils.buildRPMSForGivenPackageInContainer(
self.base.package,
containerID,
self.base.listBuildOptionPackages,
self.base.pkgBuildOptionFile,
destLogPath)
self.base.logger.info("BuildContainer-buildPackage: Successfully built the package: " + self.base.package)
except Exception as e:
self.base.logger.error("Failed while building package:" + self.base.package)
if containerID is not None:
self.base.logger.debug("Container " + containerID.short_id + " retained for debugging.")
logFileName = os.path.join(destLogPath, self.base.package + ".log")
fileLog = os.popen('tail -n 20 ' + logFileName).read()
self.base.logger.debug(fileLog)
raise e
# Remove the container
if containerID is not None:
containerID.remove(force=True)
# Remove the dummy chroot
if chrootID is not None:
chrUtils = ChrootUtils(self.base.logName, self.base.logPath)
chrUtils.destroyChroot(chrootID)
class PackageBuilderChroot(object):
def __init__(self, mapPackageToCycles, listAvailableCyclicPackages, listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType):
self.base = PackageBuilderBase(mapPackageToCycles, listAvailableCyclicPackages,
listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType)
def buildPackageThreadAPI(self, package, outputMap, threadName):
self.base.buildPackageThreadAPIPrepare(package,outputMap, threadName)
try:
self.buildPackage()
outputMap[threadName]=True
except Exception as e:
# TODO: self.logger might be None |
b8ab7fb4 |
self.base.logger.exception(e) |
56c77555 |
outputMap[threadName]=False
raise e
def prepareBuildRoot(self):
chrootID=None
chrootName="build-"+self.base.package
try:
chrUtils = ChrootUtils(self.base.logName,self.base.logPath)
returnVal,chrootID = chrUtils.createChroot(chrootName)
self.base.logger.debug("Created new chroot: " + chrootID)
if not returnVal:
raise Exception("Unable to prepare build root")
tUtils=ToolChainUtils(self.base.logName,self.base.logPath)
tUtils.installToolChainRPMS(chrootID, self.base.package, self.base.logPath)
except Exception as e:
if chrootID is not None:
self.base.logger.debug("Deleting chroot: " + chrootID)
chrUtils.destroyChroot(chrootID)
raise e
return chrootID
def buildPackage(self):
#do not build if RPM is already built
#test only if the package is in the testForceRPMS with rpmCheck
#build only if the package is not in the testForceRPMS with rpmCheck
if self.base.checkIfPackageIsAlreadyBuilt():
if not constants.rpmCheck:
self.base.logger.info("Skipping building the package:" + self.base.package)
return
elif constants.rpmCheck and self.base.package not in constants.testForceRPMS:
self.base.logger.info("Skipping testing the package:" + self.base.package)
return
chrUtils = ChrootUtils(self.base.logName,self.base.logPath)
chrootID=None
try:
chrootID = self.prepareBuildRoot()
listInstalledPackages, listInstalledRPMs = self.base.findInstalledPackages(chrootID)
listDependentPackages=self.base.findBuildTimeRequiredPackages()
if constants.rpmCheck and self.base.package in constants.testForceRPMS:
listDependentPackages.extend(self.base.findBuildTimeCheckRequiredPackages())
testPackages=set(constants.listMakeCheckRPMPkgtoInstall)-set(listInstalledPackages)-set([self.base.package])
listDependentPackages.extend(testPackages)
listDependentPackages=list(set(listDependentPackages))
pkgUtils = PackageUtils(self.base.logName,self.base.logPath)
if len(listDependentPackages) != 0:
self.base.logger.info("Installing the build time dependent packages......")
for pkg in listDependentPackages:
self.base.installPackage(pkgUtils, pkg, chrootID, self.base.logPath, listInstalledPackages, listInstalledRPMs)
pkgUtils.installRPMSInAOneShot(chrootID, self.base.logPath)
self.base.logger.info("Finished installing the build time dependent packages......")
pkgUtils.adjustGCCSpecs(self.base.package, chrootID, self.base.logPath)
pkgUtils.buildRPMSForGivenPackage(self.base.package, chrootID,self.base.listBuildOptionPackages,
self.base.pkgBuildOptionFile, self.base.logPath)
self.base.logger.info("Successfully built the package:" + self.base.package)
except Exception as e:
self.base.logger.error("Failed while building package:" + self.base.package)
self.base.logger.debug("Chroot with ID: " + chrootID + " not deleted for debugging.")
logFileName = os.path.join(self.base.logPath, self.base.package + ".log")
fileLog = os.popen('tail -n 100 ' + logFileName).read()
self.base.logger.debug(fileLog)
raise e
if chrootID is not None:
chrUtils.destroyChroot(chrootID) |