aboutsummaryrefslogtreecommitdiff
path: root/pym
diff options
context:
space:
mode:
authorJason Stubbs <jstubbs@gentoo.org>2005-05-10 15:50:26 +0000
committerJason Stubbs <jstubbs@gentoo.org>2005-05-10 15:50:26 +0000
commit664061788117de1ac3ce05baf720d4ec9b55faa1 (patch)
treef3a6dc3d1b05b17de86bec71bcfec98dc5ffd966 /pym
parent$Header: $ fixes (diff)
downloadportage-cvs-664061788117de1ac3ce05baf720d4ec9b55faa1.tar.gz
portage-cvs-664061788117de1ac3ce05baf720d4ec9b55faa1.tar.bz2
portage-cvs-664061788117de1ac3ce05baf720d4ec9b55faa1.zip
Redesigned and rewrote DependSpec
Diffstat (limited to 'pym')
-rw-r--r--pym/portage_syntax.py560
1 files changed, 320 insertions, 240 deletions
diff --git a/pym/portage_syntax.py b/pym/portage_syntax.py
index 1694896..475d3ad 100644
--- a/pym/portage_syntax.py
+++ b/pym/portage_syntax.py
@@ -1,4 +1,6 @@
-import re,string,copy
+import re
+
+from copy import *
pkg_regexp = re.compile("^[a-zA-Z0-9]([-_+a-zA-Z0-9]*[+a-zA-Z0-9])?$")
@@ -134,8 +136,8 @@ class CPV(object):
# 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))]
+ list1 = [int(match1.group(2))]
+ list2 = [int(match2.group(2))]
# this part would greatly benefit from a fixed-length version pattern
if len(match1.group(3)) or len(match2.group(3)):
@@ -144,18 +146,18 @@ class CPV(object):
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]))
+ list2.append(int(vlist2[i]))
elif len(vlist2) <= i or len(vlist2[i]) == 0:
- list1.append(string.atoi(vlist1[i]))
+ list1.append(int(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]))
+ list1.append(int(vlist1[i]))
+ list2.append(int(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]))
+ list1.append(float("0."+vlist1[i]))
+ list2.append(float("0."+vlist2[i]))
# and now the final letter
if len(match1.group(5)):
@@ -189,9 +191,9 @@ class CPV(object):
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])
+ try: r1 = int(s1[1])
except ValueError: r1 = 0
- try: r2 = string.atoi(s2[1])
+ try: r2 = int(s2[1])
except ValueError: r2 = 0
return r1 - r2
@@ -286,7 +288,7 @@ class Atom(object):
raise ValueError(self.atomstr)
if not self.__dict__.has_key(name):
- raise AttributeError(name)
+ return self.cpv.__getattr__(name)
return self.__dict__[name]
@@ -408,271 +410,349 @@ class Atom(object):
return False
-class DependSpec:
- """
- Attributes
- list elements
- bool preferential
- str condition
- Methods
+class UseCondition(object):
- int __str__()
- str __repr__()
- """
+ _use_regex = re.compile("^!?[\\w-]+\?$")
- def __init__(self, dependstr="", element_class=str):
+ def can_parse(cls, condition_str):
+ return (cls._use_regex.match(condition_str) is not None)
+ can_parse = classmethod(can_parse)
- if not isinstance(dependstr, str):
- raise ValueError(dependstr)
- if isinstance(element_class, DependSpec):
- raise ValueError
+ def __init__(self, condition_str):
+ condition_str = condition_str[:-1]
+ self.__dict__["_hash"] = hash(condition_str)
+ self.__dict__["negated"] = (condition_str[0] == "!")
+ if self.negated:
+ self.__dict__["flag"] = condition_str[1:]
+ else:
+ self.__dict__["flag"] = condition_str
- dependstr = " ".join(dependstr.split())
- self.element_class = element_class
- self.dependstr = dependstr
- self.condition = None
- self.preferential = False
- self.elements = []
-
- depstrlen = len(dependstr)
- parseidx = 0
- condition = None
- element = None
+ def __setattr__(self, name, value):
+ raise TypeError("UseCondition has only read-only attributes (assign to "+name+")")
- while parseidx != depstrlen:
- c = dependstr[parseidx]
+ def __hash__(self):
+ return self._hash
- if c == " ":
- parseidx += 1
- continue
+ def __eq__(self, other):
+ return (isinstance(other, UseCondition) and self._hash == other._hash)
- if c == ")":
- raise ValueError(self.dependstr)
+ def __copy__(self):
+ return self
- if c == "|" and not element and dependstr[parseidx:].startswith("||"):
- parseidx += 2
- (subdependstr, parseidx) = self._extract_dependstr(dependstr, parseidx)
- element = DependSpec(subdependstr, element_class)
- if len(element.elements) > 1:
- element.preferential = True
- if condition:
- element.condition = condition
- condition = None
- self.elements.append(element)
- element = None
- continue
+ def conflicts_with(self, other):
+ return (self.flag == other.flag and self.negated != other.negated)
- if c == "(":
- (subdependstr, parseidx) = self._extract_dependstr(dependstr, parseidx)
- element = DependSpec(subdependstr, element_class)
- if condition:
- element.condition = condition
- condition = None
- self.elements.append(element)
- element = None
- continue
- if dependstr.find(" ", parseidx) != -1:
- element = dependstr[parseidx:dependstr.find(" ", parseidx)]
- else:
- element = dependstr[parseidx:]
- parseidx += len(element)
+class ParseError(Exception):
+ pass
- if element[-1] == "?":
- if condition:
- raise ValueError(self.dependstr)
- condition = element[:-1]
- if not condition:
- raise ValueError(self.dependstr)
- element = None
- elif condition:
- if not element:
- raise ValueError(self.dependstr)
- if not isinstance(element, DependSpec):
- element = DependSpec(element, element_class)
- element.condition = condition
- condition = None
- self.elements.append(element)
- element = None
- else:
- element = element_class(element)
- self.elements.append(element)
- element = None
- self.dependstr = None
+class DependSpec(object):
- def _extract_dependstr(self, dependstr, parseidx):
- depstrlen = len(dependstr)
+ def __init__(self, dependstr="", element_class=str):
+ dependstr = " ( ".join(dependstr.split("("))
+ dependstr = " ) ".join(dependstr.split(")"))
+ dependstr = " ".join(dependstr.split())
+ self.__dict__["_origstr"] = dependstr
+ self.__dict__["_str"] = None
+ self.__dict__["_element_class"] = element_class
+ self.__dict__["_needs_brackets"] = True
+ self.__dict__["_specials"] = []
+ self.__dict__["condition"] = None
- while dependstr[parseidx] != "(":
- parseidx += 1
- if parseidx == depstrlen or dependstr[parseidx] not in [" ", "("]:
- raise ValueError(self.dependstr)
+ def __copy__(self):
+ dependspec = self.__class__()
+ dependspec.__dict__["_element_class"] = self._element_class
+ dependspec.__dict__["_specials"] = self._specials[:]
+ dependspec.__dict__["condition"] = copy(self.condition)
+ dependspec.__dict__["_needs_brackets"] = self._needs_brackets
+ self._parsed
+ dependspec.__dict__["_elements"] = self._elements[:]
+ dependspec.__dict__["_parsed"] = True
+ return dependspec
- parseidx += 1
- startpos = parseidx
- bracketcount = 1
+ def __setattr__(self, name, value):
+ raise TypeError("DependSpec has only read-only attributes (assign to "+name+")")
- while bracketcount:
- if parseidx == depstrlen:
- raise ValueError(self.dependstr)
+ def __str__(self):
+ if self._str is not None:
+ return self._str
+ self._parsed
+ mystr = []
+ for element in self._elements:
+ x = str(element)
+ if x:
+ if isinstance(element, DependSpec) and element._needs_brackets:
+ x = "( "+x+" )"
+ mystr.append(x)
+ mystr = " ".join(mystr)
+ if self.condition:
+ mystr = str(self.condition)+" ( "+mystr+" )"
+ self.__dict__["_str"] = mystr
+ return mystr
- nextopen = dependstr.find("(", parseidx)
- nextclose = dependstr.find(")", parseidx)
- if nextopen == -1 and nextclose == -1:
- raise ValueError(self.dependstr)
+ def _needs_brackets(self):
+ return True
- if nextclose == -1 or nextopen != -1 and nextopen < nextclose:
- parseidx = nextopen + 1
- bracketcount += 1
- else:
- parseidx = nextclose + 1
- bracketcount -= 1
+ def __hash__(self):
+ return hash(str(self))
- subdependstr = dependstr[startpos:parseidx-1]
- return (subdependstr, parseidx)
+ def __eq__(self, other):
+ return (isinstance(other, DependSpec) and str(self) == str(other))
- def __repr__(self):
- return "DependSpec('" + str(self) + "')"
+ def __getattr__(self, name):
+ if "_parsed" not in self.__dict__:
+ self._parse()
+ return self.__dict__[name]
- def __eq__(self, other):
- return str(self) == str(other)
+ def __getitem__(self, idx):
+ self._parsed
+ return self._elements[idx]
- def __str__(self):
- if self.dependstr:
- return self.dependstr
+ def __len__(self):
+ self._parsed
+ return len(self._elements)
- dependstr = ""
- if self.condition:
- dependstr = self.condition + "? ( "
- if self.preferential:
- dependstr += "|| ( "
- for element in self.elements:
- if isinstance(element, DependSpec) and len(element.elements) > 1 and not element.preferential and not element.condition:
- dependstr += "( " + str(element) + " )"
+ def _parse(self):
+ dependstr = self._origstr
+ if dependstr.count("(") != dependstr.count(")"):
+ raise ParseError(dependstr)
+ self.__dict__["_elements"] = []
+ specials_found = []
+ condition = None
+ strlen = len(dependstr)
+ pos = 0
+ while pos != strlen:
+ if dependstr[pos] == " ":
+ pos += 1
+ continue
+ if dependstr[pos] == ")":
+ raise ParseError(dependstr)
+ if dependstr[pos] == "(":
+ pos += 1
+ bracket_count = 1
+ nextpos = pos
+ while bracket_count:
+ nextpos_d = {}
+ nextpos_d[dependstr.find("(", nextpos)] = True
+ nextpos_d[dependstr.find(")", nextpos)] = True
+ if -1 in nextpos_d:
+ del nextpos_d[-1]
+ nextpos = min(nextpos_d.keys())
+ if dependstr[nextpos] == "(":
+ bracket_count += 1
+ else:
+ bracket_count -= 1
+ nextpos += 1
+ element = self.__class__(dependstr[pos:nextpos-1])
+ element.__dict__["_element_class"] = self._element_class
+ if condition:
+ element.__dict__["condition"] = condition
+ condition = None
+ pos = nextpos
+ self._elements.append(element)
+ continue
+ nextpos_d = {strlen:True}
+ nextpos_d[dependstr.find(" ", pos)] = True
+ nextpos_d[dependstr.find("(", pos)] = True
+ nextpos_d[dependstr.find(")", pos)] = True
+ if -1 in nextpos_d:
+ del nextpos_d[-1]
+ nextpos = min(nextpos_d.keys())
+ element = dependstr[pos:nextpos]
+ if element in self._specials:
+ specials_found += [(element, len(self._elements))]
+ elif UseCondition.can_parse(element):
+ if condition:
+ raise ParseError(dependstr)
+ condition = UseCondition(element)
else:
- dependstr += str(element)
- dependstr += " "
- if self.elements:
- dependstr = dependstr[:-1]
- if self.preferential:
- dependstr += " )"
+ if condition:
+ raise ParseError(dependstr)
+ self._elements.append(self._element_class(element))
+ pos = nextpos
+ if condition:
+ raise ParseError(dependstr)
+ for special in specials_found:
+ if special[1] == len(self._elements):
+ raise ParseError(dependstr)
+ try:
+ self._do_special(special[0], special[1])
+ except ParseError:
+ raise ParseError(dependstr)
+ self.__dict__["_parsed"] = True
+
+ def all_conditions(self):
+ cond_d = {}
if self.condition:
- dependstr += " )"
- self.dependstr == dependstr
- return dependstr
+ cond_d[self.condition] = True
+ yield self.condition
- def flatten(self):
- for element in self.elements:
+ self._parsed
+ for element in self._elements:
if isinstance(element, DependSpec):
- element.flatten()
-
- self.compact()
-
- if not self.preferential:
- for idx in range(len(self.elements)):
- if isinstance(self.elements[idx], DependSpec) and self.elements[idx].preferential:
- otherelements = []
- for idx2 in range(len(self.elements)):
- if idx2 != idx:
- otherelements.append(self.elements[idx2])
- newelements = []
- for element in self.elements[idx].elements:
- dependspec = DependSpec(element_class=self.element_class)
- dependspec.elements.extend(otherelements)
- dependspec.elements.append(DependSpec(element_class=self.element_class))
- dependspec.elements[-1].condition = self.elements[idx].condition
- dependspec.elements[-1].elements.append(element)
- newelements.append(dependspec)
- self.elements = newelements
- self.preferential = True
- self.flatten()
- return
-
- def compact(self):
- for element in self.elements:
- if isinstance(element, DependSpec):
- element.compact()
-
- changed = True
- while changed:
- changed = False
- for x in range(len(self.elements)-1, -1, -1):
- if isinstance(self.elements[x], DependSpec) and not len(self.elements[x].elements):
- del self.elements[x]
- for x in range(len(self.elements)-1, -1, -1):
- if isinstance(self.elements[x], DependSpec):
- if self.elements[x].condition == self.condition and self.elements[x].preferential == self.preferential:
- self.elements.extend(self.elements[x].elements)
- del self.elements[x]
- changed = True
-
- elements = self.elements[:]
- del self.elements[:]
- for element in elements:
- if element not in self.elements:
- self.elements.append(element)
-
- if self.preferential and len(self.elements) == 1:
- self.preferential = False
-
- if not self.condition and not self.preferential and len(self.elements) == 1 and isinstance(self.elements[0], DependSpec):
- element = self.elements[0]
- self.condition = element.condition
- self.preferential = element.preferential
- self.elements = element.elements
-
- self.dependstr = None
-
- def __copy__(self):
- dependspec = DependSpec(element_class=self.element_class)
- dependspec.condition = self.condition
- dependspec.preferential = self.preferential
- for element in self.elements:
- dependspec.add_element(copy.copy(element))
+ for cond in element.all_conditions():
+ if cond not in cond_d:
+ cond_d[cond] = True
+ yield cond
+
+ def with_only_conditions(self, conditions):
+ if self.condition and self.condition not in conditions:
+ return self.__class__()
+ self._parsed
+ dependspec = copy(self)
+ dependspec.__dict__["condition"] = None
+ for idx in range(len(dependspec._elements)):
+ if isinstance(dependspec._elements[idx], DependSpec):
+ dependspec._elements[idx] = dependspec._elements[idx].with_only_conditions(conditions)
return dependspec
- def resolve_conditions(self, truths):
- mycondition = self.condition
- self.condition = None
+ def _can_combine_with(self, other):
+ return self.condition == other.condition
- if mycondition:
- if mycondition[0] == "!":
- mycondition = mycondition[1:]
- keep = (mycondition not in truths)
+ def compacted(self):
+ elements = []
+ element_d = {}
+ self._parsed
+ for element in self._elements:
+ if element in element_d:
+ continue
+ if isinstance(element, DependSpec):
+ element = element.compacted()
+ if not len(element._elements):
+ continue
+ if self._can_combine_with(element):
+ for element in element._elements:
+ if element in element_d:
+ continue
+ elements.append(element)
+ element_d[element] = True
+ else:
+ elements.append(element)
+ element_d[element] = True
else:
- keep = (mycondition in truths)
- if not keep:
- del self.elements[:]
- return
+ elements.append(element)
+ element_d[element] = True
+ if not elements:
+ return self.__class__()
+ dependspec = copy(self)
+ dependspec.__dict__["_elements"] = elements
+ return dependspec
- for element in self.elements:
- if isinstance(element, DependSpec):
- element.resolve_conditions(truths)
- def add_element(self, element):
- if isinstance(element, self.element_class) or (isinstance(element, DependSpec) and element.element_class is self.element_class):
- self.elements.append(element)
- else:
- raise ValueError(element)
- self.dependstr = None
+class AtomDependSpec(DependSpec):
- def remove_element(self, element):
- self.elements.remove(element)
- self.dependstr = None
+ def create_from(atoms, preferential=False):
+ dependstr = []
+ for atom in atoms:
+ dependstr.append(str(atom))
+ dependstr = " ".join(dependstr)
+ if preferential:
+ dependstr = "|| ( "+dependstr+" )"
+ return AtomDependSpec(dependstr)
+ create_from = staticmethod(create_from)
+ def __init__(self, dependstr=""):
+ super(self.__class__, self).__init__(dependstr, element_class=Atom)
+ self.__dict__["preferential"] = False
+ self.__dict__["_specials"] = ["||"]
-class GluePkg(CPV):
+ def __copy__(self):
+ atomdependspec = super(self.__class__, self).__copy__()
+ atomdependspec.__dict__["preferential"] = self.preferential
+ return atomdependspec
+
+ def __str__(self):
+ if self._str is not None:
+ return self._str
+ mystr = super(self.__class__, self).__str__()
+ if self.preferential:
+ mystr = "|| ( "+mystr+" )"
+ self.__dict__["_str"] = mystr
+ return mystr
+
+ def _do_special(self, special, idx):
+ if not isinstance(self._elements[idx], AtomDependSpec) or self._elements[idx].preferential:
+ raise ParseError()
+ self._elements[idx].__dict__["preferential"] = True
+ self._elements[idx].__dict__["_needs_brackets"] = False
+
+ def _can_combine_with(self, other):
+ if self.preferential != other.preferential:
+ return False
+ return super(self.__class__, self)._can_combine_with(other)
+
+ def compacted(self):
+ atomdependspec = super(self.__class__, self).compacted()
+ if atomdependspec.preferential and len(atomdependspec._elements) <= 1:
+ atomdependspec.__dict__["preferential"] = False
+ atomdependspec.__dict__["_needs_brackets"] = True
+ atomdependspec = atomdependspec.compacted()
+ return atomdependspec
+
+ def with_keys_transformed(self, key_map):
+ atomdependspec = copy(self)
+ atomdependspec._parsed
+ for x in range(len(atomdependspec._elements)):
+ if isinstance(atomdependspec._elements[x], AtomDependSpec):
+ atomdependspec._elements[x] = atomdependspec._elements[x].with_keys_transformed()
+ elif atomdependspec._elements[x].key in key_map:
+ elements = []
+ for newkey in key_map[atomdependspec._elements[x].key]:
+ elements.append(atomdependspec._elements[x].with_key(newkey))
+ atomdependspec._elements[x] = AtomDependSpec.create_from(elements, preferential=True)
+ atomdependspec.__dict__["_str"] = None
+ return atomdependspec
+
+ def combinations(self):
+ if not self._elements:
+ return []
- def __init__(self, cpv, db, slot, use, bdeps, rdeps):
- CPV.__init__(self, cpv)
- self.__dict__["db"] = db
- self.__dict__["slot"] = slot
- self.__dict__["use"] = use
- bdeps.flatten()
- self.__dict__["bdeps"] = bdeps
- rdeps.flatten()
- self.__dict__["rdeps"] = rdeps
+ if self.condition:
+ raise NotImplementedError()
+
+ combinations = []
+
+ if self.preferential:
+ for element in self._elements:
+ if isinstance(element, AtomDependSpec):
+ combinations += element.combinations()
+ else:
+ combinations += [[element]]
+ else:
+ singles = []
+ others = []
+ for element in self._elements:
+ if isinstance(element, AtomDependSpec):
+ others += [element.combinations()]
+ else:
+ singles += [element]
+ if others:
+ indexes = []
+ endindex = len(others)
+ for x in range(endindex):
+ indexes.append(0)
+ index = 0
+ while index != endindex:
+ if indexes[index] >= len(others[index]):
+ index += 1
+ if index == endindex:
+ continue
+ for x in range(index):
+ indexes[x] = 0
+ indexes[index] += 1
+ continue
+ else:
+ index = 0
+ newcomb = singles[:]
+ for x in range(endindex):
+ if others[x]:
+ newcomb.extend(others[x][indexes[x]])
+ combinations.append(newcomb)
+ indexes[index] += 1
+ else:
+ combinations = [singles]
+ return combinations