aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Harring <ferringb@gentoo.org>2005-08-16 00:19:57 +0000
committerBrian Harring <ferringb@gentoo.org>2005-08-16 00:19:57 +0000
commit4247fb899526f02f6382d9c8ae8bd691b9b1b861 (patch)
treee6f0eb159db71349ea5c4ce7d99bb82d4a7a1c87
parentadjusted filename on tercel's request (diff)
downloadportage-cvs-4247fb899526f02f6382d9c8ae8bd691b9b1b861.tar.gz
portage-cvs-4247fb899526f02f6382d9c8ae8bd691b9b1b861.tar.bz2
portage-cvs-4247fb899526f02f6382d9c8ae8bd691b9b1b861.zip
restriction subsystem slight redesign.
bugs probably exist in force_(Fail,True), although containmentmatch appears to work (use deps are working now) packages is package level restrictions values is value level restrictions; package restrictions gank the attributes, and hand them off to value restrictions (effectively) collapsed is package level. boolean is a base of boolean logic classes, properly support the full potential combinations NAND and OR have (that sucked). same with ContainmentMatch
-rw-r--r--portage/restrictions/boolean.py411
-rw-r--r--portage/restrictions/packages.py140
-rw-r--r--portage/restrictions/restrictionSet.py167
-rw-r--r--portage/restrictions/values.py286
4 files changed, 837 insertions, 167 deletions
diff --git a/portage/restrictions/boolean.py b/portage/restrictions/boolean.py
new file mode 100644
index 0000000..05bd820
--- /dev/null
+++ b/portage/restrictions/boolean.py
@@ -0,0 +1,411 @@
+# 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/boolean.py,v 1.1 2005/08/16 00:19:57 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.
+"""
+
+from itertools import imap, islice
+from portage.util.iterate import enumerate
+
+__all__ = ("AndRestriction", "OrRestriction", "XorRestriction")
+import restriction
+
+class base(restriction.base):
+ __slots__ = tuple(["restrictions"] + restriction.base.__slots__)
+ required_base = None
+
+ 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"]
+ else:
+ finalize = False
+ super(base, self).__init__(**kwds)
+ for x in restrictions:
+ if not isinstance(x, restriction.base):
+ #bad monkey.
+ raise TypeError, x
+
+ if finalize:
+ self.restrictions = tuple(restrictions)
+ else:
+ self.restrictions = list(restrictions)
+
+
+ def add_restriction(self, *new_restrictions):
+ """add restriction(s), must be isinstance of required_base
+ """
+ if len(new_restrictions) == 0:
+ raise TypeError("need at least one restriction handed in")
+ for r in new_restrictions:
+ if not isinstance(r, self.required_base):
+ raise TypeError("instance '%s' isn't a derivative '%s'" % (r, self.required_base))
+
+ self.restrictions.extend(new_restrictions)
+
+ def finalize(self):
+ self.restrictions = tuple(self.restrictions)
+
+ def total_len(self): return sum(imap(lambda x: x.total_len(), self.restrictions)) + 1
+
+ def __len__(self): return len(self.restrictions)
+
+ def __iter__(self): return iter(self.restrictions)
+
+ def match(self, action, *vals):
+ raise NotImplementedError
+
+ force_False, force_True = match, match
+
+ def __getitem__(self, key):
+ return self.restrictions[key]
+
+
+# this beast, handles N^2 permutations. convert to stack based.
+def iterative_quad_toggling(pkg, pvals, restrictions, starting, end, truths, filter, desired_false=None, desired_true=None, kill_switch=None):
+ if desired_false == None:
+ desired_false = lambda r, a:r.force_False(*a)
+ if desired_true == None:
+ desired_true = lambda r, a:r.force_True(*a)
+
+# import pdb;pdb.set_trace()
+ reset = True
+ if starting == 0:
+ if filter(truths):
+ yield True
+ for index, rest in enumerate(restrictions, starting, end):
+ if reset:
+ entry = pkg.changes_count()
+ reset = False
+ if truths[index]:
+ if desired_false(rest, pvals):
+ reset = True
+ t = truths[:]
+ t[index] = False
+ if filter(t):
+ yield True
+ for x in iterative_quad_toggling(pkg, pvals, restrictions, index + 1, end, t, filter,
+ desired_false=desired_false, desired_true=desired_true, kill_switch=kill_switch):
+# import pdb;pdb.set_trace()
+ yield True
+ reset = True
+ else:
+ if kill_switch != None and kill_switch(truths, index):
+ return
+ else:
+ if desired_true(rest, pvals):
+ reset = True
+ t = truths[:]
+ t[index] = True
+ if filter(t):
+ yield True
+ for x in iterative_quad_toggling(pkg, pvals, restrictions, index + 1, end, t, filter,
+ desired_false=desired_false, desired_true=desired_true):
+# import pdb;pdb.set_trace()
+ yield True
+ reset = True
+ elif index == end:
+ if filter(truths):
+# import pdb;pdb.set_trace()
+ yield True
+ else:
+ if kill_switch != None and kill_switch(truths, index):
+ return
+
+ if reset:
+ pkg.rollback(entry)
+
+
+class AndRestriction(base):
+ """Boolean AND grouping of restrictions. negation is a NAND"""
+ __slots__ = tuple(base.__slots__)
+
+ def match(self, vals):
+ if self.negate:
+ # 1|1 == 0, 1|0 == 0|1 == 0|0 == 1
+ missed = False
+ for rest in self.restrictions:
+ if not rest.match(vals):
+ missed = True
+ elif missed:
+ return True
+ return False
+ for rest in self.restrictions:
+ if not rest.match(vals):
+ return False
+ return True
+
+ def force_True(self, pkg, *vals):
+ pvals = [pkg]
+ pvals.extend(vals)
+ entry_point = pkg.changes_count()
+ # get the simple one out of the way first.
+ if not self.negate:
+ for r in self.restrictions:
+ if not r.force_True(*pvals):
+ pkg.rollback(entry_point)
+ return
+ yield True
+ return
+
+ # <insert page long curse here>, NAND logic, len(restrictions)**2 potential solutions.
+ # 0|0 == 0, 0|1 == 1|0 == 0|0 == 1.
+ # XXX this is quadratic. patches welcome to dodge the requirement to push through all potential
+ # truths.
+ truths = [r.match(*pvals) for r in self.restrictions]
+ def filter(truths):
+ return False in truths
+
+ for x in iterative_quad_toggling(pkg, pvals, self.restrictions, 0, len(self.restrictions), truths, filter):
+ yield True
+
+ def force_False(self, pkg, *vals):
+ pvals = [pkg]
+ pvals.extend(vals)
+ entry_point = pkg.changes_count()
+ # get the simple one out of the way first.
+ if self.negate:
+ for r in self.restrictions:
+ if not r.force_True(*pvals):
+ pkg.rollback(entry_point)
+ return
+ yield True
+ return
+
+ # <insert page long curse here>, NAND logic, (len(restrictions)^2)-1 potential solutions.
+ # 1|1 == 0, 0|1 == 1|0 == 0|0 == 1.
+ # XXX this is quadratic. patches welcome to dodge the requirement to push through all potential
+ # truths.
+ truths = [r.match(*pvals) for r in self.restrictions]
+ def filter(truths):
+ return False in truths
+ for x in iterative_quad_toggling(pkg, pvals, self.restrictions, 0, len(self.restrictions), truths, filter):
+ yield True
+
+ def __str__(self):
+ if self.negate: return "not ( %s )" % " && ".join(imap(str, self.restrictions))
+ return "( %s )" % " && ".join(imap(str, self.restrictions))
+
+
+class OrRestriction(base):
+ """Boolean OR grouping of restrictions."""
+ __slots__ = base.__slots__
+
+ def match(self, vals):
+ if self.negate:
+ # 1|1 == 1|0 == 0|1 == 0, 0|0 == 1
+ for rest in self.restrictions:
+ if rest.match(vals):
+ return
+ return True
+ for rest in self.restrictions:
+ if rest.match(vals):
+ return True
+ return False
+
+ def force_True(self, pkg, *vals):
+ pvals = [pkg]
+ pvals.extend(vals)
+ entry_point = pkg.changes_count()
+ # get the simple one out of the way first.
+ if self.negate:
+ for r in self.restrictions:
+ if not r.force_False(*pvals):
+ pkg.rollback(entry_point)
+ return
+ yield True
+ return
+
+ # <insert page long curse here>, OR logic, len(restrictions)**2-1 potential solutions.
+ # 0|0 == 0, 0|1 == 1|0 == 1|1 == 1.
+ # XXX this is quadratic. patches welcome to dodge the requirement to push through all potential
+ # truths.
+ truths = [r.match(*pvals) for r in self.restrictions]
+ def filter(truths):
+ return True in truths
+ for x in iterative_quad_toggling(pkg, pvals, self.restrictions, 0, len(self.restrictions), truths, filter):
+ yield True
+
+
+ def force_False(self, pkg, *vals):
+ pvals = [pkg]
+ pvals.extend(vals)
+ entry_point = pkg.changes_count()
+ # get the simple one out of the way first.
+ if not self.negate:
+ for r in self.restrictions:
+ if not r.force_False(*vals):
+ pkg.rollback(entry_point)
+ return
+ yield True
+ return
+
+ # <insert page long curse here>, OR logic, (len(restrictions)**2)-1 potential solutions.
+ # 0|0 == 0, 0|1 == 1|0 == 1|1 == 1.
+ # XXX this is quadratic. patches welcome to dodge the requirement to push through all potential
+ # truths.
+ truths = [r.match(*pvals) for r in self.restrictions]
+ def filter(truths):
+ return True in truths
+ for x in iterative_quad_toggling(pkg, pvals, self.restrictions, 0, len(self.restrictions), truths, filter):
+ yield True
+
+
+ def __str__(self):
+ if self.negate: return "not ( %s )" % " || ".join(imap(str, self.restrictions))
+ return "( %s )" % " || ".join(imap(str, self.restrictions))
+
+
+class XorRestriction(base):
+ """Boolean XOR grouping of restrictions."""
+ __slots__ = tuple(base.__slots__)
+
+ def match(self, vals):
+ if len(self.restrictions) == 0:
+ return not self.negate
+
+ if self.negate:
+ # 1|1 == 0|0 == 1, 0|1 == 1|0 == 0
+ armed = self.restrictions[0].match(*vals)
+ for rest in islice(self.restrictions, 1, len(self.restrictions)):
+ if armed != rest.match(vals):
+ return False
+ return True
+ # 0|1 == 1|0 == 1, 0|0 == 1|1 == 0
+ armed = False
+ for rest in self.restrictions:
+ if armed == rest.match(vals):
+ if armed:
+ return False
+ else:
+ if not armed:
+ armed = True
+ if armed:
+ return True
+ return False
+
+ def force_True(self, pkg, *vals):
+ pvals = [pkg]
+ pvals.extend(vals)
+ entry_point = pkg.changes_count()
+ truths = [r.match(*pvals) for r in self.restrictions]
+ count = truths.count(True)
+ # get the simple one out of the way first.
+ l = len(truths)
+ if self.negate:
+ f = lambda r: r.force_False(*pvals)
+ t = lambda r: r.force_True(*pvals)
+ if count > l/2: order = ((t, count, True), (f, l - count, False))
+ else: order = ((f, l - count, False), (t, count, True))
+ for action, current, desired in order:
+ if current == l:
+ yield True
+ continue
+ for x, r in enumerate(self.restrictions):
+ if truths[x] != desired:
+ if action(r):
+ current += 1
+ else:
+ break
+ if current == l:
+ yield True
+ pkg.rollback(entry_point)
+ return
+
+ stack = []
+ for x, val in enumerate(truths):
+ falses = filter(None, val)
+ if truths[x]:
+ falses.remove(x)
+ stack.append((falses, None))
+ else:
+ stack.append((falses, x))
+
+ if count == 1:
+ yield True
+ del stack[truths.index(True)]
+
+ for falses, truths in stack:
+ failed = False
+ for x in falses:
+ if not self.restrictions[x].force_False(*pvals):
+ failed = True
+ break
+ if not failed:
+ if trues != None:
+ if self.restrictions[x].force_True(*pvals):
+ yield True
+ else:
+ yield True
+ pkg.rollback(entry_point)
+
+
+ def force_False(self, pkg, *vals):
+ pvals = [pkg]
+ pvals.extend(vals)
+ entry_point = pkg.changes_count()
+ truths = [r.match(*pvals) for r in self.restrictions]
+ count = truths.count(True)
+ # get the simple one out of the way first.
+ l = len(truths)
+ if not self.negate:
+ f = lambda r: r.force_False(*pvals)
+ t = lambda r: r.force_True(*pvals)
+ if count > l/2: order = ((t, count, True), (f, l - count, False))
+ else: order = ((f, l - count, False), (t, count, True))
+ for action, current, desired in order:
+ if current == l:
+ yield True
+ continue
+ for x, r in enumerate(self.restrictions):
+ if truths[x] != desired:
+ if action(r):
+ current += 1
+ else:
+ break
+ if current == l:
+ yield True
+ pkg.rollback(entry_point)
+ return
+ # the fun one.
+ stack = []
+ for x, val in enumerate(truths):
+ falses = filter(None, val)
+ if truths[x]:
+ falses.remove(x)
+ stack.append((falses, None))
+ else:
+ stack.append((falses, x))
+
+ if count == 1:
+ yield True
+ del stack[truths.index(True)]
+
+ for falses, truths in stack:
+ failed = False
+ for x in falses:
+ if not self.restrictions[x].force_False(*pvals):
+ failed = True
+ break
+ if not failed:
+ if trues != None:
+ if self.restrictions[x].force_True(*pvals):
+ yield True
+ else:
+ yield True
+ pkg.rollback(entry_point)
+
+
+ def __str__(self):
+ if self.negate: return "not ( %s )" % " ^^ ".join(imap(str, self.restrictions))
+ return "( %s )" % " ^^ ".join(imap(str, self.restrictions))
+
+
diff --git a/portage/restrictions/packages.py b/portage/restrictions/packages.py
new file mode 100644
index 0000000..ae44150
--- /dev/null
+++ b/portage/restrictions/packages.py
@@ -0,0 +1,140 @@
+# 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/packages.py,v 1.1 2005/08/16 00:19:57 ferringb Exp $
+
+import restriction
+import boolean
+from portage.util.lists import unique
+import values
+
+class base(restriction.base):
+ package_matching = True
+
+class PackageRestriction(base):
+ """cpv data restriction. Inherit for anything that's more then cpv mangling please"""
+
+ __slots__ = tuple(["attr_split", "attr", "restriction"] + base.__slots__)
+
+ def __init__(self, attr, restriction, **kwds):
+ super(PackageRestriction, self).__init__(**kwds)
+ self.attr_split = attr.split(".")
+ self.attr = attr
+ if not isinstance(restriction, values.base):
+ raise TypeError("restriction must be of a restriction type")
+ self.restriction = restriction
+
+ def __pull_attr(self, pkg):
+ try:
+ o = pkg
+ for x in self.attr_split:
+ o = getattr(o, x)
+ return o
+ except AttributeError,ae:
+ logging.debug("failed getting attribute %s from %s, exception %s" % \
+ (self.attr, str(pkg), str(ae)))
+ raise
+
+ def match(self, pkg):
+ try:
+ return self.restriction.match(self.__pull_attr(pkg)) ^ self.negate
+ except AttributeError:
+ return self.negate
+
+
+ def force_False(self, pkg):
+# import pdb;pdb.set_trace()
+ if self.negate:
+ i = self.restriction.force_True(pkg, self.attr, self.__pull_attr(pkg))
+ else:
+ i = self.restriction.force_False(pkg, self.attr, self.__pull_attr(pkg))
+ if isinstance(i, bool):
+ yield i
+ else:
+ for x in i:
+ yield True
+ return
+
+ def force_True(self, pkg):
+# import pdb;pdb.set_trace()
+ if self.negate:
+ i = self.restriction.force_False(pkg, self.attr, self.__pull_attr(pkg))
+ else:
+ i = self.restriction.force_True(pkg, self.attr, self.__pull_attr(pkg))
+ if isinstance(i, bool):
+ yield i
+ else:
+ for x in i:
+ yield True
+ return
+
+
+ def __getitem__(self, key):
+ if not isinstance(self.restriction, boolean.base):
+ if key != 0:
+ raise IndexError("restriction isn't indexable")
+ else:
+ return self
+ try:
+ g = self.restriction[key]
+ except TypeError:
+ if key == 0:
+ return self.restriction
+ raise IndexError("index out of range")
+
+ def __len__(self):
+ if not isinstance(self.restriction, boolean.base):
+ return 1
+ return len(self.restriction) + 1
+
+ def intersect(self, other):
+ if self.negate != other.negate or self.attr != other.attr:
+ return None
+ if isinstance(self.restriction, other.restriction.__class__):
+ s = self.restriction.intersect(other.restriction)
+ elif isinstance(other.restriction, self.restriction.__class__):
+ s = other.restriction.intersect(self.restriction)
+ else: return None
+ if s == None:
+ return None
+ if s == self.restriction: return self
+ elif s == other.restriction: return other
+
+ # this can probably bite us in the ass self or other is a derivative, and the other isn't.
+ return self.__class__(self.attr, s)
+
+ def __eq__(self, other):
+ return self.negate == self.negate and self.attr == other.attr and self.restriction == other.restriction
+
+ def __str__(self):
+ s = self.attr
+ if self.negate: self.attr += "not "
+ return s + str(self.restriction)
+
+
+class AndRestriction(base, boolean.AndRestriction):
+ __slots__ = tuple(unique(list(boolean.AndRestriction.__slots__) + base.__slots__))
+ required_base = base
+
+
+class OrRestriction(base, boolean.OrRestriction):
+ __slots__ = tuple(unique(list(boolean.OrRestriction.__slots__) + base.__slots__))
+ required_base = base
+
+class XorRestriction(base, boolean.XorRestriction):
+ __slots__ = tuple(unique(list(boolean.XorRestriction.__slots__) + base.__slots__))
+ required_base = base
+
+class AlwaysBoolRestriction(restriction.AlwaysBoolMatch, base):
+ __slots__=("negate")
+def __init__(self, val):
+ self.negate = val
+def match(self, *a):
+ return self.negate
+def force_False(self, *a):
+ return self.negate == False
+def force_True(self, *a):
+ return self.negate == True
+
+AlwaysTrue = AlwaysBoolRestriction(True)
+AlwaysFalse = AlwaysBoolRestriction(True)
diff --git a/portage/restrictions/restrictionSet.py b/portage/restrictions/restrictionSet.py
deleted file mode 100644
index 67288d1..0000000
--- a/portage/restrictions/restrictionSet.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# 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.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"]
- else:
- finalize = False
- super(RestrictionSet, self).__init__(**kwds)
- for x in restrictions:
- if not isinstance(x, restriction.base):
- #bad monkey.
- raise TypeError, x
-
- if finalize:
- self.restrictions = tuple(restrictions)
- else:
- self.restrictions = list(restrictions)
-
-
- 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(imap(lambda x: x.total_len(), self.restrictions)) + 1
-
- def __len__(self): return len(self.restrictions)
-
- def __iter__(self): return iter(self.restrictions)
-
- 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
-
- # 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: 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):
- for rest in self.restrictions:
- if rest.match(packagedataInstance):
- 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: 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):
- armed = False
- for rest in self.restrictions:
- if rest.match(pkginst):
- if armed:
- return self.negate
- 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: return "not ( %s )" % " ^^ ".join(imap(str, self.restrictions))
- return "( %s )" % " ^^ ".join(imap(str, self.restrictions))
-
-
-bases = (AndRestrictionSet, OrRestrictionSet, XorRestrictionSet)
diff --git a/portage/restrictions/values.py b/portage/restrictions/values.py
new file mode 100644
index 0000000..8e96442
--- /dev/null
+++ b/portage/restrictions/values.py
@@ -0,0 +1,286 @@
+# 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/values.py,v 1.1 2005/08/16 00:19:57 ferringb Exp $
+
+import re, logging
+import restriction
+import boolean
+
+class base(restriction.base):
+ """base restriction matching object; overrides setattr to provide the usual write once trickery
+ all derivatives *must* be __slot__ based"""
+
+ __slots__ = restriction.base.__slots__
+
+ def force_True(self, pkg, attr, val):
+ if self.match(val) ^ self.negate: return True
+ elif self.negate: return pkg.request_disable(attr, val)
+ else: return pkg.request_enable(attr, val)
+
+ def force_False(self, pkg, attr, val):
+ if self.match(val) ^ self.negate: return True
+ elif self.negate: return pkg.request_enable(attr, val)
+ else: return pkg.request_disable(attr, val)
+
+
+class VersionRestriction(base):
+ """use this as base for version restrictions, gives a clue to what the restriction does"""
+ pass
+
+
+class StrMatch(base):
+ """ Base string matching restriction. all derivatives must be __slot__ based classes"""
+ __slots__ = ["flags"] + base.__slots__
+ pass
+
+
+class StrRegexMatch(StrMatch):
+ #potentially redesign this to jit the compiled_re object
+ __slots__ = tuple(["regex", "compiled_re"] + StrMatch.__slots__)
+
+ def __init__(self, regex, CaseSensitive=True, **kwds):
+ super(StrRegexMatch, self).__init__(**kwds)
+ self.regex = regex
+ flags = 0
+ if not CaseSensitive:
+ flags = re.I
+ self.flags = flags
+ self.compiled_re = re.compile(regex, flags)
+
+ def match(self, value):
+ return (self.compiled_re.match(str(value)) != None) ^ self.negate
+
+ def intersect(self, other):
+ if self.regex == other.regex and self.negate == other.negate and self.flags == other.flags:
+ return self
+ return None
+
+ def __eq__(self, other):
+ return self.regex == other.regex and self.negate == other.negate and self.flags == other.flags
+
+ def __str__(self):
+ if self.negate: return "not like %s" % self.regex
+ return "like %s" % self.regex
+
+
+class StrExactMatch(StrMatch):
+ __slots__ = tuple(["exact", "flags"] + StrMatch.__slots__)
+
+ def __init__(self, exact, CaseSensitive=True, **kwds):
+ super(StrExactMatch, self).__init__(**kwds)
+ if not CaseSensitive:
+ self.flags = re.I
+ self.exact = str(exact).lower()
+ else:
+ self.flags = 0
+ self.exact = str(exact)
+
+ def match(self, value):
+ if self.flags & re.I: return (self.exact == str(value).lower()) ^ self.negate
+ else: return (self.exact == str(value)) ^ self.negate
+
+ def intersect(self, other):
+ s1, s2 = self.exact, other.exact
+ if other.flags and not self.flags:
+ s1 = s1.lower()
+ elif self.flags and not other.flags:
+ s2 = s2.lower()
+ if s1 == s2 and self.negate == other.negate:
+ if other.flags:
+ return other
+ return self
+ return None
+
+ def __eq__(self, other):
+ return self.exact == other.exact and self.negate == other.negate and self.flags == other.flags
+
+ def __str__(self):
+ if self.negate: return "!= "+self.exact
+ return "== "+self.exact
+
+
+class StrGlobMatch(StrMatch):
+ __slots__ = tuple(["glob"] + StrMatch.__slots__)
+ def __init__(self, glob, CaseSensitive=True, **kwds):
+ super(StrGlobMatch, self).__init__(**kwds)
+ if not CaseSensitive:
+ self.flags = re.I
+ self.glob = str(glob).lower()
+ else:
+ self.flags = 0
+ self.glob = str(glob)
+
+ def match(self, value):
+ 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):
+ if self.negate == other.negate:
+ return other
+ elif other.match(self.glob):
+ if self.negate == other.negate:
+ return self
+ return None
+
+ def __eq__(self, other):
+ return self.glob == other.glob and self.negate == other.negate and self.flags == other.flags
+
+ def __str__(self):
+ if self.negate: return "not "+self.glob+"*"
+ return self.glob+"*"
+
+
+class ContainmentMatch(base):
+ """used for an 'in' style operation, 'x86' in ['x86','~x86'] for example
+ note that negation of this *does* not result in a true NAND when all is on."""
+ __slots__ = tuple(["vals", "vals_len", "all"] + base.__slots__)
+
+ def __init__(self, *vals, **kwds):
+ """vals must support a contaiment test
+ if all is set to True, all vals must match"""
+
+ if "all" in kwds:
+ self.all = kwds["all"]
+ del kwds["all"]
+ else:
+ self.all = False
+ super(ContainmentMatch, self).__init__(**kwds)
+ self.vals = set(vals)
+ self.vals_len = len(self.vals)
+
+ def match(self, val):
+ if isinstance(val, (str, unicode)):
+ return val in self.vals ^ self.negate
+ rem = set(self.vals)
+ try:
+ # assume our lookup is faster, since we don't know if val is constant lookup or not
+ for x in val:
+ if x in rem:
+ if self.all:
+ rem.remove(x)
+ if len(rem) == 0:
+ return not self.negate
+ else:
+ return not self.negate
+ return self.negate
+ except TypeError:
+ return self.negate
+# return val in self.vals ^ self.negate
+
+ def force_False(self, pkg, attr, val):
+ if isinstance(val, (str, unicode)):
+ # unchangable
+ if self.all:
+ if len(self.vals) != 1:
+ yield False
+ else:
+ yield (self.vals[0] in val) ^ self.negate
+ else:
+ yield (val in self.vals) ^ self.negate
+ return
+
+ entry = pkg.changes_count()
+ if self.negate:
+ if self.all:
+ def filter(truths): return False in truths
+ def true(r, pvals): return pkg.request_enable(attr, r)
+ def false(r, pvals): return pkg.request_disable(attr, r)
+
+ truths = [x in val for x in self.vals]
+
+ for x in boolean.iterative_quad_toggling(pkg, None, list(self.vals), 0, len(self.vals), truths, filter,
+ desired_false=false, desired_true=true):
+ yield True
+ else:
+ if pkg.request_disable(attr, *self.vals):
+ yield True
+ return
+
+ if not self.all:
+ if pkg.request_disable(attr, *self.vals):
+ yield True
+ else:
+ l = len(self.vals)
+ def filter(truths): return truths.count(True) < l
+ def true(r, pvals): return pkg.request_enable(attr, r)
+ def false(r, pvals): return pkg.request_disable(attr, r)
+ truths=[x in val for x in self.vals]
+ for x in boolean.iterative_quad_toggling(pkg, None, list(self.vals), 0, l, truths, filter,
+ desired_false=false, desired_true=true):
+ yield True
+
+ return
+
+
+ def force_True(self, pkg, attr, val):
+ import pdb;pdb.set_trace()
+ if isinstance(val, (str, unicode)):
+ # unchangable
+ if self.all:
+ if len(self.vals) != 1:
+ yield False
+ else:
+ yield (self.vals[0] in val) ^ self.negate
+ else:
+ yield (val in self.vals) ^ self.negate
+ return
+
+ entry = pkg.changes_count()
+ if not self.negate:
+ if not self.all:
+ def filter(truths): return True in truths
+ def true(r, pvals): return pkg.request_enable(attr, r)
+ def false(r, pvals): return pkg.request_disable(attr, r)
+
+ truths = [x in val for x in self.vals]
+
+ for x in boolean.iterative_quad_toggling(pkg, None, list(self.vals), 0, len(self.vals), truths, filter,
+ desired_false=false, desired_true=true):
+ yield True
+ else:
+ if pkg.request_enable(attr, *self.vals):
+ yield True
+ return
+
+ # negation
+ if not self.all:
+ if pkg.request_disable(attr, *self.vals):
+ yield True
+ else:
+ def filter(truths): return True not in truths
+ def true(r, pvals): return pkg.request_enable(attr, r)
+ def false(r, pvals): return pkg.request_disable(attr, r)
+ truths=[x in val for x in self.vals]
+ for x in boolean.iterative_quad_toggling(pkg, None, list(self.vals), 0, len(self.vals), truths, filter,
+ desired_false=false, desired_true=true):
+ yield True
+ return
+
+
+ def __str__(self):
+ if self.negate: s="not contains [%s]"
+ else: s="contains [%s]"
+ return s % ', '.join(map(str, self.vals))
+
+def get_val(pkg, attr):
+ attr_list = '.'.split(attr)
+ o=pkg
+ try:
+ for x in attr:
+ o=getattr(o, x)
+ return x
+ except AttributeError, ae:
+ logger.warn("impossible happened, unable to get attr '%s' from pkg '%s', yet it was handed into my parent"
+ % (attr, pkg))
+ raise
+