From 9f3a46665c40b48206c90fabc5befaaeff6b43d0 Mon Sep 17 00:00:00 2001 From: Marius Mauch Date: Sun, 13 Nov 2005 16:07:28 +0000 Subject: Backport of version code rewrite (bug 37406), should be completely backwards compatible (and the algorithm has been tested on the whole tree multiple times already). Also adds some new features in version syntax like cvs version prefixes (in the same package) and multiple suffixes. svn path=/main/trunk/; revision=2309 --- pym/portage.py | 339 +----------------------------------------------- pym/portage_versions.py | 222 +++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+), 335 deletions(-) create mode 100644 pym/portage_versions.py (limited to 'pym') diff --git a/pym/portage.py b/pym/portage.py index 60ab80e4b..63a67f6e8 100644 --- a/pym/portage.py +++ b/pym/portage.py @@ -100,6 +100,10 @@ try: from portage_checksum import perform_md5,perform_checksum,prelink_capable import eclass_cache from portage_localization import _ + + # Need these functions directly in portage namespace to not break every external tool in existence + from portage_versions import ververify,vercmp,catsplit,catpkgsplit,pkgsplit,pkgcmp + except SystemExit, e: raise except Exception, e: @@ -3009,150 +3013,6 @@ def unmerge(cat,pkg,myroot,mysettings,mytrimworld=1): mylink.unmerge(trimworld=mytrimworld,cleanup=1) mylink.delete() -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 SystemExit, e: - raise - 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=int(x) - except SystemExit, e: - raise - 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=int(myval[-1]) - vercache[myorigval]=1 - return 1 - except SystemExit, e: - raise - 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=int(myval[-1][:-1]) - vercache[myorigval]=1 - return 1 - # 1a, 2.0b, etc. - except SystemExit, e: - raise - 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=int(ep[0][-1]) - chk=ep[0] - except SystemExit, e: - raise - except: - # because it's ok last char is not numeric. example: foo-1.0.0a_pre1 - chk=ep[0][:-1] - - try: - foo=int(chk) - except SystemExit, e: - raise - 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=int(ep[1][len(mye):]) - vercache[myorigval]=1 - return 1 - except SystemExit, e: - raise - except: - #if no endversions work, *then* we return 0 - pass - if not silent: - print "!!! Name error in",myorigval - vercache[myorigval]=0 - return 0 - def isvalidatom(atom): mycpv_cps = catpkgsplit(dep_getcpv(atom)) operator = get_operator(atom) @@ -3198,201 +3058,10 @@ def isspecific(mypkg): iscache[mypkg]=0 return 0 -# This function can be used as a package verification function, i.e. -# "pkgsplit("foo-1.2-1") will return None if foo-1.2-1 isn't a valid -# package (with version) name. If it is a valid name, pkgsplit will -# return a list containing: [ pkgname, pkgversion(norev), pkgrev ]. -# For foo-1.2-1, this list would be [ "foo", "1.2", "1" ]. For -# Mesa-3.0, this list would be [ "Mesa", "3.0", "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: - int(myrev[1:]) - revok=1 - except SystemExit, e: - raise - except: - pass - if revok: - if ververify(myparts[-2]): - if len(myparts)==2: - pkgcache[mypkg]=None - return None - else: - for x in myparts[:-2]: - if ververify(x): - pkgcache[mypkg]=None - return None - #names can't have versiony looking parts - myval=[string.join(myparts[:-2],"-"),myparts[-2],myparts[-1]] - pkgcache[mypkg]=myval - return myval - else: - pkgcache[mypkg]=None - return None - - elif ververify(myparts[-1],silent=silent): - if len(myparts)==1: - if not silent: - print "!!! Name error in",mypkg+": missing name part." - pkgcache[mypkg]=None - return None - else: - for x in myparts[:-1]: - if ververify(x): - if not silent: - print "!!! Name error in",mypkg+": multiple version parts." - pkgcache[mypkg]=None - return None - myval=[string.join(myparts[:-1],"-"),myparts[-1],"r0"] - pkgcache[mypkg]=myval[:] - return myval - else: - pkgcache[mypkg]=None - return None - def getCPFromCPV(mycpv): """Calls pkgsplit on a cpv and returns only the cp.""" return pkgsplit(mycpv)[0] -catcache={} -def catpkgsplit(mydata,silent=1): - "returns [cat, pkgname, version, rev ]" - try: - if not catcache[mydata]: - return None - return catcache[mydata][:] - except KeyError: - pass - mysplit=mydata.split("/") - p_split=None - if len(mysplit)==1: - retval=["null"] - p_split=pkgsplit(mydata,silent=silent) - elif len(mysplit)==2: - retval=[mysplit[0]] - p_split=pkgsplit(mysplit[1],silent=silent) - if not p_split: - catcache[mydata]=None - return None - retval.extend(p_split) - catcache[mydata]=retval - return retval - -# 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)0: - return 1 - if mycmp<0: - return -1 - r1=int(pkg1[2][1:]) - r2=int(pkg2[2][1:]) - if r1>r2: - return 1 - if r2>r1: - return -1 - return 0 - def dep_parenreduce(mysplit,mypos=0): "Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists" while (mypos0: + 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 + +catcache={} +def catpkgsplit(mydata,silent=1): + "returns [cat, pkgname, version, rev ]" + try: + if not catcache[mydata]: + return None + return catcache[mydata][:] + except KeyError: + pass + mysplit=mydata.split("/") + p_split=None + if len(mysplit)==1: + retval=["null"] + p_split=pkgsplit(mydata,silent=silent) + elif len(mysplit)==2: + retval=[mysplit[0]] + p_split=pkgsplit(mysplit[1],silent=silent) + if not p_split: + catcache[mydata]=None + return None + retval.extend(p_split) + catcache[mydata]=retval + return retval + +def catsplit(mydep): + return mydep.split("/", 1) + -- cgit v1.2.3-1-g7c22