aboutsummaryrefslogtreecommitdiff
blob: 127d630491fc7e0889196e49b2b05e693157aaf5 (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
# 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.5 2005/08/16 00:21:49 ferringb Exp $

__all__=("DictBased")
from inspect import isroutine
from boolean import base as bool_base
from packages import AndRestriction, OrRestriction, AlwaysTrue, AlwaysFalse, base
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):
		"""restriction_items is a source of restriction keys and remaining restriction (if none, set it to None)
		get_key is a function to get the key from a pkg instance"""

		if not isroutine(get_key_from_package):
			raise TypeError(get_key_from_package)

		super(DictBased, self).__init__(*args, **kwargs)
		self.restricts_dict = {}
		for r in restriction_items:
			key, remaining = get_key_from_atom(r)
			if len(remaining) == 0:
				remaining = AlwaysTrue
			else:
				if len(remaining) == 1 and (isinstance(remaining, list) or isinstance(remaining, tuple)):
					remaining = remaining[0]
				elif isinstance(remaining, (tuple, list)):
					remaining = AndRestriction(*remaining)
				elif not isinstance(remaining, base):
					print "remaining=",remaining
					print "base=",base
					raise KeyError("unable to convert '%s', remaining '%s' isn't of a known base" % (str(r), str(remaining)))

			if key in self.restricts_dict:
				self.restricts_dict[key].add_restriction(remaining)
			else:
				self.restricts_dict[key] = OrRestriction(remaining)

		self.get_pkg_key, self.get_atom_key = get_key_from_package, get_key_from_atom


	def match(self, pkginst):
		try:
			key = self.get_pkg_key(pkginst)
		except (TypeError, AttributeError):
			return self.negate
		if key not in self.restricts_dict:
			return self.negate
	
		remaining = self.restricts_dict[key]
		return remaining.match(pkginst) ^ self.negate

			
	def __contains__(self, restriction):
		if isinstance(restriction, base):
			key, r = self.get_atom_key(restriction)
		if key != None and key in self.restricts_dict:
			return True
		return False


#	def __getitem__(self, restriction, default=None):
#		if isinstance(restriction, base):
#			key, r = self.get_atom_key(restriction)
#		if key == None:	return default
#		return self.restricts_dict.get(key, default)
#		
#
#	def __setitem__(self, restriction, val):
#		if isinstance(restriction, base):
#			key, r = self.get_atom_key(restriction)
#		if key == None:
#			raise KeyError("either passed in, or converted val became None, invalid as key")
#		self.restricts_dict[key] = val
#
#
#	def __delitem__(self, restriction):
#		if isinstance(restriction, base):
#			key = self.get_atom_key(restriction)
#		if key != None and key in self.restricts_dict:
#			del self.restricts_dict[key]