Show use conditionals in old style dep chains
authorSebastian Luther <SebastianLuther@gmx.de>
Fri, 28 Jan 2011 12:59:41 +0000 (13:59 +0100)
committerZac Medico <zmedico@gentoo.org>
Fri, 28 Jan 2011 21:13:08 +0000 (13:13 -0800)
pym/_emerge/depgraph.py
pym/portage/tests/resolver/test_old_dep_chain_display.py [new file with mode: 0644]

index a4cdaf2e64fdfce1cbb2104fb73dae3e550cec2e..3444731ab41729e9ebe0d4efd036082fa997898a 100644 (file)
@@ -2175,6 +2175,117 @@ class depgraph(object):
 
                return selected_atoms
 
+       def _get_dep_chain(self, pkg, atom=None):
+               """
+               Returns a list of (atom, node_type) pairs that represent a dep chain.
+               If atom is None, the first package shown is pkg's paretn.
+               If atom is not None the first package shown is pkg.
+               """
+               traversed_nodes = set()
+               dep_chain = []
+               node = pkg
+               first = True
+               child = None
+               all_parents = self._dynamic_config._parent_atoms
+               
+               if atom is not None:
+                       affecting_use = set()
+                       for dep_str in "DEPEND", "RDEPEND", "PDEPEND":
+                               affecting_use.update(extract_affecting_use(pkg.metadata[dep_str], atom))
+                       affecting_use.difference_update(pkg.use.mask, node.use.force)
+                       pkg_name = pkg.cpv
+                       if affecting_use:
+                               usedep = []
+                               for flag in affecting_use:
+                                       if flag in self._pkg_use_enabled(node):
+                                               usedep.append(flag)
+                                       else:
+                                               usedep.append("-"+flag)
+                               pkg_name += "[%s]" % ",".join(usedep)
+
+                       
+                       dep_chain.append(( _unicode_decode(pkg_name),  _unicode_decode(pkg.type_name)))
+       
+               while node is not None:
+                       traversed_nodes.add(node)
+
+                       if isinstance(node, DependencyArg):
+                               dep_chain.append((_unicode_decode(node), "argument"))
+
+                       elif node is not pkg:
+                               for ppkg, patom in all_parents[child]:
+                                       if ppkg == node:
+                                               atom = patom.unevaluated_atom
+                                               break
+
+                               dep_strings = set()
+                               for priority in self._dynamic_config.digraph.nodes[node][0][child]:
+                                       if priority.buildtime:
+                                               dep_strings.add(node.metadata["DEPEND"])
+                                       if priority.runtime:
+                                               dep_strings.add(node.metadata["RDEPEND"])
+                                       if priority.runtime_post:
+                                               dep_strings.add(node.metadata["PDEPEND"])
+                               
+                               affecting_use = set()
+                               for dep_str in dep_strings:
+                                       affecting_use.update(extract_affecting_use(dep_str, atom))
+
+                               #Don't show flags as 'affecting' if the user can't change them,
+                               affecting_use.difference_update(node.use.mask, \
+                                       node.use.force)
+
+                               pkg_name = node.cpv
+                               if affecting_use:
+                                       usedep = []
+                                       for flag in affecting_use:
+                                               if flag in self._pkg_use_enabled(node):
+                                                       usedep.append(flag)
+                                               else:
+                                                       usedep.append("-"+flag)
+                                       pkg_name += "[%s]" % ",".join(usedep)
+
+                               
+                               dep_chain.append(( _unicode_decode(pkg_name),  _unicode_decode(node.type_name)))
+
+                       if node not in self._dynamic_config.digraph:
+                               # The parent is not in the graph due to backtracking.
+                               break
+
+                       # When traversing to parents, prefer arguments over packages
+                       # since arguments are root nodes. Never traverse the same
+                       # package twice, in order to prevent an infinite loop.
+                       selected_parent = None
+                       for parent in self._dynamic_config.digraph.parent_nodes(node):
+                               if parent in traversed_nodes:
+                                       continue
+                               if isinstance(parent, DependencyArg):
+                                       if self._dynamic_config.digraph.parent_nodes(parent):
+                                               selected_parent = parent
+                                               child = node
+                                       else:
+                                               dep_chain.append(( _unicode_decode(parent), "argument"))
+                                               selected_parent = None
+                                       break
+                               else:
+                                       selected_parent = parent
+                                       child = node
+                       node = selected_parent
+               return dep_chain
+
+       def _get_dep_chain_as_comment(self, pkg):
+               dep_chain = self._get_dep_chain(pkg)
+               display_list = []
+               for node, node_type in dep_chain:
+                       if node_type == "argument":
+                               display_list.append("required by %s (argument)" % node)
+                       else:
+                               display_list.append("required by %s" % node)
+
+               msg = "#" + ", ".join(display_list) + "\n"
+               return msg
+                               
+
        def _show_unsatisfied_dep(self, root, atom, myparent=None, arg=None,
                check_backtrack=False):
                """
@@ -2479,48 +2590,17 @@ class depgraph(object):
                else:
                        writemsg_stdout("\nemerge: there are no ebuilds to satisfy "+green(xinfo)+".\n", noiselevel=-1)
 
-               # Show parent nodes and the argument that pulled them in.
-               traversed_nodes = set()
-               node = myparent
-               if isinstance(myparent, AtomArg):
+               msg = []
+               if not isinstance(myparent, AtomArg):
                        # It's redundant to show parent for AtomArg since
                        # it's the same as 'xinfo' displayed above.
-                       node = None
-               else:
-                       node = myparent
-               msg = []
-               while node is not None:
-                       traversed_nodes.add(node)
-                       if isinstance(node, DependencyArg):
-                               msg.append('(dependency required by "%s")' % \
-                                       colorize('INFORM', _unicode_decode("%s") % (node,)))
-                       else:
+                       dep_chain = self._get_dep_chain(myparent, atom)
+       
+                       for node, node_type in dep_chain:
                                msg.append('(dependency required by "%s" [%s])' % \
-                                       (colorize('INFORM', _unicode_decode("%s") % \
-                                       (node.cpv,)), node.type_name))
-
-                       if node not in self._dynamic_config.digraph:
-                               # The parent is not in the graph due to backtracking.
-                               break
+                                               (colorize('INFORM', _unicode_decode("%s") % \
+                                               (node)), node_type))
 
-                       # When traversing to parents, prefer arguments over packages
-                       # since arguments are root nodes. Never traverse the same
-                       # package twice, in order to prevent an infinite loop.
-                       selected_parent = None
-                       for parent in self._dynamic_config.digraph.parent_nodes(node):
-                               if parent in traversed_nodes:
-                                       continue
-                               if isinstance(parent, DependencyArg):
-                                       if self._dynamic_config.digraph.parent_nodes(parent):
-                                               selected_parent = parent
-                                       else:
-                                               msg.append('(dependency required by "%s" [argument])' % \
-                                                       colorize('INFORM', _unicode_decode("%s") % (parent,)))
-                                               selected_parent = None
-                                       break
-                               else:
-                                       selected_parent = parent
-                       node = selected_parent
                if msg:
                        writemsg_stdout("\n".join(msg), noiselevel=-1)
                        writemsg_stdout("\n", noiselevel=-1)
@@ -4845,91 +4925,6 @@ class depgraph(object):
                else:
                        self._show_missed_update()
 
-               def get_dep_chain(pkg):
-                       traversed_nodes = set()
-                       msg = "#"
-                       node = pkg
-                       first = True
-                       child = None
-                       all_parents = self._dynamic_config._parent_atoms
-                       while node is not None:
-                               traversed_nodes.add(node)
-                               if isinstance(node, DependencyArg):
-                                       if first:
-                                               first = False
-                                       else:
-                                               msg += ", "
-                                       msg += _unicode_decode('required by %s') % (node,)
-                               elif node is not pkg:
-                                       for ppkg, patom in all_parents[child]:
-                                               if ppkg == node:
-                                                       atom = patom.unevaluated_atom
-                                                       break
-
-                                       dep_strings = set()
-                                       for priority in self._dynamic_config.digraph.nodes[node][0][child]:
-                                               if priority.buildtime:
-                                                       dep_strings.add(node.metadata["DEPEND"])
-                                               if priority.runtime:
-                                                       dep_strings.add(node.metadata["RDEPEND"])
-                                               if priority.runtime_post:
-                                                       dep_strings.add(node.metadata["PDEPEND"])
-                                       
-                                       affecting_use = set()
-                                       for dep_str in dep_strings:
-                                               affecting_use.update(extract_affecting_use(dep_str, atom))
-                                       
-                                       #Don't show flags as 'affecting' if the user can't change them,
-                                       affecting_use.difference_update(node.use.mask, \
-                                               node.use.force)
-
-                                       pkg_name = node.cpv
-                                       if affecting_use:
-                                               usedep = []
-                                               for flag in affecting_use:
-                                                       if flag in self._pkg_use_enabled(node):
-                                                               usedep.append(flag)
-                                                       else:
-                                                               usedep.append("-"+flag)
-                                               pkg_name += "[%s]" % ",".join(usedep)
-
-                                       if first:
-                                               first = False
-                                       else:
-                                               msg += ", "
-                                       msg += 'required by =%s' % pkg_name
-       
-                               if node not in self._dynamic_config.digraph:
-                                       # The parent is not in the graph due to backtracking.
-                                       break
-       
-                               # When traversing to parents, prefer arguments over packages
-                               # since arguments are root nodes. Never traverse the same
-                               # package twice, in order to prevent an infinite loop.
-                               selected_parent = None
-                               for parent in self._dynamic_config.digraph.parent_nodes(node):
-                                       if parent in traversed_nodes:
-                                               continue
-                                       if isinstance(parent, DependencyArg):
-                                               if self._dynamic_config.digraph.parent_nodes(parent):
-                                                       selected_parent = parent
-                                                       child = node
-                                               else:
-                                                       if first:
-                                                               first = False
-                                                       else:
-                                                               msg += ", "
-                                                       msg += _unicode_decode(
-                                                               'required by %s (argument)') % (parent,)
-                                                       selected_parent = None
-                                               break
-                                       else:
-                                               selected_parent = parent
-                                               child = node
-                               node = selected_parent
-                       msg += "\n"
-                       return msg
-
                unstable_keyword_msg = []
                for pkg in self._dynamic_config._needed_unstable_keywords:
                        self._show_merge_list()
@@ -4942,7 +4937,7 @@ class depgraph(object):
                                                reason.unmask_hint.key == 'unstable keyword':
                                                keyword = reason.unmask_hint.value
 
-                                               unstable_keyword_msg.append(get_dep_chain(pkg))
+                                               unstable_keyword_msg.append(self._get_dep_chain_as_comment(pkg))
                                                unstable_keyword_msg.append("=%s %s\n" % (pkg.cpv, keyword))
 
                use_changes_msg = []
@@ -4956,14 +4951,14 @@ class depgraph(object):
                                                adjustments.append(flag)
                                        else:
                                                adjustments.append("-" + flag)
-                               use_changes_msg.append(get_dep_chain(pkg))
+                               use_changes_msg.append(self._get_dep_chain_as_comment(pkg))
                                use_changes_msg.append("=%s %s\n" % (pkg.cpv, " ".join(adjustments)))
 
                license_msg = []
                for pkg, missing_licenses in self._dynamic_config._needed_license_changes.items():
                        self._show_merge_list()
                        if pkg in self._dynamic_config.digraph:
-                               license_msg.append(get_dep_chain(pkg))
+                               license_msg.append(self._get_dep_chain_as_comment(pkg))
                                license_msg.append("=%s %s\n" % (pkg.cpv, " ".join(sorted(missing_licenses))))
 
                if unstable_keyword_msg:
diff --git a/pym/portage/tests/resolver/test_old_dep_chain_display.py b/pym/portage/tests/resolver/test_old_dep_chain_display.py
new file mode 100644 (file)
index 0000000..57f1ff1
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class OldDepChainDisplayTestCase(TestCase):
+
+       def testOldDepChainDisplay(self):
+               ebuilds = {
+                       "dev-libs/A-1": { "DEPEND": "foo? ( dev-libs/B[-bar] )", "IUSE": "+foo", "EAPI": "2" }, 
+                       "dev-libs/A-2": { "DEPEND": "foo? ( dev-libs/C )", "IUSE": "+foo", "EAPI": "1" }, 
+                       "dev-libs/B-1": { "IUSE": "bar", "DEPEND": "!bar? ( dev-libs/D[-baz] )", "EAPI": "2" },
+                       "dev-libs/C-1": { "KEYWORDS": "~x86" },
+                       "dev-libs/D-1": { "IUSE": "+baz", "EAPI": "1" },
+                       }
+
+               test_cases = (
+                       ResolverPlaygroundTestCase(
+                               ["=dev-libs/A-1"],
+                               success = False),
+                       ResolverPlaygroundTestCase(
+                               ["=dev-libs/A-2"],
+                               success = False),
+                       )
+
+               playground = ResolverPlayground(ebuilds=ebuilds)
+               try:
+                       for test_case in test_cases:
+                               playground.run_TestCase(test_case)
+                               self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+               finally:
+                       playground.cleanup()