1 |
From: Sebastian Luther <SebastianLuther@×××.de> |
2 |
|
3 |
This one was caused by a mix of >= and < dependencies. |
4 |
--- |
5 |
pym/_emerge/depgraph.py | 92 +++++++++++++++++----- |
6 |
.../tests/resolver/test_slot_conflict_rebuild.py | 66 ++++++++++++++++ |
7 |
2 files changed, 139 insertions(+), 19 deletions(-) |
8 |
|
9 |
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py |
10 |
index cd68db6..67b8881 100644 |
11 |
--- a/pym/_emerge/depgraph.py |
12 |
+++ b/pym/_emerge/depgraph.py |
13 |
@@ -1298,7 +1298,34 @@ class depgraph(object): |
14 |
|
15 |
selected_atoms = None |
16 |
|
17 |
- for atom in replacement_parent.validated_atoms: |
18 |
+ atoms = set() |
19 |
+ invalid_metadata = False |
20 |
+ for dep_key in ("DEPEND", "HDEPEND", "RDEPEND", "PDEPEND"): |
21 |
+ dep_string = replacement_parent._metadata[dep_key] |
22 |
+ if not dep_string: |
23 |
+ continue |
24 |
+ |
25 |
+ try: |
26 |
+ dep_string = portage.dep.use_reduce(dep_string, |
27 |
+ uselist=self._pkg_use_enabled(replacement_parent), |
28 |
+ is_valid_flag=replacement_parent.iuse.is_valid_flag, |
29 |
+ flat=True, token_class=Atom, |
30 |
+ eapi=replacement_parent.eapi) |
31 |
+ except portage.exception.InvalidDependString: |
32 |
+ invalid_metadata = True |
33 |
+ break |
34 |
+ |
35 |
+ atoms.update(token for token in dep_string if isinstance(token, Atom)) |
36 |
+ |
37 |
+ if invalid_metadata: |
38 |
+ continue |
39 |
+ |
40 |
+ # List of list of child,atom pairs for each atom. |
41 |
+ replacement_candidates = [] |
42 |
+ # Set of all packages all atoms can agree on. |
43 |
+ all_candidate_pkgs = None |
44 |
+ |
45 |
+ for atom in atoms: |
46 |
if atom.blocker or \ |
47 |
atom.cp != dep.atom.cp: |
48 |
continue |
49 |
@@ -1316,6 +1343,8 @@ class depgraph(object): |
50 |
# parent and search for another. |
51 |
break |
52 |
|
53 |
+ candidate_pkg_atoms = [] |
54 |
+ candidate_pkgs = [] |
55 |
for pkg in self._iter_similar_available( |
56 |
dep.child, atom): |
57 |
if pkg.slot == dep.child.slot and \ |
58 |
@@ -1367,26 +1396,51 @@ class depgraph(object): |
59 |
if unevaluated_atom not in selected_atoms: |
60 |
continue |
61 |
|
62 |
- if debug: |
63 |
- msg = [] |
64 |
- msg.append("") |
65 |
- msg.append("") |
66 |
- msg.append("slot_operator_update_probe:") |
67 |
- msg.append(" existing child package: %s" % dep.child) |
68 |
- msg.append(" existing parent package: %s" % dep.parent) |
69 |
- msg.append(" new child package: %s" % pkg) |
70 |
- msg.append(" new parent package: %s" % replacement_parent) |
71 |
- if insignificant: |
72 |
- msg.append("insignificant changes detected") |
73 |
- msg.append("") |
74 |
- writemsg_level("\n".join(msg), |
75 |
- noiselevel=-1, level=logging.DEBUG) |
76 |
+ if not insignificant: |
77 |
+ candidate_pkg_atoms.append((pkg, unevaluated_atom)) |
78 |
+ candidate_pkgs.append(pkg) |
79 |
+ |
80 |
+ replacement_candidates.append(candidate_pkg_atoms) |
81 |
+ if all_candidate_pkgs is None: |
82 |
+ all_candidate_pkgs = set(candidate_pkgs) |
83 |
+ else: |
84 |
+ all_candidate_pkgs.intersection_update(candidate_pkgs) |
85 |
+ |
86 |
+ if not all_candidate_pkgs: |
87 |
+ # If the atoms that connect parent and child can't agree on |
88 |
+ # any replacement child, we can't do anything. |
89 |
+ continue |
90 |
+ |
91 |
+ # Now select one of the pkgs as replacement. This is as easy as |
92 |
+ # selecting the highest version. |
93 |
+ # The more complicated part is to choose an atom for the |
94 |
+ # new Dependency object. Choose the one which ranked the selected |
95 |
+ # parent highest. |
96 |
+ selected = None |
97 |
+ for candidate_pkg_atoms in replacement_candidates: |
98 |
+ for i, (pkg, atom) in enumerate(candidate_pkg_atoms): |
99 |
+ if pkg not in all_candidate_pkgs: |
100 |
+ continue |
101 |
+ if selected is None or \ |
102 |
+ selected[0] < pkg or \ |
103 |
+ (selected[0] is pkg and i < selected[2]): |
104 |
+ selected = (pkg, atom, i) |
105 |
|
106 |
- if insignificant: |
107 |
- return None |
108 |
+ if debug: |
109 |
+ msg = [] |
110 |
+ msg.append("") |
111 |
+ msg.append("") |
112 |
+ msg.append("slot_operator_update_probe:") |
113 |
+ msg.append(" existing child package: %s" % dep.child) |
114 |
+ msg.append(" existing parent package: %s" % dep.parent) |
115 |
+ msg.append(" new child package: %s" % selected[0]) |
116 |
+ msg.append(" new parent package: %s" % replacement_parent) |
117 |
+ msg.append("") |
118 |
+ writemsg_level("\n".join(msg), |
119 |
+ noiselevel=-1, level=logging.DEBUG) |
120 |
|
121 |
- return Dependency(parent=replacement_parent, |
122 |
- child=pkg, atom=unevaluated_atom) |
123 |
+ return Dependency(parent=replacement_parent, |
124 |
+ child=selected[0], atom=selected[1]) |
125 |
|
126 |
if debug: |
127 |
msg = [] |
128 |
diff --git a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py |
129 |
index c7c62dd..6599a82 100644 |
130 |
--- a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py |
131 |
+++ b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py |
132 |
@@ -298,3 +298,69 @@ class SlotConflictRebuildTestCase(TestCase): |
133 |
self.assertEqual(test_case.test_success, True, test_case.fail_msg) |
134 |
finally: |
135 |
playground.cleanup() |
136 |
+ |
137 |
+ |
138 |
+ def testSlotConflictDontKnow(self): |
139 |
+ """ |
140 |
+ Bug 487198 |
141 |
+ For parents with mixed >= and < dependencies, we scheduled rebuilds for the |
142 |
+ >= atom, but in the end didn't install the child update becaue of the < atom. |
143 |
+ """ |
144 |
+ ebuilds = { |
145 |
+ "cat/slotted-lib-1" : { |
146 |
+ "EAPI": "5", |
147 |
+ "SLOT": "1" |
148 |
+ }, |
149 |
+ "cat/slotted-lib-2" : { |
150 |
+ "EAPI": "5", |
151 |
+ "SLOT": "2" |
152 |
+ }, |
153 |
+ "cat/slotted-lib-3" : { |
154 |
+ "EAPI": "5", |
155 |
+ "SLOT": "3" |
156 |
+ }, |
157 |
+ "cat/slotted-lib-4" : { |
158 |
+ "EAPI": "5", |
159 |
+ "SLOT": "4" |
160 |
+ }, |
161 |
+ "cat/slotted-lib-5" : { |
162 |
+ "EAPI": "5", |
163 |
+ "SLOT": "5" |
164 |
+ }, |
165 |
+ "cat/user-1" : { |
166 |
+ "EAPI": "5", |
167 |
+ "DEPEND": ">=cat/slotted-lib-2:= <cat/slotted-lib-4:=", |
168 |
+ "RDEPEND": ">=cat/slotted-lib-2:= <cat/slotted-lib-4:=", |
169 |
+ }, |
170 |
+ } |
171 |
+ |
172 |
+ installed = { |
173 |
+ "cat/slotted-lib-3" : { |
174 |
+ "EAPI": "5", |
175 |
+ "SLOT": "3" |
176 |
+ }, |
177 |
+ "cat/user-1" : { |
178 |
+ "EAPI": "5", |
179 |
+ "DEPEND": ">=cat/slotted-lib-2:3/3= <cat/slotted-lib-4:3/3=", |
180 |
+ "RDEPEND": ">=cat/slotted-lib-2:3/3= <cat/slotted-lib-4:3/3=", |
181 |
+ }, |
182 |
+ } |
183 |
+ |
184 |
+ test_cases = ( |
185 |
+ ResolverPlaygroundTestCase( |
186 |
+ ["cat/user"], |
187 |
+ options = {"--deep": True, "--update": True}, |
188 |
+ success = True, |
189 |
+ mergelist = []), |
190 |
+ ) |
191 |
+ |
192 |
+ world = [] |
193 |
+ |
194 |
+ playground = ResolverPlayground(ebuilds=ebuilds, |
195 |
+ installed=installed, world=world, debug=False) |
196 |
+ try: |
197 |
+ for test_case in test_cases: |
198 |
+ playground.run_TestCase(test_case) |
199 |
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg) |
200 |
+ finally: |
201 |
+ playground.cleanup() |
202 |
-- |
203 |
1.8.1.5 |