1 |
Fix check_reverse_dependencies to ignore direct circular dependencies, |
2 |
since these dependencies tend to prevent updates of packages. This |
3 |
solves a missed update from llvm:0 to llvm:4 when clang is not in the |
4 |
world file, as demonstrated by the included test case. |
5 |
|
6 |
X-Gentoo-bug: 612874 |
7 |
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=612874 |
8 |
--- |
9 |
pym/_emerge/depgraph.py | 31 ++++++++++++----- |
10 |
.../resolver/test_slot_operator_exclusive_slots.py | 39 ++++++++++++++++++++++ |
11 |
pym/portage/util/digraph.py | 6 ++++ |
12 |
3 files changed, 68 insertions(+), 8 deletions(-) |
13 |
|
14 |
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py |
15 |
index f4145d0..e94b96c 100644 |
16 |
--- a/pym/_emerge/depgraph.py |
17 |
+++ b/pym/_emerge/depgraph.py |
18 |
@@ -1844,14 +1844,29 @@ class depgraph(object): |
19 |
if (not self._too_deep(parent.depth) and |
20 |
not self._frozen_config.excluded_pkgs. |
21 |
findAtomForPackage(parent, |
22 |
- modified_use=self._pkg_use_enabled(parent)) and |
23 |
- (self._upgrade_available(parent) or |
24 |
- (parent.installed and self._in_blocker_conflict(parent)))): |
25 |
- # This parent may be irrelevant, since an |
26 |
- # update is available (see bug 584626), or |
27 |
- # it could be uninstalled in order to solve |
28 |
- # a blocker conflict (bug 612772). |
29 |
- continue |
30 |
+ modified_use=self._pkg_use_enabled(parent))): |
31 |
+ # Check for common reasons that the parent's |
32 |
+ # dependency might be irrelevant. |
33 |
+ if self._upgrade_available(parent): |
34 |
+ # This parent could be replaced by |
35 |
+ # an upgrade (bug 584626). |
36 |
+ continue |
37 |
+ if parent.installed and self._in_blocker_conflict(parent): |
38 |
+ # This parent could be uninstalled in order |
39 |
+ # to solve a blocker conflict (bug 612772). |
40 |
+ continue |
41 |
+ if self._dynamic_config.digraph.has_edge(parent, |
42 |
+ existing_pkg): |
43 |
+ # There is a direct circular dependency between |
44 |
+ # parent and existing_pkg. This type of |
45 |
+ # relationship tends to prevent updates |
46 |
+ # of packages (bug 612874). Since candidate_pkg |
47 |
+ # is available, we risk a missed update if we |
48 |
+ # don't try to eliminate this parent from the |
49 |
+ # graph. Therefore, we give candidate_pkg a |
50 |
+ # chance, and assume that it will be masked |
51 |
+ # by backtracking if necessary. |
52 |
+ continue |
53 |
|
54 |
atom_set = InternalPackageSet(initial_atoms=(atom,), |
55 |
allow_repo=True) |
56 |
diff --git a/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py b/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py |
57 |
index 2ab379c..689ed31 100644 |
58 |
--- a/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py |
59 |
+++ b/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py |
60 |
@@ -107,3 +107,42 @@ class SlotOperatorExclusiveSlotsTestCase(TestCase): |
61 |
test_case.fail_msg) |
62 |
finally: |
63 |
playground.cleanup() |
64 |
+ |
65 |
+ |
66 |
+ world = ["media-libs/mesa"] |
67 |
+ |
68 |
+ test_cases = ( |
69 |
+ |
70 |
+ # Test bug #612874, where a direct circular dependency |
71 |
+ # between llvm-3.9.1 and clang-3.9.1-r100 causes a |
72 |
+ # missed update from llvm:0 to llvm:4. Since llvm:4 does |
73 |
+ # not have a dependency on clang, the upgrade from llvm:0 |
74 |
+ # to llvm:4 makes the installed sys-devel/clang-3.9.1-r100 |
75 |
+ # instance eligible for removal by emerge --depclean, which |
76 |
+ # explains why clang does not appear in the mergelist. |
77 |
+ ResolverPlaygroundTestCase( |
78 |
+ ["@world"], |
79 |
+ options = {"--update": True, "--deep": True}, |
80 |
+ success = True, |
81 |
+ ambiguous_merge_order = True, |
82 |
+ mergelist = [ |
83 |
+ 'sys-devel/llvm-4.0.0', |
84 |
+ ( |
85 |
+ 'media-libs/mesa-17.0.1', |
86 |
+ '[uninstall]sys-devel/llvm-3.9.1', |
87 |
+ '!sys-devel/llvm:0', |
88 |
+ ) |
89 |
+ ], |
90 |
+ ), |
91 |
+ |
92 |
+ ) |
93 |
+ |
94 |
+ playground = ResolverPlayground(ebuilds=ebuilds, |
95 |
+ installed=installed, world=world) |
96 |
+ try: |
97 |
+ for test_case in test_cases: |
98 |
+ playground.run_TestCase(test_case) |
99 |
+ self.assertEqual(test_case.test_success, True, |
100 |
+ test_case.fail_msg) |
101 |
+ finally: |
102 |
+ playground.cleanup() |
103 |
diff --git a/pym/portage/util/digraph.py b/pym/portage/util/digraph.py |
104 |
index 4a9cb43..b6be0c9 100644 |
105 |
--- a/pym/portage/util/digraph.py |
106 |
+++ b/pym/portage/util/digraph.py |
107 |
@@ -93,6 +93,12 @@ class digraph(object): |
108 |
del self.nodes[node] |
109 |
self.order = order |
110 |
|
111 |
+ def has_edge(self, child, parent): |
112 |
+ """ |
113 |
+ Return True if the given edge exists. |
114 |
+ """ |
115 |
+ return child in self.nodes[parent][0] |
116 |
+ |
117 |
def remove_edge(self, child, parent): |
118 |
""" |
119 |
Remove edge in the direction from child to parent. Note that it is |
120 |
-- |
121 |
2.10.2 |