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
223
224
225
226
227
228
229
230
231
232
233
|
# Copyright 2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
__all__ = (
'VirtualsManager',
)
from copy import deepcopy
from portage import os
from portage.dep import Atom
from portage.exception import InvalidAtom
from portage.localization import _
from portage.util import grabdict, stack_dictlist, writemsg
from portage.versions import cpv_getkey
class VirtualsManager(object):
def __init__(self, *args, **kwargs):
if kwargs.get("_copy"):
return
assert len(args) == 1, "VirtualsManager.__init__ takes one positional arguments"
assert not kwargs, "unknown keyword argument(s) '%s' passed to VirtualsManager.__init__" % \
", ".join(kwargs)
profiles = args[0]
self._virtuals = None
self._dirVirtuals = None
self._virts_p = None
# Virtuals obtained from the vartree
self._treeVirtuals = None
# Virtuals added by the depgraph via self.add_depgraph_virtuals().
self._depgraphVirtuals = {}
#Initialise _dirVirtuals.
self._read_dirVirtuals(profiles)
#We could initialise _treeVirtuals here, but some consumers want to
#pass their own vartree.
def _read_dirVirtuals(self, profiles):
"""
Read the 'virtuals' file in all profiles.
"""
virtuals_list = []
for x in profiles:
virtuals_file = os.path.join(x, "virtuals")
virtuals_dict = grabdict(virtuals_file)
atoms_dict = {}
for k, v in virtuals_dict.items():
try:
virt_atom = Atom(k)
except InvalidAtom:
virt_atom = None
else:
if virt_atom.blocker or \
str(virt_atom) != str(virt_atom.cp):
virt_atom = None
if virt_atom is None:
writemsg(_("--- Invalid virtuals atom in %s: %s\n") % \
(virtuals_file, k), noiselevel=-1)
continue
providers = []
for atom in v:
atom_orig = atom
if atom[:1] == '-':
# allow incrementals
atom = atom[1:]
try:
atom = Atom(atom)
except InvalidAtom:
atom = None
else:
if atom.blocker:
atom = None
if atom is None:
writemsg(_("--- Invalid atom in %s: %s\n") % \
(virtuals_file, atom_orig), noiselevel=-1)
else:
if atom_orig == str(atom):
# normal atom, so return as Atom instance
providers.append(atom)
else:
# atom has special prefix, so return as string
providers.append(atom_orig)
if providers:
atoms_dict[virt_atom] = providers
if atoms_dict:
virtuals_list.append(atoms_dict)
self._dirVirtuals = stack_dictlist(virtuals_list, incremental=True)
for virt in self._dirVirtuals:
# Preference for virtuals decreases from left to right.
self._dirVirtuals[virt].reverse()
def __deepcopy__(self, memo=None):
if memo is None:
memo = {}
result = VirtualsManager(_copy=True)
memo[id(self)] = result
# immutable attributes (internal policy ensures lack of mutation)
# _treeVirtuals is initilised by _populate_treeVirtuals().
# Before that it's 'None'.
result._treeVirtuals = self._treeVirtuals
memo[id(self._treeVirtuals)] = self._treeVirtuals
# _dirVirtuals is initilised by __init__.
result._dirVirtuals = self._dirVirtuals
memo[id(self._dirVirtuals)] = self._dirVirtuals
# mutable attributes (change when add_depgraph_virtuals() is called)
result._virtuals = deepcopy(self._virtuals, memo)
result._depgraphVirtuals = deepcopy(self._depgraphVirtuals, memo)
result._virts_p = deepcopy(self._virts_p, memo)
return result
def _compile_virtuals(self):
"""Stack installed and profile virtuals. Preference for virtuals
decreases from left to right.
Order of preference:
1. installed and in profile
2. installed only
3. profile only
"""
assert self._treeVirtuals is not None, "_populate_treeVirtuals() must be called before " + \
"any query about virtuals"
# Virtuals by profile+tree preferences.
ptVirtuals = {}
for virt, installed_list in self._treeVirtuals.items():
profile_list = self._dirVirtuals.get(virt, None)
if not profile_list:
continue
for cp in installed_list:
if cp in profile_list:
ptVirtuals.setdefault(virt, [])
ptVirtuals[virt].append(cp)
virtuals = stack_dictlist([ptVirtuals, self._treeVirtuals,
self._dirVirtuals, self._depgraphVirtuals])
self._virtuals = virtuals
self._virts_p = None
def getvirtuals(self):
"""
Computes self._virtuals if necessary and returns it.
self._virtuals is only computed on the first call.
"""
if self._virtuals is None:
self._compile_virtuals()
return self._virtuals
def _populate_treeVirtuals(self, vartree):
"""
Initialize _treeVirtuals from the given vartree.
It must not have been initialized already, otherwise
our assumptions about immutability don't hold.
"""
assert self._treeVirtuals is None, "treeVirtuals must not be reinitialized"
self._treeVirtuals = {}
for provide, cpv_list in vartree.get_all_provides().items():
try:
provide = Atom(provide)
except InvalidAtom:
continue
self._treeVirtuals[provide.cp] = \
[Atom(cpv_getkey(cpv)) for cpv in cpv_list]
def populate_treeVirtuals_if_needed(self, vartree):
"""
Initialize _treeVirtuals if it hasn't been done already.
This is a hack for consumers that already have an populated vartree.
"""
if self._treeVirtuals is not None:
return
self._populate_treeVirtuals(vartree)
def add_depgraph_virtuals(self, mycpv, virts):
"""This updates the preferences for old-style virtuals,
affecting the behavior of dep_expand() and dep_check()
calls. It can change dbapi.match() behavior since that
calls dep_expand(). However, dbapi instances have
internal match caches that are not invalidated when
preferences are updated here. This can potentially
lead to some inconsistency (relevant to bug #1343)."""
#Ensure that self._virtuals is populated.
if self._virtuals is None:
self.getvirtuals()
modified = False
cp = Atom(cpv_getkey(mycpv))
for virt in virts:
try:
virt = Atom(virt).cp
except InvalidAtom:
continue
providers = self._virtuals.get(virt)
if providers and cp in providers:
continue
providers = self._depgraphVirtuals.get(virt)
if providers is None:
providers = []
self._depgraphVirtuals[virt] = providers
if cp not in providers:
providers.append(cp)
modified = True
if modified:
self._compile_virtuals()
def get_virts_p(self):
if self._virts_p is not None:
return self._virts_p
virts = self.getvirtuals()
virts_p = {}
for x in virts:
vkeysplit = x.split("/")
if vkeysplit[1] not in virts_p:
virts_p[vkeysplit[1]] = virts[x]
self._virts_p = virts_p
return virts_p
|