discardBlocker: fix bug in slot match code
[portage.git] / pym / _emerge / BlockerDB.py
1 # Copyright 1999-2009 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 import sys
5
6 import portage
7 from portage import os
8 from portage import digraph
9 from portage._sets.base import InternalPackageSet
10
11 from _emerge.BlockerCache import BlockerCache
12 from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
13
14 if sys.hexversion >= 0x3000000:
15         long = int
16
17 class BlockerDB(object):
18
19         def __init__(self, fake_vartree):
20                 root_config = fake_vartree._root_config
21                 self._root_config = root_config
22                 self._vartree = root_config.trees["vartree"]
23                 self._portdb = root_config.trees["porttree"].dbapi
24
25                 self._dep_check_trees = None
26                 self._fake_vartree = fake_vartree
27                 self._dep_check_trees = {
28                         self._vartree.root : {
29                                 "porttree"    :  fake_vartree,
30                                 "vartree"     :  fake_vartree,
31                 }}
32
33         def findInstalledBlockers(self, new_pkg):
34                 """
35                 Search for installed run-time blockers in the root where
36                 new_pkg is planned to be installed. This ignores build-time
37                 blockers, since new_pkg is assumed to be built already.
38                 """
39                 blocker_cache = BlockerCache(self._vartree.root, self._vartree.dbapi)
40                 dep_keys = ["RDEPEND", "PDEPEND"]
41                 settings = self._vartree.settings
42                 stale_cache = set(blocker_cache)
43                 fake_vartree = self._fake_vartree
44                 dep_check_trees = self._dep_check_trees
45                 vardb = fake_vartree.dbapi
46                 installed_pkgs = list(vardb)
47
48                 for inst_pkg in installed_pkgs:
49                         stale_cache.discard(inst_pkg.cpv)
50                         cached_blockers = blocker_cache.get(inst_pkg.cpv)
51                         if cached_blockers is not None and \
52                                 cached_blockers.counter != long(inst_pkg.metadata["COUNTER"]):
53                                 cached_blockers = None
54                         if cached_blockers is not None:
55                                 blocker_atoms = cached_blockers.atoms
56                         else:
57                                 # Use aux_get() to trigger FakeVartree global
58                                 # updates on *DEPEND when appropriate.
59                                 depstr = " ".join(vardb.aux_get(inst_pkg.cpv, dep_keys))
60                                 success, atoms = portage.dep_check(depstr,
61                                         vardb, settings, myuse=inst_pkg.use.enabled,
62                                         trees=dep_check_trees, myroot=inst_pkg.root)
63                                 if not success:
64                                         pkg_location = os.path.join(inst_pkg.root,
65                                                 portage.VDB_PATH, inst_pkg.category, inst_pkg.pf)
66                                         portage.writemsg("!!! %s/*DEPEND: %s\n" % \
67                                                 (pkg_location, atoms), noiselevel=-1)
68                                         continue
69
70                                 blocker_atoms = [atom for atom in atoms \
71                                         if atom.startswith("!")]
72                                 blocker_atoms.sort()
73                                 counter = long(inst_pkg.metadata["COUNTER"])
74                                 blocker_cache[inst_pkg.cpv] = \
75                                         blocker_cache.BlockerData(counter, blocker_atoms)
76                 for cpv in stale_cache:
77                         del blocker_cache[cpv]
78                 blocker_cache.flush()
79
80                 blocker_parents = digraph()
81                 blocker_atoms = []
82                 for pkg in installed_pkgs:
83                         for blocker_atom in blocker_cache[pkg.cpv].atoms:
84                                 blocker_atom = blocker_atom.lstrip("!")
85                                 blocker_atoms.append(blocker_atom)
86                                 blocker_parents.add(blocker_atom, pkg)
87
88                 blocker_atoms = InternalPackageSet(initial_atoms=blocker_atoms)
89                 blocking_pkgs = set()
90                 for atom in blocker_atoms.iterAtomsForPackage(new_pkg):
91                         blocking_pkgs.update(blocker_parents.parent_nodes(atom))
92
93                 # Check for blockers in the other direction.
94                 depstr = " ".join(new_pkg.metadata[k] for k in dep_keys)
95                 success, atoms = portage.dep_check(depstr,
96                         vardb, settings, myuse=new_pkg.use.enabled,
97                         trees=dep_check_trees, myroot=new_pkg.root)
98                 if not success:
99                         # We should never get this far with invalid deps.
100                         show_invalid_depstring_notice(new_pkg, depstr, atoms)
101                         assert False
102
103                 blocker_atoms = [atom.lstrip("!") for atom in atoms \
104                         if atom[:1] == "!"]
105                 if blocker_atoms:
106                         blocker_atoms = InternalPackageSet(initial_atoms=blocker_atoms)
107                         for inst_pkg in installed_pkgs:
108                                 try:
109                                         next(blocker_atoms.iterAtomsForPackage(inst_pkg))
110                                 except (portage.exception.InvalidDependString, StopIteration):
111                                         continue
112                                 blocking_pkgs.add(inst_pkg)
113
114                 return blocking_pkgs
115
116         def discardBlocker(self, pkg):
117                 """Discard a package from the list of potential blockers.
118                 This will match any package(s) with identical cpv or cp:slot."""
119                 for cpv_match in self._fake_vartree.dbapi.match_pkgs("=%s" % (pkg.cpv,)):
120                         if cpv_match.cp == pkg.cp:
121                                 self._fake_vartree.cpv_discard(cpv_match)
122                 for slot_match in self._fake_vartree.dbapi.match_pkgs(pkg.slot_atom):
123                         if slot_match.cp == pkg.cp:
124                                 self._fake_vartree.cpv_discard(slot_match)