support/package-builder/SpecParser.py
2820c61a
 import re
 from StringUtils import StringUtils
 from SpecStructures import *
 
 class SpecParser(object):
     def __init__(self):
         self.cleanMacro=rpmMacro().setName("clean")
         self.prepMacro=rpmMacro().setName("prep")
         self.buildMacro=rpmMacro().setName("build")
         self.installMacro=rpmMacro().setName("install")
         self.changelogMacro=rpmMacro().setName("changelog")
         self.checkMacro=rpmMacro().setName("check")
         self.packages={}
         self.specAdditionalContent=""
cb4e8710
         self.globalSecurityHardening=""
2820c61a
         
     
     def readPkgNameFromPackageMacro(self,data,basePkgName=None):
         data=" ".join(data.split())
         pkgHeaderName=data.split(" ")
         lenpkgHeaderName = len(pkgHeaderName)
         
         if (lenpkgHeaderName >= 3 and pkgHeaderName[1] != "-n"):
             lenpkgHeaderName = 1
         if (lenpkgHeaderName == 2 or lenpkgHeaderName == 1 ) and basePkgName is None :
             print "Invalid basePkgName"
             return False,None
         if lenpkgHeaderName == 3 :
             return True,pkgHeaderName[2]
         if lenpkgHeaderName == 2 :
             return True,basePkgName + "-"+pkgHeaderName[1]
         if lenpkgHeaderName == 1:
             return True, basePkgName
     
     def parseSpecFile(self,specfile):
         self.createDefaultPackage()
         currentPkg="default"
         specFile = open(specfile)
         lines = specFile.readlines()
         totalLines=len(lines)
         i=0
         while i < totalLines:
             line = lines[i].strip()
             if self.isSpecMacro(line):
                 macro,i=self.readMacroFromFile(i, lines)
                 self.updateMacro(macro)
             elif self.isPackageMacro(line):
                 defaultpkg = self.packages.get('default')
                 returnVal,packageName=self.readPkgNameFromPackageMacro(line, defaultpkg.name)
                 packageName=defaultpkg.decodeContents(packageName)
                 if not returnVal:
                     return False
                 if re.search('^'+'%package',line) :
                     pkg = Package(defaultpkg)
                     pkg.name=packageName
                     currentPkg=packageName
                     self.packages[pkg.name]=pkg
                 else:
                     if defaultpkg.name == packageName :
                         packageName = 'default'
                     if not self.packages.has_key(packageName):
                         return False
                     macro,i=self.readMacroFromFile(i, lines)
                     self.packages[packageName].updatePackageMacro(macro)
             elif self.isPackageHeaders(line):
                 self.readPackageHeaders(line, self.packages[currentPkg])
cb4e8710
             elif self.isGlobalSecurityHardening(line):
                 self.readSecurityHardening(line)
3cc43c92
             elif self.isChecksum(line):
                 self.readChecksum(line, self.packages[currentPkg])
2820c61a
             else:
                 self.specAdditionalContent+=line+"\n"
             i=i+1
         specFile.close()
     
     def createDefaultPackage(self):
         pkg = Package()
         self.packages["default"]=pkg
     
     def readMacroFromFile(self,currentPos,lines):
         macro = rpmMacro()
         line = lines[currentPos]
         macro.position = currentPos
         macro.endposition=currentPos
         endPos=len(lines)
         line = " ".join(line.split())
         flagindex = line.find(" ")
         if flagindex != -1:
             macro.macroFlag=line[flagindex+1:]
             macro.macroName=line[:flagindex]
         else:
             macro.macroName=line
 
         if currentPos+1 < len(lines) and self.isMacro(lines[currentPos+1]):
             return macro,currentPos
             
         for j in range(currentPos+1,endPos):
             content = lines[j]
             if j+1 < endPos and self.isMacro(lines[j+1]):
                 return macro,j
             macro.content += content +'\n'
             macro.endposition=j
         return macro,endPos
         
 
     def updateMacro(self,macro):
         if macro.macroName == "%clean":
             self.cleanMacro=macro
             return True
         if macro.macroName == "%prep":
             self.prepMacro=macro
             return True
         if macro.macroName == "%build":
             self.buildMacro=macro
             return True
         if macro.macroName == "%install":
             self.installMacro=macro
             return True
         if macro.macroName == "%changelog":
             self.changelogMacro=macro
             return True
         if macro.macroName == "%check":
             self.checkMacro=macro
             return True
         return False
             
     def isMacro(self,line):
         return self.isPackageMacro(line) or self.isSpecMacro(line)
     
     def isSpecMacro(self,line):
         if re.search('^'+'%clean',line) :
             return True
         elif re.search('^'+'%prep',line) :
             return True            
         elif re.search('^'+'%build',line) :
             return True
         elif re.search('^'+'%install',line) :
             return True
         elif re.search('^'+'%changelog',line) :
             return True
         elif re.search('^'+'%check',line) :
             return True
         return False
     
     def isPackageMacro(self,line):
         line=line.strip()
 
         if re.search('^'+'%post',line) :
             return True
         elif re.search('^'+'%postun',line) :
             return True
         elif re.search('^'+'%files',line) :
             return True
         elif re.search('^'+'%description',line) :
             return True
         elif re.search('^'+'%package',line) :
             return True
         return False
     
     def isPackageHeaders(self,line):
         if re.search('^'+'summary:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'name:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'group:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'license:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'version:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'release:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'distribution:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'requires:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'provides:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'obsoletes:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'conflicts:',line,flags=re.IGNORECASE) :
             return True
920a9773
         elif re.search('^'+'url:',line,flags=re.IGNORECASE) :
             return True
2820c61a
         elif re.search('^'+'source[0-9]*:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'patch[0-9]*:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'buildrequires:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'buildprovides:',line,flags=re.IGNORECASE) :
             return True
         elif re.search('^'+'buildarch:',line,flags=re.IGNORECASE) :
             return True
         return False
 
cb4e8710
     def isGlobalSecurityHardening(self,line):
         if re.search('^%global *security_hardening',line,flags=re.IGNORECASE) :
             return True
         return False
 
3cc43c92
     def isChecksum(self,line):
         if re.search('^%define *sha1',line,flags=re.IGNORECASE) :
             return True
         return False
 
2820c61a
     def readHeader(self,line):
         headerSplitIndex=line.find(":")
         if(headerSplitIndex+1 == len(line) ):
             print line
             print "Error:Invalid header"
             return False, None,None
         headerName=line[0:headerSplitIndex].lower()
         headerContent=line[headerSplitIndex+1:].strip()
         return True,headerName,headerContent
 
 
     def readDependentPackageData(self,line):
         strUtils = StringUtils()
         listPackages=line.split(",")
         listdependentpkgs=[]
         for line in listPackages:
             line=strUtils.getStringInBrackets(line)
             listContents=line.split()
             totalContents = len(listContents)
             i=0
             while i < totalContents:
                 dpkg = dependentPackageData()
                 compare=None
                 if i+2 < len(listContents):
                     if listContents[i+1] == ">=":
                         compare="gte"
                     elif listContents[i+1] == "<=":
                         compare="lte"
                     elif listContents[i+1] == "==":
                         compare="eq"
                     elif listContents[i+1] == "<":
                         compare="lt"
                     elif listContents[i+1] == ">":
                         compare="gt"
                     elif listContents[i+1] == "=":
                         compare="eq"
                     
                 if compare is not None:
                     dpkg.package=listContents[i]
                     dpkg.compare=compare
                     dpkg.version=listContents[i+2]
                     i=i+3
                 else:
                     dpkg.package=listContents[i]
                     i=i+1
                 listdependentpkgs.append(dpkg)
         return listdependentpkgs
 
     def readPackageHeaders(self,line,pkg):
         returnVal,headerName,headerContent=self.readHeader(line)
         if not returnVal:
             return False
 
         headerContent=pkg.decodeContents(headerContent)
         if headerName == 'summary':
             pkg.summary=headerContent
             return True
         if headerName == 'name':
             pkg.name=headerContent
             return True
         if headerName == 'group':
             pkg.group=headerContent
             return True
         if headerName == 'license':
             pkg.license=headerContent
             return True
         if headerName == 'version':
             pkg.version=headerContent
             return True
         if headerName == 'buildarch':
             pkg.buildarch=headerContent
             return True
         if headerName == 'release':
             pkg.release=headerContent
             return True
         if headerName == 'distribution':
             pkg.distribution=headerContent
             return True
920a9773
         if headerName == 'url':
             pkg.URL=headerContent
             return True
2820c61a
         if headerName.find('source') != -1:
             pkg.sources.append(headerContent)
             return True
         if headerName.find('patch') != -1:
             pkg.patches.append(headerContent)
             return True
         if headerName == 'requires' or headerName == 'provides' or headerName == 'obsoletes' or headerName == 'conflicts' or headerName == 'buildrequires' or headerName == 'buildprovides':
             dpkg=self.readDependentPackageData(headerContent)
             if dpkg is None:
                 return False
             if headerName == 'requires':
                 pkg.requires.extend(dpkg)
             if headerName == 'provides':
                 pkg.provides.extend(dpkg)
             if headerName == 'obsoletes':
                 pkg.obsoletes.extend(dpkg)
             if headerName == 'conflicts':
                 pkg.conflicts.extend(dpkg)
             if headerName == 'buildrequires':
                 pkg.buildrequires.extend(dpkg)
             if headerName == 'buildprovides':
                 pkg.buildprovides.extend(dpkg)
                     
             return True
         return False
cb4e8710
 
     def readSecurityHardening(self,line):
         data = line.lower().strip();
         words=data.split(" ")
         nrWords = len(words)
         if (nrWords != 3):
             print "Error: Unable to parse line: "+line
             return False
         if (words[2] != "none" and words[2] != "nonow") :
             print "Error: Invalid security_hardening value: " + words[2]
             return False
         self.globalSecurityHardening = words[2]
         return True;
3cc43c92
 
     def readChecksum(self,line,pkg):
         strUtils = StringUtils()
         data = line.strip();
         words=data.split(" ")
         nrWords = len(words)
         if (nrWords != 3):
             print "Error: Unable to parse line: "+line
             return False
         value=words[2].split("=")
         if (len(value) != 2):
             print "Error: Unable to parse line: "+line
             return False
         matchedSources=[]
         for source in pkg.sources:
             sourceName=strUtils.getFileNameFromURL(source)
             if (sourceName.startswith(value[0])):
                 matchedSources.append(sourceName)
         if (len(matchedSources) == 0):
             print "Error: Can not find match for sha1 "+value[0]
             return False
         if (len(matchedSources) > 1):
             print "Error: Too many matches in sources: "+matchedSources+" for sha1 "+value[0]
             return False
         pkg.checksums[sourceName] = value[1]
         return True;