aboutsummaryrefslogtreecommitdiff
blob: 67288d115ed0708ea135de935e4082190cb387af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# 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)