summaryrefslogtreecommitdiff
path: root/portato/dependency.py
blob: cce736027ae93ee0f02fc6b15dac93aecf672ba0 (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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# -*- coding: utf-8 -*-
#
# File: portato/dependency.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
# Copyright (C) 2008 René 'Necoro' Neumann
# This is free software.  You may redistribute copies of it under the terms of
# the GNU General Public License version 2.
# There is NO WARRANTY, to the extent permitted by law.
#
# Written by René 'Necoro' Neumann <necoro@necoro.net>

"""
Provides classes for the presentation of dependencies.
"""

from __future__ import absolute_import, with_statement
__docformat__ = "restructuredtext"


from .helper import debug
from .backend import system

class Dependency (object):

	"""
	A simple dependency as it also is noted inside ebuilds.

	:IVariables:

		dep : string
			The dependency string. It is immutable.

		satisfied : boolean
			Is this dependency satisfied?
	"""

	def __init__ (self, dep):
		"""
		Creates a dependency out of a dep string.

		:param dep: dependency string
		:type dep: string
		"""
		self._dep = dep

	def is_satisfied (self):
		"""
		Checks if this dependency is satisfied.

		:rtype: boolean
		"""
		return system.find_best_match(self.dep, only_cpv = True, only_installed = True) is not None

	def __cmp__ (self, b):
		return cmp(self.dep, b.dep)

	def __hash__ (self):
		return hash(self.dep)

	def __str__ (self):
		return "<Dependency '%s'>" % self.dep

	__repr__ = __str__

	@property
	def dep (self):
		return self._dep

	satisfied = property(is_satisfied)

class OrDependency (Dependency):
	"""
	Dependency representing an "or".
	
	:note: Order is important. ``|| ( a b )`` != ``|| ( b a )``

	:IVariables:

		dep : tuple(`Dependency`,...)
			The dependencies. The tuple and the dependencies are immutable.
	"""

	def __init__ (self, deps):
		"""
		Creates an or-dependency out of a list (or tuple) of deps.

		:param deps: The or'ed dependencies.
		:type deps: iter<string>
		"""

		_dep = []
		for dep in deps:
			if not hasattr(dep, "__iter__"):
				assert not dep.endswith("?")
				_dep.append(Dependency(dep))
			else:
				_dep.append(AllOfDependency(dep))

		self._dep = tuple(_dep)
	
	def __str__ (self):
		return "<|| %s>" % str(self.dep)
	
	__repr__ = __str__

class AllOfDependency (Dependency):
	"""
	Dependency representing a set of packages inside "or".
	If the or is: ``|| (a ( b c ) )`` the `AllOfDependency` would be the ``( b c )``.

	:IVariables:

		dep : tuple(`Dependency`,...)
			The dependencies . The tuple and the deps are immutable.
	"""

	def __init__ (self, deps):
		"""
		Creates an or-dependency out of a list (or tuple) of deps.

		:param deps: The dependencies.
		:type deps: iter<string>
		"""

		self._dep = tuple(Dependency(dep) for dep in deps)

	def __str__ (self):
		return "<ALL %s>" % str(self.dep)
	
	__repr__ = __str__

class DependencyTree (object):

	"""
	The DependencyTree shows all dependencies for a package and shows which useflags want which dependencies.

	:IVariables:

		deps : set(`Dependency`)
			The list of dependencies which are not dependent on a useflag.

		flags : string -> `DependencyTree`
			Holds the additional dependency trees per useflag.
	"""

	def __init__ (self):

		self.deps = set()
		self.flags = {}

	def add (self, dep, *moredeps):
		"""
		Adds one or more normal dependencies to the tree.

		:Parameters:

			dep : string
				A dependency string.

			moredeps
				More parameters are allowed :)
		"""
		self.deps.add(Dependency(dep))

		for dep in moredeps:
			self.deps.add(Dependency(dep))

	def add_or (self, orlist):
		"""
		Adds a list of dependencies, which are or'ed.

		:param orlist: the dependency list
		:type orlist: iter<string>
		"""
		self.deps.add(OrDependency(orlist))

	def add_flag (self, flag):
		"""
		Adds a new useflag to this tree.
		For convenience the newly created sub-tree is returned.

		:param flag: the new flag
		:rtype: `DependencyTree`
		"""
		if not flag in self.flags:
			self.flags[flag] = DependencyTree()

		return self.get_flag_tree(flag)

	def get_flag_tree (self, flag):
		"""
		Returns the sub-tree of a specific tree.

		:raises KeyError: if the flag is not (yet) in this tree
		:rtype: `DependencyTree`
		"""
		return self.flags[flag]