diff options
-rw-r--r-- | pym/_emerge/depgraph.py | 50 | ||||
-rw-r--r-- | pym/portage/tests/resolver/test_runtime_cycle_merge_order.py | 72 |
2 files changed, 98 insertions, 24 deletions
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index fc957f59d..26037adbe 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -7415,36 +7415,38 @@ class depgraph(object): selected_nodes = set() if gather_deps(ignore_priority, mergeable_nodes, selected_nodes, node): - # When selecting asap_nodes, we need to ensure - # that we haven't selected a large runtime cycle - # that is obviously sub-optimal. This will be - # obvious if any of the non-asap selected_nodes - # is a leaf node when medium_soft deps are - # ignored. - if prefer_asap and asap_nodes and \ - len(selected_nodes) > 1: - for node in selected_nodes.difference( - asap_nodes): - if not mygraph.child_nodes(node, - ignore_priority = - DepPriorityNormalRange.ignore_medium_soft): - selected_nodes = None - break - if selected_nodes: - if smallest_cycle is None or \ - len(selected_nodes) < len(smallest_cycle): - smallest_cycle = selected_nodes + if smallest_cycle is None or \ + len(selected_nodes) < len(smallest_cycle): + smallest_cycle = selected_nodes selected_nodes = smallest_cycle - if selected_nodes and debug: - writemsg("\nruntime cycle digraph (%s nodes):\n\n" % - (len(selected_nodes),), noiselevel=-1) + if selected_nodes is not None: cycle_digraph = mygraph.copy() cycle_digraph.difference_update([x for x in cycle_digraph if x not in selected_nodes]) - cycle_digraph.debug_print() - writemsg("\n", noiselevel=-1) + + leaves = cycle_digraph.leaf_nodes() + if leaves: + # NOTE: This case should only be triggered when + # prefer_asap is True, since otherwise these + # leaves would have been selected to merge + # before this point. Since these "leaves" may + # actually have some low-priority dependencies + # that we have intentionally ignored, select + # only one node here, so that merge order + # accounts for as many dependencies as possible. + selected_nodes = [leaves[0]] + + if debug: + writemsg("\nruntime cycle digraph (%s nodes):\n\n" % + (len(selected_nodes),), noiselevel=-1) + cycle_digraph.debug_print() + writemsg("\n", noiselevel=-1) + + if leaves: + writemsg("runtime cycle leaf: %s\n\n" % + (selected_nodes[0],), noiselevel=-1) if prefer_asap and asap_nodes and not selected_nodes: # We failed to find any asap nodes to merge, so ignore diff --git a/pym/portage/tests/resolver/test_runtime_cycle_merge_order.py b/pym/portage/tests/resolver/test_runtime_cycle_merge_order.py new file mode 100644 index 000000000..438d9cbfc --- /dev/null +++ b/pym/portage/tests/resolver/test_runtime_cycle_merge_order.py @@ -0,0 +1,72 @@ +# Copyright 2016 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 RuntimeCycleMergeOrderTestCase(TestCase): + + def testRuntimeCycleMergeOrder(self): + ebuilds = { + 'app-misc/plugins-consumer-1' : { + 'EAPI': '6', + 'DEPEND' : 'app-misc/plugin-b:=', + 'RDEPEND' : 'app-misc/plugin-b:=', + }, + 'app-misc/plugin-b-1' : { + 'EAPI': '6', + 'RDEPEND' : 'app-misc/runtime-cycle-b', + 'PDEPEND': 'app-misc/plugins-consumer', + }, + 'app-misc/runtime-cycle-b-1' : { + 'RDEPEND' : 'app-misc/plugin-b app-misc/branch-b', + }, + 'app-misc/branch-b-1' : { + 'RDEPEND' : 'app-misc/leaf-b app-misc/branch-c', + }, + 'app-misc/leaf-b-1' : {}, + 'app-misc/branch-c-1' : { + 'RDEPEND' : 'app-misc/runtime-cycle-c app-misc/runtime-c', + }, + 'app-misc/runtime-cycle-c-1' : { + 'RDEPEND' : 'app-misc/branch-c', + }, + 'app-misc/runtime-c-1' : { + 'RDEPEND' : 'app-misc/branch-d', + }, + 'app-misc/branch-d-1' : { + 'RDEPEND' : 'app-misc/leaf-d app-misc/branch-e', + }, + 'app-misc/branch-e-1' : { + 'RDEPEND' : 'app-misc/leaf-e', + }, + 'app-misc/leaf-d-1' : {}, + 'app-misc/leaf-e-1' : {}, + } + + test_cases = ( + ResolverPlaygroundTestCase( + ['app-misc/plugin-b'], + success = True, + ambiguous_merge_order = True, + mergelist = [ + ('app-misc/leaf-b-1', 'app-misc/leaf-d-1', 'app-misc/leaf-e-1'), + ('app-misc/branch-d-1', 'app-misc/branch-e-1'), + 'app-misc/runtime-c-1', + ('app-misc/runtime-cycle-c-1', 'app-misc/branch-c-1'), + 'app-misc/branch-b-1', + ('app-misc/runtime-cycle-b-1', 'app-misc/plugin-b-1'), + 'app-misc/plugins-consumer-1', + ], + ), + ) + + 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() |