resume_depgraph: check for alternative installed
authorZac Medico <zmedico@gentoo.org>
Wed, 2 Jan 2013 06:03:54 +0000 (22:03 -0800)
committerZac Medico <zmedico@gentoo.org>
Wed, 2 Jan 2013 10:45:14 +0000 (02:45 -0800)
When pruning packages from the merge list, only prune them if the
relevant dependency is not satisfied by an alternative package which
is already installed. This should fix bug #448176, and now there's also
reasons logged for why a particular package is dropped.

pym/_emerge/Scheduler.py
pym/_emerge/actions.py
pym/_emerge/depgraph.py

index 6a494970e7b80b92e3a33a1fbe832b71501fba8d..a4232747371628e3c7ff273bb45a7093bd478748 100644 (file)
@@ -1791,7 +1791,7 @@ class Scheduler(PollScheduler):
                        #              scope
                        e = exc
                        mydepgraph = e.depgraph
-                       dropped_tasks = set()
+                       dropped_tasks = {}
 
                if e is not None:
                        def unsatisfied_resume_dep_msg():
@@ -1841,7 +1841,7 @@ class Scheduler(PollScheduler):
                self._init_graph(mydepgraph.schedulerGraph())
 
                msg_width = 75
-               for task in dropped_tasks:
+               for task, atoms in dropped_tasks.items():
                        if not (isinstance(task, Package) and task.operation == "merge"):
                                continue
                        pkg = task
@@ -1849,7 +1849,10 @@ class Scheduler(PollScheduler):
                                " %s" % (pkg.cpv,)
                        if pkg.root_config.settings["ROOT"] != "/":
                                msg += " for %s" % (pkg.root,)
-                       msg += " dropped due to unsatisfied dependency."
+                       if not atoms:
+                               msg += " dropped because it is masked or unavailable"
+                       else:
+                               msg += " dropped because it requires %s" % ", ".join(atoms)
                        for line in textwrap.wrap(msg, msg_width):
                                eerror(line, phase="other", key=pkg.cpv)
                        settings = self.pkgsettings[pkg.root]
index 6a3815a9cc6cca27f0aa5dd64c4b63a01f5991c1..19265d03e8477eb043e8852949a0348ccbda5ccb 100644 (file)
@@ -286,8 +286,14 @@ def action_build(settings, trees, mtimedb,
                                        "dropped due to\n" + \
                                        "!!! masking or unsatisfied dependencies:\n\n",
                                        noiselevel=-1)
-                               for task in dropped_tasks:
-                                       portage.writemsg("  " + str(task) + "\n", noiselevel=-1)
+                               for task, atoms in dropped_tasks.items():
+                                       if not atoms:
+                                               writemsg("  %s is masked or unavailable\n" %
+                                                       (task,), noiselevel=-1)
+                                       else:
+                                               writemsg("  %s requires %s\n" %
+                                                       (task, ", ".join(atoms)), noiselevel=-1)
+
                                portage.writemsg("\n", noiselevel=-1)
                        del dropped_tasks
                else:
index 47f1b6002f4e5289113c422467750a3e97d94f28..f02ccb6e9f423b8c52664a05db2c281c5e6a4f49 100644 (file)
@@ -7477,7 +7477,7 @@ def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
        skip_masked = True
        skip_unsatisfied = True
        mergelist = mtimedb["resume"]["mergelist"]
-       dropped_tasks = set()
+       dropped_tasks = {}
        frozen_config = _frozen_depgraph_config(settings, trees,
                myopts, spinner)
        while True:
@@ -7491,12 +7491,21 @@ def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
                                raise
 
                        graph = mydepgraph._dynamic_config.digraph
-                       unsatisfied_parents = dict((dep.parent, dep.parent) \
-                               for dep in e.value)
+                       unsatisfied_parents = {}
                        traversed_nodes = set()
-                       unsatisfied_stack = list(unsatisfied_parents)
+                       unsatisfied_stack = [(dep.parent, dep.atom) for dep in e.value]
                        while unsatisfied_stack:
-                               pkg = unsatisfied_stack.pop()
+                               pkg, atom = unsatisfied_stack.pop()
+                               if atom is not None and \
+                                       mydepgraph._select_pkg_from_installed(
+                                       pkg.root, atom)[0] is not None:
+                                       continue
+                               atoms = unsatisfied_parents.get(pkg)
+                               if atoms is None:
+                                       atoms = []
+                                       unsatisfied_parents[pkg] = atoms
+                               if atom is not None:
+                                       atoms.append(atom)
                                if pkg in traversed_nodes:
                                        continue
                                traversed_nodes.add(pkg)
@@ -7505,7 +7514,8 @@ def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
                                # package scheduled for merge, removing this
                                # package may cause the the parent package's
                                # dependency to become unsatisfied.
-                               for parent_node in graph.parent_nodes(pkg):
+                               for parent_node, atom in \
+                                       mydepgraph._dynamic_config._parent_atoms.get(pkg, []):
                                        if not isinstance(parent_node, Package) \
                                                or parent_node.operation not in ("merge", "nomerge"):
                                                continue
@@ -7513,8 +7523,7 @@ def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
                                        # ensure that a package with an unsatisfied depenedency
                                        # won't get pulled in, even indirectly via a soft
                                        # dependency.
-                                       unsatisfied_parents[parent_node] = parent_node
-                                       unsatisfied_stack.append(parent_node)
+                                       unsatisfied_stack.append((parent_node, atom))
 
                        unsatisfied_tuples = frozenset(tuple(parent_node)
                                for parent_node in unsatisfied_parents
@@ -7535,8 +7544,8 @@ def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
                        # Exclude installed packages that have been removed from the graph due
                        # to failure to build/install runtime dependencies after the dependent
                        # package has already been installed.
-                       dropped_tasks.update(pkg for pkg in \
-                               unsatisfied_parents if pkg.operation != "nomerge")
+                       dropped_tasks.update((pkg, atoms) for pkg, atoms in \
+                               unsatisfied_parents.items() if pkg.operation != "nomerge")
 
                        del e, graph, traversed_nodes, \
                                unsatisfied_parents, unsatisfied_stack