aboutsummaryrefslogtreecommitdiff
blob: f0ec71202688774c54b0ec6bbbf1c94499c68f1e (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
# R Overlay -- ebuild creation, <?>
# Copyright 2006-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import roverlay.static.depres

from roverlay.ebuild import evars

# move this to const / config
FIELDS = {
	'R_SUGGESTS' : [ 'Suggests' ],
	'DEPENDS'    : [ 'Depends', 'Imports' ],
	'RDEPENDS'   : [ 'LinkingTo', 'SystemRequirements' ]
}

EBUILDVARS = {
	'R_SUGGESTS' : evars.R_SUGGESTS,
	'DEPENDS'    : evars.DEPEND,
	'RDEPENDS'   : evars.RDEPEND,
}


class EbuildDepRes ( object ):

	def __init__ (
		self, package_info, logger,
		depres_channel_spawner=None, create_iuse=True, run_now=True
	):
		self.logger       = logger
		self.package_info = package_info

		if depres_channel_spawner is None:
			self.request_resolver = roverlay.static.depres.get_ebuild_channel
		else:
			self.request_resolver = depres_channel_spawner

		# > 0 busy/working; 0 == done,success; < 0 done,fail
		self.status       = 1
		self.result       = None
		self.has_suggests = None
		self.create_iuse  = create_iuse

		self._channels    = None

		if run_now:
			self.resolve()

	# --- end of __init__ (...) ---

	def done    ( self ) : return self.status  < 1
	def busy    ( self ) : return self.status  > 0
	def success ( self ) : return self.status == 0
	def fail    ( self ) : return self.status  < 0

	def get_result ( self ):
		return ( self.status, self.result, self.has_suggests )
	# --- end of get_result (...) ---

	def resolve ( self ):
		try:
			self.result = None
			self._init_channels()

			if self._wait_resolve():
				self._make_result()
				self.status = 0

			else:
				# unresolvable
				self.logger.info ( "Cannot satisfy dependencies!" )

				self.result = None
				self.status = -5

		finally:
			self._close_channels()
	# --- end of resolve (...) ---

	def _get_channel ( self, dependency_type ):
		if dependency_type not in self._channels:
			self._channels [dependency_type] = self.request_resolver (
				dependency_type,
				self.logger
			)
		return self._channels [dependency_type]
	# --- end of get_channel (...) ---

	def _init_channels ( self ):
		# collect dep strings and initialize resolver channels

		if self.request_resolver is None:
			self.logger.warning (
				"Cannot resolve dependencies, no resolver available!"
			)
			return True

		desc = self.package_info ['desc_data']
		self._channels = dict()

		dep_type = desc_field = None

		for dep_type in FIELDS:
			resolver = None

			for desc_field in FIELDS [dep_type]:
				if desc_field in desc:
					if not resolver:
						resolver = self._get_channel ( dep_type )

					if isinstance ( desc [desc_field], str ):
						resolver.add_dependency ( desc [desc_field] )
					elif hasattr ( desc [desc_field], '__iter__' ):
						resolver.add_dependencies ( desc [desc_field] )
					else:
						logger.warning (
							"Cannot add dependency '%s'." % desc [desc_field]
					)
		# -- for dep_type

		self.has_suggests = bool ( 'R_SUGGESTS' in self._channels )

	# --- end of _init_channels (...) ---

	def _close_channels ( self ):
		if self._channels is None: return

		for channel in self._channels.values(): channel.close()
		del self._channels
	# --- end of _close_channels (...) ---

	def _wait_resolve ( self ):
		# True if no channels
		for c in self._channels.values():
			if c.satisfy_request() is None:
				return False
		return True
	# --- end of _wait_resolve (...) ---

	def _make_result ( self ):
		_result = list()
		for dep_type, channel in self._channels.items():
			deplist = list ( filter ( None, channel.collect_dependencies() ) )

			if deplist is None:
				## FIXME: false positive: "empty" channel
				raise Exception (
					'dep_resolver is broken: '
					'lookup() returns None but satisfy_request() says ok.'
				)
			elif hasattr ( deplist, '__iter__' ):
				# add dependencies in no_append/override mode
				self.logger.debug ( "adding %s to %s", deplist, dep_type )
				_result.append (
					EBUILDVARS [dep_type] (
						deplist,
						using_suggests=self.has_suggests
					)
				)
			else:
				raise Exception ( "dep_resolver is broken: iterable expected!" )
		# -- for dep_type,..

		if self.create_iuse:
			_result.append ( evars.IUSE ( using_suggests=self.has_suggests ) )

		self.result = tuple ( _result )
	# --- end of _make_result (...) ---