diff options
-rw-r--r-- | portage/restrictions/collapsed.py | 21 | ||||
-rw-r--r-- | portage/restrictions/restriction.py | 81 | ||||
-rw-r--r-- | portage/restrictions/restrictionSet.py | 105 |
3 files changed, 140 insertions, 67 deletions
diff --git a/portage/restrictions/collapsed.py b/portage/restrictions/collapsed.py index a8c9388..32e91b4 100644 --- a/portage/restrictions/collapsed.py +++ b/portage/restrictions/collapsed.py @@ -1,14 +1,33 @@ # Copyright: 2005 Gentoo Foundation # Author(s): Brian Harring (ferringb@gentoo.org) # License: GPL2 -# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/portage/restrictions/collapsed.py,v 1.2 2005/08/03 00:20:55 ferringb Exp $ +# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/portage/restrictions/collapsed.py,v 1.3 2005/08/09 07:51:09 ferringb Exp $ +__all__=("DictBased") from restriction import base, AlwaysTrue from inspect import isroutine from restrictionSet import bases, OrRestrictionSet from portage.util.inheritance import check_for_base class DictBased(base): + """Restrictions are (by default) executed in a depth/breadth method; for long chains of restrictions, + this grows inneficient. For example, package.mask'ing has over 300 atoms, effectively over 1800 objects in use. + + Running the filter on each package instance returned from a repo would be exceedingly slow, a way to get as close to + constant lookup as possible is needed. + + DictBased works by using supplied functions to collapse long chains of restrictions into a dict, with key + defined by get_key_from_atom (with get_key_from_package returning the key of a pkg instance), and with the + value of that key holding the remaining restrictions (if any). + + Common usage at this point is to collapse category and package attribute restrictions into constant lookup, with + any remaining version restrictions being handed off as a val. + + Example usage of this class should be available in portage.config.domain.domain + + Aside from that, method of generating keys/collapsing restrictions is subject to change, still need to push metadata + in re: what restriction types are being collapsed; short version, api isn't declared stable yet. + """ __slots__ = tuple(["restricts_dict", "get_pkg_key", "get_atom_key"] + base.__slots__) def __init__(self, restriction_items, get_key_from_package, get_key_from_atom, *args, **kwargs): diff --git a/portage/restrictions/restriction.py b/portage/restrictions/restriction.py index c155181..60d1831 100644 --- a/portage/restrictions/restriction.py +++ b/portage/restrictions/restriction.py @@ -1,7 +1,7 @@ # Copyright: 2005 Gentoo Foundation # Author(s): Brian Harring (ferringb@gentoo.org) # License: GPL2 -# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/portage/restrictions/restriction.py,v 1.7 2005/08/03 00:20:55 ferringb Exp $ +# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/portage/restrictions/restriction.py,v 1.8 2005/08/09 07:51:09 ferringb Exp $ import re, logging @@ -26,6 +26,9 @@ class base(object): def match(self, *arg, **kwargs): raise NotImplementedError + def cmatch(self, *arg, **kwargs): + return self.match(*arg, **kwargs) + def intersect(self, other): return None @@ -119,43 +122,6 @@ class StrExactMatch(StrMatch): return "== "+self.exact -class StrSubstringMatch(StrMatch): - __slots__ = tuple(["substr"] + StrMatch.__slots__) - - def __init__(self, substr, CaseSensitive=True, **kwds): - super(StrSubstringMatch, self).__init__(**kwds) - if not CaseSensitive: - self.flags = re.I - self.substr = str(substr).lower() - else: - self.flags = 0 - self.substr = str(substr) - - def match(self, value): - if self.flags & re.I: value = str(value).lower() - else: value = str(value) - return (value.find(self.substr) != -1) ^ self.negate - - def intersect(self, other): - if self.negate == other.negate: - if self.substr == other.substr and self.flags == other.flags: - return self - else: - return None - s1, s2 = self.substr, other.substr - if other.flags and not self.flags: - s1 = s1.lower() - elif self.flags and not other.flags: - s2 = s2.lower() - if s1.find(s2) != -1: - return self - elif s2.find(s1) != -1: - return other - return None - - def __eq__(self, other): - return self.substr == other.substr and self.negate == other.negate and self.flags == other.flags - class StrGlobMatch(StrMatch): __slots__ = tuple(["glob"] + StrMatch.__slots__) @@ -169,9 +135,16 @@ class StrGlobMatch(StrMatch): self.glob = str(glob) def match(self, value): - value = str(value) - if self.flags & re.I: value = value.lower() - return value.startswith(self.glob) ^ self.negate + if isinstance(value, (list, tuple)): + for x in value: + print "trying %s against %s" % (x, self.glob) + if self.match(x): + return not self.negate + return self.negate + else: + value = str(value) + if self.flags & re.I: value = value.lower() + return value.startswith(self.glob) ^ self.negate def intersect(self, other): if self.match(other.glob): @@ -252,18 +225,30 @@ class PackageRestriction(base): class ContainmentMatch(base): """used for an 'in' style operation, 'x86' in ['x86','~x86'] for example""" - __slots__ = tuple(["vals"] + base.__slots__) + __slots__ = tuple(["vals", "vals_len"] + base.__slots__) - def __init__(self, vals, **kwds): + def __init__(self, *vals, **kwds): """vals must support a contaiment test""" super(ContainmentMatch, self).__init__(**kwds) - self.vals = vals - + self.vals = set(vals) + self.vals_len = len(self.vals) + def match(self, val): - return (val in self.vals) ^ self.negate + if isinstance(val, (str, unicode)): + return val in self.vals ^ self.negate + try: + # assume our lookup is faster, since we don't know if val is constant lookup or not + l = len(val) + for x in val: + if x in self.vals: + return not self.negate + return self.negate + except TypeError: + return val in self.vals ^ self.negate + def __str__(self): - if self.negate: s="not in [%s]" - else: s="in [%s]" + if self.negate: s="not contains [%s]" + else: s="contains [%s]" return s % ', '.join(map(str, self.vals)) diff --git a/portage/restrictions/restrictionSet.py b/portage/restrictions/restrictionSet.py index e93bd13..67288d1 100644 --- a/portage/restrictions/restrictionSet.py +++ b/portage/restrictions/restrictionSet.py @@ -1,14 +1,25 @@ # Copyright: 2005 Gentoo Foundation # Author(s): Brian Harring (ferringb@gentoo.org) # License: GPL2 -# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/portage/restrictions/Attic/restrictionSet.py,v 1.8 2005/08/03 00:20:55 ferringb Exp $ +# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/portage/restrictions/Attic/restrictionSet.py,v 1.9 2005/08/09 07:51:09 ferringb Exp $ + +""" +This module provides classes that can be used to combine arbitrary collections of restrictions in AND, NAND, OR, NOR, XOR, XNOR +style operations. +""" import restriction +from itertools import imap +__all__ = ("AndRestrictionSet", "OrRestrictionSet", "XorRestrictionSet") class RestrictionSet(restriction.base): __slots__ = tuple(["restrictions"] + restriction.base.__slots__) def __init__(self, *restrictions, **kwds): + """Optionally hand in (positionally) restrictions to use as the basis of this restriction + finalize=False, set it to True to notify this instance to internally finalize itself (no way to reverse it yet) + negate=False, controls whether matching results are negated + """ if "finalize" in kwds: finalize = kwds["finalize"] del kwds["finalize"] @@ -26,16 +37,23 @@ class RestrictionSet(restriction.base): self.restrictions = list(restrictions) - def add_restriction(self, NewRestriction, strict=True): - if strict and not isinstance(NewRestriction, restriction.base): - raise TypeError, NewRestriction - - self.restrictions.append(NewRestriction) + def add_restriction(self, *new_restrictions, **kwds): + """add restriction(s) + strict=True, set to false to disable isinstance checks to ensure all restrictions are restriction.base derivatives + """ + if len(new_restrictions) == 0: + raise TypeError("need at least one restriction handed in") + if kwds.get("strict", True): + for r in new_restrictions: + if not isinstance(r, restriction.base): + raise TypeError("instance '%s' isn't a restriction.base, and strict is on" % r) + + self.restrictions.extend(new_restrictions) def finalize(self): self.restrictions = tuple(self.restrictions) - def total_len(self): return sum(map(lambda x: x.total_len(), self.restrictions)) + 1 + def total_len(self): return sum(imap(lambda x: x.total_len(), self.restrictions)) + 1 def __len__(self): return len(self.restrictions) @@ -44,25 +62,46 @@ class RestrictionSet(restriction.base): def __getitem__(self, key): return self.restrictions[key] +def unwind_changes(pkg, pop_count, negate): + while pop_count: + pkg.pop_change() + pop_count-=1 + if negate: + return pkg + return None + class AndRestrictionSet(RestrictionSet): + """Boolean AND grouping of restrictions.""" __slots__ = tuple(RestrictionSet.__slots__) - + def match(self, packagedataInstance): for rest in self.restrictions: if not rest.match(packagedataInstance): return self.negate return not self.negate + def cmatch(self, pkg): + entry_point = pkg.changes_count() + for rest in self.restrictions: + if c.match(pkg) == False: + pkg.rollback_changes(entry_point) + if self.negate: return pkg + return self.negate -# def intersect(self, other): + # for this to be reached, things went well. + if self.negate: + pkg.rollback_changes(entry_point) + # yes, normally it's "not negate", but we no negates status already via the if + return False + return True def __str__(self): - if self.negate: s=" !& " - else: s=" && " - return '( %s )' % s.join(map(str,self.restrictions)) + if self.negate: return "not ( %s )" % " && ".join(imap(str, self.restrictions)) + return "( %s )" % " && ".join(imap(str, self.restrictions)) class OrRestrictionSet(RestrictionSet): + """Boolean OR grouping of restrictions.""" __slots__ = tuple(RestrictionSet.__slots__) def match(self, packagedataInstance): @@ -71,13 +110,27 @@ class OrRestrictionSet(RestrictionSet): return not self.negate return self.negate + def cmatch(self, pkg): + entry_point = pkg.changes_count() + for rest in self.restrictions: + if rest.cmatch(pkg) == True: + if self.negate: + pkg.rollback_changes(entry_point) + return not self.negate + else: + pkg.rollback_changes(entry_point) + + if self.negate: + pkg.rollback_changes(entry_point) + return self.negate + def __str__(self): - if self.negate: s=" !| " - else: s=" || " - return '( %s )' % s.join(map(str,self.restrictions)) + if self.negate: return "not ( %s )" % " || ".join(imap(str, self.restrictions)) + return "( %s )" % " || ".join(imap(str, self.restrictions)) class XorRestrictionSet(RestrictionSet): + """Boolean XOR grouping of restrictions.""" __slots__ = tuple(RestrictionSet.__slots__) def match(self, pkginst): @@ -89,10 +142,26 @@ class XorRestrictionSet(RestrictionSet): armed = True return armed ^ self.negate + def cmatch(self, pkg): + entry_point = None + armed = False + for ret in self.restrictions: + node_entry_point = pkg.changes_count() + if rest.cmatch(pkg): + if armed: + pkg.rollback_changes(entry_point) + return self.negate + armed = True + else: + pkg.rollback_changes(node_entry_point) + + if self.negate and entry_point != None: + pkg.rollback_changes(entry_point) + return armed ^ self.negate + def __str__(self): - if self.negate: s=" !^ " - else: s=" ^^ " - return '( %s )' % s.join(map(str,self.restrictions)) + if self.negate: return "not ( %s )" % " ^^ ".join(imap(str, self.restrictions)) + return "( %s )" % " ^^ ".join(imap(str, self.restrictions)) bases = (AndRestrictionSet, OrRestrictionSet, XorRestrictionSet) |