#! /usr/bin/env python2.2 # #This file contains basic functionality to process Status files #and assign/compare ebuild levels. #It is imported by portage.py. #See also Status.skel for more info # import os from portage_exceptions import * class StatusError(GenericPortageError): """A very basic one""" def __init__ (self,reason=None): #this "self" in invocation *is* necessary GenericPortageError.__init__(self,reason) #I'll do the list of status levels. This will allow to do comparisions in an #extensible way - so that if there is a decision to change level stucture #doing that will be a matter of changing few lists only. #ATTENTION: order is important!! eStatusList=["unstable","new","confirmed","appr-new","core-new","approved","core"] #these are the levels as defined in make.conf etc. to be assigned to #StabilityLevel and rsyncLevel #the following switches are used in Status files eStatusSwitches=["unstable","no","yes","core"] #the order in Status file: confirmed_flag approved_flag - #thus "yes no" will correspond to confirmed (and not approved) status #this one maps unique pairs to corresponding states #the rest (two "special cases") are processed in the code eStatusMap={("no","no"):"new",("yes","no"):"confirmed",("no","yes"):"appr-new", ("yes","yes"):"approved",("no","core"):"core-new",("yes","core"):"core"} #this class will process ebuild Status (single line) class ebuildStatus: def __init__ (self,pkgName,mypkgVR=None,myConf=None,myAppr=None,statusStr=None): '''call like: eStatus(pkgName,PVR,Conf,Appr) or: eStatus(pkgName,statusStr=str_from_Status_file)''' if pkgName:self.pkgName=pkgName else:raise StatusError("pkgname missing from ebuildStatus invocation") #store (PVR,conf,appr) tuple internally #generate Status string as necessary if mypkgVR and myConf and myAppr: self.PVR=mypkgVR self.confInd=eStatusSwitches.index(myConf) self.apprInd=eStatusSwitches.index(myAppr) else:self.setFromStr(statusStr) #check validity tmp=self.get() def get (self): "returns status from the eStatusList" #check unstable first, then use Map and then check for core #ATTN!! the following line relies on "unstable" being 1st in eStatusList if (eStatusSwitches[self.confInd]=="unstable") or (eStatusSwitches[self.apprInd]=="unstable"): return "unstable" ind=(eStatusSwitches[self.confInd],eStatusSwitches[self.apprInd]) if eStatusMap.has_key(ind):return eStatusMap[ind] #now only 3 possible variants left: ("core","core/yes/no") #since "core" is not supposed to appear in confirmed field I'll raise an exception raise StatusError("unexpected 'core' in confirmedStatus field; override eStatusClass.get to change this behavior") def getStatusStr (self): "returns string suitable for Status file" return " ".join((self.PVR,eStatusSwitches[self.confInd],eStatusSwitches[self.apprInd])) def setFromStr (self,myStr): "initializes object from Status string" try: self.PVR,conf,appr=myStr.split() except:raise StatusError('''while processing %s: problematic Status string: Incorrect number of entries in one of the lines!''' %self.pkgName) try: self.confInd=eStatusSwitches.index(conf) self.apprInd=eStatusSwitches.index(appr) except ValueError:raise StatusError('''while processing %s-%s: problematic Status string: Incorrect Status entries!''' % (self.pkgName,self.PVR)) def isAllowed (self,StabLevel): "returns true if status is greater (more stable) then specified level" #StabLevel:eStateList return eStatusList.index(StabLevel) <= eStatusList.index(self.get()) class pkgStatus(dict): '''This will hold info on all ebuilds associated with certain package This class will have properties similar to dictionary but can be initialized from the Status file''' def __init__(self,pkgDir): '''Reads Status file in pkgDir''' #This constructor enforces pkgName==PN==dirName #that is: ebuild PN part must be the same as dir name in which it resides #The enforcement is done by this code only checking dir name #thus ebuild having different name will not be found and #will assume "new" status per default self.clear() #extract package name if pkgDir[-1]=='/':pkgDir=pkgDir[:-1] self.pkgName=os.path.basename(pkgDir) if os.path.exists(pkgDir+"/Status"): StatusLines=file(pkgDir+"/Status","r").readlines() else:return for line in StatusLines: if (line[0]=="#") or (line.strip()==""):continue self[line.split()[0]]=ebuildStatus(self.pkgName,statusStr=line) def __getitem__(self,key): "need to override default method to return 'new' status in case of absent key" if self.has_key(key): return dict(self).get(key) else: return ebuildStatus(self.pkgName,key,"no","no")