summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pym/portage.py339
-rw-r--r--pym/portage_versions.py222
2 files changed, 226 insertions, 335 deletions
diff --git a/pym/portage.py b/pym/portage.py
index 60ab80e4..63a67f6e 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: <v1>.<v2>...<vx>[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)<len(val1):
- val2.extend(["0"]*(len(val1)-len(val2)))
- elif len(val1)<len(val2):
- val1.extend(["0"]*(len(val2)-len(val1)))
-
- # add back _prepart tails
- if val1_prepart:
- val1[-1] += '_' + val1_prepart
- if val2_prepart:
- val2[-1] += '_' + val2_prepart
- #The above code will extend version numbers out so they
- #have the same number of digits.
- for x in range(0,len(val1)):
- cmp1=relparse(val1[x])
- cmp2=relparse(val2[x])
- for y in range(0,4):
- myret=cmp1[y]-cmp2[y]
- if myret != 0:
- vcmpcache[valkey]=myret
- return myret
- vcmpcache[valkey]=0
- return 0
-
-
-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=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 (mypos<len(mysplit)):
diff --git a/pym/portage_versions.py b/pym/portage_versions.py
new file mode 100644
index 00000000..ddb35a38
--- /dev/null
+++ b/pym/portage_versions.py
@@ -0,0 +1,222 @@
+import re,string
+
+ver_regexp = re.compile("^(cvs\\.)?(\\d+)((\\.\\d+)*)([a-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]))
+
+ # 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]:
+ # it's possible that the s(1|2)[1] == ''
+ # in such a case, fudge it.
+ try: r1 = string.atoi(s1[1])
+ except ValueError: r1 = 0
+ try: r2 = string.atoi(s2[1])
+ except ValueError: r2 = 0
+ return r1 - r2
+
+ # 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
+
+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)
+