# Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import sys import portage from portage import os from portage import digraph from portage._sets.base import InternalPackageSet from portage.dep import Atom from _emerge.BlockerCache import BlockerCache from _emerge.Package import Package from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice if sys.hexversion >= 0x3000000: long = int class BlockerDB(object): def __init__(self, fake_vartree): root_config = fake_vartree._root_config self._root_config = root_config self._vartree = root_config.trees["vartree"] self._portdb = root_config.trees["porttree"].dbapi self._dep_check_trees = None self._fake_vartree = fake_vartree self._dep_check_trees = { self._vartree.settings["EROOT"] : { "porttree" : fake_vartree, "vartree" : fake_vartree, }} def findInstalledBlockers(self, new_pkg): """ Search for installed run-time blockers in the root where new_pkg is planned to be installed. This ignores build-time blockers, since new_pkg is assumed to be built already. """ blocker_cache = BlockerCache(None, self._vartree.dbapi) dep_keys = Package._runtime_keys settings = self._vartree.settings stale_cache = set(blocker_cache) fake_vartree = self._fake_vartree dep_check_trees = self._dep_check_trees vardb = fake_vartree.dbapi installed_pkgs = list(vardb) for inst_pkg in installed_pkgs: stale_cache.discard(inst_pkg.cpv) cached_blockers = blocker_cache.get(inst_pkg.cpv) if cached_blockers is not None and \ cached_blockers.counter != inst_pkg.counter: cached_blockers = None if cached_blockers is not None: blocker_atoms = cached_blockers.atoms else: # Use aux_get() to trigger FakeVartree global # updates on *DEPEND when appropriate. depstr = " ".join(vardb.aux_get(inst_pkg.cpv, dep_keys)) success, atoms = portage.dep_check(depstr, vardb, settings, myuse=inst_pkg.use.enabled, trees=dep_check_trees, myroot=inst_pkg.root) if not success: pkg_location = os.path.join(inst_pkg.root, portage.VDB_PATH, inst_pkg.category, inst_pkg.pf) portage.writemsg("!!! %s/*DEPEND: %s\n" % \ (pkg_location, atoms), noiselevel=-1) continue blocker_atoms = [atom for atom in atoms \ if atom.startswith("!")] blocker_atoms.sort() blocker_cache[inst_pkg.cpv] = \ blocker_cache.BlockerData(inst_pkg.counter, blocker_atoms) for cpv in stale_cache: del blocker_cache[cpv] blocker_cache.flush() blocker_parents = digraph() blocker_atoms = [] for pkg in installed_pkgs: for blocker_atom in blocker_cache[pkg.cpv].atoms: blocker_atom = blocker_atom.lstrip("!") blocker_atoms.append(blocker_atom) blocker_parents.add(blocker_atom, pkg) blocker_atoms = InternalPackageSet(initial_atoms=blocker_atoms) blocking_pkgs = set() for atom in blocker_atoms.iterAtomsForPackage(new_pkg): blocking_pkgs.update(blocker_parents.parent_nodes(atom)) # Check for blockers in the other direction. depstr = " ".join(new_pkg._metadata[k] for k in dep_keys) success, atoms = portage.dep_check(depstr, vardb, settings, myuse=new_pkg.use.enabled, trees=dep_check_trees, myroot=new_pkg.root) if not success: # We should never get this far with invalid deps. show_invalid_depstring_notice(new_pkg, atoms) assert False blocker_atoms = [atom.lstrip("!") for atom in atoms \ if atom[:1] == "!"] if blocker_atoms: blocker_atoms = InternalPackageSet(initial_atoms=blocker_atoms) for inst_pkg in installed_pkgs: try: next(blocker_atoms.iterAtomsForPackage(inst_pkg)) except (portage.exception.InvalidDependString, StopIteration): continue blocking_pkgs.add(inst_pkg) return blocking_pkgs def discardBlocker(self, pkg): """Discard a package from the list of potential blockers. This will match any package(s) with identical cpv or cp:slot.""" for cpv_match in self._fake_vartree.dbapi.match_pkgs(Atom("=%s" % (pkg.cpv,))): if cpv_match.cp == pkg.cp: self._fake_vartree.cpv_discard(cpv_match) for slot_match in self._fake_vartree.dbapi.match_pkgs(pkg.slot_atom): if slot_match.cp == pkg.cp: self._fake_vartree.cpv_discard(slot_match)