summaryrefslogtreecommitdiff
path: root/geneticone/package.py
blob: 6916f49ea2d2d0f5f60b436bd7da8be1a68849e9 (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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#!/usr/bin/python

#
# File: geneticone/package.py
# This file is part of the Genetic/One-Project, a graphical portage-frontend.
#
# Copyright (C) 2006 Necoro d.M.
# 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 Necoro d.M. <necoro@necoro.net>

from geneticone import *

import gentoolkit
import portage
from portage_util import unique_array

class Package (gentoolkit.Package):
	"""This is just a subclass of the Package-class of gentoolkit."""

	def __init__ (self, cpv):
		if isinstance(cpv, gentoolkit.Package):
			cpv = cpv.get_cpv()
		gentoolkit.Package.__init__(self, cpv)
	
	def get_mask_status(self):
		'''gets the numeric mask status of a package
		can be translated as string:
		maskmodes = [ "  ", " ~", " -", "M ", "M~", "M-" ]
		(0=unmasked 1=~arch 2=-arch etc.)
		
		This method adapted from equery 0.1.4 
		Original author: Karl Trygve Kalleberg <karltk@gentoo.org>
		'''
		
		pkgmask = 0
		if self.is_masked():
			pkgmask = pkgmask + 3
		keywords = self.get_env_var("KEYWORDS").split()
		if "~" + gentoolkit.settings["ARCH"] in keywords:
			pkgmask = pkgmask + 1
		elif "-*" in keywords or "-" + gentoolkit.settings["ARCH"] in keywords:
			pkgmask = pkgmask + 2
		return pkgmask

	def get_size (self):
		return self.size()

	def get_all_useflags (self):
		"""Returns a list of _all_ useflags for this package."""
		return unique_array(self.get_env_var("IUSE").split())

	def get_all_deps (self):
		"""Returns a linearised list of all first-level dependencies for this package, on
		the form [(comparator, [use flags], cpv), ...]"""
		return unique_array(self.get_compiletime_deps()+self.get_runtime_deps()+self.get_postmerge_deps())

	def get_dep_packages (self):
		"""Returns a cpv-list of packages on which this package depends and which have not been installed yet.
		raises: BlockedException, PackageNotFoundException."""
		dep_pkgs = [] # the package list
		
		# let portage do the main stuff ;)
		# pay attention to any changes here
		deps = portage.dep_check (self.get_env_var("RDEPEND")+" "+self.get_env_var("DEPEND"), vartree.dbapi, self._settings)
		
		if not deps: # what is the difference to [1, []] ?
			return [] 

		deps = deps[1]

		for dep in deps:
			if dep[0] == '!':
				blocked = find_installed_packages(dep[1:])
				if blocked != []:
					raise BlockedException, blocked[0].get_cpv()
				else: # next flag
					continue

			pkg = find_best_match(dep)
			if not dep:
				raise PackageNotFoundException, dep
			else:
				dep_pkgs.append(pkg.get_cpv())

		return dep_pkgs

	def own_get_dep_packages (self, old_cpv_dict = {}):
		# XXX: after having finished this, i realized, that there is already a portage function -.- ;
		# will keep this in case portage changes anything
		"""Returns a list of all packages (i.e. package-cpvs) which this package depends on and which not have been installed yet.
		Param old_cpv_dict is a {cp: version}-dictionary holding already found deps.
		Raises a BlockedException if the package is being blocked by another installed package."""
		# XXX: This won't find blocking dependencies
		# XXX: Has some problems with modular X (this has a very strange ebuild) ... we should enhance _parse_deps
		print "Actual: "+self._cpv # debug output
		
		uses = [] # list of actual useflags / useflags the package has been installed with
		dep_packages = [] # list of packages returned
		dep_cpv_dict = {} # all dependencies are inserted here
		
		# get useflags
		if self.is_installed():
			uses = self.get_set_useflags()
		else:
			uses = self.get_settings("USE")
		
		# cycle through dependencies
		for (comp, flags, dep_cpv) in self.get_all_deps():

			# find blocking packages
			if comp and comp[0] == '!':
				blocked = find_installed_packages(comp[1:]+dep_cpv)
				if blocked != []:
					raise BlockedException, blocked[0].get_cpv()
				else: # next flag
					continue
			
			# look whether this package is really required
			needDep = True
			for flag in flags:
				if (flag[0] == '!' and flag[1:] in uses) or (flag[0] != '!' and flag not in uses):
					needDep = False
					break

			if needDep: # it is ...
				if find_installed_packages(comp+dep_cpv) == []: # ... and not installed yet
					d = find_best_match(comp+dep_cpv)
					if not d: # no package found
						raise PackageNotFoundException, dep_cpv
					if d.get_cp() not in old_cpv_dict: # ... and not found already by an other package
						dep_cpv_dict[d.get_cp()] = d.get_version()
						print "Dep: "+d.get_cpv() # debug
						dep_packages.append(d.get_cpv())
		
		for dep in dep_packages: # find dependencies for each package
			old_cpv_dict.update(dep_cpv_dict)
			old_cpv_dict.update({self.get_cp() : self.get_version()})
			dep_packages += find_packages("="+dep)[0].own_get_dep_packages(old_cpv_dict)

		return unique_array(dep_packages)

	def get_set_useflags (self):
		"""Returns a list of the useflags enabled at installation time. If package is not installed, it returns an empty list."""
		if self.is_installed():
			uses = self.get_use_flags().split()
			iuses = self.get_all_useflags()
			set = []
			for u in iuses:
				if u in uses:
					set.append(u)
			return set
		else:
			return []

	def get_cp (self):
		"""Returns category/package."""
		return self.get_category()+"/"+self.get_name()

	def is_masked (self):
		"""Returns True if either masked by package.mask or by profile."""
		# XXX: Better solution than string comparison?
		status = portage.getmaskingstatus(self._cpv)
		if "profile" in status or "package.mask" in status:
			return True
		return False

	def matches (self, criterion):
		"""This checks, whether this package matches a specific verisioning criterion - e.g.: "<=net-im/foobar-1.2"."""
		if portage.match_from_list(criterion, [self.get_cpv()]) == []:
			return False
		else:
			return True

	def _parse_deps(self,deps,curuse=[],level=0):
		"""Modified method "_parse_deps" of gentoolkit.Package.
		Do NOT ignore blocks."""
		# store (comparator, [use predicates], cpv)
		r = []
		comparators = ["~","<",">","=","<=",">="]
		end = len(deps)
		i = 0
		while i < end:
			blocked = False
			tok = deps[i]
			if tok == ')':
				return r,i
			if tok[-1] == "?":
				tok = tok.replace("?","")
				sr,l = self._parse_deps(deps[i+2:],curuse=curuse+[tok],level=level+1)
				r += sr
				i += l + 3
				continue
			if tok == "||":
				sr,l = self._parse_deps(deps[i+2:],curuse,level=level+1)
				r += sr
				i += l + 3
				continue
			# conjonction, like in "|| ( ( foo bar ) baz )" => recurse
			if tok == "(":
				sr,l = self._parse_deps(deps[i+1:],curuse,level=level+1)
				r += sr
				i += l + 2
				continue
			# pkg block "!foo/bar" => ignore it
			if tok[0] == "!":
				#i += 1
				#continue
				blocked = True # added
				tok = tok[1:] # added
			# pick out comparator, if any
			cmp = ""
			for c in comparators:
				if tok.find(c) == 0:
					cmp = c
					if blocked: cmp = "!"+cmp # added
			tok = tok[len(cmp):]
			r.append((cmp,curuse,tok))
			i += 1
		return r,i