1 |
commit: dbdc835ba201fb580985101955725e85f1b83586 |
2 |
Author: Magnus Granberg <zorry <AT> gentoo <DOT> org> |
3 |
AuthorDate: Thu Nov 29 22:10:06 2012 +0000 |
4 |
Commit: Magnus Granberg <zorry <AT> gentoo <DOT> org> |
5 |
CommitDate: Thu Nov 29 22:10:06 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=dev/zorry.git;a=commit;h=dbdc835b |
7 |
|
8 |
Rework on the db and some code |
9 |
|
10 |
--- |
11 |
gobs/bin/gobs_host_jobs | 3 +- |
12 |
gobs/pym/ConnectionManager.py | 3 +- |
13 |
gobs/pym/buildquerydb.py | 2 +- |
14 |
gobs/pym/categories.py | 30 - |
15 |
gobs/pym/depgraph.py | 1637 +++++++++++++++++++++++------------------ |
16 |
gobs/pym/jobs.py | 136 ++-- |
17 |
gobs/pym/old_cpv.py | 14 +- |
18 |
gobs/pym/package.py | 561 ++++++++------- |
19 |
gobs/pym/pgsql.py | 8 +- |
20 |
gobs/pym/pgsql_querys.py | 308 ++++++++ |
21 |
gobs/pym/repoman_gobs.py | 10 +- |
22 |
gobs/pym/text.py | 4 +- |
23 |
gobs/pym/updatedb.py | 129 ++-- |
24 |
13 files changed, 1673 insertions(+), 1172 deletions(-) |
25 |
|
26 |
diff --git a/gobs/bin/gobs_host_jobs b/gobs/bin/gobs_host_jobs |
27 |
index 5ece453..72683c9 100755 |
28 |
--- a/gobs/bin/gobs_host_jobs |
29 |
+++ b/gobs/bin/gobs_host_jobs |
30 |
@@ -1,5 +1,4 @@ |
31 |
#!/usr/bin/python |
32 |
-# Copyright 2006-2011 Gentoo Foundation |
33 |
# Distributed under the terms of the GNU General Public License v2 |
34 |
|
35 |
from __future__ import print_function |
36 |
@@ -15,7 +14,7 @@ from gobs.ConnectionManager import connectionManager |
37 |
CM=connectionManager(gobs_settings_dict) |
38 |
#selectively import the pgsql/mysql querys |
39 |
if CM.getName()=='pgsql': |
40 |
- from gobs.pgsql import * |
41 |
+ from gobs.pgsql_querys import add_gobs_logs |
42 |
|
43 |
import logging |
44 |
import time |
45 |
|
46 |
diff --git a/gobs/pym/ConnectionManager.py b/gobs/pym/ConnectionManager.py |
47 |
index ff0e07f..5e8a763 100644 |
48 |
--- a/gobs/pym/ConnectionManager.py |
49 |
+++ b/gobs/pym/ConnectionManager.py |
50 |
@@ -11,6 +11,7 @@ class connectionManager(object): |
51 |
if not cls._instance: |
52 |
cls._instance = super(connectionManager, cls).__new__(cls, *args, **kwargs) |
53 |
#read the sql user/host etc and store it in the local object |
54 |
+ cls._backend=settings_dict['sql_backend'] |
55 |
cls._host=settings_dict['sql_host'] |
56 |
cls._user=settings_dict['sql_user'] |
57 |
cls._password=settings_dict['sql_passwd'] |
58 |
@@ -21,7 +22,7 @@ class connectionManager(object): |
59 |
cls._connectionNumber=numberOfconnections |
60 |
#always create 1 connection |
61 |
cls._pool=pool.ThreadedConnectionPool(1,cls._connectionNumber,host=cls._host,database=cls._database,user=cls._user,password=cls._password) |
62 |
- cls._name='pgsql' |
63 |
+ cls._name=cls._backend |
64 |
except ImportError: |
65 |
print("Please install a recent version of dev-python/psycopg for Python") |
66 |
sys.exit(1) |
67 |
|
68 |
diff --git a/gobs/pym/buildquerydb.py b/gobs/pym/buildquerydb.py |
69 |
index e0745e2..abd5ea9 100644 |
70 |
--- a/gobs/pym/buildquerydb.py |
71 |
+++ b/gobs/pym/buildquerydb.py |
72 |
@@ -68,7 +68,7 @@ def add_buildquery_main(config_id): |
73 |
log_msg = "Check configs done" |
74 |
add_gobs_logs(conn, log_msg, "info", config_profile) |
75 |
# Get default config from the configs table and default_config=1 |
76 |
- default_config_root = "/var/lib/gobs/" + gobs_settings_dict['gobs_gitreponame'] + "/" + config_id + "/" |
77 |
+ default_config_root = "/var/cache/gobs/" + gobs_settings_dict['gobs_gitreponame'] + "/" + config_id + "/" |
78 |
# Set config_root (PORTAGE_CONFIGROOT) to default_config_root |
79 |
mysettings = portage.config(config_root = default_config_root) |
80 |
myportdb = portage.portdbapi(mysettings=mysettings) |
81 |
|
82 |
diff --git a/gobs/pym/categories.py b/gobs/pym/categories.py |
83 |
deleted file mode 100644 |
84 |
index dae1207..0000000 |
85 |
--- a/gobs/pym/categories.py |
86 |
+++ /dev/null |
87 |
@@ -1,30 +0,0 @@ |
88 |
-#from gobs.text import gobs_text |
89 |
-from gobs.text import get_file_text |
90 |
-import portage |
91 |
-from gobs.readconf import get_conf_settings |
92 |
-reader=get_conf_settings() |
93 |
-gobs_settings_dict=reader.read_gobs_settings_all() |
94 |
-# make a CM |
95 |
-from gobs.ConnectionManager import connectionManager |
96 |
-CM=connectionManager(gobs_settings_dict) |
97 |
-#selectively import the pgsql/mysql querys |
98 |
-if CM.getName()=='pgsql': |
99 |
- from gobs.pgsql import * |
100 |
- |
101 |
-class gobs_categories(object): |
102 |
- |
103 |
- def __init__(self, mysettings): |
104 |
- self._mysettings = mysettings |
105 |
- |
106 |
- def update_categories_db(self, categories): |
107 |
- conn=CM.getConnection() |
108 |
- # Update categories_meta in the db |
109 |
- categories_dir = self._mysettings['PORTDIR'] + "/" + categories + "/" |
110 |
- categories_metadata_xml_checksum_tree = portage.checksum.sha256hash(categories_dir + "metadata.xml")[0] |
111 |
- categories_metadata_xml_text_tree = get_file_text(categories_dir + "metadata.xml") |
112 |
- categories_metadata_xml_checksum_db = get_categories_checksum_db(conn, categories) |
113 |
- if categories_metadata_xml_checksum_db is None: |
114 |
- add_new_categories_meta_sql(conn,categories, categories_metadata_xml_checksum_tree, categories_metadata_xml_text_tree) |
115 |
- elif categories_metadata_xml_checksum_db != categories_metadata_xml_checksum_tree: |
116 |
- update_categories_meta_sql(conn,categories, categories_metadata_xml_checksum_tree, categories_metadata_xml_text_tree) |
117 |
- CM.putConnection(conn) |
118 |
|
119 |
diff --git a/gobs/pym/depgraph.py b/gobs/pym/depgraph.py |
120 |
index 7c46cde..0a6afc8 100644 |
121 |
--- a/gobs/pym/depgraph.py |
122 |
+++ b/gobs/pym/depgraph.py |
123 |
@@ -1,6 +1,5 @@ |
124 |
# Copyright 1999-2012 Gentoo Foundation |
125 |
# Distributed under the terms of the GNU General Public License v2 |
126 |
-# Copy of ../pym/_emerge/depgraph.py from Portage |
127 |
|
128 |
from __future__ import print_function |
129 |
|
130 |
@@ -19,14 +18,19 @@ from portage import os, OrderedDict |
131 |
from portage import _unicode_decode, _unicode_encode, _encodings |
132 |
from portage.const import PORTAGE_PACKAGE_ATOM, USER_CONFIG_PATH |
133 |
from portage.dbapi import dbapi |
134 |
+from portage.dbapi.dep_expand import dep_expand |
135 |
from portage.dep import Atom, best_match_to_list, extract_affecting_use, \ |
136 |
- check_required_use, human_readable_required_use, _repo_separator, \ |
137 |
- _RequiredUseBranch, _RequiredUseLeaf |
138 |
-from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use |
139 |
-from portage.exception import InvalidAtom, InvalidDependString, PortageException |
140 |
+ check_required_use, human_readable_required_use, match_from_list, \ |
141 |
+ _repo_separator |
142 |
+from portage.dep._slot_operator import ignore_built_slot_operator_deps |
143 |
+from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use, \ |
144 |
+ _get_eapi_attrs |
145 |
+from portage.exception import (InvalidAtom, InvalidData, InvalidDependString, |
146 |
+ PackageNotFound, PortageException) |
147 |
from portage.output import colorize, create_color_func, \ |
148 |
darkgreen, green |
149 |
bad = create_color_func("BAD") |
150 |
+from portage.package.ebuild.config import _get_feature_flags |
151 |
from portage.package.ebuild.getmaskingstatus import \ |
152 |
_getmaskingstatus, _MaskReason |
153 |
from portage._sets import SETPREFIX |
154 |
@@ -73,6 +77,9 @@ from _emerge.resolver.output import Display |
155 |
if sys.hexversion >= 0x3000000: |
156 |
basestring = str |
157 |
long = int |
158 |
+ _unicode = str |
159 |
+else: |
160 |
+ _unicode = unicode |
161 |
|
162 |
class _scheduler_graph_config(object): |
163 |
def __init__(self, trees, pkg_cache, graph, mergelist): |
164 |
@@ -85,9 +92,9 @@ def _wildcard_set(atoms): |
165 |
pkgs = InternalPackageSet(allow_wildcard=True) |
166 |
for x in atoms: |
167 |
try: |
168 |
- x = Atom(x, allow_wildcard=True) |
169 |
+ x = Atom(x, allow_wildcard=True, allow_repo=False) |
170 |
except portage.exception.InvalidAtom: |
171 |
- x = Atom("*/" + x, allow_wildcard=True) |
172 |
+ x = Atom("*/" + x, allow_wildcard=True, allow_repo=False) |
173 |
pkgs.add(x) |
174 |
return pkgs |
175 |
|
176 |
@@ -110,6 +117,8 @@ class _frozen_depgraph_config(object): |
177 |
self._pkg_cache = {} |
178 |
self._highest_license_masked = {} |
179 |
dynamic_deps = myopts.get("--dynamic-deps", "y") != "n" |
180 |
+ ignore_built_slot_operator_deps = myopts.get( |
181 |
+ "--ignore-built-slot-operator-deps", "n") == "y" |
182 |
for myroot in trees: |
183 |
self.trees[myroot] = {} |
184 |
# Create a RootConfig instance that references |
185 |
@@ -124,7 +133,8 @@ class _frozen_depgraph_config(object): |
186 |
FakeVartree(trees[myroot]["root_config"], |
187 |
pkg_cache=self._pkg_cache, |
188 |
pkg_root_config=self.roots[myroot], |
189 |
- dynamic_deps=dynamic_deps) |
190 |
+ dynamic_deps=dynamic_deps, |
191 |
+ ignore_built_slot_operator_deps=ignore_built_slot_operator_deps) |
192 |
self.pkgsettings[myroot] = portage.config( |
193 |
clone=self.trees[myroot]["vartree"].settings) |
194 |
|
195 |
@@ -366,12 +376,15 @@ class _dynamic_depgraph_config(object): |
196 |
# This use used to check if we have accounted for blockers |
197 |
# relevant to a package. |
198 |
self._traversed_pkg_deps = set() |
199 |
- self._slot_collision_info = {} |
200 |
+ # This should be ordered such that the backtracker will |
201 |
+ # attempt to solve conflicts which occurred earlier first, |
202 |
+ # since an earlier conflict can be the cause of a conflict |
203 |
+ # which occurs later. |
204 |
+ self._slot_collision_info = OrderedDict() |
205 |
# Slot collision nodes are not allowed to block other packages since |
206 |
# blocker validation is only able to account for one package per slot. |
207 |
self._slot_collision_nodes = set() |
208 |
self._parent_atoms = {} |
209 |
- self._slot_conflict_parent_atoms = set() |
210 |
self._slot_conflict_handler = None |
211 |
self._circular_dependency_handler = None |
212 |
self._serialized_tasks_cache = None |
213 |
@@ -400,7 +413,9 @@ class _dynamic_depgraph_config(object): |
214 |
self._needed_p_mask_changes = backtrack_parameters.needed_p_mask_changes |
215 |
self._needed_license_changes = backtrack_parameters.needed_license_changes |
216 |
self._needed_use_config_changes = backtrack_parameters.needed_use_config_changes |
217 |
+ self._needed_required_use_config_changes = backtrack_parameters.needed_required_use_config_changes |
218 |
self._runtime_pkg_mask = backtrack_parameters.runtime_pkg_mask |
219 |
+ self._slot_operator_replace_installed = backtrack_parameters.slot_operator_replace_installed |
220 |
self._need_restart = False |
221 |
# For conditions that always require user intervention, such as |
222 |
# unsatisfied REQUIRED_USE (currently has no autounmask support). |
223 |
@@ -410,6 +425,8 @@ class _dynamic_depgraph_config(object): |
224 |
self._autounmask = depgraph._frozen_config.myopts.get('--autounmask') != 'n' |
225 |
self._success_without_autounmask = False |
226 |
self._traverse_ignored_deps = False |
227 |
+ self._complete_mode = False |
228 |
+ self._slot_operator_deps = {} |
229 |
|
230 |
for myroot in depgraph._frozen_config.trees: |
231 |
self.sets[myroot] = _depgraph_sets() |
232 |
@@ -487,8 +504,6 @@ class _dynamic_depgraph_config(object): |
233 |
class depgraph(object): |
234 |
|
235 |
pkg_tree_map = RootConfig.pkg_tree_map |
236 |
- |
237 |
- _dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"] |
238 |
|
239 |
def __init__(self, settings, trees, myopts, myparams, spinner, |
240 |
frozen_config=None, backtrack_parameters=BacktrackParameter(), allow_backtracking=False): |
241 |
@@ -521,10 +536,6 @@ class depgraph(object): |
242 |
preload_installed_pkgs = \ |
243 |
"--nodeps" not in self._frozen_config.myopts |
244 |
|
245 |
- if self._frozen_config.myopts.get("--root-deps") is not None and \ |
246 |
- myroot != self._frozen_config.target_root: |
247 |
- continue |
248 |
- |
249 |
fake_vartree = self._frozen_config.trees[myroot]["vartree"] |
250 |
if not fake_vartree.dbapi: |
251 |
# This needs to be called for the first depgraph, but not for |
252 |
@@ -599,11 +610,17 @@ class depgraph(object): |
253 |
"due to non matching USE:\n\n", noiselevel=-1) |
254 |
|
255 |
for pkg, flags in self._dynamic_config.ignored_binaries.items(): |
256 |
- writemsg(" =%s" % pkg.cpv, noiselevel=-1) |
257 |
+ flag_display = [] |
258 |
+ for flag in sorted(flags): |
259 |
+ if flag not in pkg.use.enabled: |
260 |
+ flag = "-" + flag |
261 |
+ flag_display.append(flag) |
262 |
+ flag_display = " ".join(flag_display) |
263 |
+ # The user can paste this line into package.use |
264 |
+ writemsg(" =%s %s" % (pkg.cpv, flag_display), noiselevel=-1) |
265 |
if pkg.root_config.settings["ROOT"] != "/": |
266 |
- writemsg(" for %s" % (pkg.root,), noiselevel=-1) |
267 |
- writemsg("\n use flag(s): %s\n" % ", ".join(sorted(flags)), |
268 |
- noiselevel=-1) |
269 |
+ writemsg(" # for %s" % (pkg.root,), noiselevel=-1) |
270 |
+ writemsg("\n", noiselevel=-1) |
271 |
|
272 |
msg = [ |
273 |
"", |
274 |
@@ -615,7 +632,7 @@ class depgraph(object): |
275 |
for line in msg: |
276 |
if line: |
277 |
line = colorize("INFORM", line) |
278 |
- writemsg_stdout(line + "\n", noiselevel=-1) |
279 |
+ writemsg(line + "\n", noiselevel=-1) |
280 |
|
281 |
def _show_missed_update(self): |
282 |
|
283 |
@@ -801,37 +818,400 @@ class depgraph(object): |
284 |
|
285 |
def _process_slot_conflicts(self): |
286 |
""" |
287 |
+ If there are any slot conflicts and backtracking is enabled, |
288 |
+ _complete_graph should complete the graph before this method |
289 |
+ is called, so that all relevant reverse dependencies are |
290 |
+ available for use in backtracking decisions. |
291 |
+ """ |
292 |
+ for (slot_atom, root), slot_nodes in \ |
293 |
+ self._dynamic_config._slot_collision_info.items(): |
294 |
+ self._process_slot_conflict(root, slot_atom, slot_nodes) |
295 |
+ |
296 |
+ def _process_slot_conflict(self, root, slot_atom, slot_nodes): |
297 |
+ """ |
298 |
Process slot conflict data to identify specific atoms which |
299 |
lead to conflict. These atoms only match a subset of the |
300 |
packages that have been pulled into a given slot. |
301 |
""" |
302 |
- for (slot_atom, root), slot_nodes \ |
303 |
- in self._dynamic_config._slot_collision_info.items(): |
304 |
|
305 |
- all_parent_atoms = set() |
306 |
- for pkg in slot_nodes: |
307 |
- parent_atoms = self._dynamic_config._parent_atoms.get(pkg) |
308 |
- if not parent_atoms: |
309 |
+ debug = "--debug" in self._frozen_config.myopts |
310 |
+ |
311 |
+ slot_parent_atoms = set() |
312 |
+ for pkg in slot_nodes: |
313 |
+ parent_atoms = self._dynamic_config._parent_atoms.get(pkg) |
314 |
+ if not parent_atoms: |
315 |
+ continue |
316 |
+ slot_parent_atoms.update(parent_atoms) |
317 |
+ |
318 |
+ conflict_pkgs = [] |
319 |
+ conflict_atoms = {} |
320 |
+ for pkg in slot_nodes: |
321 |
+ |
322 |
+ if self._dynamic_config._allow_backtracking and \ |
323 |
+ pkg in self._dynamic_config._runtime_pkg_mask: |
324 |
+ if debug: |
325 |
+ writemsg_level( |
326 |
+ "!!! backtracking loop detected: %s %s\n" % \ |
327 |
+ (pkg, |
328 |
+ self._dynamic_config._runtime_pkg_mask[pkg]), |
329 |
+ level=logging.DEBUG, noiselevel=-1) |
330 |
+ |
331 |
+ parent_atoms = self._dynamic_config._parent_atoms.get(pkg) |
332 |
+ if parent_atoms is None: |
333 |
+ parent_atoms = set() |
334 |
+ self._dynamic_config._parent_atoms[pkg] = parent_atoms |
335 |
+ |
336 |
+ all_match = True |
337 |
+ for parent_atom in slot_parent_atoms: |
338 |
+ if parent_atom in parent_atoms: |
339 |
continue |
340 |
- all_parent_atoms.update(parent_atoms) |
341 |
+ # Use package set for matching since it will match via |
342 |
+ # PROVIDE when necessary, while match_from_list does not. |
343 |
+ parent, atom = parent_atom |
344 |
+ atom_set = InternalPackageSet( |
345 |
+ initial_atoms=(atom,), allow_repo=True) |
346 |
+ if atom_set.findAtomForPackage(pkg, |
347 |
+ modified_use=self._pkg_use_enabled(pkg)): |
348 |
+ parent_atoms.add(parent_atom) |
349 |
+ else: |
350 |
+ all_match = False |
351 |
+ conflict_atoms.setdefault(parent_atom, set()).add(pkg) |
352 |
|
353 |
- for pkg in slot_nodes: |
354 |
- parent_atoms = self._dynamic_config._parent_atoms.get(pkg) |
355 |
- if parent_atoms is None: |
356 |
- parent_atoms = set() |
357 |
- self._dynamic_config._parent_atoms[pkg] = parent_atoms |
358 |
- for parent_atom in all_parent_atoms: |
359 |
- if parent_atom in parent_atoms: |
360 |
+ if not all_match: |
361 |
+ conflict_pkgs.append(pkg) |
362 |
+ |
363 |
+ if conflict_pkgs and \ |
364 |
+ self._dynamic_config._allow_backtracking and \ |
365 |
+ not self._accept_blocker_conflicts(): |
366 |
+ remaining = [] |
367 |
+ for pkg in conflict_pkgs: |
368 |
+ if self._slot_conflict_backtrack_abi(pkg, |
369 |
+ slot_nodes, conflict_atoms): |
370 |
+ backtrack_infos = self._dynamic_config._backtrack_infos |
371 |
+ config = backtrack_infos.setdefault("config", {}) |
372 |
+ config.setdefault("slot_conflict_abi", set()).add(pkg) |
373 |
+ else: |
374 |
+ remaining.append(pkg) |
375 |
+ if remaining: |
376 |
+ self._slot_confict_backtrack(root, slot_atom, |
377 |
+ slot_parent_atoms, remaining) |
378 |
+ |
379 |
+ def _slot_confict_backtrack(self, root, slot_atom, |
380 |
+ all_parents, conflict_pkgs): |
381 |
+ |
382 |
+ debug = "--debug" in self._frozen_config.myopts |
383 |
+ existing_node = self._dynamic_config._slot_pkg_map[root][slot_atom] |
384 |
+ backtrack_data = [] |
385 |
+ # The ordering of backtrack_data can make |
386 |
+ # a difference here, because both mask actions may lead |
387 |
+ # to valid, but different, solutions and the one with |
388 |
+ # 'existing_node' masked is usually the better one. Because |
389 |
+ # of that, we choose an order such that |
390 |
+ # the backtracker will first explore the choice with |
391 |
+ # existing_node masked. The backtracker reverses the |
392 |
+ # order, so the order it uses is the reverse of the |
393 |
+ # order shown here. See bug #339606. |
394 |
+ if existing_node in conflict_pkgs and \ |
395 |
+ existing_node is not conflict_pkgs[-1]: |
396 |
+ conflict_pkgs.remove(existing_node) |
397 |
+ conflict_pkgs.append(existing_node) |
398 |
+ for to_be_masked in conflict_pkgs: |
399 |
+ # For missed update messages, find out which |
400 |
+ # atoms matched to_be_selected that did not |
401 |
+ # match to_be_masked. |
402 |
+ parent_atoms = \ |
403 |
+ self._dynamic_config._parent_atoms.get(to_be_masked, set()) |
404 |
+ conflict_atoms = set(parent_atom for parent_atom in all_parents \ |
405 |
+ if parent_atom not in parent_atoms) |
406 |
+ backtrack_data.append((to_be_masked, conflict_atoms)) |
407 |
+ |
408 |
+ if len(backtrack_data) > 1: |
409 |
+ # NOTE: Generally, we prefer to mask the higher |
410 |
+ # version since this solves common cases in which a |
411 |
+ # lower version is needed so that all dependencies |
412 |
+ # will be satisfied (bug #337178). However, if |
413 |
+ # existing_node happens to be installed then we |
414 |
+ # mask that since this is a common case that is |
415 |
+ # triggered when --update is not enabled. |
416 |
+ if existing_node.installed: |
417 |
+ pass |
418 |
+ elif any(pkg > existing_node for pkg in conflict_pkgs): |
419 |
+ backtrack_data.reverse() |
420 |
+ |
421 |
+ to_be_masked = backtrack_data[-1][0] |
422 |
+ |
423 |
+ self._dynamic_config._backtrack_infos.setdefault( |
424 |
+ "slot conflict", []).append(backtrack_data) |
425 |
+ self._dynamic_config._need_restart = True |
426 |
+ if debug: |
427 |
+ msg = [] |
428 |
+ msg.append("") |
429 |
+ msg.append("") |
430 |
+ msg.append("backtracking due to slot conflict:") |
431 |
+ msg.append(" first package: %s" % existing_node) |
432 |
+ msg.append(" package to mask: %s" % to_be_masked) |
433 |
+ msg.append(" slot: %s" % slot_atom) |
434 |
+ msg.append(" parents: %s" % ", ".join( \ |
435 |
+ "(%s, '%s')" % (ppkg, atom) for ppkg, atom in all_parents)) |
436 |
+ msg.append("") |
437 |
+ writemsg_level("".join("%s\n" % l for l in msg), |
438 |
+ noiselevel=-1, level=logging.DEBUG) |
439 |
+ |
440 |
+ def _slot_conflict_backtrack_abi(self, pkg, slot_nodes, conflict_atoms): |
441 |
+ """ |
442 |
+ If one or more conflict atoms have a slot/sub-slot dep that can be resolved |
443 |
+ by rebuilding the parent package, then schedule the rebuild via |
444 |
+ backtracking, and return True. Otherwise, return False. |
445 |
+ """ |
446 |
+ |
447 |
+ found_update = False |
448 |
+ for parent_atom, conflict_pkgs in conflict_atoms.items(): |
449 |
+ parent, atom = parent_atom |
450 |
+ if atom.slot_operator != "=" or not parent.built: |
451 |
+ continue |
452 |
+ |
453 |
+ if pkg not in conflict_pkgs: |
454 |
+ continue |
455 |
+ |
456 |
+ for other_pkg in slot_nodes: |
457 |
+ if other_pkg in conflict_pkgs: |
458 |
+ continue |
459 |
+ |
460 |
+ dep = Dependency(atom=atom, child=other_pkg, |
461 |
+ parent=parent, root=pkg.root) |
462 |
+ |
463 |
+ if self._slot_operator_update_probe(dep): |
464 |
+ self._slot_operator_update_backtrack(dep) |
465 |
+ found_update = True |
466 |
+ |
467 |
+ return found_update |
468 |
+ |
469 |
+ def _slot_operator_update_backtrack(self, dep, new_child_slot=None): |
470 |
+ if new_child_slot is None: |
471 |
+ child = dep.child |
472 |
+ else: |
473 |
+ child = new_child_slot |
474 |
+ if "--debug" in self._frozen_config.myopts: |
475 |
+ msg = [] |
476 |
+ msg.append("") |
477 |
+ msg.append("") |
478 |
+ msg.append("backtracking due to missed slot abi update:") |
479 |
+ msg.append(" child package: %s" % child) |
480 |
+ if new_child_slot is not None: |
481 |
+ msg.append(" new child slot package: %s" % new_child_slot) |
482 |
+ msg.append(" parent package: %s" % dep.parent) |
483 |
+ msg.append(" atom: %s" % dep.atom) |
484 |
+ msg.append("") |
485 |
+ writemsg_level("\n".join(msg), |
486 |
+ noiselevel=-1, level=logging.DEBUG) |
487 |
+ backtrack_infos = self._dynamic_config._backtrack_infos |
488 |
+ config = backtrack_infos.setdefault("config", {}) |
489 |
+ |
490 |
+ # mask unwanted binary packages if necessary |
491 |
+ abi_masks = {} |
492 |
+ if new_child_slot is None: |
493 |
+ if not child.installed: |
494 |
+ abi_masks.setdefault(child, {})["slot_operator_mask_built"] = None |
495 |
+ if not dep.parent.installed: |
496 |
+ abi_masks.setdefault(dep.parent, {})["slot_operator_mask_built"] = None |
497 |
+ if abi_masks: |
498 |
+ config.setdefault("slot_operator_mask_built", {}).update(abi_masks) |
499 |
+ |
500 |
+ # trigger replacement of installed packages if necessary |
501 |
+ abi_reinstalls = set() |
502 |
+ if dep.parent.installed: |
503 |
+ abi_reinstalls.add((dep.parent.root, dep.parent.slot_atom)) |
504 |
+ if new_child_slot is None and child.installed: |
505 |
+ abi_reinstalls.add((child.root, child.slot_atom)) |
506 |
+ if abi_reinstalls: |
507 |
+ config.setdefault("slot_operator_replace_installed", |
508 |
+ set()).update(abi_reinstalls) |
509 |
+ |
510 |
+ self._dynamic_config._need_restart = True |
511 |
+ |
512 |
+ def _slot_operator_update_probe(self, dep, new_child_slot=False): |
513 |
+ """ |
514 |
+ slot/sub-slot := operators tend to prevent updates from getting pulled in, |
515 |
+ since installed packages pull in packages with the slot/sub-slot that they |
516 |
+ were built against. Detect this case so that we can schedule rebuilds |
517 |
+ and reinstalls when appropriate. |
518 |
+ NOTE: This function only searches for updates that involve upgrades |
519 |
+ to higher versions, since the logic required to detect when a |
520 |
+ downgrade would be desirable is not implemented. |
521 |
+ """ |
522 |
+ |
523 |
+ if dep.child.installed and \ |
524 |
+ self._frozen_config.excluded_pkgs.findAtomForPackage(dep.child, |
525 |
+ modified_use=self._pkg_use_enabled(dep.child)): |
526 |
+ return None |
527 |
+ |
528 |
+ if dep.parent.installed and \ |
529 |
+ self._frozen_config.excluded_pkgs.findAtomForPackage(dep.parent, |
530 |
+ modified_use=self._pkg_use_enabled(dep.parent)): |
531 |
+ return None |
532 |
+ |
533 |
+ debug = "--debug" in self._frozen_config.myopts |
534 |
+ want_downgrade = None |
535 |
+ |
536 |
+ for replacement_parent in self._iter_similar_available(dep.parent, |
537 |
+ dep.parent.slot_atom): |
538 |
+ |
539 |
+ for atom in replacement_parent.validated_atoms: |
540 |
+ if not atom.slot_operator == "=" or \ |
541 |
+ atom.blocker or \ |
542 |
+ atom.cp != dep.atom.cp: |
543 |
+ continue |
544 |
+ |
545 |
+ # Discard USE deps, we're only searching for an approximate |
546 |
+ # pattern, and dealing with USE states is too complex for |
547 |
+ # this purpose. |
548 |
+ atom = atom.without_use |
549 |
+ |
550 |
+ if replacement_parent.built and \ |
551 |
+ portage.dep._match_slot(atom, dep.child): |
552 |
+ # Our selected replacement_parent appears to be built |
553 |
+ # for the existing child selection. So, discard this |
554 |
+ # parent and search for another. |
555 |
+ break |
556 |
+ |
557 |
+ for pkg in self._iter_similar_available( |
558 |
+ dep.child, atom): |
559 |
+ if pkg.slot == dep.child.slot and \ |
560 |
+ pkg.sub_slot == dep.child.sub_slot: |
561 |
+ # If slot/sub-slot is identical, then there's |
562 |
+ # no point in updating. |
563 |
continue |
564 |
- # Use package set for matching since it will match via |
565 |
- # PROVIDE when necessary, while match_from_list does not. |
566 |
- parent, atom = parent_atom |
567 |
- atom_set = InternalPackageSet( |
568 |
- initial_atoms=(atom,), allow_repo=True) |
569 |
- if atom_set.findAtomForPackage(pkg, modified_use=self._pkg_use_enabled(pkg)): |
570 |
- parent_atoms.add(parent_atom) |
571 |
+ if new_child_slot: |
572 |
+ if pkg.slot == dep.child.slot: |
573 |
+ continue |
574 |
+ if pkg < dep.child: |
575 |
+ # the new slot only matters if the |
576 |
+ # package version is higher |
577 |
+ continue |
578 |
else: |
579 |
- self._dynamic_config._slot_conflict_parent_atoms.add(parent_atom) |
580 |
+ if pkg.slot != dep.child.slot: |
581 |
+ continue |
582 |
+ if pkg < dep.child: |
583 |
+ if want_downgrade is None: |
584 |
+ want_downgrade = self._downgrade_probe(dep.child) |
585 |
+ # be careful not to trigger a rebuild when |
586 |
+ # the only version available with a |
587 |
+ # different slot_operator is an older version |
588 |
+ if not want_downgrade: |
589 |
+ continue |
590 |
+ |
591 |
+ if debug: |
592 |
+ msg = [] |
593 |
+ msg.append("") |
594 |
+ msg.append("") |
595 |
+ msg.append("slot_operator_update_probe:") |
596 |
+ msg.append(" existing child package: %s" % dep.child) |
597 |
+ msg.append(" existing parent package: %s" % dep.parent) |
598 |
+ msg.append(" new child package: %s" % pkg) |
599 |
+ msg.append(" new parent package: %s" % replacement_parent) |
600 |
+ msg.append("") |
601 |
+ writemsg_level("\n".join(msg), |
602 |
+ noiselevel=-1, level=logging.DEBUG) |
603 |
+ |
604 |
+ return pkg |
605 |
+ |
606 |
+ if debug: |
607 |
+ msg = [] |
608 |
+ msg.append("") |
609 |
+ msg.append("") |
610 |
+ msg.append("slot_operator_update_probe:") |
611 |
+ msg.append(" existing child package: %s" % dep.child) |
612 |
+ msg.append(" existing parent package: %s" % dep.parent) |
613 |
+ msg.append(" new child package: %s" % None) |
614 |
+ msg.append(" new parent package: %s" % None) |
615 |
+ msg.append("") |
616 |
+ writemsg_level("\n".join(msg), |
617 |
+ noiselevel=-1, level=logging.DEBUG) |
618 |
+ |
619 |
+ return None |
620 |
+ |
621 |
+ def _downgrade_probe(self, pkg): |
622 |
+ """ |
623 |
+ Detect cases where a downgrade of the given package is considered |
624 |
+ desirable due to the current version being masked or unavailable. |
625 |
+ """ |
626 |
+ available_pkg = None |
627 |
+ for available_pkg in self._iter_similar_available(pkg, |
628 |
+ pkg.slot_atom): |
629 |
+ if available_pkg >= pkg: |
630 |
+ # There's an available package of the same or higher |
631 |
+ # version, so downgrade seems undesirable. |
632 |
+ return False |
633 |
+ |
634 |
+ return available_pkg is not None |
635 |
+ |
636 |
+ def _iter_similar_available(self, graph_pkg, atom): |
637 |
+ """ |
638 |
+ Given a package that's in the graph, do a rough check to |
639 |
+ see if a similar package is available to install. The given |
640 |
+ graph_pkg itself may be yielded only if it's not installed. |
641 |
+ """ |
642 |
+ |
643 |
+ usepkgonly = "--usepkgonly" in self._frozen_config.myopts |
644 |
+ useoldpkg_atoms = self._frozen_config.useoldpkg_atoms |
645 |
+ use_ebuild_visibility = self._frozen_config.myopts.get( |
646 |
+ '--use-ebuild-visibility', 'n') != 'n' |
647 |
+ |
648 |
+ for pkg in self._iter_match_pkgs_any( |
649 |
+ graph_pkg.root_config, atom): |
650 |
+ if pkg.cp != graph_pkg.cp: |
651 |
+ # discard old-style virtual match |
652 |
+ continue |
653 |
+ if pkg.installed: |
654 |
+ continue |
655 |
+ if pkg in self._dynamic_config._runtime_pkg_mask: |
656 |
+ continue |
657 |
+ if self._frozen_config.excluded_pkgs.findAtomForPackage(pkg, |
658 |
+ modified_use=self._pkg_use_enabled(pkg)): |
659 |
+ continue |
660 |
+ if not self._pkg_visibility_check(pkg): |
661 |
+ continue |
662 |
+ if pkg.built: |
663 |
+ if self._equiv_binary_installed(pkg): |
664 |
+ continue |
665 |
+ if not (not use_ebuild_visibility and |
666 |
+ (usepkgonly or useoldpkg_atoms.findAtomForPackage( |
667 |
+ pkg, modified_use=self._pkg_use_enabled(pkg)))) and \ |
668 |
+ not self._equiv_ebuild_visible(pkg): |
669 |
+ continue |
670 |
+ yield pkg |
671 |
+ |
672 |
+ def _slot_operator_trigger_reinstalls(self): |
673 |
+ """ |
674 |
+ Search for packages with slot-operator deps on older slots, and schedule |
675 |
+ rebuilds if they can link to a newer slot that's in the graph. |
676 |
+ """ |
677 |
+ |
678 |
+ rebuild_if_new_slot = self._dynamic_config.myparams.get( |
679 |
+ "rebuild_if_new_slot", "y") == "y" |
680 |
+ |
681 |
+ for slot_key, slot_info in self._dynamic_config._slot_operator_deps.items(): |
682 |
+ |
683 |
+ for dep in slot_info: |
684 |
+ if not (dep.child.built and dep.parent and |
685 |
+ isinstance(dep.parent, Package) and dep.parent.built): |
686 |
+ continue |
687 |
+ |
688 |
+ # Check for slot update first, since we don't want to |
689 |
+ # trigger reinstall of the child package when a newer |
690 |
+ # slot will be used instead. |
691 |
+ if rebuild_if_new_slot: |
692 |
+ new_child = self._slot_operator_update_probe(dep, |
693 |
+ new_child_slot=True) |
694 |
+ if new_child: |
695 |
+ self._slot_operator_update_backtrack(dep, |
696 |
+ new_child_slot=new_child) |
697 |
+ break |
698 |
+ |
699 |
+ if dep.want_update: |
700 |
+ if self._slot_operator_update_probe(dep): |
701 |
+ self._slot_operator_update_backtrack(dep) |
702 |
+ break |
703 |
|
704 |
def _reinstall_for_flags(self, pkg, forced_flags, |
705 |
orig_use, orig_iuse, cur_use, cur_iuse): |
706 |
@@ -845,18 +1225,22 @@ class depgraph(object): |
707 |
in ("y", "auto")) |
708 |
newuse = "--newuse" in self._frozen_config.myopts |
709 |
changed_use = "changed-use" == self._frozen_config.myopts.get("--reinstall") |
710 |
+ feature_flags = _get_feature_flags( |
711 |
+ _get_eapi_attrs(pkg.metadata["EAPI"])) |
712 |
|
713 |
if newuse or (binpkg_respect_use and not changed_use): |
714 |
flags = set(orig_iuse.symmetric_difference( |
715 |
cur_iuse).difference(forced_flags)) |
716 |
flags.update(orig_iuse.intersection(orig_use).symmetric_difference( |
717 |
cur_iuse.intersection(cur_use))) |
718 |
+ flags.difference_update(feature_flags) |
719 |
if flags: |
720 |
return flags |
721 |
|
722 |
elif changed_use or binpkg_respect_use: |
723 |
- flags = orig_iuse.intersection(orig_use).symmetric_difference( |
724 |
- cur_iuse.intersection(cur_use)) |
725 |
+ flags = set(orig_iuse.intersection(orig_use).symmetric_difference( |
726 |
+ cur_iuse.intersection(cur_use))) |
727 |
+ flags.difference_update(feature_flags) |
728 |
if flags: |
729 |
return flags |
730 |
return None |
731 |
@@ -1100,12 +1484,13 @@ class depgraph(object): |
732 |
# package selection, since we want to prompt the user |
733 |
# for USE adjustment rather than have REQUIRED_USE |
734 |
# affect package selection and || dep choices. |
735 |
- """if not pkg.built and pkg.metadata.get("REQUIRED_USE") and \ |
736 |
+ if not pkg.built and pkg.metadata.get("REQUIRED_USE") and \ |
737 |
eapi_has_required_use(pkg.metadata["EAPI"]): |
738 |
required_use_is_sat = check_required_use( |
739 |
pkg.metadata["REQUIRED_USE"], |
740 |
self._pkg_use_enabled(pkg), |
741 |
- pkg.iuse.is_valid_flag) |
742 |
+ pkg.iuse.is_valid_flag, |
743 |
+ eapi=pkg.metadata["EAPI"]) |
744 |
if not required_use_is_sat: |
745 |
if dep.atom is not None and dep.parent is not None: |
746 |
self._add_parent_atom(pkg, (dep.parent, dep.atom)) |
747 |
@@ -1119,9 +1504,10 @@ class depgraph(object): |
748 |
if atom is None: |
749 |
atom = Atom("=" + pkg.cpv) |
750 |
self._dynamic_config._unsatisfied_deps_for_display.append( |
751 |
- ((pkg.root, atom), {"myparent":dep.parent})) |
752 |
+ ((pkg.root, atom), |
753 |
+ {"myparent" : dep.parent, "show_req_use" : pkg})) |
754 |
self._dynamic_config._skip_restart = True |
755 |
- return 0""" |
756 |
+ return 0 |
757 |
|
758 |
if not pkg.onlydeps: |
759 |
|
760 |
@@ -1150,121 +1536,7 @@ class depgraph(object): |
761 |
(dep.parent, dep.atom)) |
762 |
return 1 |
763 |
else: |
764 |
- # A slot conflict has occurred. |
765 |
- # The existing node should not already be in |
766 |
- # runtime_pkg_mask, since that would trigger an |
767 |
- # infinite backtracking loop. |
768 |
- if self._dynamic_config._allow_backtracking and \ |
769 |
- existing_node in \ |
770 |
- self._dynamic_config._runtime_pkg_mask: |
771 |
- if "--debug" in self._frozen_config.myopts: |
772 |
- writemsg( |
773 |
- "!!! backtracking loop detected: %s %s\n" % \ |
774 |
- (existing_node, |
775 |
- self._dynamic_config._runtime_pkg_mask[ |
776 |
- existing_node]), noiselevel=-1) |
777 |
- elif self._dynamic_config._allow_backtracking and \ |
778 |
- not self._accept_blocker_conflicts() and \ |
779 |
- not self.need_restart(): |
780 |
- |
781 |
- self._add_slot_conflict(pkg) |
782 |
- if dep.atom is not None and dep.parent is not None: |
783 |
- self._add_parent_atom(pkg, (dep.parent, dep.atom)) |
784 |
- |
785 |
- if arg_atoms: |
786 |
- for parent_atom in arg_atoms: |
787 |
- parent, atom = parent_atom |
788 |
- self._add_parent_atom(pkg, parent_atom) |
789 |
- self._process_slot_conflicts() |
790 |
- |
791 |
- backtrack_data = [] |
792 |
- fallback_data = [] |
793 |
- all_parents = set() |
794 |
- # The ordering of backtrack_data can make |
795 |
- # a difference here, because both mask actions may lead |
796 |
- # to valid, but different, solutions and the one with |
797 |
- # 'existing_node' masked is usually the better one. Because |
798 |
- # of that, we choose an order such that |
799 |
- # the backtracker will first explore the choice with |
800 |
- # existing_node masked. The backtracker reverses the |
801 |
- # order, so the order it uses is the reverse of the |
802 |
- # order shown here. See bug #339606. |
803 |
- for to_be_selected, to_be_masked in (existing_node, pkg), (pkg, existing_node): |
804 |
- # For missed update messages, find out which |
805 |
- # atoms matched to_be_selected that did not |
806 |
- # match to_be_masked. |
807 |
- parent_atoms = \ |
808 |
- self._dynamic_config._parent_atoms.get(to_be_selected, set()) |
809 |
- if parent_atoms: |
810 |
- conflict_atoms = self._dynamic_config._slot_conflict_parent_atoms.intersection(parent_atoms) |
811 |
- if conflict_atoms: |
812 |
- parent_atoms = conflict_atoms |
813 |
- |
814 |
- all_parents.update(parent_atoms) |
815 |
- |
816 |
- all_match = True |
817 |
- for parent, atom in parent_atoms: |
818 |
- i = InternalPackageSet(initial_atoms=(atom,), |
819 |
- allow_repo=True) |
820 |
- if not i.findAtomForPackage(to_be_masked): |
821 |
- all_match = False |
822 |
- break |
823 |
- |
824 |
- fallback_data.append((to_be_masked, parent_atoms)) |
825 |
- |
826 |
- if all_match: |
827 |
- # 'to_be_masked' does not violate any parent atom, which means |
828 |
- # there is no point in masking it. |
829 |
- pass |
830 |
- else: |
831 |
- backtrack_data.append((to_be_masked, parent_atoms)) |
832 |
- |
833 |
- if not backtrack_data: |
834 |
- # This shouldn't happen, but fall back to the old |
835 |
- # behavior if this gets triggered somehow. |
836 |
- backtrack_data = fallback_data |
837 |
- |
838 |
- if len(backtrack_data) > 1: |
839 |
- # NOTE: Generally, we prefer to mask the higher |
840 |
- # version since this solves common cases in which a |
841 |
- # lower version is needed so that all dependencies |
842 |
- # will be satisfied (bug #337178). However, if |
843 |
- # existing_node happens to be installed then we |
844 |
- # mask that since this is a common case that is |
845 |
- # triggered when --update is not enabled. |
846 |
- if existing_node.installed: |
847 |
- pass |
848 |
- elif pkg > existing_node: |
849 |
- backtrack_data.reverse() |
850 |
- |
851 |
- to_be_masked = backtrack_data[-1][0] |
852 |
- |
853 |
- self._dynamic_config._backtrack_infos["slot conflict"] = backtrack_data |
854 |
- self._dynamic_config._need_restart = True |
855 |
- if "--debug" in self._frozen_config.myopts: |
856 |
- msg = [] |
857 |
- msg.append("") |
858 |
- msg.append("") |
859 |
- msg.append("backtracking due to slot conflict:") |
860 |
- if backtrack_data is fallback_data: |
861 |
- msg.append("!!! backtrack_data fallback") |
862 |
- msg.append(" first package: %s" % existing_node) |
863 |
- msg.append(" second package: %s" % pkg) |
864 |
- msg.append(" package to mask: %s" % to_be_masked) |
865 |
- msg.append(" slot: %s" % pkg.slot_atom) |
866 |
- msg.append(" parents: %s" % ", ".join( \ |
867 |
- "(%s, '%s')" % (ppkg, atom) for ppkg, atom in all_parents)) |
868 |
- msg.append("") |
869 |
- writemsg_level("".join("%s\n" % l for l in msg), |
870 |
- noiselevel=-1, level=logging.DEBUG) |
871 |
- return 0 |
872 |
- |
873 |
- # A slot collision has occurred. Sometimes this coincides |
874 |
- # with unresolvable blockers, so the slot collision will be |
875 |
- # shown later if there are no unresolvable blockers. |
876 |
self._add_slot_conflict(pkg) |
877 |
- slot_collision = True |
878 |
- |
879 |
if debug: |
880 |
writemsg_level( |
881 |
"%s%s %s\n" % ("Slot Conflict:".ljust(15), |
882 |
@@ -1273,6 +1545,8 @@ class depgraph(object): |
883 |
modified_use=self._pkg_use_enabled(existing_node))), |
884 |
level=logging.DEBUG, noiselevel=-1) |
885 |
|
886 |
+ slot_collision = True |
887 |
+ |
888 |
if slot_collision: |
889 |
# Now add this node to the graph so that self.display() |
890 |
# can show use flags and --tree portage.output. This node is |
891 |
@@ -1329,10 +1603,27 @@ class depgraph(object): |
892 |
# Installing package A, we need to make sure package A's deps are met. |
893 |
# emerge --deep <pkgspec>; we need to recursively check dependencies of pkgspec |
894 |
# If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies. |
895 |
- if arg_atoms: |
896 |
- depth = 0 |
897 |
+ if arg_atoms and depth > 0: |
898 |
+ for parent, atom in arg_atoms: |
899 |
+ if parent.reset_depth: |
900 |
+ depth = 0 |
901 |
+ break |
902 |
+ |
903 |
+ if previously_added and pkg.depth is not None: |
904 |
+ depth = min(pkg.depth, depth) |
905 |
pkg.depth = depth |
906 |
deep = self._dynamic_config.myparams.get("deep", 0) |
907 |
+ update = "--update" in self._frozen_config.myopts |
908 |
+ |
909 |
+ dep.want_update = (not self._dynamic_config._complete_mode and |
910 |
+ (arg_atoms or update) and |
911 |
+ not (deep is not True and depth > deep)) |
912 |
+ |
913 |
+ dep.child = pkg |
914 |
+ if (not pkg.onlydeps and pkg.built and |
915 |
+ dep.atom and dep.atom.slot_operator_built): |
916 |
+ self._add_slot_operator_dep(dep) |
917 |
+ |
918 |
recurse = deep is True or depth + 1 <= deep |
919 |
dep_stack = self._dynamic_config._dep_stack |
920 |
if "recurse" not in self._dynamic_config.myparams: |
921 |
@@ -1364,6 +1655,14 @@ class depgraph(object): |
922 |
self._dynamic_config._parent_atoms[pkg] = parent_atoms |
923 |
parent_atoms.add(parent_atom) |
924 |
|
925 |
+ def _add_slot_operator_dep(self, dep): |
926 |
+ slot_key = (dep.root, dep.child.slot_atom) |
927 |
+ slot_info = self._dynamic_config._slot_operator_deps.get(slot_key) |
928 |
+ if slot_info is None: |
929 |
+ slot_info = [] |
930 |
+ self._dynamic_config._slot_operator_deps[slot_key] = slot_info |
931 |
+ slot_info.append(dep) |
932 |
+ |
933 |
def _add_slot_conflict(self, pkg): |
934 |
self._dynamic_config._slot_collision_nodes.add(pkg) |
935 |
slot_key = (pkg.slot_atom, pkg.root) |
936 |
@@ -1379,10 +1678,10 @@ class depgraph(object): |
937 |
myroot = pkg.root |
938 |
metadata = pkg.metadata |
939 |
removal_action = "remove" in self._dynamic_config.myparams |
940 |
+ eapi_attrs = _get_eapi_attrs(pkg.metadata["EAPI"]) |
941 |
|
942 |
edepend={} |
943 |
- depkeys = ["DEPEND","RDEPEND","PDEPEND"] |
944 |
- for k in depkeys: |
945 |
+ for k in Package._dep_keys: |
946 |
edepend[k] = metadata[k] |
947 |
|
948 |
if not pkg.built and \ |
949 |
@@ -1409,31 +1708,44 @@ class depgraph(object): |
950 |
# Removal actions never traverse ignored buildtime |
951 |
# dependencies, so it's safe to discard them early. |
952 |
edepend["DEPEND"] = "" |
953 |
+ edepend["HDEPEND"] = "" |
954 |
ignore_build_time_deps = True |
955 |
|
956 |
+ ignore_depend_deps = ignore_build_time_deps |
957 |
+ ignore_hdepend_deps = ignore_build_time_deps |
958 |
+ |
959 |
if removal_action: |
960 |
depend_root = myroot |
961 |
else: |
962 |
- depend_root = self._frozen_config._running_root.root |
963 |
- root_deps = self._frozen_config.myopts.get("--root-deps") |
964 |
- if root_deps is not None: |
965 |
- if root_deps is True: |
966 |
- depend_root = myroot |
967 |
- elif root_deps == "rdeps": |
968 |
- ignore_build_time_deps = True |
969 |
+ if eapi_attrs.hdepend: |
970 |
+ depend_root = myroot |
971 |
+ else: |
972 |
+ depend_root = self._frozen_config._running_root.root |
973 |
+ root_deps = self._frozen_config.myopts.get("--root-deps") |
974 |
+ if root_deps is not None: |
975 |
+ if root_deps is True: |
976 |
+ depend_root = myroot |
977 |
+ elif root_deps == "rdeps": |
978 |
+ ignore_depend_deps = True |
979 |
|
980 |
# If rebuild mode is not enabled, it's safe to discard ignored |
981 |
# build-time dependencies. If you want these deps to be traversed |
982 |
# in "complete" mode then you need to specify --with-bdeps=y. |
983 |
- if ignore_build_time_deps and \ |
984 |
- not self._rebuild.rebuild: |
985 |
- edepend["DEPEND"] = "" |
986 |
+ if not self._rebuild.rebuild: |
987 |
+ if ignore_depend_deps: |
988 |
+ edepend["DEPEND"] = "" |
989 |
+ if ignore_hdepend_deps: |
990 |
+ edepend["HDEPEND"] = "" |
991 |
|
992 |
deps = ( |
993 |
(depend_root, edepend["DEPEND"], |
994 |
self._priority(buildtime=True, |
995 |
- optional=(pkg.built or ignore_build_time_deps), |
996 |
- ignored=ignore_build_time_deps)), |
997 |
+ optional=(pkg.built or ignore_depend_deps), |
998 |
+ ignored=ignore_depend_deps)), |
999 |
+ (self._frozen_config._running_root.root, edepend["HDEPEND"], |
1000 |
+ self._priority(buildtime=True, |
1001 |
+ optional=(pkg.built or ignore_hdepend_deps), |
1002 |
+ ignored=ignore_hdepend_deps)), |
1003 |
(myroot, edepend["RDEPEND"], |
1004 |
self._priority(runtime=True)), |
1005 |
(myroot, edepend["PDEPEND"], |
1006 |
@@ -1455,7 +1767,10 @@ class depgraph(object): |
1007 |
|
1008 |
try: |
1009 |
dep_string = portage.dep.use_reduce(dep_string, |
1010 |
- uselist=self._pkg_use_enabled(pkg), is_valid_flag=pkg.iuse.is_valid_flag) |
1011 |
+ uselist=self._pkg_use_enabled(pkg), |
1012 |
+ is_valid_flag=pkg.iuse.is_valid_flag, |
1013 |
+ opconvert=True, token_class=Atom, |
1014 |
+ eapi=pkg.metadata['EAPI']) |
1015 |
except portage.exception.InvalidDependString as e: |
1016 |
if not pkg.installed: |
1017 |
# should have been masked before it was selected |
1018 |
@@ -1467,7 +1782,9 @@ class depgraph(object): |
1019 |
# practical to ignore this issue for installed packages. |
1020 |
try: |
1021 |
dep_string = portage.dep.use_reduce(dep_string, |
1022 |
- uselist=self._pkg_use_enabled(pkg)) |
1023 |
+ uselist=self._pkg_use_enabled(pkg), |
1024 |
+ opconvert=True, token_class=Atom, |
1025 |
+ eapi=pkg.metadata['EAPI']) |
1026 |
except portage.exception.InvalidDependString as e: |
1027 |
self._dynamic_config._masked_installed.add(pkg) |
1028 |
del e |
1029 |
@@ -1488,9 +1805,6 @@ class depgraph(object): |
1030 |
if not dep_string: |
1031 |
continue |
1032 |
|
1033 |
- dep_string = portage.dep.paren_enclose(dep_string, |
1034 |
- unevaluated_atom=True) |
1035 |
- |
1036 |
if not self._add_pkg_dep_string( |
1037 |
pkg, dep_root, dep_priority, dep_string, |
1038 |
allow_unsatisfied): |
1039 |
@@ -1524,7 +1838,9 @@ class depgraph(object): |
1040 |
if debug: |
1041 |
writemsg_level("\nParent: %s\n" % (pkg,), |
1042 |
noiselevel=-1, level=logging.DEBUG) |
1043 |
- writemsg_level("Depstring: %s\n" % (dep_string,), |
1044 |
+ dep_repr = portage.dep.paren_enclose(dep_string, |
1045 |
+ unevaluated_atom=True, opconvert=True) |
1046 |
+ writemsg_level("Depstring: %s\n" % (dep_repr,), |
1047 |
noiselevel=-1, level=logging.DEBUG) |
1048 |
writemsg_level("Priority: %s\n" % (dep_priority,), |
1049 |
noiselevel=-1, level=logging.DEBUG) |
1050 |
@@ -1602,16 +1918,11 @@ class depgraph(object): |
1051 |
self._dynamic_config._slot_pkg_map[dep.child.root].get( |
1052 |
dep.child.slot_atom) is None: |
1053 |
myarg = None |
1054 |
- if dep.root == self._frozen_config.target_root: |
1055 |
- try: |
1056 |
- myarg = next(self._iter_atoms_for_pkg(dep.child)) |
1057 |
- except StopIteration: |
1058 |
- pass |
1059 |
- except InvalidDependString: |
1060 |
- if not dep.child.installed: |
1061 |
- # This shouldn't happen since the package |
1062 |
- # should have been masked. |
1063 |
- raise |
1064 |
+ try: |
1065 |
+ myarg = next(self._iter_atoms_for_pkg(dep.child), None) |
1066 |
+ except InvalidDependString: |
1067 |
+ if not dep.child.installed: |
1068 |
+ raise |
1069 |
|
1070 |
if myarg is None: |
1071 |
# Existing child selection may not be valid unless |
1072 |
@@ -1717,14 +2028,11 @@ class depgraph(object): |
1073 |
self._dynamic_config._slot_pkg_map[dep.child.root].get( |
1074 |
dep.child.slot_atom) is None: |
1075 |
myarg = None |
1076 |
- if dep.root == self._frozen_config.target_root: |
1077 |
- try: |
1078 |
- myarg = next(self._iter_atoms_for_pkg(dep.child)) |
1079 |
- except StopIteration: |
1080 |
- pass |
1081 |
- except InvalidDependString: |
1082 |
- if not dep.child.installed: |
1083 |
- raise |
1084 |
+ try: |
1085 |
+ myarg = next(self._iter_atoms_for_pkg(dep.child), None) |
1086 |
+ except InvalidDependString: |
1087 |
+ if not dep.child.installed: |
1088 |
+ raise |
1089 |
|
1090 |
if myarg is None: |
1091 |
ignored = True |
1092 |
@@ -1818,9 +2126,14 @@ class depgraph(object): |
1093 |
# Yield ~, =*, < and <= atoms first, since those are more likely to |
1094 |
# cause slot conflicts, and we want those atoms to be displayed |
1095 |
# in the resulting slot conflict message (see bug #291142). |
1096 |
+ # Give similar treatment to slot/sub-slot atoms. |
1097 |
conflict_atoms = [] |
1098 |
normal_atoms = [] |
1099 |
+ abi_atoms = [] |
1100 |
for atom in cp_atoms: |
1101 |
+ if atom.slot_operator_built: |
1102 |
+ abi_atoms.append(atom) |
1103 |
+ continue |
1104 |
conflict = False |
1105 |
for child_pkg in atom_pkg_graph.child_nodes(atom): |
1106 |
existing_node, matches = \ |
1107 |
@@ -1833,7 +2146,7 @@ class depgraph(object): |
1108 |
else: |
1109 |
normal_atoms.append(atom) |
1110 |
|
1111 |
- for atom in chain(conflict_atoms, normal_atoms): |
1112 |
+ for atom in chain(abi_atoms, conflict_atoms, normal_atoms): |
1113 |
child_pkgs = atom_pkg_graph.child_nodes(atom) |
1114 |
# if more than one child, yield highest version |
1115 |
if len(child_pkgs) > 1: |
1116 |
@@ -1846,34 +2159,22 @@ class depgraph(object): |
1117 |
Yields non-disjunctive deps. Raises InvalidDependString when |
1118 |
necessary. |
1119 |
""" |
1120 |
- i = 0 |
1121 |
- while i < len(dep_struct): |
1122 |
- x = dep_struct[i] |
1123 |
+ for x in dep_struct: |
1124 |
if isinstance(x, list): |
1125 |
- for y in self._queue_disjunctive_deps( |
1126 |
- pkg, dep_root, dep_priority, x): |
1127 |
- yield y |
1128 |
- elif x == "||": |
1129 |
- self._queue_disjunction(pkg, dep_root, dep_priority, |
1130 |
- [ x, dep_struct[ i + 1 ] ] ) |
1131 |
- i += 1 |
1132 |
+ if x and x[0] == "||": |
1133 |
+ self._queue_disjunction(pkg, dep_root, dep_priority, [x]) |
1134 |
+ else: |
1135 |
+ for y in self._queue_disjunctive_deps( |
1136 |
+ pkg, dep_root, dep_priority, x): |
1137 |
+ yield y |
1138 |
else: |
1139 |
- try: |
1140 |
- x = portage.dep.Atom(x, eapi=pkg.metadata["EAPI"]) |
1141 |
- except portage.exception.InvalidAtom: |
1142 |
- if not pkg.installed: |
1143 |
- raise portage.exception.InvalidDependString( |
1144 |
- "invalid atom: '%s'" % x) |
1145 |
+ # Note: Eventually this will check for PROPERTIES=virtual |
1146 |
+ # or whatever other metadata gets implemented for this |
1147 |
+ # purpose. |
1148 |
+ if x.cp.startswith('virtual/'): |
1149 |
+ self._queue_disjunction(pkg, dep_root, dep_priority, [x]) |
1150 |
else: |
1151 |
- # Note: Eventually this will check for PROPERTIES=virtual |
1152 |
- # or whatever other metadata gets implemented for this |
1153 |
- # purpose. |
1154 |
- if x.cp.startswith('virtual/'): |
1155 |
- self._queue_disjunction( pkg, dep_root, |
1156 |
- dep_priority, [ str(x) ] ) |
1157 |
- else: |
1158 |
- yield str(x) |
1159 |
- i += 1 |
1160 |
+ yield x |
1161 |
|
1162 |
def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct): |
1163 |
self._dynamic_config._dep_disjunctive_stack.append( |
1164 |
@@ -1886,10 +2187,8 @@ class depgraph(object): |
1165 |
""" |
1166 |
pkg, dep_root, dep_priority, dep_struct = \ |
1167 |
self._dynamic_config._dep_disjunctive_stack.pop() |
1168 |
- dep_string = portage.dep.paren_enclose(dep_struct, |
1169 |
- unevaluated_atom=True) |
1170 |
if not self._add_pkg_dep_string( |
1171 |
- pkg, dep_root, dep_priority, dep_string, allow_unsatisfied): |
1172 |
+ pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied): |
1173 |
return 0 |
1174 |
return 1 |
1175 |
|
1176 |
@@ -1999,8 +2298,18 @@ class depgraph(object): |
1177 |
writemsg("!!! Please ensure the tbz2 exists as specified.\n\n", noiselevel=-1) |
1178 |
return 0, myfavorites |
1179 |
mytbz2=portage.xpak.tbz2(x) |
1180 |
- mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0] |
1181 |
- if os.path.realpath(x) != \ |
1182 |
+ mykey = None |
1183 |
+ cat = mytbz2.getfile("CATEGORY") |
1184 |
+ if cat is not None: |
1185 |
+ cat = _unicode_decode(cat.strip(), |
1186 |
+ encoding=_encodings['repo.content']) |
1187 |
+ mykey = cat + "/" + os.path.basename(x)[:-5] |
1188 |
+ |
1189 |
+ if mykey is None: |
1190 |
+ writemsg(colorize("BAD", "\n*** Package is missing CATEGORY metadata: %s.\n\n" % x), noiselevel=-1) |
1191 |
+ self._dynamic_config._skip_restart = True |
1192 |
+ return 0, myfavorites |
1193 |
+ elif os.path.realpath(x) != \ |
1194 |
os.path.realpath(bindb.bintree.getname(mykey)): |
1195 |
writemsg(colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n\n"), noiselevel=-1) |
1196 |
self._dynamic_config._skip_restart = True |
1197 |
@@ -2193,13 +2502,8 @@ class depgraph(object): |
1198 |
return 0, [] |
1199 |
|
1200 |
for cpv in owners: |
1201 |
- slot = vardb.aux_get(cpv, ["SLOT"])[0] |
1202 |
- if not slot: |
1203 |
- # portage now masks packages with missing slot, but it's |
1204 |
- # possible that one was installed by an older version |
1205 |
- atom = Atom(portage.cpv_getkey(cpv)) |
1206 |
- else: |
1207 |
- atom = Atom("%s:%s" % (portage.cpv_getkey(cpv), slot)) |
1208 |
+ pkg = vardb._pkg_str(cpv, None) |
1209 |
+ atom = Atom("%s:%s" % (pkg.cp, pkg.slot)) |
1210 |
args.append(AtomArg(arg=atom, atom=atom, |
1211 |
root_config=root_config)) |
1212 |
|
1213 |
@@ -2247,6 +2551,7 @@ class depgraph(object): |
1214 |
args = revised_greedy_args |
1215 |
del revised_greedy_args |
1216 |
|
1217 |
+ args.extend(self._gen_reinstall_sets()) |
1218 |
self._set_args(args) |
1219 |
|
1220 |
myfavorites = set(myfavorites) |
1221 |
@@ -2254,7 +2559,8 @@ class depgraph(object): |
1222 |
if isinstance(arg, (AtomArg, PackageArg)): |
1223 |
myfavorites.add(arg.atom) |
1224 |
elif isinstance(arg, SetArg): |
1225 |
- myfavorites.add(arg.arg) |
1226 |
+ if not arg.internal: |
1227 |
+ myfavorites.add(arg.arg) |
1228 |
myfavorites = list(myfavorites) |
1229 |
|
1230 |
if debug: |
1231 |
@@ -2264,7 +2570,33 @@ class depgraph(object): |
1232 |
self._dynamic_config._initial_arg_list = args[:] |
1233 |
|
1234 |
return self._resolve(myfavorites) |
1235 |
- |
1236 |
+ |
1237 |
+ def _gen_reinstall_sets(self): |
1238 |
+ |
1239 |
+ atom_list = [] |
1240 |
+ for root, atom in self._rebuild.rebuild_list: |
1241 |
+ atom_list.append((root, '__auto_rebuild__', atom)) |
1242 |
+ for root, atom in self._rebuild.reinstall_list: |
1243 |
+ atom_list.append((root, '__auto_reinstall__', atom)) |
1244 |
+ for root, atom in self._dynamic_config._slot_operator_replace_installed: |
1245 |
+ atom_list.append((root, '__auto_slot_operator_replace_installed__', atom)) |
1246 |
+ |
1247 |
+ set_dict = {} |
1248 |
+ for root, set_name, atom in atom_list: |
1249 |
+ set_dict.setdefault((root, set_name), []).append(atom) |
1250 |
+ |
1251 |
+ for (root, set_name), atoms in set_dict.items(): |
1252 |
+ yield SetArg(arg=(SETPREFIX + set_name), |
1253 |
+ # Set reset_depth=False here, since we don't want these |
1254 |
+ # special sets to interact with depth calculations (see |
1255 |
+ # the emerge --deep=DEPTH option), though we want them |
1256 |
+ # to behave like normal arguments in most other respects. |
1257 |
+ pset=InternalPackageSet(initial_atoms=atoms), |
1258 |
+ force_reinstall=True, |
1259 |
+ internal=True, |
1260 |
+ reset_depth=False, |
1261 |
+ root_config=self._frozen_config.roots[root]) |
1262 |
+ |
1263 |
def _resolve(self, myfavorites): |
1264 |
"""Given self._dynamic_config._initial_arg_list, pull in the root nodes, |
1265 |
call self._creategraph to process theier deps and return |
1266 |
@@ -2276,10 +2608,7 @@ class depgraph(object): |
1267 |
pprovideddict = pkgsettings.pprovideddict |
1268 |
virtuals = pkgsettings.getvirtuals() |
1269 |
args = self._dynamic_config._initial_arg_list[:] |
1270 |
- for root, atom in chain(self._rebuild.rebuild_list, |
1271 |
- self._rebuild.reinstall_list): |
1272 |
- args.append(AtomArg(arg=atom, atom=atom, |
1273 |
- root_config=self._frozen_config.roots[root])) |
1274 |
+ |
1275 |
for arg in self._expand_set_args(args, add_to_digraph=True): |
1276 |
for atom in arg.pset.getAtoms(): |
1277 |
self._spinner_update() |
1278 |
@@ -2389,22 +2718,12 @@ class depgraph(object): |
1279 |
except self._unknown_internal_error: |
1280 |
return False, myfavorites |
1281 |
|
1282 |
- digraph_set = frozenset(self._dynamic_config.digraph) |
1283 |
- |
1284 |
- if digraph_set.intersection( |
1285 |
- self._dynamic_config._needed_unstable_keywords) or \ |
1286 |
- digraph_set.intersection( |
1287 |
- self._dynamic_config._needed_p_mask_changes) or \ |
1288 |
- digraph_set.intersection( |
1289 |
- self._dynamic_config._needed_use_config_changes) or \ |
1290 |
- digraph_set.intersection( |
1291 |
- self._dynamic_config._needed_license_changes) : |
1292 |
- #We failed if the user needs to change the configuration |
1293 |
- self._dynamic_config._success_without_autounmask = True |
1294 |
+ if (self._dynamic_config._slot_collision_info and |
1295 |
+ not self._accept_blocker_conflicts()) or \ |
1296 |
+ (self._dynamic_config._allow_backtracking and |
1297 |
+ "slot conflict" in self._dynamic_config._backtrack_infos): |
1298 |
return False, myfavorites |
1299 |
|
1300 |
- digraph_set = None |
1301 |
- |
1302 |
if self._rebuild.trigger_rebuilds(): |
1303 |
backtrack_infos = self._dynamic_config._backtrack_infos |
1304 |
config = backtrack_infos.setdefault("config", {}) |
1305 |
@@ -2413,6 +2732,32 @@ class depgraph(object): |
1306 |
self._dynamic_config._need_restart = True |
1307 |
return False, myfavorites |
1308 |
|
1309 |
+ if "config" in self._dynamic_config._backtrack_infos and \ |
1310 |
+ ("slot_operator_mask_built" in self._dynamic_config._backtrack_infos["config"] or |
1311 |
+ "slot_operator_replace_installed" in self._dynamic_config._backtrack_infos["config"]) and \ |
1312 |
+ self.need_restart(): |
1313 |
+ return False, myfavorites |
1314 |
+ |
1315 |
+ # Any failures except those due to autounmask *alone* should return |
1316 |
+ # before this point, since the success_without_autounmask flag that's |
1317 |
+ # set below is reserved for cases where there are *zero* other |
1318 |
+ # problems. For reference, see backtrack_depgraph, where it skips the |
1319 |
+ # get_best_run() call when success_without_autounmask is True. |
1320 |
+ |
1321 |
+ digraph_nodes = self._dynamic_config.digraph.nodes |
1322 |
+ |
1323 |
+ if any(x in digraph_nodes for x in |
1324 |
+ self._dynamic_config._needed_unstable_keywords) or \ |
1325 |
+ any(x in digraph_nodes for x in |
1326 |
+ self._dynamic_config._needed_p_mask_changes) or \ |
1327 |
+ any(x in digraph_nodes for x in |
1328 |
+ self._dynamic_config._needed_use_config_changes) or \ |
1329 |
+ any(x in digraph_nodes for x in |
1330 |
+ self._dynamic_config._needed_license_changes) : |
1331 |
+ #We failed if the user needs to change the configuration |
1332 |
+ self._dynamic_config._success_without_autounmask = True |
1333 |
+ return False, myfavorites |
1334 |
+ |
1335 |
# We're true here unless we are missing binaries. |
1336 |
return (True, myfavorites) |
1337 |
|
1338 |
@@ -2485,14 +2830,15 @@ class depgraph(object): |
1339 |
slots = set() |
1340 |
for cpv in vardb.match(atom): |
1341 |
# don't mix new virtuals with old virtuals |
1342 |
- if portage.cpv_getkey(cpv) == highest_pkg.cp: |
1343 |
- slots.add(vardb.aux_get(cpv, ["SLOT"])[0]) |
1344 |
+ pkg = vardb._pkg_str(cpv, None) |
1345 |
+ if pkg.cp == highest_pkg.cp: |
1346 |
+ slots.add(pkg.slot) |
1347 |
|
1348 |
- slots.add(highest_pkg.metadata["SLOT"]) |
1349 |
+ slots.add(highest_pkg.slot) |
1350 |
if len(slots) == 1: |
1351 |
return [] |
1352 |
greedy_pkgs = [] |
1353 |
- slots.remove(highest_pkg.metadata["SLOT"]) |
1354 |
+ slots.remove(highest_pkg.slot) |
1355 |
while slots: |
1356 |
slot = slots.pop() |
1357 |
slot_atom = portage.dep.Atom("%s:%s" % (highest_pkg.cp, slot)) |
1358 |
@@ -2506,7 +2852,7 @@ class depgraph(object): |
1359 |
return [pkg.slot_atom for pkg in greedy_pkgs] |
1360 |
|
1361 |
blockers = {} |
1362 |
- blocker_dep_keys = ["DEPEND", "PDEPEND", "RDEPEND"] |
1363 |
+ blocker_dep_keys = Package._dep_keys |
1364 |
for pkg in greedy_pkgs + [highest_pkg]: |
1365 |
dep_str = " ".join(pkg.metadata[k] for k in blocker_dep_keys) |
1366 |
try: |
1367 |
@@ -2567,6 +2913,22 @@ class depgraph(object): |
1368 |
"""This will raise InvalidDependString if necessary. If trees is |
1369 |
None then self._dynamic_config._filtered_trees is used.""" |
1370 |
|
1371 |
+ if not isinstance(depstring, list): |
1372 |
+ eapi = None |
1373 |
+ is_valid_flag = None |
1374 |
+ if parent is not None: |
1375 |
+ eapi = parent.metadata['EAPI'] |
1376 |
+ if not parent.installed: |
1377 |
+ is_valid_flag = parent.iuse.is_valid_flag |
1378 |
+ depstring = portage.dep.use_reduce(depstring, |
1379 |
+ uselist=myuse, opconvert=True, token_class=Atom, |
1380 |
+ is_valid_flag=is_valid_flag, eapi=eapi) |
1381 |
+ |
1382 |
+ if (self._dynamic_config.myparams.get( |
1383 |
+ "ignore_built_slot_operator_deps", "n") == "y" and |
1384 |
+ parent and parent.built): |
1385 |
+ ignore_built_slot_operator_deps(depstring) |
1386 |
+ |
1387 |
pkgsettings = self._frozen_config.pkgsettings[root] |
1388 |
if trees is None: |
1389 |
trees = self._dynamic_config._filtered_trees |
1390 |
@@ -2751,7 +3113,7 @@ class depgraph(object): |
1391 |
|
1392 |
if target_atom is not None and isinstance(node, Package): |
1393 |
affecting_use = set() |
1394 |
- for dep_str in "DEPEND", "RDEPEND", "PDEPEND": |
1395 |
+ for dep_str in Package._dep_keys: |
1396 |
try: |
1397 |
affecting_use.update(extract_affecting_use( |
1398 |
node.metadata[dep_str], target_atom, |
1399 |
@@ -2832,13 +3194,13 @@ class depgraph(object): |
1400 |
if priorities is None: |
1401 |
# This edge comes from _parent_atoms and was not added to |
1402 |
# the graph, and _parent_atoms does not contain priorities. |
1403 |
- dep_strings.add(node.metadata["DEPEND"]) |
1404 |
- dep_strings.add(node.metadata["RDEPEND"]) |
1405 |
- dep_strings.add(node.metadata["PDEPEND"]) |
1406 |
+ for k in Package._dep_keys: |
1407 |
+ dep_strings.add(node.metadata[k]) |
1408 |
else: |
1409 |
for priority in priorities: |
1410 |
if priority.buildtime: |
1411 |
- dep_strings.add(node.metadata["DEPEND"]) |
1412 |
+ for k in Package._buildtime_keys: |
1413 |
+ dep_strings.add(node.metadata[k]) |
1414 |
if priority.runtime: |
1415 |
dep_strings.add(node.metadata["RDEPEND"]) |
1416 |
if priority.runtime_post: |
1417 |
@@ -2930,7 +3292,7 @@ class depgraph(object): |
1418 |
|
1419 |
|
1420 |
def _show_unsatisfied_dep(self, root, atom, myparent=None, arg=None, |
1421 |
- check_backtrack=False, check_autounmask_breakage=False): |
1422 |
+ check_backtrack=False, check_autounmask_breakage=False, show_req_use=None): |
1423 |
""" |
1424 |
When check_backtrack=True, no output is produced and |
1425 |
the method either returns or raises _backtrack_mask if |
1426 |
@@ -3037,7 +3399,8 @@ class depgraph(object): |
1427 |
if not check_required_use( |
1428 |
pkg.metadata["REQUIRED_USE"], |
1429 |
self._pkg_use_enabled(pkg), |
1430 |
- pkg.iuse.is_valid_flag): |
1431 |
+ pkg.iuse.is_valid_flag, |
1432 |
+ eapi=pkg.metadata["EAPI"]): |
1433 |
required_use_unsatisfied.append(pkg) |
1434 |
continue |
1435 |
root_slot = (pkg.root, pkg.slot_atom) |
1436 |
@@ -3082,7 +3445,7 @@ class depgraph(object): |
1437 |
|
1438 |
untouchable_flags = \ |
1439 |
frozenset(chain(pkg.use.mask, pkg.use.force)) |
1440 |
- if untouchable_flags.intersection( |
1441 |
+ if any(x in untouchable_flags for x in |
1442 |
chain(need_enable, need_disable)): |
1443 |
continue |
1444 |
|
1445 |
@@ -3096,8 +3459,10 @@ class depgraph(object): |
1446 |
new_use.add(flag) |
1447 |
for flag in need_disable: |
1448 |
new_use.discard(flag) |
1449 |
- if check_required_use(required_use, old_use, pkg.iuse.is_valid_flag) and \ |
1450 |
- not check_required_use(required_use, new_use, pkg.iuse.is_valid_flag): |
1451 |
+ if check_required_use(required_use, old_use, |
1452 |
+ pkg.iuse.is_valid_flag, eapi=pkg.metadata["EAPI"]) \ |
1453 |
+ and not check_required_use(required_use, new_use, |
1454 |
+ pkg.iuse.is_valid_flag, eapi=pkg.metadata["EAPI"]): |
1455 |
required_use_warning = ", this change violates use flag constraints " + \ |
1456 |
"defined by %s: '%s'" % (pkg.cpv, human_readable_required_use(required_use)) |
1457 |
|
1458 |
@@ -3132,7 +3497,7 @@ class depgraph(object): |
1459 |
|
1460 |
untouchable_flags = \ |
1461 |
frozenset(chain(myparent.use.mask, myparent.use.force)) |
1462 |
- if untouchable_flags.intersection(involved_flags): |
1463 |
+ if any(x in untouchable_flags for x in involved_flags): |
1464 |
continue |
1465 |
|
1466 |
required_use = myparent.metadata.get("REQUIRED_USE") |
1467 |
@@ -3145,8 +3510,12 @@ class depgraph(object): |
1468 |
new_use.discard(flag) |
1469 |
else: |
1470 |
new_use.add(flag) |
1471 |
- if check_required_use(required_use, old_use, myparent.iuse.is_valid_flag) and \ |
1472 |
- not check_required_use(required_use, new_use, myparent.iuse.is_valid_flag): |
1473 |
+ if check_required_use(required_use, old_use, |
1474 |
+ myparent.iuse.is_valid_flag, |
1475 |
+ eapi=myparent.metadata["EAPI"]) and \ |
1476 |
+ not check_required_use(required_use, new_use, |
1477 |
+ myparent.iuse.is_valid_flag, |
1478 |
+ eapi=myparent.metadata["EAPI"]): |
1479 |
required_use_warning = ", this change violates use flag constraints " + \ |
1480 |
"defined by %s: '%s'" % (myparent.cpv, \ |
1481 |
human_readable_required_use(required_use)) |
1482 |
@@ -3211,62 +3580,72 @@ class depgraph(object): |
1483 |
|
1484 |
mask_docs = False |
1485 |
|
1486 |
- if required_use_unsatisfied: |
1487 |
+ if show_req_use is None and required_use_unsatisfied: |
1488 |
# We have an unmasked package that only requires USE adjustment |
1489 |
# in order to satisfy REQUIRED_USE, and nothing more. We assume |
1490 |
# that the user wants the latest version, so only the first |
1491 |
# instance is displayed. |
1492 |
- pkg = required_use_unsatisfied[0] |
1493 |
+ show_req_use = required_use_unsatisfied[0] |
1494 |
+ self._dynamic_config._needed_required_use_config_changesuse_config_changes[pkg] = (new_use, new_changes) |
1495 |
+ backtrack_infos = self._dynamic_config._backtrack_infos |
1496 |
+ backtrack_infos.setdefault("config", {}) |
1497 |
+ backtrack_infos["config"].setdefault("needed_required_use_config_changes", []) |
1498 |
+ backtrack_infos["config"]["needed_required_use_config_changes"].append((pkg, (new_use, new_changes))) |
1499 |
+ |
1500 |
+ if show_req_use is not None: |
1501 |
+ |
1502 |
+ pkg = show_req_use |
1503 |
output_cpv = pkg.cpv + _repo_separator + pkg.repo |
1504 |
- writemsg_stdout("\n!!! " + \ |
1505 |
+ writemsg("\n!!! " + \ |
1506 |
colorize("BAD", "The ebuild selected to satisfy ") + \ |
1507 |
colorize("INFORM", xinfo) + \ |
1508 |
colorize("BAD", " has unmet requirements.") + "\n", |
1509 |
noiselevel=-1) |
1510 |
use_display = pkg_use_display(pkg, self._frozen_config.myopts) |
1511 |
- writemsg_stdout("- %s %s\n" % (output_cpv, use_display), |
1512 |
+ writemsg("- %s %s\n" % (output_cpv, use_display), |
1513 |
noiselevel=-1) |
1514 |
- writemsg_stdout("\n The following REQUIRED_USE flag constraints " + \ |
1515 |
+ writemsg("\n The following REQUIRED_USE flag constraints " + \ |
1516 |
"are unsatisfied:\n", noiselevel=-1) |
1517 |
reduced_noise = check_required_use( |
1518 |
pkg.metadata["REQUIRED_USE"], |
1519 |
self._pkg_use_enabled(pkg), |
1520 |
- pkg.iuse.is_valid_flag).tounicode() |
1521 |
- writemsg_stdout(" %s\n" % \ |
1522 |
+ pkg.iuse.is_valid_flag, |
1523 |
+ eapi=pkg.metadata["EAPI"]).tounicode() |
1524 |
+ writemsg(" %s\n" % \ |
1525 |
human_readable_required_use(reduced_noise), |
1526 |
noiselevel=-1) |
1527 |
normalized_required_use = \ |
1528 |
" ".join(pkg.metadata["REQUIRED_USE"].split()) |
1529 |
if reduced_noise != normalized_required_use: |
1530 |
- writemsg_stdout("\n The above constraints " + \ |
1531 |
+ writemsg("\n The above constraints " + \ |
1532 |
"are a subset of the following complete expression:\n", |
1533 |
noiselevel=-1) |
1534 |
- writemsg_stdout(" %s\n" % \ |
1535 |
+ writemsg(" %s\n" % \ |
1536 |
human_readable_required_use(normalized_required_use), |
1537 |
noiselevel=-1) |
1538 |
- writemsg_stdout("\n", noiselevel=-1) |
1539 |
+ writemsg("\n", noiselevel=-1) |
1540 |
|
1541 |
elif show_missing_use: |
1542 |
- writemsg_stdout("\nemerge: there are no ebuilds built with USE flags to satisfy "+green(xinfo)+".\n", noiselevel=-1) |
1543 |
- writemsg_stdout("!!! One of the following packages is required to complete your request:\n", noiselevel=-1) |
1544 |
+ writemsg("\nemerge: there are no ebuilds built with USE flags to satisfy "+green(xinfo)+".\n", noiselevel=-1) |
1545 |
+ writemsg("!!! One of the following packages is required to complete your request:\n", noiselevel=-1) |
1546 |
for pkg, mreasons in show_missing_use: |
1547 |
- writemsg_stdout("- "+pkg.cpv+_repo_separator+pkg.repo+" ("+", ".join(mreasons)+")\n", noiselevel=-1) |
1548 |
+ writemsg("- "+pkg.cpv+_repo_separator+pkg.repo+" ("+", ".join(mreasons)+")\n", noiselevel=-1) |
1549 |
|
1550 |
elif masked_packages: |
1551 |
- writemsg_stdout("\n!!! " + \ |
1552 |
+ writemsg("\n!!! " + \ |
1553 |
colorize("BAD", "All ebuilds that could satisfy ") + \ |
1554 |
colorize("INFORM", xinfo) + \ |
1555 |
colorize("BAD", " have been masked.") + "\n", noiselevel=-1) |
1556 |
- writemsg_stdout("!!! One of the following masked packages is required to complete your request:\n", noiselevel=-1) |
1557 |
+ writemsg("!!! One of the following masked packages is required to complete your request:\n", noiselevel=-1) |
1558 |
have_eapi_mask = show_masked_packages(masked_packages) |
1559 |
if have_eapi_mask: |
1560 |
- writemsg_stdout("\n", noiselevel=-1) |
1561 |
+ writemsg("\n", noiselevel=-1) |
1562 |
msg = ("The current version of portage supports " + \ |
1563 |
"EAPI '%s'. You must upgrade to a newer version" + \ |
1564 |
" of portage before EAPI masked packages can" + \ |
1565 |
" be installed.") % portage.const.EAPI |
1566 |
- writemsg_stdout("\n".join(textwrap.wrap(msg, 75)), noiselevel=-1) |
1567 |
- writemsg_stdout("\n", noiselevel=-1) |
1568 |
+ writemsg("\n".join(textwrap.wrap(msg, 75)), noiselevel=-1) |
1569 |
+ writemsg("\n", noiselevel=-1) |
1570 |
mask_docs = True |
1571 |
else: |
1572 |
cp_exists = False |
1573 |
@@ -3276,7 +3655,7 @@ class depgraph(object): |
1574 |
cp_exists = True |
1575 |
break |
1576 |
|
1577 |
- writemsg_stdout("\nemerge: there are no ebuilds to satisfy "+green(xinfo)+".\n", noiselevel=-1) |
1578 |
+ writemsg("\nemerge: there are no ebuilds to satisfy "+green(xinfo)+".\n", noiselevel=-1) |
1579 |
if isinstance(myparent, AtomArg) and \ |
1580 |
not cp_exists and \ |
1581 |
self._frozen_config.myopts.get( |
1582 |
@@ -3286,7 +3665,7 @@ class depgraph(object): |
1583 |
if cat == "null": |
1584 |
cat = None |
1585 |
|
1586 |
- writemsg_stdout("\nemerge: searching for similar names..." |
1587 |
+ writemsg("\nemerge: searching for similar names..." |
1588 |
, noiselevel=-1) |
1589 |
|
1590 |
all_cp = set() |
1591 |
@@ -3334,16 +3713,16 @@ class depgraph(object): |
1592 |
matches = matches_orig_case |
1593 |
|
1594 |
if len(matches) == 1: |
1595 |
- writemsg_stdout("\nemerge: Maybe you meant " + matches[0] + "?\n" |
1596 |
+ writemsg("\nemerge: Maybe you meant " + matches[0] + "?\n" |
1597 |
, noiselevel=-1) |
1598 |
elif len(matches) > 1: |
1599 |
- writemsg_stdout( |
1600 |
+ writemsg( |
1601 |
"\nemerge: Maybe you meant any of these: %s?\n" % \ |
1602 |
(", ".join(matches),), noiselevel=-1) |
1603 |
else: |
1604 |
# Generally, this would only happen if |
1605 |
# all dbapis are empty. |
1606 |
- writemsg_stdout(" nothing similar found.\n" |
1607 |
+ writemsg(" nothing similar found.\n" |
1608 |
, noiselevel=-1) |
1609 |
msg = [] |
1610 |
if not isinstance(myparent, AtomArg): |
1611 |
@@ -3356,12 +3735,12 @@ class depgraph(object): |
1612 |
(node)), node_type)) |
1613 |
|
1614 |
if msg: |
1615 |
- writemsg_stdout("\n".join(msg), noiselevel=-1) |
1616 |
- writemsg_stdout("\n", noiselevel=-1) |
1617 |
+ writemsg("\n".join(msg), noiselevel=-1) |
1618 |
+ writemsg("\n", noiselevel=-1) |
1619 |
|
1620 |
if mask_docs: |
1621 |
show_mask_docs() |
1622 |
- writemsg_stdout("\n", noiselevel=-1) |
1623 |
+ writemsg("\n", noiselevel=-1) |
1624 |
|
1625 |
def _iter_match_pkgs_any(self, root_config, atom, onlydeps=False): |
1626 |
for db, pkg_type, built, installed, db_keys in \ |
1627 |
@@ -3379,60 +3758,12 @@ class depgraph(object): |
1628 |
""" |
1629 |
|
1630 |
db = root_config.trees[self.pkg_tree_map[pkg_type]].dbapi |
1631 |
- |
1632 |
- if hasattr(db, "xmatch"): |
1633 |
- # For portdbapi we match only against the cpv, in order |
1634 |
- # to bypass unnecessary cache access for things like IUSE |
1635 |
- # and SLOT. Later, we cache the metadata in a Package |
1636 |
- # instance, and use that for further matching. This |
1637 |
- # optimization is especially relevant since |
1638 |
- # pordbapi.aux_get() does not cache calls that have |
1639 |
- # myrepo or mytree arguments. |
1640 |
- cpv_list = db.xmatch("match-all-cpv-only", atom) |
1641 |
- else: |
1642 |
- cpv_list = db.match(atom) |
1643 |
- |
1644 |
- # USE=multislot can make an installed package appear as if |
1645 |
- # it doesn't satisfy a slot dependency. Rebuilding the ebuild |
1646 |
- # won't do any good as long as USE=multislot is enabled since |
1647 |
- # the newly built package still won't have the expected slot. |
1648 |
- # Therefore, assume that such SLOT dependencies are already |
1649 |
- # satisfied rather than forcing a rebuild. |
1650 |
+ atom_exp = dep_expand(atom, mydb=db, settings=root_config.settings) |
1651 |
+ cp_list = db.cp_list(atom_exp.cp) |
1652 |
+ matched_something = False |
1653 |
installed = pkg_type == 'installed' |
1654 |
- if installed and not cpv_list and atom.slot: |
1655 |
- |
1656 |
- if "remove" in self._dynamic_config.myparams: |
1657 |
- # We need to search the portdbapi, which is not in our |
1658 |
- # normal dbs list, in order to find the real SLOT. |
1659 |
- portdb = self._frozen_config.trees[root_config.root]["porttree"].dbapi |
1660 |
- db_keys = list(portdb._aux_cache_keys) |
1661 |
- dbs = [(portdb, "ebuild", False, False, db_keys)] |
1662 |
- else: |
1663 |
- dbs = self._dynamic_config._filtered_trees[root_config.root]["dbs"] |
1664 |
|
1665 |
- for cpv in db.match(atom.cp): |
1666 |
- slot_available = False |
1667 |
- for other_db, other_type, other_built, \ |
1668 |
- other_installed, other_keys in dbs: |
1669 |
- try: |
1670 |
- if atom.slot == \ |
1671 |
- other_db.aux_get(cpv, ["SLOT"])[0]: |
1672 |
- slot_available = True |
1673 |
- break |
1674 |
- except KeyError: |
1675 |
- pass |
1676 |
- if not slot_available: |
1677 |
- continue |
1678 |
- inst_pkg = self._pkg(cpv, "installed", |
1679 |
- root_config, installed=installed, myrepo = atom.repo) |
1680 |
- # Remove the slot from the atom and verify that |
1681 |
- # the package matches the resulting atom. |
1682 |
- if portage.match_from_list( |
1683 |
- atom.without_slot, [inst_pkg]): |
1684 |
- yield inst_pkg |
1685 |
- return |
1686 |
- |
1687 |
- if cpv_list: |
1688 |
+ if cp_list: |
1689 |
atom_set = InternalPackageSet(initial_atoms=(atom,), |
1690 |
allow_repo=True) |
1691 |
if atom.repo is None and hasattr(db, "getRepositories"): |
1692 |
@@ -3441,8 +3772,13 @@ class depgraph(object): |
1693 |
repo_list = [atom.repo] |
1694 |
|
1695 |
# descending order |
1696 |
- cpv_list.reverse() |
1697 |
- for cpv in cpv_list: |
1698 |
+ cp_list.reverse() |
1699 |
+ for cpv in cp_list: |
1700 |
+ # Call match_from_list on one cpv at a time, in order |
1701 |
+ # to avoid unnecessary match_from_list comparisons on |
1702 |
+ # versions that are never yielded from this method. |
1703 |
+ if not match_from_list(atom_exp, [cpv]): |
1704 |
+ continue |
1705 |
for repo in repo_list: |
1706 |
|
1707 |
try: |
1708 |
@@ -3459,26 +3795,65 @@ class depgraph(object): |
1709 |
# Make sure that cpv from the current repo satisfies the atom. |
1710 |
# This might not be the case if there are several repos with |
1711 |
# the same cpv, but different metadata keys, like SLOT. |
1712 |
- # Also, for portdbapi, parts of the match that require |
1713 |
- # metadata access are deferred until we have cached the |
1714 |
- # metadata in a Package instance. |
1715 |
+ # Also, parts of the match that require metadata access |
1716 |
+ # are deferred until we have cached the metadata in a |
1717 |
+ # Package instance. |
1718 |
if not atom_set.findAtomForPackage(pkg, |
1719 |
modified_use=self._pkg_use_enabled(pkg)): |
1720 |
continue |
1721 |
+ matched_something = True |
1722 |
yield pkg |
1723 |
|
1724 |
+ # USE=multislot can make an installed package appear as if |
1725 |
+ # it doesn't satisfy a slot dependency. Rebuilding the ebuild |
1726 |
+ # won't do any good as long as USE=multislot is enabled since |
1727 |
+ # the newly built package still won't have the expected slot. |
1728 |
+ # Therefore, assume that such SLOT dependencies are already |
1729 |
+ # satisfied rather than forcing a rebuild. |
1730 |
+ if not matched_something and installed and atom.slot is not None: |
1731 |
+ |
1732 |
+ if "remove" in self._dynamic_config.myparams: |
1733 |
+ # We need to search the portdbapi, which is not in our |
1734 |
+ # normal dbs list, in order to find the real SLOT. |
1735 |
+ portdb = self._frozen_config.trees[root_config.root]["porttree"].dbapi |
1736 |
+ db_keys = list(portdb._aux_cache_keys) |
1737 |
+ dbs = [(portdb, "ebuild", False, False, db_keys)] |
1738 |
+ else: |
1739 |
+ dbs = self._dynamic_config._filtered_trees[root_config.root]["dbs"] |
1740 |
+ |
1741 |
+ cp_list = db.cp_list(atom_exp.cp) |
1742 |
+ if cp_list: |
1743 |
+ atom_set = InternalPackageSet( |
1744 |
+ initial_atoms=(atom.without_slot,), allow_repo=True) |
1745 |
+ atom_exp_without_slot = atom_exp.without_slot |
1746 |
+ cp_list.reverse() |
1747 |
+ for cpv in cp_list: |
1748 |
+ if not match_from_list(atom_exp_without_slot, [cpv]): |
1749 |
+ continue |
1750 |
+ slot_available = False |
1751 |
+ for other_db, other_type, other_built, \ |
1752 |
+ other_installed, other_keys in dbs: |
1753 |
+ try: |
1754 |
+ if atom.slot == \ |
1755 |
+ other_db._pkg_str(_unicode(cpv), None).slot: |
1756 |
+ slot_available = True |
1757 |
+ break |
1758 |
+ except (KeyError, InvalidData): |
1759 |
+ pass |
1760 |
+ if not slot_available: |
1761 |
+ continue |
1762 |
+ inst_pkg = self._pkg(cpv, "installed", |
1763 |
+ root_config, installed=installed, myrepo=atom.repo) |
1764 |
+ # Remove the slot from the atom and verify that |
1765 |
+ # the package matches the resulting atom. |
1766 |
+ if atom_set.findAtomForPackage(inst_pkg): |
1767 |
+ yield inst_pkg |
1768 |
+ return |
1769 |
+ |
1770 |
def _select_pkg_highest_available(self, root, atom, onlydeps=False): |
1771 |
- cache_key = (root, atom, atom.unevaluated_atom, onlydeps) |
1772 |
+ cache_key = (root, atom, atom.unevaluated_atom, onlydeps, self._dynamic_config._autounmask) |
1773 |
ret = self._dynamic_config._highest_pkg_cache.get(cache_key) |
1774 |
if ret is not None: |
1775 |
- pkg, existing = ret |
1776 |
- if pkg and not existing: |
1777 |
- existing = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom) |
1778 |
- if existing and existing == pkg: |
1779 |
- # Update the cache to reflect that the |
1780 |
- # package has been added to the graph. |
1781 |
- ret = pkg, pkg |
1782 |
- self._dynamic_config._highest_pkg_cache[cache_key] = ret |
1783 |
return ret |
1784 |
ret = self._select_pkg_highest_available_imp(root, atom, onlydeps=onlydeps) |
1785 |
self._dynamic_config._highest_pkg_cache[cache_key] = ret |
1786 |
@@ -3495,21 +3870,55 @@ class depgraph(object): |
1787 |
True if the user has not explicitly requested for this package |
1788 |
to be replaced (typically via an atom on the command line). |
1789 |
""" |
1790 |
- if "selective" not in self._dynamic_config.myparams and \ |
1791 |
- pkg.root == self._frozen_config.target_root: |
1792 |
- if self._frozen_config.excluded_pkgs.findAtomForPackage(pkg, |
1793 |
- modified_use=self._pkg_use_enabled(pkg)): |
1794 |
- return True |
1795 |
- try: |
1796 |
- next(self._iter_atoms_for_pkg(pkg)) |
1797 |
- except StopIteration: |
1798 |
- pass |
1799 |
- except portage.exception.InvalidDependString: |
1800 |
- pass |
1801 |
- else: |
1802 |
+ if self._frozen_config.excluded_pkgs.findAtomForPackage(pkg, |
1803 |
+ modified_use=self._pkg_use_enabled(pkg)): |
1804 |
+ return True |
1805 |
+ |
1806 |
+ arg = False |
1807 |
+ try: |
1808 |
+ for arg, atom in self._iter_atoms_for_pkg(pkg): |
1809 |
+ if arg.force_reinstall: |
1810 |
+ return False |
1811 |
+ except InvalidDependString: |
1812 |
+ pass |
1813 |
+ |
1814 |
+ if "selective" in self._dynamic_config.myparams: |
1815 |
+ return True |
1816 |
+ |
1817 |
+ return not arg |
1818 |
+ |
1819 |
+ def _equiv_ebuild_visible(self, pkg, autounmask_level=None): |
1820 |
+ try: |
1821 |
+ pkg_eb = self._pkg( |
1822 |
+ pkg.cpv, "ebuild", pkg.root_config, myrepo=pkg.repo) |
1823 |
+ except portage.exception.PackageNotFound: |
1824 |
+ pkg_eb_visible = False |
1825 |
+ for pkg_eb in self._iter_match_pkgs(pkg.root_config, |
1826 |
+ "ebuild", Atom("=%s" % (pkg.cpv,))): |
1827 |
+ if self._pkg_visibility_check(pkg_eb, autounmask_level): |
1828 |
+ pkg_eb_visible = True |
1829 |
+ break |
1830 |
+ if not pkg_eb_visible: |
1831 |
return False |
1832 |
+ else: |
1833 |
+ if not self._pkg_visibility_check(pkg_eb, autounmask_level): |
1834 |
+ return False |
1835 |
+ |
1836 |
return True |
1837 |
|
1838 |
+ def _equiv_binary_installed(self, pkg): |
1839 |
+ build_time = pkg.metadata.get('BUILD_TIME') |
1840 |
+ if not build_time: |
1841 |
+ return False |
1842 |
+ |
1843 |
+ try: |
1844 |
+ inst_pkg = self._pkg(pkg.cpv, "installed", |
1845 |
+ pkg.root_config, installed=True) |
1846 |
+ except PackageNotFound: |
1847 |
+ return False |
1848 |
+ |
1849 |
+ return build_time == inst_pkg.metadata.get('BUILD_TIME') |
1850 |
+ |
1851 |
class _AutounmaskLevel(object): |
1852 |
__slots__ = ("allow_use_changes", "allow_unstable_keywords", "allow_license_changes", \ |
1853 |
"allow_missing_keywords", "allow_unmasks") |
1854 |
@@ -3525,7 +3934,8 @@ class depgraph(object): |
1855 |
""" |
1856 |
Iterate over the different allowed things to unmask. |
1857 |
|
1858 |
- 1. USE |
1859 |
+ 0. USE |
1860 |
+ 1. USE + license |
1861 |
2. USE + ~arch + license |
1862 |
3. USE + ~arch + license + missing keywords |
1863 |
4. USE + ~arch + license + masks |
1864 |
@@ -3544,8 +3954,12 @@ class depgraph(object): |
1865 |
autounmask_level = self._AutounmaskLevel() |
1866 |
|
1867 |
autounmask_level.allow_use_changes = True |
1868 |
+ yield autounmask_level |
1869 |
|
1870 |
- for only_use_changes in (True, False): |
1871 |
+ autounmask_level.allow_license_changes = True |
1872 |
+ yield autounmask_level |
1873 |
+ |
1874 |
+ for only_use_changes in (False,): |
1875 |
|
1876 |
autounmask_level.allow_unstable_keywords = (not only_use_changes) |
1877 |
autounmask_level.allow_license_changes = (not only_use_changes) |
1878 |
@@ -3573,7 +3987,7 @@ class depgraph(object): |
1879 |
pkg = None |
1880 |
|
1881 |
if self._dynamic_config._autounmask is True: |
1882 |
- pkg = None |
1883 |
+ reset_pkg(pkg) |
1884 |
|
1885 |
for autounmask_level in self._autounmask_levels(): |
1886 |
if pkg is not None: |
1887 |
@@ -3734,7 +4148,7 @@ class depgraph(object): |
1888 |
if pkg not in self._dynamic_config.digraph.nodes: |
1889 |
return False |
1890 |
|
1891 |
- for key in "DEPEND", "RDEPEND", "PDEPEND", "LICENSE": |
1892 |
+ for key in Package._dep_keys + ("LICENSE",): |
1893 |
dep = pkg.metadata[key] |
1894 |
old_val = set(portage.dep.use_reduce(dep, pkg.use.enabled, is_valid_flag=pkg.iuse.is_valid_flag, flat=True)) |
1895 |
new_val = set(portage.dep.use_reduce(dep, new_use, is_valid_flag=pkg.iuse.is_valid_flag, flat=True)) |
1896 |
@@ -3749,7 +4163,7 @@ class depgraph(object): |
1897 |
new_use, changes = self._dynamic_config._needed_use_config_changes.get(pkg) |
1898 |
for ppkg, atom in parent_atoms: |
1899 |
if not atom.use or \ |
1900 |
- not atom.use.required.intersection(changes): |
1901 |
+ not any(x in atom.use.required for x in changes): |
1902 |
continue |
1903 |
else: |
1904 |
return True |
1905 |
@@ -3759,12 +4173,14 @@ class depgraph(object): |
1906 |
if new_changes != old_changes: |
1907 |
#Don't do the change if it violates REQUIRED_USE. |
1908 |
required_use = pkg.metadata.get("REQUIRED_USE") |
1909 |
- if required_use and check_required_use(required_use, old_use, pkg.iuse.is_valid_flag) and \ |
1910 |
- not check_required_use(required_use, new_use, pkg.iuse.is_valid_flag): |
1911 |
+ if required_use and check_required_use(required_use, old_use, |
1912 |
+ pkg.iuse.is_valid_flag, eapi=pkg.metadata["EAPI"]) and \ |
1913 |
+ not check_required_use(required_use, new_use, |
1914 |
+ pkg.iuse.is_valid_flag, eapi=pkg.metadata["EAPI"]): |
1915 |
return old_use |
1916 |
|
1917 |
- if pkg.use.mask.intersection(new_changes) or \ |
1918 |
- pkg.use.force.intersection(new_changes): |
1919 |
+ if any(x in pkg.use.mask for x in new_changes) or \ |
1920 |
+ any(x in pkg.use.force for x in new_changes): |
1921 |
return old_use |
1922 |
|
1923 |
self._dynamic_config._needed_use_config_changes[pkg] = (new_use, new_changes) |
1924 |
@@ -3776,199 +4192,6 @@ class depgraph(object): |
1925 |
self._dynamic_config._need_restart = True |
1926 |
return new_use |
1927 |
|
1928 |
- def change_required_use(self, pkg): |
1929 |
- """ |
1930 |
- Checks if the use flags listed in 'use' satisfy all |
1931 |
- constraints specified in 'constraints'. |
1932 |
- |
1933 |
- @param required_use: REQUIRED_USE string |
1934 |
- @type required_use: String |
1935 |
- @param use: Enabled use flags |
1936 |
- @param use: List |
1937 |
- @param iuse_match: Callable that takes a single flag argument and returns |
1938 |
- True if the flag is matched, false otherwise, |
1939 |
- @param iuse_match: Callable |
1940 |
- @rtype: Bool |
1941 |
- @return: Indicates if REQUIRED_USE constraints are satisfied |
1942 |
- """ |
1943 |
- |
1944 |
- required_use = pkg.metadata["REQUIRED_USE"] |
1945 |
- use =self._pkg_use_enabled(pkg) |
1946 |
- iuse_match = pkg.iuse.is_valid_flag |
1947 |
- |
1948 |
- def is_active(token): |
1949 |
- if token.startswith("!"): |
1950 |
- flag = token[1:] |
1951 |
- is_negated = True |
1952 |
- else: |
1953 |
- flag = token |
1954 |
- is_negated = False |
1955 |
- |
1956 |
- if not flag or not iuse_match(flag): |
1957 |
- msg = _("USE flag '%s' is not in IUSE") \ |
1958 |
- % (flag,) |
1959 |
- e = InvalidData(msg, category='IUSE.missing') |
1960 |
- raise InvalidDependString(msg, errors=(e,)) |
1961 |
- |
1962 |
- return (flag in use and not is_negated) or \ |
1963 |
- (flag not in use and is_negated) |
1964 |
- |
1965 |
- def is_satisfied(operator, argument): |
1966 |
- if not argument: |
1967 |
- #|| ( ) -> True |
1968 |
- return True |
1969 |
- |
1970 |
- if operator == "||": |
1971 |
- return (True in argument) |
1972 |
- elif operator == "^^": |
1973 |
- return (argument.count(True) == 1) |
1974 |
- elif operator[-1] == "?": |
1975 |
- return (False not in argument) |
1976 |
- |
1977 |
- mysplit = required_use.split() |
1978 |
- level = 0 |
1979 |
- stack = [[]] |
1980 |
- tree = portage.dep._RequiredUseBranch() |
1981 |
- node = tree |
1982 |
- need_bracket = False |
1983 |
- target_use = {} |
1984 |
- |
1985 |
- for token in mysplit: |
1986 |
- if token == "(": |
1987 |
- if not need_bracket: |
1988 |
- child = portage.dep._RequiredUseBranch(parent=node) |
1989 |
- node._children.append(child) |
1990 |
- node = child |
1991 |
- |
1992 |
- need_bracket = False |
1993 |
- stack.append([]) |
1994 |
- level += 1 |
1995 |
- elif token == ")": |
1996 |
- if need_bracket: |
1997 |
- raise InvalidDependString( |
1998 |
- _("malformed syntax: '%s'") % required_use) |
1999 |
- if level > 0: |
2000 |
- level -= 1 |
2001 |
- l = stack.pop() |
2002 |
- op = None |
2003 |
- if stack[level]: |
2004 |
- if stack[level][-1] in ("||", "^^"): |
2005 |
- op = stack[level].pop() |
2006 |
- satisfied = is_satisfied(op, l) |
2007 |
- stack[level].append(satisfied) |
2008 |
- node._satisfied = satisfied |
2009 |
- |
2010 |
- elif not isinstance(stack[level][-1], bool) and \ |
2011 |
- stack[level][-1][-1] == "?": |
2012 |
- op = stack[level].pop() |
2013 |
- if is_active(op[:-1]): |
2014 |
- satisfied = is_satisfied(op, l) |
2015 |
- stack[level].append(satisfied) |
2016 |
- node._satisfied = satisfied |
2017 |
- else: |
2018 |
- node._satisfied = True |
2019 |
- last_node = node._parent._children.pop() |
2020 |
- if last_node is not node: |
2021 |
- raise AssertionError( |
2022 |
- "node is not last child of parent") |
2023 |
- node = node._parent |
2024 |
- continue |
2025 |
- |
2026 |
- if op is None: |
2027 |
- satisfied = False not in l |
2028 |
- node._satisfied = satisfied |
2029 |
- if l: |
2030 |
- stack[level].append(satisfied) |
2031 |
- |
2032 |
- if len(node._children) <= 1 or \ |
2033 |
- node._parent._operator not in ("||", "^^"): |
2034 |
- last_node = node._parent._children.pop() |
2035 |
- if last_node is not node: |
2036 |
- raise AssertionError( |
2037 |
- "node is not last child of parent") |
2038 |
- for child in node._children: |
2039 |
- node._parent._children.append(child) |
2040 |
- if isinstance(child, portage.dep._RequiredUseBranch): |
2041 |
- child._parent = node._parent |
2042 |
- |
2043 |
- elif not node._children: |
2044 |
- last_node = node._parent._children.pop() |
2045 |
- if last_node is not node: |
2046 |
- raise AssertionError( |
2047 |
- "node is not last child of parent") |
2048 |
- |
2049 |
- elif len(node._children) == 1 and op in ("||", "^^"): |
2050 |
- last_node = node._parent._children.pop() |
2051 |
- if last_node is not node: |
2052 |
- raise AssertionError( |
2053 |
- "node is not last child of parent") |
2054 |
- node._parent._children.append(node._children[0]) |
2055 |
- if isinstance(node._children[0], portage.dep._RequiredUseBranch): |
2056 |
- node._children[0]._parent = node._parent |
2057 |
- node = node._children[0] |
2058 |
- if node._operator is None and \ |
2059 |
- node._parent._operator not in ("||", "^^"): |
2060 |
- last_node = node._parent._children.pop() |
2061 |
- if last_node is not node: |
2062 |
- raise AssertionError( |
2063 |
- "node is not last child of parent") |
2064 |
- for child in node._children: |
2065 |
- node._parent._children.append(child) |
2066 |
- if isinstance(child, portage.dep._RequiredUseBranch): |
2067 |
- child._parent = node._parent |
2068 |
- |
2069 |
- node = node._parent |
2070 |
- else: |
2071 |
- raise InvalidDependString( |
2072 |
- _("malformed syntax: '%s'") % required_use) |
2073 |
- elif token in ("||", "^^"): |
2074 |
- if need_bracket: |
2075 |
- raise InvalidDependString( |
2076 |
- _("malformed syntax: '%s'") % required_use) |
2077 |
- need_bracket = True |
2078 |
- stack[level].append(token) |
2079 |
- child = portage.dep._RequiredUseBranch(operator=token, parent=node) |
2080 |
- node._children.append(child) |
2081 |
- node = child |
2082 |
- else: |
2083 |
- if need_bracket or "(" in token or ")" in token or \ |
2084 |
- "|" in token or "^" in token: |
2085 |
- raise InvalidDependString( |
2086 |
- _("malformed syntax: '%s'") % required_use) |
2087 |
- |
2088 |
- if token[-1] == "?": |
2089 |
- need_bracket = True |
2090 |
- stack[level].append(token) |
2091 |
- child = portage.dep._RequiredUseBranch(operator=token, parent=node) |
2092 |
- node._children.append(child) |
2093 |
- node = child |
2094 |
- else: |
2095 |
- satisfied = is_active(token) |
2096 |
- stack[level].append(satisfied) |
2097 |
- node._children.append(portage.dep._RequiredUseLeaf(token, satisfied)) |
2098 |
- print("satisfied:", satisfied) |
2099 |
- if satisfied is False: |
2100 |
- new_changes = {} |
2101 |
- new_changes[token] = True |
2102 |
- print("new_changes:", new_changes) |
2103 |
- if pkg.use.mask.intersection(new_changes) or \ |
2104 |
- pkg.use.force.intersection(new_changes): |
2105 |
- print("mask or force") |
2106 |
- else: |
2107 |
- print("new_changes2:", new_changes) |
2108 |
- if token in pkg.use.enabled: |
2109 |
- target_use[token] = False |
2110 |
- elif not token in pkg.use.enabled: |
2111 |
- target_use[token] = True |
2112 |
- return target_use |
2113 |
- |
2114 |
- if level != 0 or need_bracket: |
2115 |
- raise InvalidDependString( |
2116 |
- _("malformed syntax: '%s'") % required_use) |
2117 |
- |
2118 |
- tree._satisfied = False not in stack[0] |
2119 |
- return target_use |
2120 |
- |
2121 |
def _wrapped_select_pkg_highest_available_imp(self, root, atom, onlydeps=False, autounmask_level=None): |
2122 |
root_config = self._frozen_config.roots[root] |
2123 |
pkgsettings = self._frozen_config.pkgsettings[root] |
2124 |
@@ -4128,37 +4351,24 @@ class depgraph(object): |
2125 |
if not use_ebuild_visibility and (usepkgonly or useoldpkg): |
2126 |
if pkg.installed and pkg.masks: |
2127 |
continue |
2128 |
- else: |
2129 |
- try: |
2130 |
- pkg_eb = self._pkg( |
2131 |
- pkg.cpv, "ebuild", root_config, myrepo=pkg.repo) |
2132 |
- except portage.exception.PackageNotFound: |
2133 |
- pkg_eb_visible = False |
2134 |
- for pkg_eb in self._iter_match_pkgs(pkg.root_config, |
2135 |
- "ebuild", Atom("=%s" % (pkg.cpv,))): |
2136 |
- if self._pkg_visibility_check(pkg_eb, autounmask_level): |
2137 |
- pkg_eb_visible = True |
2138 |
- break |
2139 |
- if not pkg_eb_visible: |
2140 |
- continue |
2141 |
- else: |
2142 |
- if not self._pkg_visibility_check(pkg_eb, autounmask_level): |
2143 |
- continue |
2144 |
+ elif not self._equiv_ebuild_visible(pkg, |
2145 |
+ autounmask_level=autounmask_level): |
2146 |
+ continue |
2147 |
|
2148 |
# Calculation of USE for unbuilt ebuilds is relatively |
2149 |
# expensive, so it is only performed lazily, after the |
2150 |
# above visibility checks are complete. |
2151 |
|
2152 |
myarg = None |
2153 |
- if root == self._frozen_config.target_root: |
2154 |
- try: |
2155 |
- myarg = next(self._iter_atoms_for_pkg(pkg)) |
2156 |
- except StopIteration: |
2157 |
- pass |
2158 |
- except portage.exception.InvalidDependString: |
2159 |
- if not installed: |
2160 |
- # masked by corruption |
2161 |
- continue |
2162 |
+ try: |
2163 |
+ for myarg, myarg_atom in self._iter_atoms_for_pkg(pkg): |
2164 |
+ if myarg.force_reinstall: |
2165 |
+ reinstall = True |
2166 |
+ break |
2167 |
+ except InvalidDependString: |
2168 |
+ if not installed: |
2169 |
+ # masked by corruption |
2170 |
+ continue |
2171 |
if not installed and myarg: |
2172 |
found_available_arg = True |
2173 |
|
2174 |
@@ -4169,17 +4379,8 @@ class depgraph(object): |
2175 |
# since IUSE cannot be adjusted by the user. |
2176 |
continue |
2177 |
|
2178 |
- if pkg.metadata.get("REQUIRED_USE") and eapi_has_required_use(pkg.metadata["EAPI"]): |
2179 |
- required_use_is_sat = check_required_use(pkg.metadata["REQUIRED_USE"], |
2180 |
- self._pkg_use_enabled(pkg), pkg.iuse.is_valid_flag) |
2181 |
- if not required_use_is_sat: |
2182 |
- if autounmask_level and autounmask_level.allow_use_changes \ |
2183 |
- and not pkg.built: |
2184 |
- target_use = self.change_required_use(pkg) |
2185 |
- if not target_use is None: |
2186 |
- use = self._pkg_use_enabled(pkg, target_use) |
2187 |
- |
2188 |
if atom.use: |
2189 |
+ |
2190 |
matched_pkgs_ignore_use.append(pkg) |
2191 |
if autounmask_level and autounmask_level.allow_use_changes and not pkg.built: |
2192 |
target_use = {} |
2193 |
@@ -4197,7 +4398,7 @@ class depgraph(object): |
2194 |
missing_disabled = atom.use.missing_disabled.difference(pkg.iuse.all) |
2195 |
|
2196 |
if atom.use.enabled: |
2197 |
- if atom.use.enabled.intersection(missing_disabled): |
2198 |
+ if any(x in atom.use.enabled for x in missing_disabled): |
2199 |
use_match = False |
2200 |
can_adjust_use = False |
2201 |
need_enabled = atom.use.enabled.difference(use) |
2202 |
@@ -4206,11 +4407,11 @@ class depgraph(object): |
2203 |
if need_enabled: |
2204 |
use_match = False |
2205 |
if can_adjust_use: |
2206 |
- if pkg.use.mask.intersection(need_enabled): |
2207 |
+ if any(x in pkg.use.mask for x in need_enabled): |
2208 |
can_adjust_use = False |
2209 |
|
2210 |
if atom.use.disabled: |
2211 |
- if atom.use.disabled.intersection(missing_enabled): |
2212 |
+ if any(x in atom.use.disabled for x in missing_enabled): |
2213 |
use_match = False |
2214 |
can_adjust_use = False |
2215 |
need_disabled = atom.use.disabled.intersection(use) |
2216 |
@@ -4219,8 +4420,8 @@ class depgraph(object): |
2217 |
if need_disabled: |
2218 |
use_match = False |
2219 |
if can_adjust_use: |
2220 |
- if pkg.use.force.difference( |
2221 |
- pkg.use.mask).intersection(need_disabled): |
2222 |
+ if any(x in pkg.use.force and x not in |
2223 |
+ pkg.use.mask for x in need_disabled): |
2224 |
can_adjust_use = False |
2225 |
|
2226 |
if not use_match: |
2227 |
@@ -4486,9 +4687,19 @@ class depgraph(object): |
2228 |
"recurse" not in self._dynamic_config.myparams: |
2229 |
return 1 |
2230 |
|
2231 |
+ complete_if_new_use = self._dynamic_config.myparams.get( |
2232 |
+ "complete_if_new_use", "y") == "y" |
2233 |
+ complete_if_new_ver = self._dynamic_config.myparams.get( |
2234 |
+ "complete_if_new_ver", "y") == "y" |
2235 |
+ rebuild_if_new_slot = self._dynamic_config.myparams.get( |
2236 |
+ "rebuild_if_new_slot", "y") == "y" |
2237 |
+ complete_if_new_slot = rebuild_if_new_slot |
2238 |
+ |
2239 |
if "complete" not in self._dynamic_config.myparams and \ |
2240 |
- self._dynamic_config.myparams.get("complete_if_new_ver", "y") == "y": |
2241 |
- # Enable complete mode if an installed package version will change. |
2242 |
+ (complete_if_new_use or |
2243 |
+ complete_if_new_ver or complete_if_new_slot): |
2244 |
+ # Enable complete mode if an installed package will change somehow. |
2245 |
+ use_change = False |
2246 |
version_change = False |
2247 |
for node in self._dynamic_config.digraph: |
2248 |
if not isinstance(node, Package) or \ |
2249 |
@@ -4496,12 +4707,35 @@ class depgraph(object): |
2250 |
continue |
2251 |
vardb = self._frozen_config.roots[ |
2252 |
node.root].trees["vartree"].dbapi |
2253 |
- inst_pkg = vardb.match_pkgs(node.slot_atom) |
2254 |
- if inst_pkg and (inst_pkg[0] > node or inst_pkg[0] < node): |
2255 |
- version_change = True |
2256 |
- break |
2257 |
|
2258 |
- if version_change: |
2259 |
+ if complete_if_new_use or complete_if_new_ver: |
2260 |
+ inst_pkg = vardb.match_pkgs(node.slot_atom) |
2261 |
+ if inst_pkg and inst_pkg[0].cp == node.cp: |
2262 |
+ inst_pkg = inst_pkg[0] |
2263 |
+ if complete_if_new_ver and \ |
2264 |
+ (inst_pkg < node or node < inst_pkg): |
2265 |
+ version_change = True |
2266 |
+ break |
2267 |
+ |
2268 |
+ # Intersect enabled USE with IUSE, in order to |
2269 |
+ # ignore forced USE from implicit IUSE flags, since |
2270 |
+ # they're probably irrelevant and they are sensitive |
2271 |
+ # to use.mask/force changes in the profile. |
2272 |
+ if complete_if_new_use and \ |
2273 |
+ (node.iuse.all != inst_pkg.iuse.all or |
2274 |
+ self._pkg_use_enabled(node).intersection(node.iuse.all) != |
2275 |
+ self._pkg_use_enabled(inst_pkg).intersection(inst_pkg.iuse.all)): |
2276 |
+ use_change = True |
2277 |
+ break |
2278 |
+ |
2279 |
+ if complete_if_new_slot: |
2280 |
+ cp_list = vardb.match_pkgs(Atom(node.cp)) |
2281 |
+ if (cp_list and cp_list[0].cp == node.cp and |
2282 |
+ not any(node.slot == pkg.slot for pkg in cp_list)): |
2283 |
+ version_change = True |
2284 |
+ break |
2285 |
+ |
2286 |
+ if use_change or version_change: |
2287 |
self._dynamic_config.myparams["complete"] = True |
2288 |
|
2289 |
if "complete" not in self._dynamic_config.myparams: |
2290 |
@@ -4515,6 +4749,7 @@ class depgraph(object): |
2291 |
# scheduled for replacement. Also, toggle the "deep" |
2292 |
# parameter so that all dependencies are traversed and |
2293 |
# accounted for. |
2294 |
+ self._dynamic_config._complete_mode = True |
2295 |
self._select_atoms = self._select_atoms_from_graph |
2296 |
if "remove" in self._dynamic_config.myparams: |
2297 |
self._select_package = self._select_pkg_from_installed |
2298 |
@@ -4673,7 +4908,7 @@ class depgraph(object): |
2299 |
# For installed packages, always ignore blockers from DEPEND since |
2300 |
# only runtime dependencies should be relevant for packages that |
2301 |
# are already built. |
2302 |
- dep_keys = ["RDEPEND", "PDEPEND"] |
2303 |
+ dep_keys = Package._runtime_keys |
2304 |
for myroot in self._frozen_config.trees: |
2305 |
|
2306 |
if self._frozen_config.myopts.get("--root-deps") is not None and \ |
2307 |
@@ -5130,16 +5365,24 @@ class depgraph(object): |
2308 |
root_config.root]["root_config"] = root_config |
2309 |
|
2310 |
def _resolve_conflicts(self): |
2311 |
+ |
2312 |
+ if "complete" not in self._dynamic_config.myparams and \ |
2313 |
+ self._dynamic_config._allow_backtracking and \ |
2314 |
+ self._dynamic_config._slot_collision_nodes and \ |
2315 |
+ not self._accept_blocker_conflicts(): |
2316 |
+ self._dynamic_config.myparams["complete"] = True |
2317 |
+ |
2318 |
if not self._complete_graph(): |
2319 |
raise self._unknown_internal_error() |
2320 |
|
2321 |
+ self._process_slot_conflicts() |
2322 |
+ |
2323 |
+ self._slot_operator_trigger_reinstalls() |
2324 |
+ |
2325 |
if not self._validate_blockers(): |
2326 |
self._dynamic_config._skip_restart = True |
2327 |
raise self._unknown_internal_error() |
2328 |
|
2329 |
- if self._dynamic_config._slot_collision_info: |
2330 |
- self._process_slot_conflicts() |
2331 |
- |
2332 |
def _serialize_tasks(self): |
2333 |
|
2334 |
debug = "--debug" in self._frozen_config.myopts |
2335 |
@@ -5434,7 +5677,7 @@ class depgraph(object): |
2336 |
for node in nodes: |
2337 |
parents = mygraph.parent_nodes(node, |
2338 |
ignore_priority=DepPrioritySatisfiedRange.ignore_soft) |
2339 |
- if parents and set(parents).intersection(asap_nodes): |
2340 |
+ if any(x in asap_nodes for x in parents): |
2341 |
selected_nodes = [node] |
2342 |
break |
2343 |
else: |
2344 |
@@ -6119,7 +6362,7 @@ class depgraph(object): |
2345 |
if is_latest: |
2346 |
unstable_keyword_msg[root].append(">=%s %s\n" % (pkg.cpv, keyword)) |
2347 |
elif is_latest_in_slot: |
2348 |
- unstable_keyword_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.metadata["SLOT"], keyword)) |
2349 |
+ unstable_keyword_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.slot, keyword)) |
2350 |
else: |
2351 |
unstable_keyword_msg[root].append("=%s %s\n" % (pkg.cpv, keyword)) |
2352 |
else: |
2353 |
@@ -6159,7 +6402,7 @@ class depgraph(object): |
2354 |
if is_latest: |
2355 |
p_mask_change_msg[root].append(">=%s\n" % pkg.cpv) |
2356 |
elif is_latest_in_slot: |
2357 |
- p_mask_change_msg[root].append(">=%s:%s\n" % (pkg.cpv, pkg.metadata["SLOT"])) |
2358 |
+ p_mask_change_msg[root].append(">=%s:%s\n" % (pkg.cpv, pkg.slot)) |
2359 |
else: |
2360 |
p_mask_change_msg[root].append("=%s\n" % pkg.cpv) |
2361 |
else: |
2362 |
@@ -6184,7 +6427,7 @@ class depgraph(object): |
2363 |
if is_latest: |
2364 |
use_changes_msg[root].append(">=%s %s\n" % (pkg.cpv, " ".join(adjustments))) |
2365 |
elif is_latest_in_slot: |
2366 |
- use_changes_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.metadata["SLOT"], " ".join(adjustments))) |
2367 |
+ use_changes_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.slot, " ".join(adjustments))) |
2368 |
else: |
2369 |
use_changes_msg[root].append("=%s %s\n" % (pkg.cpv, " ".join(adjustments))) |
2370 |
|
2371 |
@@ -6201,7 +6444,7 @@ class depgraph(object): |
2372 |
if is_latest: |
2373 |
license_msg[root].append(">=%s %s\n" % (pkg.cpv, " ".join(sorted(missing_licenses)))) |
2374 |
elif is_latest_in_slot: |
2375 |
- license_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.metadata["SLOT"], " ".join(sorted(missing_licenses)))) |
2376 |
+ license_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.slot, " ".join(sorted(missing_licenses)))) |
2377 |
else: |
2378 |
license_msg[root].append("=%s %s\n" % (pkg.cpv, " ".join(sorted(missing_licenses)))) |
2379 |
|
2380 |
@@ -6308,27 +6551,27 @@ class depgraph(object): |
2381 |
settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH) |
2382 |
|
2383 |
if len(roots) > 1: |
2384 |
- writemsg_stdout("\nFor %s:\n" % abs_user_config, noiselevel=-1) |
2385 |
+ writemsg("\nFor %s:\n" % abs_user_config, noiselevel=-1) |
2386 |
|
2387 |
if root in unstable_keyword_msg: |
2388 |
- writemsg_stdout("\nThe following " + colorize("BAD", "keyword changes") + \ |
2389 |
+ writemsg("\nThe following " + colorize("BAD", "keyword changes") + \ |
2390 |
" are necessary to proceed:\n", noiselevel=-1) |
2391 |
- writemsg_stdout(format_msg(unstable_keyword_msg[root]), noiselevel=-1) |
2392 |
+ writemsg(format_msg(unstable_keyword_msg[root]), noiselevel=-1) |
2393 |
|
2394 |
if root in p_mask_change_msg: |
2395 |
- writemsg_stdout("\nThe following " + colorize("BAD", "mask changes") + \ |
2396 |
+ writemsg("\nThe following " + colorize("BAD", "mask changes") + \ |
2397 |
" are necessary to proceed:\n", noiselevel=-1) |
2398 |
- writemsg_stdout(format_msg(p_mask_change_msg[root]), noiselevel=-1) |
2399 |
+ writemsg(format_msg(p_mask_change_msg[root]), noiselevel=-1) |
2400 |
|
2401 |
if root in use_changes_msg: |
2402 |
- writemsg_stdout("\nThe following " + colorize("BAD", "USE changes") + \ |
2403 |
+ writemsg("\nThe following " + colorize("BAD", "USE changes") + \ |
2404 |
" are necessary to proceed:\n", noiselevel=-1) |
2405 |
- writemsg_stdout(format_msg(use_changes_msg[root]), noiselevel=-1) |
2406 |
+ writemsg(format_msg(use_changes_msg[root]), noiselevel=-1) |
2407 |
|
2408 |
if root in license_msg: |
2409 |
- writemsg_stdout("\nThe following " + colorize("BAD", "license changes") + \ |
2410 |
+ writemsg("\nThe following " + colorize("BAD", "license changes") + \ |
2411 |
" are necessary to proceed:\n", noiselevel=-1) |
2412 |
- writemsg_stdout(format_msg(license_msg[root]), noiselevel=-1) |
2413 |
+ writemsg(format_msg(license_msg[root]), noiselevel=-1) |
2414 |
|
2415 |
protect_obj = {} |
2416 |
if write_to_file: |
2417 |
@@ -6375,7 +6618,7 @@ class depgraph(object): |
2418 |
for line in msg: |
2419 |
if line: |
2420 |
line = colorize("INFORM", line) |
2421 |
- writemsg_stdout(line + "\n", noiselevel=-1) |
2422 |
+ writemsg(line + "\n", noiselevel=-1) |
2423 |
|
2424 |
if ask and write_to_file and file_to_write_to: |
2425 |
prompt = "\nWould you like to add these " + \ |
2426 |
@@ -6407,14 +6650,14 @@ class depgraph(object): |
2427 |
file_to_write_to.get((abs_user_config, "package.license"))) |
2428 |
|
2429 |
if problems: |
2430 |
- writemsg_stdout("\nThe following problems occurred while writing autounmask changes:\n", \ |
2431 |
+ writemsg("\nThe following problems occurred while writing autounmask changes:\n", \ |
2432 |
noiselevel=-1) |
2433 |
- writemsg_stdout("".join(problems), noiselevel=-1) |
2434 |
+ writemsg("".join(problems), noiselevel=-1) |
2435 |
elif write_to_file and roots: |
2436 |
- writemsg_stdout("\nAutounmask changes successfully written. Remember to run dispatch-conf.\n", \ |
2437 |
+ writemsg("\nAutounmask changes successfully written. Remember to run dispatch-conf.\n", \ |
2438 |
noiselevel=-1) |
2439 |
elif not pretend and not autounmask_write and roots: |
2440 |
- writemsg_stdout("\nUse --autounmask-write to write changes to config files (honoring CONFIG_PROTECT).\n", \ |
2441 |
+ writemsg("\nUse --autounmask-write to write changes to config files (honoring CONFIG_PROTECT).\n", \ |
2442 |
noiselevel=-1) |
2443 |
|
2444 |
|
2445 |
@@ -6425,35 +6668,8 @@ class depgraph(object): |
2446 |
the merge list where it is most likely to be seen, but if display() |
2447 |
is not going to be called then this method should be called explicitly |
2448 |
to ensure that the user is notified of problems with the graph. |
2449 |
- |
2450 |
- All output goes to stderr, except for unsatisfied dependencies which |
2451 |
- go to stdout for parsing by programs such as autounmask. |
2452 |
""" |
2453 |
|
2454 |
- # Note that show_masked_packages() sends its output to |
2455 |
- # stdout, and some programs such as autounmask parse the |
2456 |
- # output in cases when emerge bails out. However, when |
2457 |
- # show_masked_packages() is called for installed packages |
2458 |
- # here, the message is a warning that is more appropriate |
2459 |
- # to send to stderr, so temporarily redirect stdout to |
2460 |
- # stderr. TODO: Fix output code so there's a cleaner way |
2461 |
- # to redirect everything to stderr. |
2462 |
- sys.stdout.flush() |
2463 |
- sys.stderr.flush() |
2464 |
- stdout = sys.stdout |
2465 |
- try: |
2466 |
- sys.stdout = sys.stderr |
2467 |
- self._display_problems() |
2468 |
- finally: |
2469 |
- sys.stdout = stdout |
2470 |
- sys.stdout.flush() |
2471 |
- sys.stderr.flush() |
2472 |
- |
2473 |
- # This goes to stdout for parsing by programs like autounmask. |
2474 |
- for pargs, kwargs in self._dynamic_config._unsatisfied_deps_for_display: |
2475 |
- self._show_unsatisfied_dep(*pargs, **kwargs) |
2476 |
- |
2477 |
- def _display_problems(self): |
2478 |
if self._dynamic_config._circular_deps_for_display is not None: |
2479 |
self._show_circular_deps( |
2480 |
self._dynamic_config._circular_deps_for_display) |
2481 |
@@ -6572,6 +6788,9 @@ class depgraph(object): |
2482 |
show_mask_docs() |
2483 |
writemsg("\n", noiselevel=-1) |
2484 |
|
2485 |
+ for pargs, kwargs in self._dynamic_config._unsatisfied_deps_for_display: |
2486 |
+ self._show_unsatisfied_dep(*pargs, **kwargs) |
2487 |
+ |
2488 |
def saveNomergeFavorites(self): |
2489 |
"""Find atoms in favorites that are not in the mergelist and add them |
2490 |
to the world file if necessary.""" |
2491 |
@@ -6618,6 +6837,9 @@ class depgraph(object): |
2492 |
continue |
2493 |
if arg.root_config.root != root_config.root: |
2494 |
continue |
2495 |
+ if arg.internal: |
2496 |
+ # __auto_* sets |
2497 |
+ continue |
2498 |
k = arg.name |
2499 |
if k in ("selected", "world") or \ |
2500 |
not root_config.sets[k].world_candidate: |
2501 |
@@ -6629,9 +6851,13 @@ class depgraph(object): |
2502 |
all_added.extend(added_favorites) |
2503 |
all_added.sort() |
2504 |
for a in all_added: |
2505 |
+ if a.startswith(SETPREFIX): |
2506 |
+ filename = "world_sets" |
2507 |
+ else: |
2508 |
+ filename = "world" |
2509 |
writemsg_stdout( |
2510 |
- ">>> Recording %s in \"world\" favorites file...\n" % \ |
2511 |
- colorize("INFORM", str(a)), noiselevel=-1) |
2512 |
+ ">>> Recording %s in \"%s\" favorites file...\n" % |
2513 |
+ (colorize("INFORM", _unicode(a)), filename), noiselevel=-1) |
2514 |
if all_added: |
2515 |
world_set.update(all_added) |
2516 |
|
2517 |
@@ -7010,13 +7236,8 @@ class _dep_check_composite_db(dbapi): |
2518 |
return ret[:] |
2519 |
|
2520 |
def _visible(self, pkg): |
2521 |
- if pkg.installed and "selective" not in self._depgraph._dynamic_config.myparams: |
2522 |
- try: |
2523 |
|