import re,string ############### new code ############### ver_regexp = re.compile("^(cvs\\.)?(\\d+)((\\.\\d+)*)([a-zA-Z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?$") suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$") suffix_value = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1} def ververify(myver, silent=1): if ver_regexp.match(myver): return 1 else: if not silent: print "!!! syntax error in version: %s" % myver return 0 vercmp_cache = {} def vercmp(ver1, ver2, silent=1): if ver1 == ver2: return 0 mykey=ver1+":"+ver2 try: return vercmp_cache[mykey] except KeyError: pass match1 = ver_regexp.match(ver1) match2 = ver_regexp.match(ver2) # checking that the versions are valid if not match1 or not match1.groups(): if not silent: print "!!! syntax error in version: %s" % ver1 return None if not match2 or not match2.groups(): if not silent: print "!!! syntax error in version: %s" % ver2 return None # shortcut for cvs ebuilds (new style) if match1.group(1) and not match2.group(1): vercmp_cache[mykey] = 1 return 1 elif match2.group(1) and not match1.group(1): vercmp_cache[mykey] = -1 return -1 # building lists of the version parts before the suffix # first part is simple list1 = [string.atoi(match1.group(2))] list2 = [string.atoi(match2.group(2))] # this part would greatly benefit from a fixed-length version pattern if len(match1.group(3)) or len(match2.group(3)): vlist1 = match1.group(3)[1:].split(".") vlist2 = match2.group(3)[1:].split(".") for i in range(0, max(len(vlist1), len(vlist2))): if len(vlist1) <= i or len(vlist1[i]) == 0: list1.append(0) list2.append(string.atoi(vlist2[i])) elif len(vlist2) <= i or len(vlist2[i]) == 0: list1.append(string.atoi(vlist1[i])) list2.append(0) # Let's make life easy and use integers unless we're forced to use floats elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"): list1.append(string.atoi(vlist1[i])) list2.append(string.atoi(vlist2[i])) # now we have to use floats so 1.02 compares correctly against 1.1 else: list1.append(string.atof("0."+vlist1[i])) list2.append(string.atof("0."+vlist2[i])) print list1 print list2 # and now the final letter if len(match1.group(5)): list1.append(ord(match1.group(5))) if len(match2.group(5)): list2.append(ord(match2.group(5))) for i in range(0, max(len(list1), len(list2))): if len(list1) <= i: vercmp_cache[mykey] = -1 return -1 elif len(list2) <= i: vercmp_cache[mykey] = 1 return 1 elif list1[i] != list2[i]: vercmp_cache[mykey] = list1[i] - list2[i] return list1[i] - list2[i] # main version is equal, so now compare the _suffix part list1 = match1.group(6).split("_")[1:] list2 = match2.group(6).split("_")[1:] for i in range(0, max(len(list1), len(list2))): if len(list1) <= i: s1 = ("p","0") else: s1 = suffix_regexp.match(list1[i]).groups() if len(list2) <= i: s2 = ("p","0") else: s2 = suffix_regexp.match(list2[i]).groups() if s1[0] != s2[0]: return suffix_value[s1[0]] - suffix_value[s2[0]] if s1[1] != s2[1]: return string.atoi(s1[1]) - string.atoi(s2[1]) # the suffix part is equal to, so finally check the revision if match1.group(10): r1 = string.atoi(match1.group(10)) else: r1 = 0 if match2.group(10): r2 = string.atoi(match2.group(10)) else: r2 = 0 vercmp_cache[mykey] = r1 - r2 return r1 - r2 def pkgcmp(pkg1, pkg2): if pkg1[0] != pkg2[0]: return None mycmp=vercmp(pkg1[1],pkg2[1]) if mycmp>0: return 1 if mycmp<0: return -1 r1=string.atof(pkg1[2][1:]) r2=string.atof(pkg2[2][1:]) if r1>r2: return 1 if r2>r1: return -1 return 0 pkgcache={} def pkgsplit(mypkg,silent=1): try: if not pkgcache[mypkg]: return None return pkgcache[mypkg][:] except KeyError: pass myparts=string.split(mypkg,'-') if len(myparts)<2: if not silent: print "!!! Name error in",mypkg+": missing a version or name part." pkgcache[mypkg]=None return None for x in myparts: if len(x)==0: if not silent: print "!!! Name error in",mypkg+": empty \"-\" part." pkgcache[mypkg]=None return None #verify rev revok=0 myrev=myparts[-1] if len(myrev) and myrev[0]=="r": try: string.atoi(myrev[1:]) revok=1 except: pass if revok: verPos = -2 revision = myparts[-1] else: verPos = -1 revision = "r0" if ververify(myparts[verPos]): if len(myparts)== (-1*verPos): pkgcache[mypkg]=None return None else: for x in myparts[:verPos]: if ververify(x): pkgcache[mypkg]=None return None #names can't have versiony looking parts myval=[string.join(myparts[:verPos],"-"),myparts[verPos],revision] pkgcache[mypkg]=myval return myval else: pkgcache[mypkg]=None return None ################ old code ################### _endversion={"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} _endversion_keys = ["pre", "p", "alpha", "beta", "rc"] def _pkgcmp(pkg1,pkg2): """if returnval is less than zero, then pkg2 is newer than pkg1, zero if equal and positive if older.""" if pkg1[0] != pkg2[0]: return None mycmp=vercmp(pkg1[1],pkg2[1]) if mycmp>0: return 1 if mycmp<0: return -1 r1=string.atoi(pkg1[2][1:]) r2=string.atoi(pkg2[2][1:]) if r1>r2: return 1 if r2>r1: return -1 return 0 def _relparse(myver): "converts last version part into three components" number=0 suffix=0 endtype=0 endnumber=0 mynewver=string.split(myver,"_") myver=mynewver[0] #normal number or number with letter at end divider=len(myver)-1 if myver[divider:] not in "1234567890": #letter at end suffix=ord(myver[divider:]) number=string.atof(myver[0:divider]) else: number=string.atof(myver) if len(mynewver)==2: #an endversion for x in _endversion_keys: elen=len(x) if mynewver[1][:elen] == x: match=1 endtype=_endversion[x] try: endnumber=string.atof(mynewver[1][elen:]) except: endnumber=0 break return [number,suffix,endtype,endnumber] #returns 1 if valid version string, else 0 # valid string in format: ....[a-z,_{endversion}[vy]] # ververify doesn't do package rev. _vercache={} def _ververify(myorigval,silent=1): try: return _vercache[myorigval] except KeyError: pass if len(myorigval)==0: if not silent: print "!!! Name error: package contains empty \"-\" part." return 0 myval=string.split(myorigval,'.') if len(myval)==0: if not silent: print "!!! Name error: empty version string." _vercache[myorigval]=0 return 0 #all but the last version must be a numeric for x in myval[:-1]: if not len(x): if not silent: print "!!! Name error in",myorigval+": two decimal points in a row" _vercache[myorigval]=0 return 0 try: foo=string.atoi(x) except: if not silent: print "!!! Name error in",myorigval+": \""+x+"\" is not a valid version component." _vercache[myorigval]=0 return 0 if not len(myval[-1]): if not silent: print "!!! Name error in",myorigval+": two decimal points in a row" _vercache[myorigval]=0 return 0 try: foo=string.atoi(myval[-1]) _vercache[myorigval]=1 return 1 except: pass #ok, our last component is not a plain number or blank, let's continue if myval[-1][-1] in string.lowercase: try: foo=string.atoi(myval[-1][:-1]) return 1 _vercache[myorigval]=1 # 1a, 2.0b, etc. except: pass #ok, maybe we have a 1_alpha or 1_beta2; let's see #ep="endpart" ep=string.split(myval[-1],"_") if len(ep)!=2: if not silent: print "!!! Name error in",myorigval _vercache[myorigval]=0 return 0 try: foo=string.atoi(ep[0][-1]) chk=ep[0] except: # because it's ok last char is not numeric. example: foo-1.0.0a_pre1 chk=ep[0][:-1] try: foo=string.atoi(chk) except: #this needs to be numeric or numeric+single letter, #i.e. the "1" in "1_alpha" or "1a_alpha" if not silent: print "!!! Name error in",myorigval+": characters before _ must be numeric or numeric+single letter" _vercache[myorigval]=0 return 0 for mye in _endversion_keys: if ep[1][0:len(mye)]==mye: if len(mye)==len(ep[1]): #no trailing numeric; ok _vercache[myorigval]=1 return 1 else: try: foo=string.atoi(ep[1][len(mye):]) _vercache[myorigval]=1 return 1 except: #if no endversions work, *then* we return 0 pass if not silent: print "!!! Name error in",myorigval _vercache[myorigval]=0 return 0 # vercmp: # This takes two version strings and returns an integer to tell you whether # the versions are the same, val1>val2 or val2>val1. _vcmpcache={} def _vercmp(val1,val2): if val1==val2: #quick short-circuit return 0 valkey=val1+" "+val2 try: return _vcmpcache[valkey] try: return -_vcmpcache[val2+" "+val1] except KeyError: pass except KeyError: pass # consider 1_p2 vc 1.1 # after expansion will become (1_p2,0) vc (1,1) # then 1_p2 is compared with 1 before 0 is compared with 1 # to solve the bug we need to convert it to (1,0_p2) # by splitting _prepart part and adding it back _after_expansion val1_prepart = val2_prepart = '' if val1.count('_'): val1, val1_prepart = val1.split('_', 1) if val2.count('_'): val2, val2_prepart = val2.split('_', 1) # replace '-' by '.' # FIXME: Is it needed? can val1/2 contain '-'? val1=string.split(val1,'-') if len(val1)==2: val1[0]=val1[0]+"."+val1[1] val2=string.split(val2,'-') if len(val2)==2: val2[0]=val2[0]+"."+val2[1] val1=string.split(val1[0],'.') val2=string.split(val2[0],'.') #add back decimal point so that .03 does not become "3" ! for x in range(1,len(val1)): if val1[x][0] == '0' : val1[x]='.' + val1[x] for x in range(1,len(val2)): if val2[x][0] == '0' : val2[x]='.' + val2[x] # extend version numbers if len(val2)