diff options
authorZac Medico <zmedico@gentoo.org>2020-11-15 21:55:54 -0800
committerZac Medico <zmedico@gentoo.org>2020-11-21 19:19:29 -0800
commit5095c2023595a75e2848f1ad3dbe25b5fb451a44 (patch)
treebc2e7d105582ea0274a1d57f4e3dba9013e883b9 /lib/_emerge/depgraph.py
parentemerge: Disable profile deprecation warning inheritance (bug 753497) (diff)
find_smallest_cycle: enhance search prioritization
Enhance the find_smallest_cycle function to prioritize its search so that it will minimize the use of installed packages to break cycles. When installed packages must be used to break cycles, it will now prefer to do this for runtime dependencies over buildtime dependencies, since it's preferable to build against latest versions of buildtime dependencies whenever possible. This should solve some cases of bug 199856 which have been triggered by unsafe reliance on installed packages to break cycles. The included unit test case demonstrates correct merge order for a dependency calculation involving 6 independent cycles. This test case fails with the master branch, due to a buildtime dependency cycle of 3 packages being merged earlier than cycles of 2 packages. We can generalize this to say that the master branch may use an installed package to break an arbitrarily sized cycle in a somewhat random location, even though that cycle may be composed of smaller independent cycles which would be safer to break individually. Bug: https://bugs.gentoo.org/754903 Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib/_emerge/depgraph.py')
1 files changed, 26 insertions, 17 deletions
diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index a994caea7..d10474ab3 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -7905,7 +7905,7 @@ class depgraph:
if check_asap_parent:
for node in nodes:
parents = mygraph.parent_nodes(node,
- ignore_priority=DepPrioritySatisfiedRange.ignore_soft)
+ ignore_priority=DepPrioritySatisfiedRange.ignore_medium_soft)
if any(x in asap_nodes for x in parents):
selected_nodes = [node]
@@ -7921,7 +7921,7 @@ class depgraph:
if not selected_nodes:
- def find_smallest_cycle(mergeable_nodes, priority_ranges):
+ def find_smallest_cycle(mergeable_nodes, local_priority_range):
if prefer_asap and asap_nodes:
nodes = asap_nodes
@@ -7938,18 +7938,27 @@ class depgraph:
# these smaller independent cycles.
smallest_cycle = None
ignore_priority = None
- for node in nodes:
- if not mygraph.parent_nodes(node):
- continue
- for local_priority_range in priority_ranges:
+ # Sort nodes for deterministic results.
+ nodes = sorted(nodes)
+ for priority in (local_priority_range.ignore_priority[i] for i in range(
+ local_priority_range.MEDIUM_POST,
+ local_priority_range.MEDIUM_SOFT + 1)):
+ for node in nodes:
+ if not mygraph.parent_nodes(node):
+ continue
selected_nodes = set()
- if gather_deps(local_priority_range.ignore_medium_soft,
+ if gather_deps(priority,
mergeable_nodes, selected_nodes, node):
if smallest_cycle is None or \
len(selected_nodes) < len(smallest_cycle):
smallest_cycle = selected_nodes
- ignore_priority = local_priority_range.ignore_medium_soft
- break
+ ignore_priority = priority
+ # Exit this loop with the lowest possible priority, which
+ # minimizes the use of installed packages to break cycles.
+ if smallest_cycle is not None:
+ break
return smallest_cycle, ignore_priority
@@ -7963,7 +7972,7 @@ class depgraph:
for local_priority_range in priority_ranges:
mergeable_nodes = set(get_nodes(ignore_priority=local_priority_range.ignore_medium))
if mergeable_nodes:
- selected_nodes, ignore_priority = find_smallest_cycle(mergeable_nodes, priority_ranges)
+ selected_nodes, ignore_priority = find_smallest_cycle(mergeable_nodes, local_priority_range)
if selected_nodes:
@@ -8001,19 +8010,19 @@ class depgraph:
(selected_nodes[0],), noiselevel=-1)
if selected_nodes and ignore_priority is not None:
- # Try to merge ignored medium_soft deps as soon as possible
+ # Try to merge ignored medium_post deps as soon as possible
# if they're not satisfied by installed packages.
for node in selected_nodes:
children = set(mygraph.child_nodes(node))
soft = children.difference(
- ignore_priority=DepPrioritySatisfiedRange.ignore_soft))
- medium_soft = children.difference(
- mygraph.child_nodes(node,
ignore_priority = \
- DepPrioritySatisfiedRange.ignore_medium_soft))
- medium_soft -= soft
- for child in medium_soft:
+ DepPrioritySatisfiedRange.ignore_soft))
+ medium_post = children.difference(
+ mygraph.child_nodes(node,
+ ignore_priority=DepPrioritySatisfiedRange.ignore_medium_post))
+ medium_post -= soft
+ for child in medium_post:
if child in selected_nodes:
if child in asap_nodes: