Package _emerge :: Module depgraph
[hide private]

Source Code for Module _emerge.depgraph

   1  # Copyright 1999-2013 Gentoo Foundation 
   2  # Distributed under the terms of the GNU General Public License v2 
   3   
   4  from __future__ import print_function, unicode_literals 
   5   
   6  import errno 
   7  import io 
   8  import logging 
   9  import stat 
  10  import sys 
  11  import textwrap 
  12  import warnings 
  13  from collections import deque 
  14  from itertools import chain 
  15   
  16  import portage 
  17  from portage import os, OrderedDict 
  18  from portage import _unicode_decode, _unicode_encode, _encodings 
  19  from portage.const import PORTAGE_PACKAGE_ATOM, USER_CONFIG_PATH, VCS_DIRS 
  20  from portage.dbapi import dbapi 
  21  from portage.dbapi.dep_expand import dep_expand 
  22  from portage.dbapi._similar_name_search import similar_name_search 
  23  from portage.dep import Atom, best_match_to_list, extract_affecting_use, \ 
  24          check_required_use, human_readable_required_use, match_from_list, \ 
  25          _repo_separator 
  26  from portage.dep._slot_operator import ignore_built_slot_operator_deps 
  27  from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use, \ 
  28          _get_eapi_attrs 
  29  from portage.exception import (InvalidAtom, InvalidData, InvalidDependString, 
  30          PackageNotFound, PortageException) 
  31  from portage.output import colorize, create_color_func, \ 
  32          darkgreen, green 
  33  bad = create_color_func("BAD") 
  34  from portage.package.ebuild.config import _get_feature_flags 
  35  from portage.package.ebuild.getmaskingstatus import \ 
  36          _getmaskingstatus, _MaskReason 
  37  from portage._sets import SETPREFIX 
  38  from portage._sets.base import InternalPackageSet 
  39  from portage.util import ConfigProtect, shlex_split, new_protect_filename 
  40  from portage.util import cmp_sort_key, writemsg, writemsg_stdout 
  41  from portage.util import ensure_dirs 
  42  from portage.util import writemsg_level, write_atomic 
  43  from portage.util.digraph import digraph 
  44  from portage.util._async.TaskScheduler import TaskScheduler 
  45  from portage.util._eventloop.EventLoop import EventLoop 
  46  from portage.util._eventloop.global_event_loop import global_event_loop 
  47  from portage.versions import catpkgsplit 
  48   
  49  from _emerge.AtomArg import AtomArg 
  50  from _emerge.Blocker import Blocker 
  51  from _emerge.BlockerCache import BlockerCache 
  52  from _emerge.BlockerDepPriority import BlockerDepPriority 
  53  from .chk_updated_cfg_files import chk_updated_cfg_files 
  54  from _emerge.countdown import countdown 
  55  from _emerge.create_world_atom import create_world_atom 
  56  from _emerge.Dependency import Dependency 
  57  from _emerge.DependencyArg import DependencyArg 
  58  from _emerge.DepPriority import DepPriority 
  59  from _emerge.DepPriorityNormalRange import DepPriorityNormalRange 
  60  from _emerge.DepPrioritySatisfiedRange import DepPrioritySatisfiedRange 
  61  from _emerge.EbuildMetadataPhase import EbuildMetadataPhase 
  62  from _emerge.FakeVartree import FakeVartree 
  63  from _emerge._find_deep_system_runtime_deps import _find_deep_system_runtime_deps 
  64  from _emerge.is_valid_package_atom import insert_category_into_atom, \ 
  65          is_valid_package_atom 
  66  from _emerge.Package import Package 
  67  from _emerge.PackageArg import PackageArg 
  68  from _emerge.PackageVirtualDbapi import PackageVirtualDbapi 
  69  from _emerge.RootConfig import RootConfig 
  70  from _emerge.search import search 
  71  from _emerge.SetArg import SetArg 
  72  from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice 
  73  from _emerge.UnmergeDepPriority import UnmergeDepPriority 
  74  from _emerge.UseFlagDisplay import pkg_use_display 
  75  from _emerge.userquery import userquery 
  76   
  77  from _emerge.resolver.backtracking import Backtracker, BacktrackParameter 
  78  from _emerge.resolver.slot_collision import slot_conflict_handler 
  79  from _emerge.resolver.circular_dependency import circular_dependency_handler 
  80  from _emerge.resolver.output import Display 
  81   
  82  if sys.hexversion >= 0x3000000: 
  83          basestring = str 
  84          long = int 
  85          _unicode = str 
  86  else: 
  87          _unicode = unicode 
  88   
89 -class _scheduler_graph_config(object):
90 - def __init__(self, trees, pkg_cache, graph, mergelist):
91 self.trees = trees 92 self.pkg_cache = pkg_cache 93 self.graph = graph 94 self.mergelist = mergelist
95
96 -def _wildcard_set(atoms):
97 pkgs = InternalPackageSet(allow_wildcard=True) 98 for x in atoms: 99 try: 100 x = Atom(x, allow_wildcard=True, allow_repo=False) 101 except portage.exception.InvalidAtom: 102 x = Atom("*/" + x, allow_wildcard=True, allow_repo=False) 103 pkgs.add(x) 104 return pkgs
105
106 -class _frozen_depgraph_config(object):
107
108 - def __init__(self, settings, trees, myopts, spinner):
109 self.settings = settings 110 self.target_root = settings["EROOT"] 111 self.myopts = myopts 112 self.edebug = 0 113 if settings.get("PORTAGE_DEBUG", "") == "1": 114 self.edebug = 1 115 self.spinner = spinner 116 self._running_root = trees[trees._running_eroot]["root_config"] 117 self.pkgsettings = {} 118 self.trees = {} 119 self._trees_orig = trees 120 self.roots = {} 121 # All Package instances 122 self._pkg_cache = {} 123 self._highest_license_masked = {} 124 dynamic_deps = myopts.get("--dynamic-deps", "y") != "n" 125 ignore_built_slot_operator_deps = myopts.get( 126 "--ignore-built-slot-operator-deps", "n") == "y" 127 for myroot in trees: 128 self.trees[myroot] = {} 129 # Create a RootConfig instance that references 130 # the FakeVartree instead of the real one. 131 self.roots[myroot] = RootConfig( 132 trees[myroot]["vartree"].settings, 133 self.trees[myroot], 134 trees[myroot]["root_config"].setconfig) 135 for tree in ("porttree", "bintree"): 136 self.trees[myroot][tree] = trees[myroot][tree] 137 self.trees[myroot]["vartree"] = \ 138 FakeVartree(trees[myroot]["root_config"], 139 pkg_cache=self._pkg_cache, 140 pkg_root_config=self.roots[myroot], 141 dynamic_deps=dynamic_deps, 142 ignore_built_slot_operator_deps=ignore_built_slot_operator_deps) 143 self.pkgsettings[myroot] = portage.config( 144 clone=self.trees[myroot]["vartree"].settings) 145 146 self._required_set_names = set(["world"]) 147 148 atoms = ' '.join(myopts.get("--exclude", [])).split() 149 self.excluded_pkgs = _wildcard_set(atoms) 150 atoms = ' '.join(myopts.get("--reinstall-atoms", [])).split() 151 self.reinstall_atoms = _wildcard_set(atoms) 152 atoms = ' '.join(myopts.get("--usepkg-exclude", [])).split() 153 self.usepkg_exclude = _wildcard_set(atoms) 154 atoms = ' '.join(myopts.get("--useoldpkg-atoms", [])).split() 155 self.useoldpkg_atoms = _wildcard_set(atoms) 156 atoms = ' '.join(myopts.get("--rebuild-exclude", [])).split() 157 self.rebuild_exclude = _wildcard_set(atoms) 158 atoms = ' '.join(myopts.get("--rebuild-ignore", [])).split() 159 self.rebuild_ignore = _wildcard_set(atoms) 160 161 self.rebuild_if_new_rev = "--rebuild-if-new-rev" in myopts 162 self.rebuild_if_new_ver = "--rebuild-if-new-ver" in myopts 163 self.rebuild_if_unbuilt = "--rebuild-if-unbuilt" in myopts
164
165 -class _depgraph_sets(object):
166 - def __init__(self):
167 # contains all sets added to the graph 168 self.sets = {} 169 # contains non-set atoms given as arguments 170 self.sets['__non_set_args__'] = InternalPackageSet(allow_repo=True) 171 # contains all atoms from all sets added to the graph, including 172 # atoms given as arguments 173 self.atoms = InternalPackageSet(allow_repo=True) 174 self.atom_arg_map = {}
175
176 -class _rebuild_config(object):
177 - def __init__(self, frozen_config, backtrack_parameters):
178 self._graph = digraph() 179 self._frozen_config = frozen_config 180 self.rebuild_list = backtrack_parameters.rebuild_list.copy() 181 self.orig_rebuild_list = self.rebuild_list.copy() 182 self.reinstall_list = backtrack_parameters.reinstall_list.copy() 183 self.rebuild_if_new_rev = frozen_config.rebuild_if_new_rev 184 self.rebuild_if_new_ver = frozen_config.rebuild_if_new_ver 185 self.rebuild_if_unbuilt = frozen_config.rebuild_if_unbuilt 186 self.rebuild = (self.rebuild_if_new_rev or self.rebuild_if_new_ver or 187 self.rebuild_if_unbuilt)
188
189 - def add(self, dep_pkg, dep):
190 parent = dep.collapsed_parent 191 priority = dep.collapsed_priority 192 rebuild_exclude = self._frozen_config.rebuild_exclude 193 rebuild_ignore = self._frozen_config.rebuild_ignore 194 if (self.rebuild and isinstance(parent, Package) and 195 parent.built and priority.buildtime and 196 isinstance(dep_pkg, Package) and 197 not rebuild_exclude.findAtomForPackage(parent) and 198 not rebuild_ignore.findAtomForPackage(dep_pkg)): 199 self._graph.add(dep_pkg, parent, priority)
200
201 - def _needs_rebuild(self, dep_pkg):
202 """Check whether packages that depend on dep_pkg need to be rebuilt.""" 203 dep_root_slot = (dep_pkg.root, dep_pkg.slot_atom) 204 if dep_pkg.built or dep_root_slot in self.orig_rebuild_list: 205 return False 206 207 if self.rebuild_if_unbuilt: 208 # dep_pkg is being installed from source, so binary 209 # packages for parents are invalid. Force rebuild 210 return True 211 212 trees = self._frozen_config.trees 213 vardb = trees[dep_pkg.root]["vartree"].dbapi 214 if self.rebuild_if_new_rev: 215 # Parent packages are valid if a package with the same 216 # cpv is already installed. 217 return dep_pkg.cpv not in vardb.match(dep_pkg.slot_atom) 218 219 # Otherwise, parent packages are valid if a package with the same 220 # version (excluding revision) is already installed. 221 assert self.rebuild_if_new_ver 222 cpv_norev = catpkgsplit(dep_pkg.cpv)[:-1] 223 for inst_cpv in vardb.match(dep_pkg.slot_atom): 224 inst_cpv_norev = catpkgsplit(inst_cpv)[:-1] 225 if inst_cpv_norev == cpv_norev: 226 return False 227 228 return True
229
230 - def _trigger_rebuild(self, parent, build_deps):
231 root_slot = (parent.root, parent.slot_atom) 232 if root_slot in self.rebuild_list: 233 return False 234 trees = self._frozen_config.trees 235 reinstall = False 236 for slot_atom, dep_pkg in build_deps.items(): 237 dep_root_slot = (dep_pkg.root, slot_atom) 238 if self._needs_rebuild(dep_pkg): 239 self.rebuild_list.add(root_slot) 240 return True 241 elif ("--usepkg" in self._frozen_config.myopts and 242 (dep_root_slot in self.reinstall_list or 243 dep_root_slot in self.rebuild_list or 244 not dep_pkg.installed)): 245 246 # A direct rebuild dependency is being installed. We 247 # should update the parent as well to the latest binary, 248 # if that binary is valid. 249 # 250 # To validate the binary, we check whether all of the 251 # rebuild dependencies are present on the same binhost. 252 # 253 # 1) If parent is present on the binhost, but one of its 254 # rebuild dependencies is not, then the parent should 255 # be rebuilt from source. 256 # 2) Otherwise, the parent binary is assumed to be valid, 257 # because all of its rebuild dependencies are 258 # consistent. 259 bintree = trees[parent.root]["bintree"] 260 uri = bintree.get_pkgindex_uri(parent.cpv) 261 dep_uri = bintree.get_pkgindex_uri(dep_pkg.cpv) 262 bindb = bintree.dbapi 263 if self.rebuild_if_new_ver and uri and uri != dep_uri: 264 cpv_norev = catpkgsplit(dep_pkg.cpv)[:-1] 265 for cpv in bindb.match(dep_pkg.slot_atom): 266 if cpv_norev == catpkgsplit(cpv)[:-1]: 267 dep_uri = bintree.get_pkgindex_uri(cpv) 268 if uri == dep_uri: 269 break 270 if uri and uri != dep_uri: 271 # 1) Remote binary package is invalid because it was 272 # built without dep_pkg. Force rebuild. 273 self.rebuild_list.add(root_slot) 274 return True 275 elif (parent.installed and 276 root_slot not in self.reinstall_list): 277 try: 278 bin_build_time, = bindb.aux_get(parent.cpv, 279 ["BUILD_TIME"]) 280 except KeyError: 281 continue 282 if bin_build_time != _unicode(parent.build_time): 283 # 2) Remote binary package is valid, and local package 284 # is not up to date. Force reinstall. 285 reinstall = True 286 if reinstall: 287 self.reinstall_list.add(root_slot) 288 return reinstall
289
290 - def trigger_rebuilds(self):
291 """ 292 Trigger rebuilds where necessary. If pkgA has been updated, and pkgB 293 depends on pkgA at both build-time and run-time, pkgB needs to be 294 rebuilt. 295 """ 296 need_restart = False 297 graph = self._graph 298 build_deps = {} 299 300 leaf_nodes = deque(graph.leaf_nodes()) 301 302 # Trigger rebuilds bottom-up (starting with the leaves) so that parents 303 # will always know which children are being rebuilt. 304 while graph: 305 if not leaf_nodes: 306 # We'll have to drop an edge. This should be quite rare. 307 leaf_nodes.append(graph.order[-1]) 308 309 node = leaf_nodes.popleft() 310 if node not in graph: 311 # This can be triggered by circular dependencies. 312 continue 313 slot_atom = node.slot_atom 314 315 # Remove our leaf node from the graph, keeping track of deps. 316 parents = graph.parent_nodes(node) 317 graph.remove(node) 318 node_build_deps = build_deps.get(node, {}) 319 for parent in parents: 320 if parent == node: 321 # Ignore a direct cycle. 322 continue 323 parent_bdeps = build_deps.setdefault(parent, {}) 324 parent_bdeps[slot_atom] = node 325 if not graph.child_nodes(parent): 326 leaf_nodes.append(parent) 327 328 # Trigger rebuilds for our leaf node. Because all of our children 329 # have been processed, the build_deps will be completely filled in, 330 # and self.rebuild_list / self.reinstall_list will tell us whether 331 # any of our children need to be rebuilt or reinstalled. 332 if self._trigger_rebuild(node, node_build_deps): 333 need_restart = True 334 335 return need_restart
336 337
338 -class _dynamic_depgraph_config(object):
339
340 - def __init__(self, depgraph, myparams, allow_backtracking, backtrack_parameters):
341 self.myparams = myparams.copy() 342 self._vdb_loaded = False 343 self._allow_backtracking = allow_backtracking 344 # Maps slot atom to package for each Package added to the graph. 345 self._slot_pkg_map = {} 346 # Maps nodes to the reasons they were selected for reinstallation. 347 self._reinstall_nodes = {} 348 self.mydbapi = {} 349 # Contains a filtered view of preferred packages that are selected 350 # from available repositories. 351 self._filtered_trees = {} 352 # Contains installed packages and new packages that have been added 353 # to the graph. 354 self._graph_trees = {} 355 # Caches visible packages returned from _select_package, for use in 356 # depgraph._iter_atoms_for_pkg() SLOT logic. 357 self._visible_pkgs = {} 358 #contains the args created by select_files 359 self._initial_arg_list = [] 360 self.digraph = portage.digraph() 361 # manages sets added to the graph 362 self.sets = {} 363 # contains all nodes pulled in by self.sets 364 self._set_nodes = set() 365 # Contains only Blocker -> Uninstall edges 366 self._blocker_uninstalls = digraph() 367 # Contains only Package -> Blocker edges 368 self._blocker_parents = digraph() 369 # Contains only irrelevant Package -> Blocker edges 370 self._irrelevant_blockers = digraph() 371 # Contains only unsolvable Package -> Blocker edges 372 self._unsolvable_blockers = digraph() 373 # Contains all Blocker -> Blocked Package edges 374 self._blocked_pkgs = digraph() 375 # Contains world packages that have been protected from 376 # uninstallation but may not have been added to the graph 377 # if the graph is not complete yet. 378 self._blocked_world_pkgs = {} 379 # Contains packages whose dependencies have been traversed. 380 # This use used to check if we have accounted for blockers 381 # relevant to a package. 382 self._traversed_pkg_deps = set() 383 # This should be ordered such that the backtracker will 384 # attempt to solve conflicts which occurred earlier first, 385 # since an earlier conflict can be the cause of a conflict 386 # which occurs later. 387 self._slot_collision_info = OrderedDict() 388 # Slot collision nodes are not allowed to block other packages since 389 # blocker validation is only able to account for one package per slot. 390 self._slot_collision_nodes = set() 391 self._parent_atoms = {} 392 self._slot_conflict_handler = None 393 self._circular_dependency_handler = None 394 self._serialized_tasks_cache = None 395 self._scheduler_graph = None 396 self._displayed_list = None 397 self._pprovided_args = [] 398 self._missing_args = [] 399 self._masked_installed = set() 400 self._masked_license_updates = set() 401 self._unsatisfied_deps_for_display = [] 402 self._unsatisfied_blockers_for_display = None 403 self._circular_deps_for_display = None 404 self._dep_stack = [] 405 self._dep_disjunctive_stack = [] 406 self._unsatisfied_deps = [] 407 self._initially_unsatisfied_deps = [] 408 self._ignored_deps = [] 409 self._highest_pkg_cache = {} 410 411 # Binary packages that have been rejected because their USE 412 # didn't match the user's config. It maps packages to a set 413 # of flags causing the rejection. 414 self.ignored_binaries = {} 415 416 self._needed_unstable_keywords = backtrack_parameters.needed_unstable_keywords 417 self._needed_p_mask_changes = backtrack_parameters.needed_p_mask_changes 418 self._needed_license_changes = backtrack_parameters.needed_license_changes 419 self._needed_use_config_changes = backtrack_parameters.needed_use_config_changes 420 self._runtime_pkg_mask = backtrack_parameters.runtime_pkg_mask 421 self._slot_operator_replace_installed = backtrack_parameters.slot_operator_replace_installed 422 self._prune_rebuilds = backtrack_parameters.prune_rebuilds 423 self._need_restart = False 424 # For conditions that always require user intervention, such as 425 # unsatisfied REQUIRED_USE (currently has no autounmask support). 426 self._skip_restart = False 427 self._backtrack_infos = {} 428 429 self._buildpkgonly_deps_unsatisfied = False 430 self._autounmask = depgraph._frozen_config.myopts.get('--autounmask') != 'n' 431 self._success_without_autounmask = False 432 self._traverse_ignored_deps = False 433 self._complete_mode = False 434 self._slot_operator_deps = {} 435 436 for myroot in depgraph._frozen_config.trees: 437 self.sets[myroot] = _depgraph_sets() 438 self._slot_pkg_map[myroot] = {} 439 vardb = depgraph._frozen_config.trees[myroot]["vartree"].dbapi 440 # This dbapi instance will model the state that the vdb will 441 # have after new packages have been installed. 442 fakedb = PackageVirtualDbapi(vardb.settings) 443 444 self.mydbapi[myroot] = fakedb 445 def graph_tree(): 446 pass
447 graph_tree.dbapi = fakedb 448 self._graph_trees[myroot] = {} 449 self._filtered_trees[myroot] = {} 450 # Substitute the graph tree for the vartree in dep_check() since we 451 # want atom selections to be consistent with package selections 452 # have already been made. 453 self._graph_trees[myroot]["porttree"] = graph_tree 454 self._graph_trees[myroot]["vartree"] = graph_tree 455 self._graph_trees[myroot]["graph_db"] = graph_tree.dbapi 456 self._graph_trees[myroot]["graph"] = self.digraph 457 def filtered_tree(): 458 pass
459 filtered_tree.dbapi = _dep_check_composite_db(depgraph, myroot) 460 self._filtered_trees[myroot]["porttree"] = filtered_tree 461 self._visible_pkgs[myroot] = PackageVirtualDbapi(vardb.settings) 462 463 # Passing in graph_tree as the vartree here could lead to better 464 # atom selections in some cases by causing atoms for packages that 465 # have been added to the graph to be preferred over other choices. 466 # However, it can trigger atom selections that result in 467 # unresolvable direct circular dependencies. For example, this 468 # happens with gwydion-dylan which depends on either itself or 469 # gwydion-dylan-bin. In case gwydion-dylan is not yet installed, 470 # gwydion-dylan-bin needs to be selected in order to avoid a 471 # an unresolvable direct circular dependency. 472 # 473 # To solve the problem described above, pass in "graph_db" so that 474 # packages that have been added to the graph are distinguishable 475 # from other available packages and installed packages. Also, pass 476 # the parent package into self._select_atoms() calls so that 477 # unresolvable direct circular dependencies can be detected and 478 # avoided when possible. 479 self._filtered_trees[myroot]["graph_db"] = graph_tree.dbapi 480 self._filtered_trees[myroot]["graph"] = self.digraph 481 self._filtered_trees[myroot]["vartree"] = \ 482 depgraph._frozen_config.trees[myroot]["vartree"] 483 484 dbs = [] 485 # (db, pkg_type, built, installed, db_keys) 486 if "remove" in self.myparams: 487 # For removal operations, use _dep_check_composite_db 488 # for availability and visibility checks. This provides 489 # consistency with install operations, so we don't 490 # get install/uninstall cycles like in bug #332719. 491 self._graph_trees[myroot]["porttree"] = filtered_tree 492 else: 493 if "--usepkgonly" not in depgraph._frozen_config.myopts: 494 portdb = depgraph._frozen_config.trees[myroot]["porttree"].dbapi 495 db_keys = list(portdb._aux_cache_keys) 496 dbs.append((portdb, "ebuild", False, False, db_keys)) 497 498 if "--usepkg" in depgraph._frozen_config.myopts: 499 bindb = depgraph._frozen_config.trees[myroot]["bintree"].dbapi 500 db_keys = list(bindb._aux_cache_keys) 501 dbs.append((bindb, "binary", True, False, db_keys)) 502 503 vardb = depgraph._frozen_config.trees[myroot]["vartree"].dbapi 504 db_keys = list(depgraph._frozen_config._trees_orig[myroot 505 ]["vartree"].dbapi._aux_cache_keys) 506 dbs.append((vardb, "installed", True, True, db_keys)) 507 self._filtered_trees[myroot]["dbs"] = dbs 508
509 -class depgraph(object):
510 511 pkg_tree_map = RootConfig.pkg_tree_map 512
513 - def __init__(self, settings, trees, myopts, myparams, spinner, 514 frozen_config=None, backtrack_parameters=BacktrackParameter(), allow_backtracking=False):
515 if frozen_config is None: 516 frozen_config = _frozen_depgraph_config(settings, trees, 517 myopts, spinner) 518 self._frozen_config = frozen_config 519 self._dynamic_config = _dynamic_depgraph_config(self, myparams, 520 allow_backtracking, backtrack_parameters) 521 self._rebuild = _rebuild_config(frozen_config, backtrack_parameters) 522 523 self._select_atoms = self._select_atoms_highest_available 524 self._select_package = self._select_pkg_highest_available 525 526 self._event_loop = (portage._internal_caller and 527 global_event_loop() or EventLoop(main=False))
528
529 - def _load_vdb(self):
530 """ 531 Load installed package metadata if appropriate. This used to be called 532 from the constructor, but that wasn't very nice since this procedure 533 is slow and it generates spinner output. So, now it's called on-demand 534 by various methods when necessary. 535 """ 536 537 if self._dynamic_config._vdb_loaded: 538 return 539 540 for myroot in self._frozen_config.trees: 541 542 dynamic_deps = self._dynamic_config.myparams.get( 543 "dynamic_deps", "y") != "n" 544 preload_installed_pkgs = \ 545 "--nodeps" not in self._frozen_config.myopts 546 547 fake_vartree = self._frozen_config.trees[myroot]["vartree"] 548 if not fake_vartree.dbapi: 549 # This needs to be called for the first depgraph, but not for 550 # backtracking depgraphs that share the same frozen_config. 551 fake_vartree.sync() 552 553 # FakeVartree.sync() populates virtuals, and we want 554 # self.pkgsettings to have them populated too. 555 self._frozen_config.pkgsettings[myroot] = \ 556 portage.config(clone=fake_vartree.settings) 557 558 if preload_installed_pkgs: 559 vardb = fake_vartree.dbapi 560 fakedb = self._dynamic_config._graph_trees[ 561 myroot]["vartree"].dbapi 562 563 if not dynamic_deps: 564 for pkg in vardb: 565 fakedb.cpv_inject(pkg) 566 else: 567 max_jobs = self._frozen_config.myopts.get("--jobs") 568 max_load = self._frozen_config.myopts.get("--load-average") 569 scheduler = TaskScheduler( 570 self._dynamic_deps_preload(fake_vartree, fakedb), 571 max_jobs=max_jobs, 572 max_load=max_load, 573 event_loop=fake_vartree._portdb._event_loop) 574 scheduler.start() 575 scheduler.wait() 576 577 self._dynamic_config._vdb_loaded = True
578
579 - def _dynamic_deps_preload(self, fake_vartree, fakedb):
580 portdb = fake_vartree._portdb 581 for pkg in fake_vartree.dbapi: 582 self._spinner_update() 583 fakedb.cpv_inject(pkg) 584 ebuild_path, repo_path = \ 585 portdb.findname2(pkg.cpv, myrepo=pkg.repo) 586 if ebuild_path is None: 587 fake_vartree.dynamic_deps_preload(pkg, None) 588 continue 589 metadata, ebuild_hash = portdb._pull_valid_cache( 590 pkg.cpv, ebuild_path, repo_path) 591 if metadata is not None: 592 fake_vartree.dynamic_deps_preload(pkg, metadata) 593 else: 594 proc = EbuildMetadataPhase(cpv=pkg.cpv, 595 ebuild_hash=ebuild_hash, 596 portdb=portdb, repo_path=repo_path, 597 settings=portdb.doebuild_settings) 598 proc.addExitListener( 599 self._dynamic_deps_proc_exit(pkg, fake_vartree)) 600 yield proc
601
602 - class _dynamic_deps_proc_exit(object):
603 604 __slots__ = ('_pkg', '_fake_vartree') 605
606 - def __init__(self, pkg, fake_vartree):
607 self._pkg = pkg 608 self._fake_vartree = fake_vartree
609
610 - def __call__(self, proc):
611 metadata = None 612 if proc.returncode == os.EX_OK: 613 metadata = proc.metadata 614 self._fake_vartree.dynamic_deps_preload(self._pkg, metadata)
615
616 - def _spinner_update(self):
617 if self._frozen_config.spinner: 618 self._frozen_config.spinner.update()
619
620 - def _show_ignored_binaries(self):
621 """ 622 Show binaries that have been ignored because their USE didn't 623 match the user's config. 624 """ 625 if not self._dynamic_config.ignored_binaries \ 626 or '--quiet' in self._frozen_config.myopts \ 627 or self._dynamic_config.myparams.get( 628 "binpkg_respect_use") in ("y", "n"): 629 return 630 631 for pkg in list(self._dynamic_config.ignored_binaries): 632 633 selected_pkg = self._dynamic_config.mydbapi[pkg.root 634 ].match_pkgs(pkg.slot_atom) 635 636 if not selected_pkg: 637 continue 638 639 selected_pkg = selected_pkg[-1] 640 if selected_pkg > pkg: 641 self._dynamic_config.ignored_binaries.pop(pkg) 642 continue 643 644 if selected_pkg.installed and \ 645 selected_pkg.cpv == pkg.cpv and \ 646 selected_pkg.build_time == pkg.build_time: 647 # We don't care about ignored binaries when an 648 # identical installed instance is selected to 649 # fill the slot. 650 self._dynamic_config.ignored_binaries.pop(pkg) 651 continue 652 653 if not self._dynamic_config.ignored_binaries: 654 return 655 656 self._show_merge_list() 657 658 writemsg("\n!!! The following binary packages have been ignored " + \ 659 "due to non matching USE:\n\n", noiselevel=-1) 660 661 for pkg, flags in self._dynamic_config.ignored_binaries.items(): 662 flag_display = [] 663 for flag in sorted(flags): 664 if flag not in pkg.use.enabled: 665 flag = "-" + flag 666 flag_display.append(flag) 667 flag_display = " ".join(flag_display) 668 # The user can paste this line into package.use 669 writemsg(" =%s %s" % (pkg.cpv, flag_display), noiselevel=-1) 670 if pkg.root_config.settings["ROOT"] != "/": 671 writemsg(" # for %s" % (pkg.root,), noiselevel=-1) 672 writemsg("\n", noiselevel=-1) 673 674 msg = [ 675 "", 676 "NOTE: The --binpkg-respect-use=n option will prevent emerge", 677 " from ignoring these binary packages if possible.", 678 " Using --binpkg-respect-use=y will silence this warning." 679 ] 680 681 for line in msg: 682 if line: 683 line = colorize("INFORM", line) 684 writemsg(line + "\n", noiselevel=-1)
685
686 - def _get_missed_updates(self):
687 688 # In order to minimize noise, show only the highest 689 # missed update from each SLOT. 690 missed_updates = {} 691 for pkg, mask_reasons in \ 692 self._dynamic_config._runtime_pkg_mask.items(): 693 if pkg.installed: 694 # Exclude installed here since we only 695 # want to show available updates. 696 continue 697 chosen_pkg = self._dynamic_config.mydbapi[pkg.root 698 ].match_pkgs(pkg.slot_atom) 699 if not chosen_pkg or chosen_pkg[-1] >= pkg: 700 continue 701 k = (pkg.root, pkg.slot_atom) 702 if k in missed_updates: 703 other_pkg, mask_type, parent_atoms = missed_updates[k] 704 if other_pkg > pkg: 705 continue 706 for mask_type, parent_atoms in mask_reasons.items(): 707 if not parent_atoms: 708 continue 709 missed_updates[k] = (pkg, mask_type, parent_atoms) 710 break 711 712 return missed_updates
713
714 - def _show_missed_update(self):
715 716 missed_updates = self._get_missed_updates() 717 718 if not missed_updates: 719 return 720 721 missed_update_types = {} 722 for pkg, mask_type, parent_atoms in missed_updates.values(): 723 missed_update_types.setdefault(mask_type, 724 []).append((pkg, parent_atoms)) 725 726 if '--quiet' in self._frozen_config.myopts and \ 727 '--debug' not in self._frozen_config.myopts: 728 missed_update_types.pop("slot conflict", None) 729 missed_update_types.pop("missing dependency", None) 730 731 self._show_missed_update_slot_conflicts( 732 missed_update_types.get("slot conflict")) 733 734 self._show_missed_update_unsatisfied_dep( 735 missed_update_types.get("missing dependency"))
736
737 - def _show_missed_update_unsatisfied_dep(self, missed_updates):
738 739 if not missed_updates: 740 return 741 742 self._show_merge_list() 743 backtrack_masked = [] 744 745 for pkg, parent_atoms in missed_updates: 746 747 try: 748 for parent, root, atom in parent_atoms: 749 self._show_unsatisfied_dep(root, atom, myparent=parent, 750 check_backtrack=True) 751 except self._backtrack_mask: 752 # This is displayed below in abbreviated form. 753 backtrack_masked.append((pkg, parent_atoms)) 754 continue 755 756 writemsg("\n!!! The following update has been skipped " + \ 757 "due to unsatisfied dependencies:\n\n", noiselevel=-1) 758 759 writemsg(str(pkg.slot_atom), noiselevel=-1) 760 if pkg.root_config.settings["ROOT"] != "/": 761 writemsg(" for %s" % (pkg.root,), noiselevel=-1) 762 writemsg("\n", noiselevel=-1) 763 764 for parent, root, atom in parent_atoms: 765 self._show_unsatisfied_dep(root, atom, myparent=parent) 766 writemsg("\n", noiselevel=-1) 767 768 if backtrack_masked: 769 # These are shown in abbreviated form, in order to avoid terminal 770 # flooding from mask messages as reported in bug #285832. 771 writemsg("\n!!! The following update(s) have been skipped " + \ 772 "due to unsatisfied dependencies\n" + \ 773 "!!! triggered by backtracking:\n\n", noiselevel=-1) 774 for pkg, parent_atoms in backtrack_masked: 775 writemsg(str(pkg.slot_atom), noiselevel=-1) 776 if pkg.root_config.settings["ROOT"] != "/": 777 writemsg(" for %s" % (pkg.root,), noiselevel=-1) 778 writemsg("\n", noiselevel=-1)
779
780 - def _show_missed_update_slot_conflicts(self, missed_updates):
781 782 if not missed_updates: 783 return 784 785 self._show_merge_list() 786 msg = [] 787 msg.append("\nWARNING: One or more updates have been " + \ 788 "skipped due to a dependency conflict:\n\n") 789 790 indent = " " 791 for pkg, parent_atoms in missed_updates: 792 msg.append(str(pkg.slot_atom)) 793 if pkg.root_config.settings["ROOT"] != "/": 794 msg.append(" for %s" % (pkg.root,)) 795 msg.append("\n\n") 796 797 for parent, atom in parent_atoms: 798 msg.append(indent) 799 msg.append(str(pkg)) 800 801 msg.append(" conflicts with\n") 802 msg.append(2*indent) 803 if isinstance(parent, 804 (PackageArg, AtomArg)): 805 # For PackageArg and AtomArg types, it's 806 # redundant to display the atom attribute. 807 msg.append(str(parent)) 808 else: 809 # Display the specific atom from SetArg or 810 # Package types. 811 msg.append("%s required by %s" % (atom, parent)) 812 msg.append("\n") 813 msg.append("\n") 814 815 writemsg("".join(msg), noiselevel=-1)
816
818 """Show an informational message advising the user to mask one of the 819 the packages. In some cases it may be possible to resolve this 820 automatically, but support for backtracking (removal nodes that have 821 already been selected) will be required in order to handle all possible 822 cases. 823 """ 824 825 if not self._dynamic_config._slot_collision_info: 826 return 827 828 self._show_merge_list() 829 830 self._dynamic_config._slot_conflict_handler = slot_conflict_handler(self) 831 handler = self._dynamic_config._slot_conflict_handler 832 833 conflict = handler.get_conflict() 834 writemsg(conflict, noiselevel=-1) 835 836 explanation = handler.get_explanation() 837 if explanation: 838 writemsg(explanation, noiselevel=-1) 839 return 840 841 if "--quiet" in self._frozen_config.myopts: 842 return 843 844 msg = [] 845 msg.append("It may be possible to solve this problem ") 846 msg.append("by using package.mask to prevent one of ") 847 msg.append("those packages from being selected. ") 848 msg.append("However, it is also possible that conflicting ") 849 msg.append("dependencies exist such that they are impossible to ") 850 msg.append("satisfy simultaneously. If such a conflict exists in ") 851 msg.append("the dependencies of two different packages, then those ") 852 msg.append("packages can not be installed simultaneously.") 853 backtrack_opt = self._frozen_config.myopts.get('--backtrack') 854 if not self._dynamic_config._allow_backtracking and \ 855 (backtrack_opt is None or \ 856 (backtrack_opt > 0 and backtrack_opt < 30)): 857 msg.append(" You may want to try a larger value of the ") 858 msg.append("--backtrack option, such as --backtrack=30, ") 859 msg.append("in order to see if that will solve this conflict ") 860 msg.append("automatically.") 861 862 for line in textwrap.wrap(''.join(msg), 70): 863 writemsg(line + '\n', noiselevel=-1) 864 writemsg('\n', noiselevel=-1) 865 866 msg = [] 867 msg.append("For more information, see MASKED PACKAGES ") 868 msg.append("section in the emerge man page or refer ") 869 msg.append("to the Gentoo Handbook.") 870 for line in textwrap.wrap(''.join(msg), 70): 871 writemsg(line + '\n', noiselevel=-1) 872 writemsg('\n', noiselevel=-1)
873
874 - def _process_slot_conflicts(self):
875 """ 876 If there are any slot conflicts and backtracking is enabled, 877 _complete_graph should complete the graph before this method 878 is called, so that all relevant reverse dependencies are 879 available for use in backtracking decisions. 880 """ 881 for (slot_atom, root), slot_nodes in \ 882 self._dynamic_config._slot_collision_info.items(): 883 self._process_slot_conflict(root, slot_atom, slot_nodes)
884
885 - def _process_slot_conflict(self, root, slot_atom, slot_nodes):
886 """ 887 Process slot conflict data to identify specific atoms which 888 lead to conflict. These atoms only match a subset of the 889 packages that have been pulled into a given slot. 890 """ 891 892 debug = "--debug" in self._frozen_config.myopts 893 894 slot_parent_atoms = set() 895 for pkg in slot_nodes: 896 parent_atoms = self._dynamic_config._parent_atoms.get(pkg) 897 if not parent_atoms: 898 continue 899 slot_parent_atoms.update(parent_atoms) 900 901 conflict_pkgs = [] 902 conflict_atoms = {} 903 for pkg in slot_nodes: 904 905 if self._dynamic_config._allow_backtracking and \ 906 pkg in self._dynamic_config._runtime_pkg_mask: 907 if debug: 908 writemsg_level( 909 "!!! backtracking loop detected: %s %s\n" % \ 910 (pkg, 911 self._dynamic_config._runtime_pkg_mask[pkg]), 912 level=logging.DEBUG, noiselevel=-1) 913 914 parent_atoms = self._dynamic_config._parent_atoms.get(pkg) 915 if parent_atoms is None: 916 parent_atoms = set() 917 self._dynamic_config._parent_atoms[pkg] = parent_atoms 918 919 all_match = True 920 for parent_atom in slot_parent_atoms: 921 if parent_atom in parent_atoms: 922 continue 923 # Use package set for matching since it will match via 924 # PROVIDE when necessary, while match_from_list does not. 925 parent, atom = parent_atom 926 atom_set = InternalPackageSet( 927 initial_atoms=(atom,), allow_repo=True) 928 if atom_set.findAtomForPackage(pkg, 929 modified_use=self._pkg_use_enabled(pkg)): 930 parent_atoms.add(parent_atom) 931 else: 932 all_match = False 933 conflict_atoms.setdefault(parent_atom, set()).add(pkg) 934 935 if not all_match: 936 conflict_pkgs.append(pkg) 937 938 if conflict_pkgs and \ 939 self._dynamic_config._allow_backtracking and \ 940 not self._accept_blocker_conflicts(): 941 remaining = [] 942 for pkg in conflict_pkgs: 943 if self._slot_conflict_backtrack_abi(pkg, 944 slot_nodes, conflict_atoms): 945 backtrack_infos = self._dynamic_config._backtrack_infos 946 config = backtrack_infos.setdefault("config", {}) 947 config.setdefault("slot_conflict_abi", set()).add(pkg) 948 else: 949 remaining.append(pkg) 950 if remaining: 951 self._slot_confict_backtrack(root, slot_atom, 952 slot_parent_atoms, remaining)
953
954 - def _slot_confict_backtrack(self, root, slot_atom, 955 all_parents, conflict_pkgs):
956 957 debug = "--debug" in self._frozen_config.myopts 958 existing_node = self._dynamic_config._slot_pkg_map[root][slot_atom] 959 backtrack_data = [] 960 # The ordering of backtrack_data can make 961 # a difference here, because both mask actions may lead 962 # to valid, but different, solutions and the one with 963 # 'existing_node' masked is usually the better one. Because 964 # of that, we choose an order such that 965 # the backtracker will first explore the choice with 966 # existing_node masked. The backtracker reverses the 967 # order, so the order it uses is the reverse of the 968 # order shown here. See bug #339606. 969 if existing_node in conflict_pkgs and \ 970 existing_node is not conflict_pkgs[-1]: 971 conflict_pkgs.remove(existing_node) 972 conflict_pkgs.append(existing_node) 973 for to_be_masked in conflict_pkgs: 974 # For missed update messages, find out which 975 # atoms matched to_be_selected that did not 976 # match to_be_masked. 977 parent_atoms = \ 978 self._dynamic_config._parent_atoms.get(to_be_masked, set()) 979 conflict_atoms = set(parent_atom for parent_atom in all_parents \ 980 if parent_atom not in parent_atoms) 981 backtrack_data.append((to_be_masked, conflict_atoms)) 982 983 if len(backtrack_data) > 1: 984 # NOTE: Generally, we prefer to mask the higher 985 # version since this solves common cases in which a 986 # lower version is needed so that all dependencies 987 # will be satisfied (bug #337178). However, if 988 # existing_node happens to be installed then we 989 # mask that since this is a common case that is 990 # triggered when --update is not enabled. 991 if existing_node.installed: 992 pass 993 elif any(pkg > existing_node for pkg in conflict_pkgs): 994 backtrack_data.reverse() 995 996 to_be_masked = backtrack_data[-1][0] 997 998 self._dynamic_config._backtrack_infos.setdefault( 999 "slot conflict", []).append(backtrack_data) 1000 self._dynamic_config._need_restart = True 1001 if debug: 1002 msg = [] 1003 msg.append("") 1004 msg.append("") 1005 msg.append("backtracking due to slot conflict:") 1006 msg.append(" first package: %s" % existing_node) 1007 msg.append(" package to mask: %s" % to_be_masked) 1008 msg.append(" slot: %s" % slot_atom) 1009 msg.append(" parents: %s" % ", ".join( \ 1010 "(%s, '%s')" % (ppkg, atom) for ppkg, atom in all_parents)) 1011 msg.append("") 1012 writemsg_level("".join("%s\n" % l for l in msg), 1013 noiselevel=-1, level=logging.DEBUG)
1014
1015 - def _slot_conflict_backtrack_abi(self, pkg, slot_nodes, conflict_atoms):
1016 """ 1017 If one or more conflict atoms have a slot/sub-slot dep that can be resolved 1018 by rebuilding the parent package, then schedule the rebuild via 1019 backtracking, and return True. Otherwise, return False. 1020 """ 1021 1022 found_update = False 1023 for parent_atom, conflict_pkgs in conflict_atoms.items(): 1024 parent, atom = parent_atom 1025 if atom.slot_operator != "=" or not parent.built: 1026 continue 1027 1028 if pkg not in conflict_pkgs: 1029 continue 1030 1031 for other_pkg in slot_nodes: 1032 if other_pkg in conflict_pkgs: 1033 continue 1034 1035 dep = Dependency(atom=atom, child=other_pkg, 1036 parent=parent, root=pkg.root) 1037 1038 new_dep = \ 1039 self._slot_operator_update_probe_slot_conflict(dep) 1040 if new_dep is not None: 1041 self._slot_operator_update_backtrack(dep, 1042 new_dep=new_dep) 1043 found_update = True 1044 1045 return found_update
1046
1047 - def _slot_change_probe(self, dep):
1048 """ 1049 @rtype: bool 1050 @return: True if dep.child should be rebuilt due to a change 1051 in sub-slot (without revbump, as in bug #456208). 1052 """ 1053 if not (isinstance(dep.parent, Package) and \ 1054 not dep.parent.built and dep.child.built): 1055 return None 1056 1057 root_config = self._frozen_config.roots[dep.root] 1058 matches = [] 1059 try: 1060 matches.append(self._pkg(dep.child.cpv, "ebuild", 1061 root_config, myrepo=dep.child.repo)) 1062 except PackageNotFound: 1063 pass 1064 1065 for unbuilt_child in chain(matches, 1066 self._iter_match_pkgs(root_config, "ebuild", 1067 Atom("=%s" % (dep.child.cpv,)))): 1068 if unbuilt_child in self._dynamic_config._runtime_pkg_mask: 1069 continue 1070 if self._frozen_config.excluded_pkgs.findAtomForPackage( 1071 unbuilt_child, 1072 modified_use=self._pkg_use_enabled(unbuilt_child)): 1073 continue 1074 if not self._pkg_visibility_check(unbuilt_child): 1075 continue 1076 break 1077 else: 1078 return None 1079 1080 if unbuilt_child.slot == dep.child.slot and \ 1081 unbuilt_child.sub_slot == dep.child.sub_slot: 1082 return None 1083 1084 return unbuilt_child
1085
1086 - def _slot_change_backtrack(self, dep, new_child_slot):
1087 child = dep.child 1088 if "--debug" in self._frozen_config.myopts: 1089 msg = [] 1090 msg.append("") 1091 msg.append("") 1092 msg.append("backtracking due to slot/sub-slot change:") 1093 msg.append(" child package: %s" % child) 1094 msg.append(" child slot: %s/%s" % 1095 (child.slot, child.sub_slot)) 1096 msg.append(" new child: %s" % new_child_slot) 1097 msg.append(" new child slot: %s/%s" % 1098 (new_child_slot.slot, new_child_slot.sub_slot)) 1099 msg.append(" parent package: %s" % dep.parent) 1100 msg.append(" atom: %s" % dep.atom) 1101 msg.append("") 1102 writemsg_level("\n".join(msg), 1103 noiselevel=-1, level=logging.DEBUG) 1104 backtrack_infos = self._dynamic_config._backtrack_infos 1105 config = backtrack_infos.setdefault("config", {}) 1106 1107 # mask unwanted binary packages if necessary 1108 masks = {} 1109 if not child.installed: 1110 masks.setdefault(dep.child, {})["slot_operator_mask_built"] = None 1111 if masks: 1112 config.setdefault("slot_operator_mask_built", {}).update(masks) 1113 1114 # trigger replacement of installed packages if necessary 1115 reinstalls = set() 1116 if child.installed: 1117 replacement_atom = self._replace_installed_atom(child) 1118 if replacement_atom is not None: 1119 reinstalls.add((child.root, replacement_atom)) 1120 if reinstalls: 1121 config.setdefault("slot_operator_replace_installed", 1122 set()).update(reinstalls) 1123 1124 self._dynamic_config._need_restart = True
1125
1126 - def _slot_operator_update_backtrack(self, dep, new_child_slot=None, 1127 new_dep=None):
1128 if new_child_slot is None: 1129 child = dep.child 1130 else: 1131 child = new_child_slot 1132 if "--debug" in self._frozen_config.myopts: 1133 msg = [] 1134 msg.append("") 1135 msg.append("") 1136 msg.append("backtracking due to missed slot abi update:") 1137 msg.append(" child package: %s" % child) 1138 if new_child_slot is not None: 1139 msg.append(" new child slot package: %s" % new_child_slot) 1140 msg.append(" parent package: %s" % dep.parent) 1141 if new_dep is not None: 1142 msg.append(" new parent pkg: %s" % new_dep.parent) 1143 msg.append(" atom: %s" % dep.atom) 1144 msg.append("") 1145 writemsg_level("\n".join(msg), 1146 noiselevel=-1, level=logging.DEBUG) 1147 backtrack_infos = self._dynamic_config._backtrack_infos 1148 config = backtrack_infos.setdefault("config", {}) 1149 1150 # mask unwanted binary packages if necessary 1151 abi_masks = {} 1152 if new_child_slot is None: 1153 if not child.installed: 1154 abi_masks.setdefault(child, {})["slot_operator_mask_built"] = None 1155 if not dep.parent.installed: 1156 abi_masks.setdefault(dep.parent, {})["slot_operator_mask_built"] = None 1157 if abi_masks: 1158 config.setdefault("slot_operator_mask_built", {}).update(abi_masks) 1159 1160 # trigger replacement of installed packages if necessary 1161 abi_reinstalls = set() 1162 if dep.parent.installed: 1163 if new_dep is not None: 1164 replacement_atom = new_dep.parent.slot_atom 1165 else: 1166 replacement_atom = self._replace_installed_atom(dep.parent) 1167 if replacement_atom is not None: 1168 abi_reinstalls.add((dep.parent.root, replacement_atom)) 1169 if new_child_slot is None and child.installed: 1170 replacement_atom = self._replace_installed_atom(child) 1171 if replacement_atom is not None: 1172 abi_reinstalls.add((child.root, replacement_atom)) 1173 if abi_reinstalls: 1174 config.setdefault("slot_operator_replace_installed", 1175 set()).update(abi_reinstalls) 1176 1177 self._dynamic_config._need_restart = True
1178
1180 new_dep = self._slot_operator_update_probe(dep, slot_conflict=True) 1181 1182 if new_dep is not None: 1183 return new_dep 1184 1185 if self._dynamic_config._autounmask is True: 1186 1187 for autounmask_level in self._autounmask_levels(): 1188 1189 new_dep = self._slot_operator_update_probe(dep, 1190 slot_conflict=True, autounmask_level=autounmask_level) 1191 1192 if new_dep is not None: 1193 return new_dep 1194 1195 return None
1196
1197 - def _slot_operator_update_probe(self, dep, new_child_slot=False, 1198 slot_conflict=False, autounmask_level=None):
1199 """ 1200 slot/sub-slot := operators tend to prevent updates from getting pulled in, 1201 since installed packages pull in packages with the slot/sub-slot that they 1202 were built against. Detect this case so that we can schedule rebuilds 1203 and reinstalls when appropriate. 1204 NOTE: This function only searches for updates that involve upgrades 1205 to higher versions, since the logic required to detect when a 1206 downgrade would be desirable is not implemented. 1207 """ 1208 1209 if dep.child.installed and \ 1210 self._frozen_config.excluded_pkgs.findAtomForPackage(dep.child, 1211 modified_use=self._pkg_use_enabled(dep.child)): 1212 return None 1213 1214 if dep.parent.installed and \ 1215 self._frozen_config.excluded_pkgs.findAtomForPackage(dep.parent, 1216 modified_use=self._pkg_use_enabled(dep.parent)): 1217 return None 1218 1219 debug = "--debug" in self._frozen_config.myopts 1220 selective = "selective" in self._dynamic_config.myparams 1221 want_downgrade = None 1222 1223 for replacement_parent in self._iter_similar_available(dep.parent, 1224 dep.parent.slot_atom, autounmask_level=autounmask_level): 1225 1226 selected_atoms = None 1227 1228 for atom in replacement_parent.validated_atoms: 1229 if not atom.slot_operator == "=" or \ 1230 atom.blocker or \ 1231 atom.cp != dep.atom.cp: 1232 continue 1233 1234 # Discard USE deps, we're only searching for an approximate 1235 # pattern, and dealing with USE states is too complex for 1236 # this purpose. 1237 unevaluated_atom = atom.unevaluated_atom 1238 atom = atom.without_use 1239 1240 if replacement_parent.built and \ 1241 portage.dep._match_slot(atom, dep.child): 1242 # Our selected replacement_parent appears to be built 1243 # for the existing child selection. So, discard this 1244 # parent and search for another. 1245 break 1246 1247 for pkg in self._iter_similar_available( 1248 dep.child, atom): 1249 if pkg.slot == dep.child.slot and \ 1250 pkg.sub_slot == dep.child.sub_slot: 1251 # If slot/sub-slot is identical, then there's 1252 # no point in updating. 1253 continue 1254 if new_child_slot: 1255 if pkg.slot == dep.child.slot: 1256 continue 1257 if pkg < dep.child: 1258 # the new slot only matters if the 1259 # package version is higher 1260 continue 1261 else: 1262 if pkg.slot != dep.child.slot: 1263 continue 1264 if pkg < dep.child: 1265 if want_downgrade is None: 1266 want_downgrade = self._downgrade_probe(dep.child) 1267 # be careful not to trigger a rebuild when 1268 # the only version available with a 1269 # different slot_operator is an older version 1270 if not want_downgrade: 1271 continue 1272 1273 insignificant = False 1274 if not slot_conflict and \ 1275 selective and \ 1276 dep.parent.installed and \ 1277 dep.child.installed and \ 1278 dep.parent.cpv == replacement_parent.cpv and \ 1279 dep.child.cpv == pkg.cpv: 1280 # Then can happen if the child's sub-slot changed 1281 # without a revision bump. The sub-slot change is 1282 # considered insignificant until one of its parent 1283 # packages needs to be rebuilt (which may trigger a 1284 # slot conflict). 1285 insignificant = True 1286 1287 if not insignificant: 1288 # Evaluate USE conditionals and || deps, in order 1289 # to see if this atom is really desirable, since 1290 # otherwise we may trigger an undesirable rebuild 1291 # as in bug #460304. 1292 if selected_atoms is None: 1293 selected_atoms = self._select_atoms_probe( 1294 dep.child.root, replacement_parent) 1295 if unevaluated_atom not in selected_atoms: 1296 continue 1297 1298 if debug: 1299 msg = [] 1300 msg.append("") 1301 msg.append("") 1302 msg.append("slot_operator_update_probe:") 1303 msg.append(" existing child package: %s" % dep.child) 1304 msg.append(" existing parent package: %s" % dep.parent) 1305 msg.append(" new child package: %s" % pkg) 1306 msg.append(" new parent package: %s" % replacement_parent) 1307 if insignificant: 1308 msg.append("insignificant changes detected") 1309 msg.append("") 1310 writemsg_level("\n".join(msg), 1311 noiselevel=-1, level=logging.DEBUG) 1312 1313 if insignificant: 1314 return None 1315 1316 return Dependency(parent=replacement_parent, 1317 child=pkg, atom=unevaluated_atom) 1318 1319 if debug: 1320 msg = [] 1321 msg.append("") 1322 msg.append("") 1323 msg.append("slot_operator_update_probe:") 1324 msg.append(" existing child package: %s" % dep.child) 1325 msg.append(" existing parent package: %s" % dep.parent) 1326 msg.append(" new child package: %s" % None) 1327 msg.append(" new parent package: %s" % None) 1328 msg.append("") 1329 writemsg_level("\n".join(msg), 1330 noiselevel=-1, level=logging.DEBUG) 1331 1332 return None
1333
1334 - def _slot_operator_unsatisfied_probe(self, dep):
1335 1336 if dep.parent.installed and \ 1337 self._frozen_config.excluded_pkgs.findAtomForPackage(dep.parent, 1338 modified_use=self._pkg_use_enabled(dep.parent)): 1339 return False 1340 1341 debug = "--debug" in self._frozen_config.myopts 1342 1343 for replacement_parent in self._iter_similar_available(dep.parent, 1344 dep.parent.slot_atom): 1345 1346 for atom in replacement_parent.validated_atoms: 1347 if not atom.slot_operator == "=" or \ 1348 atom.blocker or \ 1349 atom.cp != dep.atom.cp: 1350 continue 1351 1352 # Discard USE deps, we're only searching for an approximate 1353 # pattern, and dealing with USE states is too complex for 1354 # this purpose. 1355 atom = atom.without_use 1356 1357 pkg, existing_node = self._select_package(dep.root, atom, 1358 onlydeps=dep.onlydeps) 1359 1360 if pkg is not None: 1361 1362 if debug: 1363 msg = [] 1364 msg.append("") 1365 msg.append("") 1366 msg.append("slot_operator_unsatisfied_probe:") 1367 msg.append(" existing parent package: %s" % dep.parent) 1368 msg.append(" existing parent atom: %s" % dep.atom) 1369 msg.append(" new parent package: %s" % replacement_parent) 1370 msg.append(" new child package: %s" % pkg) 1371 msg.append("") 1372 writemsg_level("\n".join(msg), 1373 noiselevel=-1, level=logging.DEBUG) 1374 1375 return True 1376 1377 if debug: 1378 msg = [] 1379 msg.append("") 1380 msg.append("") 1381 msg.append("slot_operator_unsatisfied_probe:") 1382 msg.append(" existing parent package: %s" % dep.parent) 1383 msg.append(" existing parent atom: %s" % dep.atom) 1384 msg.append(" new parent package: %s" % None) 1385 msg.append(" new child package: %s" % None) 1386 msg.append("") 1387 writemsg_level("\n".join(msg), 1388 noiselevel=-1, level=logging.DEBUG) 1389 1390 return False
1391
1393 1394 parent = dep.parent 1395 1396 if "--debug" in self._frozen_config.myopts: 1397 msg = [] 1398 msg.append("") 1399 msg.append("") 1400 msg.append("backtracking due to unsatisfied " 1401 "built slot-operator dep:") 1402 msg.append(" parent package: %s" % parent) 1403 msg.append(" atom: %s" % dep.atom) 1404 msg.append("") 1405 writemsg_level("\n".join(msg), 1406 noiselevel=-1, level=logging.DEBUG) 1407 1408 backtrack_infos = self._dynamic_config._backtrack_infos 1409 config = backtrack_infos.setdefault("config", {}) 1410 1411 # mask unwanted binary packages if necessary 1412 masks = {} 1413 if not parent.installed: 1414 masks.setdefault(parent, {})["slot_operator_mask_built"] = None 1415 if masks: 1416 config.setdefault("slot_operator_mask_built", {}).update(masks) 1417 1418 # trigger replacement of installed packages if necessary 1419 reinstalls = set() 1420 if parent.installed: 1421 replacement_atom = self._replace_installed_atom(parent) 1422 if replacement_atom is not None: 1423 reinstalls.add((parent.root, replacement_atom)) 1424 if reinstalls: 1425 config.setdefault("slot_operator_replace_installed", 1426 set()).update(reinstalls) 1427 1428 self._dynamic_config._need_restart = True
1429
1430 - def _downgrade_probe(self, pkg):
1431 """ 1432 Detect cases where a downgrade of the given package is considered 1433 desirable due to the current version being masked or unavailable. 1434 """ 1435 available_pkg = None 1436 for available_pkg in self._iter_similar_available(pkg, 1437 pkg.slot_atom): 1438 if available_pkg >= pkg: 1439 # There's an available package of the same or higher 1440 # version, so downgrade seems undesirable. 1441 return False 1442 1443 return available_pkg is not None
1444
1445 - def _select_atoms_probe(self, root, pkg):
1446 selected_atoms = [] 1447 use = self._pkg_use_enabled(pkg) 1448 for k in pkg._dep_keys: 1449 v = pkg._metadata.get(k) 1450 if not v: 1451 continue 1452 selected_atoms.extend(self._select_atoms( 1453 root, v, myuse=use, parent=pkg)[pkg]) 1454 return frozenset(x.unevaluated_atom for 1455 x in selected_atoms)
1456
1457 - def _iter_similar_available(self, graph_pkg, atom, autounmask_level=None):
1458 """ 1459 Given a package that's in the graph, do a rough check to 1460 see if a similar package is available to install. The given 1461 graph_pkg itself may be yielded only if it's not installed. 1462 """ 1463 1464 usepkgonly = "--usepkgonly" in self._frozen_config.myopts 1465 useoldpkg_atoms = self._frozen_config.useoldpkg_atoms 1466 use_ebuild_visibility = self._frozen_config.myopts.get( 1467 '--use-ebuild-visibility', 'n') != 'n' 1468 1469 for pkg in self._iter_match_pkgs_any( 1470 graph_pkg.root_config, atom): 1471 if pkg.cp != graph_pkg.cp: 1472 # discard old-style virtual match 1473 continue 1474 if pkg.installed: 1475 continue 1476 if pkg in self._dynamic_config._runtime_pkg_mask: 1477 continue 1478 if self._frozen_config.excluded_pkgs.findAtomForPackage(pkg, 1479 modified_use=self._pkg_use_enabled(pkg)): 1480 continue 1481 if pkg.built: 1482 if self._equiv_binary_installed(pkg): 1483 continue 1484 if not (not use_ebuild_visibility and 1485 (usepkgonly or useoldpkg_atoms.findAtomForPackage( 1486 pkg, modified_use=self._pkg_use_enabled(pkg)))) and \ 1487 not self._equiv_ebuild_visible(pkg, 1488 autounmask_level=autounmask_level): 1489 continue 1490 if not self._pkg_visibility_check(pkg, 1491 autounmask_level=autounmask_level): 1492 continue 1493 yield pkg
1494
1495 - def _replace_installed_atom(self, inst_pkg):
1496 """ 1497 Given an installed package, generate an atom suitable for 1498 slot_operator_replace_installed backtracking info. The replacement 1499 SLOT may differ from the installed SLOT, so first search by cpv. 1500 """ 1501 built_pkgs = [] 1502 for pkg in self._iter_similar_available(inst_pkg, 1503 Atom("=%s" % inst_pkg.cpv)): 1504 if not pkg.built: 1505 return pkg.slot_atom 1506 elif not pkg.installed: 1507 # avoid using SLOT from a built instance 1508 built_pkgs.append(pkg) 1509 1510 for pkg in self._iter_similar_available(inst_pkg, inst_pkg.slot_atom): 1511 if not pkg.built: 1512 return pkg.slot_atom 1513 elif not pkg.installed: 1514 # avoid using SLOT from a built instance 1515 built_pkgs.append(pkg) 1516 1517 if built_pkgs: 1518 best_version = None 1519 for pkg in built_pkgs: 1520 if best_version is None or pkg > best_version: 1521 best_version = pkg 1522 return best_version.slot_atom 1523 1524 return None
1525
1527 """ 1528 Search for packages with slot-operator deps on older slots, and schedule 1529 rebuilds if they can link to a newer slot that's in the graph. 1530 """ 1531 1532 rebuild_if_new_slot = self._dynamic_config.myparams.get( 1533 "rebuild_if_new_slot", "y") == "y" 1534 1535 for slot_key, slot_info in self._dynamic_config._slot_operator_deps.items(): 1536 1537 for dep in slot_info: 1538 1539 atom = dep.atom 1540 if atom.slot_operator is None: 1541 continue 1542 1543 if not atom.slot_operator_built: 1544 new_child_slot = self._slot_change_probe(dep) 1545 if new_child_slot is not None: 1546 self._slot_change_backtrack(dep, new_child_slot) 1547 continue 1548 1549 if not (dep.parent and 1550 isinstance(dep.parent, Package) and dep.parent.built): 1551 continue 1552 1553 # Check for slot update first, since we don't want to 1554 # trigger reinstall of the child package when a newer 1555 # slot will be used instead. 1556 if rebuild_if_new_slot: 1557 new_dep = self._slot_operator_update_probe(dep, 1558 new_child_slot=True) 1559 if new_dep is not None: 1560 self._slot_operator_update_backtrack(dep, 1561 new_child_slot=new_dep.child) 1562 break 1563 1564 if dep.want_update: 1565 if self._slot_operator_update_probe(dep): 1566 self._slot_operator_update_backtrack(dep) 1567 break
1568
1569 - def _reinstall_for_flags(self, pkg, forced_flags, 1570 orig_use, orig_iuse, cur_use, cur_iuse):
1571 """Return a set of flags that trigger reinstallation, or None if there 1572 are no such flags.""" 1573 1574 # binpkg_respect_use: Behave like newuse by default. If newuse is 1575 # False and changed_use is True, then behave like changed_use. 1576 binpkg_respect_use = (pkg.built and 1577 self._dynamic_config.myparams.get("binpkg_respect_use") 1578 in ("y", "auto")) 1579 newuse = "--newuse" in self._frozen_config.myopts 1580 changed_use = "changed-use" == self._frozen_config.myopts.get("--reinstall") 1581 feature_flags = _get_feature_flags( 1582 _get_eapi_attrs(pkg.eapi)) 1583 1584 if newuse or (binpkg_respect_use and not changed_use): 1585 flags = set(orig_iuse.symmetric_difference( 1586 cur_iuse).difference(forced_flags)) 1587 flags.update(orig_iuse.intersection(orig_use).symmetric_difference( 1588 cur_iuse.intersection(cur_use))) 1589 flags.difference_update(feature_flags) 1590 if flags: 1591 return flags 1592 1593 elif changed_use or binpkg_respect_use: 1594 flags = set(orig_iuse.intersection(orig_use).symmetric_difference( 1595 cur_iuse.intersection(cur_use))) 1596 flags.difference_update(feature_flags) 1597 if flags: 1598 return flags 1599 return None
1600
1601 - def _create_graph(self, allow_unsatisfied=False):
1602 dep_stack = self._dynamic_config._dep_stack 1603 dep_disjunctive_stack = self._dynamic_config._dep_disjunctive_stack 1604 while dep_stack or dep_disjunctive_stack: 1605 self._spinner_update() 1606 while dep_stack: 1607 dep = dep_stack.pop() 1608 if isinstance(dep, Package): 1609 if not self._add_pkg_deps(dep, 1610 allow_unsatisfied=allow_unsatisfied): 1611 return 0 1612 continue 1613 if not self._add_dep(dep, allow_unsatisfied=allow_unsatisfied): 1614 return 0 1615 if dep_disjunctive_stack: 1616 if not self._pop_disjunction(allow_unsatisfied): 1617 return 0 1618 return 1
1619
1620 - def _expand_set_args(self, input_args, add_to_digraph=False):
1621 """ 1622 Iterate over a list of DependencyArg instances and yield all 1623 instances given in the input together with additional SetArg 1624 instances that are generated from nested sets. 1625 @param input_args: An iterable of DependencyArg instances 1626 @type input_args: Iterable 1627 @param add_to_digraph: If True then add SetArg instances 1628 to the digraph, in order to record parent -> child 1629 relationships from nested sets 1630 @type add_to_digraph: Boolean 1631 @rtype: Iterable 1632 @return: All args given in the input together with additional 1633 SetArg instances that are generated from nested sets 1634 """ 1635 1636 traversed_set_args = set() 1637 1638 for arg in input_args: 1639 if not isinstance(arg, SetArg): 1640 yield arg 1641 continue 1642 1643 root_config = arg.root_config 1644 depgraph_sets = self._dynamic_config.sets[root_config.root] 1645 arg_stack = [arg] 1646 while arg_stack: 1647 arg = arg_stack.pop() 1648 if arg in traversed_set_args: 1649 continue 1650 traversed_set_args.add(arg) 1651 1652 if add_to_digraph: 1653 self._dynamic_config.digraph.add(arg, None, 1654 priority=BlockerDepPriority.instance) 1655 1656 yield arg 1657 1658 # Traverse nested sets and add them to the stack 1659 # if they're not already in the graph. Also, graph 1660 # edges between parent and nested sets. 1661 for token in arg.pset.getNonAtoms(): 1662 if not token.startswith(SETPREFIX): 1663 continue 1664 s = token[len(SETPREFIX):] 1665 nested_set = depgraph_sets.sets.get(s) 1666 if nested_set is None: 1667 nested_set = root_config.sets.get(s) 1668 if nested_set is not None: 1669 nested_arg = SetArg(arg=token, pset=nested_set, 1670 root_config=root_config) 1671 arg_stack.append(nested_arg) 1672 if add_to_digraph: 1673 self._dynamic_config.digraph.add(nested_arg, arg, 1674 priority=BlockerDepPriority.instance) 1675 depgraph_sets.sets[nested_arg.name] = nested_arg.pset
1676
1677 - def _add_dep(self, dep, allow_unsatisfied=False):
1678 debug = "--debug" in self._frozen_config.myopts 1679 buildpkgonly = "--buildpkgonly" in self._frozen_config.myopts 1680 nodeps = "--nodeps" in self._frozen_config.myopts 1681 if dep.blocker: 1682 if not buildpkgonly and \ 1683 not nodeps and \ 1684 not dep.collapsed_priority.ignored and \ 1685 not dep.collapsed_priority.optional and \ 1686 dep.parent not in self._dynamic_config._slot_collision_nodes: 1687 if dep.parent.onlydeps: 1688 # It's safe to ignore blockers if the 1689 # parent is an --onlydeps node. 1690 return 1 1691 # The blocker applies to the root where 1692 # the parent is or will be installed. 1693 blocker = Blocker(atom=dep.atom, 1694 eapi=dep.parent.eapi, 1695 priority=dep.priority, root=dep.parent.root) 1696 self._dynamic_config._blocker_parents.add(blocker, dep.parent) 1697 return 1 1698 1699 if dep.child is None: 1700 dep_pkg, existing_node = self._select_package(dep.root, dep.atom, 1701 onlydeps=dep.onlydeps) 1702 else: 1703 # The caller has selected a specific package 1704 # via self._minimize_packages(). 1705 dep_pkg = dep.child 1706 existing_node = self._dynamic_config._slot_pkg_map[ 1707 dep.root].get(dep_pkg.slot_atom) 1708 1709 if not dep_pkg: 1710 if (dep.collapsed_priority.optional or 1711 dep.collapsed_priority.ignored): 1712 # This is an unnecessary build-time dep. 1713 return 1 1714 if allow_unsatisfied: 1715 self._dynamic_config._unsatisfied_deps.append(dep) 1716 return 1 1717 self._dynamic_config._unsatisfied_deps_for_display.append( 1718 ((dep.root, dep.atom), {"myparent":dep.parent})) 1719 1720 # The parent node should not already be in 1721 # runtime_pkg_mask, since that would trigger an 1722 # infinite backtracking loop. 1723 if self._dynamic_config._allow_backtracking: 1724 if dep.parent in self._dynamic_config._runtime_pkg_mask: 1725 if debug: 1726 writemsg( 1727 "!!! backtracking loop detected: %s %s\n" % \ 1728 (dep.parent, 1729 self._dynamic_config._runtime_pkg_mask[ 1730 dep.parent]), noiselevel=-1) 1731 elif dep.atom.slot_operator_built and \ 1732 self._slot_operator_unsatisfied_probe(dep): 1733 self._slot_operator_unsatisfied_backtrack(dep) 1734 return 1 1735 else: 1736 # Do not backtrack if only USE have to be changed in 1737 # order to satisfy the dependency. Note that when 1738 # want_restart_for_use_change sets the need_restart 1739 # flag, it causes _select_pkg_highest_available to 1740 # return None, and eventually we come through here 1741 # and skip the "missing dependency" backtracking path. 1742 dep_pkg, existing_node = \ 1743 self._select_package(dep.root, dep.atom.without_use, 1744 onlydeps=dep.onlydeps) 1745 if dep_pkg is None: 1746 self._dynamic_config._backtrack_infos["missing dependency"] = dep 1747 self._dynamic_config._need_restart = True 1748 if debug: 1749 msg = [] 1750 msg.append("") 1751 msg.append("") 1752 msg.append("backtracking due to unsatisfied dep:") 1753 msg.append(" parent: %s" % dep.parent) 1754 msg.append(" priority: %s" % dep.priority) 1755 msg.append(" root: %s" % dep.root) 1756 msg.append(" atom: %s" % dep.atom) 1757 msg.append("") 1758 writemsg_level("".join("%s\n" % l for l in msg), 1759 noiselevel=-1, level=logging.DEBUG) 1760 1761 return 0 1762 1763 self._rebuild.add(dep_pkg, dep) 1764 1765 ignore = dep.collapsed_priority.ignored and \ 1766 not self._dynamic_config._traverse_ignored_deps 1767 if not ignore and not self._add_pkg(dep_pkg, dep): 1768 return 0 1769 return 1
1770
1771 - def _check_slot_conflict(self, pkg, atom):
1772 existing_node = self._dynamic_config._slot_pkg_map[pkg.root].get(pkg.slot_atom) 1773 matches = None 1774 if existing_node: 1775 matches = pkg.cpv == existing_node.cpv 1776 if pkg != existing_node and \ 1777 atom is not None: 1778 # Use package set for matching since it will match via 1779 # PROVIDE when necessary, while match_from_list does not. 1780 matches = bool(InternalPackageSet(initial_atoms=(atom,), 1781 allow_repo=True).findAtomForPackage(existing_node, 1782 modified_use=self._pkg_use_enabled(existing_node))) 1783 1784 return (existing_node, matches)
1785
1786 - def _add_pkg(self, pkg, dep):
1787 """ 1788 Adds a package to the depgraph, queues dependencies, and handles 1789 slot conflicts. 1790 """ 1791 debug = "--debug" in self._frozen_config.myopts 1792 myparent = None 1793 priority = None 1794 depth = 0 1795 if dep is None: 1796 dep = Dependency() 1797 else: 1798 myparent = dep.parent 1799 priority = dep.priority 1800 depth = dep.depth 1801 if priority is None: 1802 priority = DepPriority() 1803 1804 if debug: 1805 writemsg_level( 1806 "\n%s%s %s\n" % ("Child:".ljust(15), pkg, 1807 pkg_use_display(pkg, self._frozen_config.myopts, 1808 modified_use=self._pkg_use_enabled(pkg))), 1809 level=logging.DEBUG, noiselevel=-1) 1810 if isinstance(myparent, 1811 (PackageArg, AtomArg)): 1812 # For PackageArg and AtomArg types, it's 1813 # redundant to display the atom attribute. 1814 writemsg_level( 1815 "%s%s\n" % ("Parent Dep:".ljust(15), myparent), 1816 level=logging.DEBUG, noiselevel=-1) 1817 else: 1818 # Display the specific atom from SetArg or 1819 # Package types. 1820 uneval = "" 1821 if dep.atom is not dep.atom.unevaluated_atom: 1822 uneval = " (%s)" % (dep.atom.unevaluated_atom,) 1823 writemsg_level( 1824 "%s%s%s required by %s\n" % 1825 ("Parent Dep:".ljust(15), dep.atom, uneval, myparent), 1826 level=logging.DEBUG, noiselevel=-1) 1827 1828 # Ensure that the dependencies of the same package 1829 # are never processed more than once. 1830 previously_added = pkg in self._dynamic_config.digraph 1831 1832 pkgsettings = self._frozen_config.pkgsettings[pkg.root] 1833 1834 arg_atoms = None 1835 if True: 1836 try: 1837 arg_atoms = list(self._iter_atoms_for_pkg(pkg)) 1838 except portage.exception.InvalidDependString as e: 1839 if not pkg.installed: 1840 # should have been masked before it was selected 1841 raise 1842 del e 1843 1844 # NOTE: REQUIRED_USE checks are delayed until after 1845 # package selection, since we want to prompt the user 1846 # for USE adjustment rather than have REQUIRED_USE 1847 # affect package selection and || dep choices. 1848 if not pkg.built and pkg._metadata.get("REQUIRED_USE") and \ 1849 eapi_has_required_use(pkg.eapi): 1850 required_use_is_sat = check_required_use( 1851 pkg._metadata["REQUIRED_USE"], 1852 self._pkg_use_enabled(pkg), 1853 pkg.iuse.is_valid_flag, 1854 eapi=pkg.eapi) 1855 if not required_use_is_sat: 1856 if dep.atom is not None and dep.parent is not None: 1857 self._add_parent_atom(pkg, (dep.parent, dep.atom)) 1858 1859 if arg_atoms: 1860 for parent_atom in arg_atoms: 1861 parent, atom = parent_atom 1862 self._add_parent_atom(pkg, parent_atom) 1863 1864 atom = dep.atom 1865 if atom is None: 1866 atom = Atom("=" + pkg.cpv) 1867 self._dynamic_config._unsatisfied_deps_for_display.append( 1868 ((pkg.root, atom), 1869 {"myparent" : dep.parent, "show_req_use" : pkg})) 1870 self._dynamic_config._skip_restart = True 1871 return 0 1872 1873 if not pkg.onlydeps: 1874 1875 existing_node, existing_node_matches = \ 1876 self._check_slot_conflict(pkg, dep.atom) 1877 slot_collision = False 1878 if existing_node: 1879 if existing_node_matches: 1880 # The existing node can be reused. 1881 if pkg != existing_node: 1882 pkg = existing_node 1883 previously_added = True 1884 try: 1885 arg_atoms = list(self._iter_atoms_for_pkg(pkg)) 1886 except InvalidDependString as e: 1887 if not pkg.installed: 1888 # should have been masked before 1889 # it was selected 1890 raise 1891 1892 if debug: 1893 writemsg_level( 1894 "%s%s %s\n" % ("Re-used Child:".ljust(15), 1895 pkg, pkg_use_display(pkg, 1896 self._frozen_config.myopts, 1897 modified_use=self._pkg_use_enabled(pkg))), 1898 level=logging.DEBUG, noiselevel=-1) 1899 1900 else: 1901 self._add_slot_conflict(pkg) 1902 if debug: 1903 writemsg_level( 1904 "%s%s %s\n" % ("Slot Conflict:".ljust(15), 1905 existing_node, pkg_use_display(existing_node, 1906 self._frozen_config.myopts, 1907 modified_use=self._pkg_use_enabled(existing_node))), 1908 level=logging.DEBUG, noiselevel=-1) 1909 1910 slot_collision = True 1911 1912 if slot_collision: 1913 # Now add this node to the graph so that self.display() 1914 # can show use flags and --tree portage.output. This node is 1915 # only being partially added to the graph. It must not be 1916 # allowed to interfere with the other nodes that have been 1917 # added. Do not overwrite data for existing nodes in 1918 # self._dynamic_config.mydbapi since that data will be used for blocker 1919 # validation. 1920 # Even though the graph is now invalid, continue to process 1921 # dependencies so that things like --fetchonly can still 1922 # function despite collisions. 1923 pass 1924 elif not previously_added: 1925 self._dynamic_config._slot_pkg_map[pkg.root][pkg.slot_atom] = pkg 1926 self._dynamic_config.mydbapi[pkg.root].cpv_inject(pkg) 1927 self._dynamic_config._filtered_trees[pkg.root]["porttree"].dbapi._clear_cache() 1928 self._dynamic_config._highest_pkg_cache.clear() 1929 self._check_masks(pkg) 1930 1931 if not pkg.installed: 1932 # Allow this package to satisfy old-style virtuals in case it 1933 # doesn't already. Any pre-existing providers will be preferred 1934 # over this one. 1935 try: 1936 pkgsettings.setinst(pkg.cpv, pkg._metadata) 1937 # For consistency, also update the global virtuals. 1938 settings = self._frozen_config.roots[pkg.root].settings 1939 settings.unlock() 1940 settings.setinst(pkg.cpv, pkg._metadata) 1941 settings.lock() 1942 except portage.exception.InvalidDependString: 1943 if not pkg.installed: 1944 # should have been masked before it was selected 1945 raise 1946 1947 if arg_atoms: 1948 self._dynamic_config._set_nodes.add(pkg) 1949 1950 # Do this even for onlydeps, so that the 1951 # parent/child relationship is always known in case 1952 # self._show_slot_collision_notice() needs to be called later. 1953 # If a direct circular dependency is not an unsatisfied 1954 # buildtime dependency then drop it here since otherwise 1955 # it can skew the merge order calculation in an unwanted 1956 # way. 1957 if pkg != dep.parent or \ 1958 (