aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2019-12-22 21:42:16 -0800
committerZac Medico <zmedico@gentoo.org>2019-12-23 16:40:07 -0800
commitf78a91e44e3e82008e89f05fe3871e2cb03a8646 (patch)
treebae0d6e422789500defeb42b471632a84fe4ec81 /lib/_emerge/depgraph.py
parent_queue_disjunctive_deps: group disjunctions recursively (bug 701996) (diff)
downloadportage-f78a91e44e3e82008e89f05fe3871e2cb03a8646.tar.gz
portage-f78a91e44e3e82008e89f05fe3871e2cb03a8646.tar.bz2
portage-f78a91e44e3e82008e89f05fe3871e2cb03a8646.zip
backtracking: adjust || preference to break dependency cycles
Store dependency cycle edges as backtracking parameters, and use them to adjust || preferences in order to break dependency cycles. This extends direct cycle breaking to handle indirect dependency cycles, which solves the cmake-bootstrap test case for bug 703440. If any cycle(s) remain unsolved by the next backtracking run, then backtracking aborts and the cycle(s) are reported as usual. Note that backtracking is necessary in order to avoid bugs of the form "emerge installs packages only to have them removed by depclean", since this sort of behavior is desirable only when it eliminates a dependency cycle. Bug: https://bugs.gentoo.org/382421 Bug: https://bugs.gentoo.org/384107 Bug: https://bugs.gentoo.org/703440 Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib/_emerge/depgraph.py')
-rw-r--r--lib/_emerge/depgraph.py42
1 files changed, 40 insertions, 2 deletions
diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 2ab1bf4ac..dcef06f93 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -480,6 +480,7 @@ class _dynamic_depgraph_config(object):
# of flags causing the rejection.
self.ignored_binaries = {}
+ self._circular_dependency = backtrack_parameters.circular_dependency
self._needed_unstable_keywords = backtrack_parameters.needed_unstable_keywords
self._needed_p_mask_changes = backtrack_parameters.needed_p_mask_changes
self._needed_license_changes = backtrack_parameters.needed_license_changes
@@ -4809,6 +4810,7 @@ class depgraph(object):
mytrees.pop("pkg_use_enabled", None)
mytrees.pop("parent", None)
mytrees.pop("atom_graph", None)
+ mytrees.pop("circular_dependency", None)
mytrees.pop("priority", None)
mytrees["pkg_use_enabled"] = self._pkg_use_enabled
@@ -4816,6 +4818,7 @@ class depgraph(object):
self._select_atoms_parent = parent
mytrees["parent"] = parent
mytrees["atom_graph"] = atom_graph
+ mytrees["circular_dependency"] = self._dynamic_config._circular_dependency
if priority is not None:
mytrees["priority"] = priority
@@ -4829,6 +4832,7 @@ class depgraph(object):
mytrees.pop("pkg_use_enabled", None)
mytrees.pop("parent", None)
mytrees.pop("atom_graph", None)
+ mytrees.pop("circular_dependency", None)
mytrees.pop("priority", None)
mytrees.update(backup_state)
if not mycheck[0]:
@@ -8226,7 +8230,30 @@ class depgraph(object):
if not selected_nodes:
self._dynamic_config._circular_deps_for_display = mygraph
- self._dynamic_config._skip_restart = True
+
+ unsolved_cycle = False
+ if self._dynamic_config._allow_backtracking:
+
+ backtrack_infos = self._dynamic_config._backtrack_infos
+ backtrack_infos.setdefault("config", {})
+ circular_dependency = backtrack_infos["config"].setdefault("circular_dependency", {})
+
+ cycles = mygraph.get_cycles(ignore_priority=DepPrioritySatisfiedRange.ignore_medium_soft)
+ for cycle in cycles:
+ for index, node in enumerate(cycle):
+ if node in self._dynamic_config._circular_dependency:
+ unsolved_cycle = True
+ if index == 0:
+ circular_child = cycle[-1]
+ else:
+ circular_child = cycle[index-1]
+ circular_dependency.setdefault(node, set()).add(circular_child)
+
+ if unsolved_cycle or not self._dynamic_config._allow_backtracking:
+ self._dynamic_config._skip_restart = True
+ else:
+ self._dynamic_config._need_restart = True
+
raise self._unknown_internal_error()
# At this point, we've succeeded in selecting one or more nodes, so
@@ -9461,6 +9488,17 @@ class depgraph(object):
return self._dynamic_config._need_restart and \
not self._dynamic_config._skip_restart
+ def need_display_problems(self):
+ """
+ Returns true if this depgraph has problems which need to be
+ displayed to the user.
+ """
+ if self.need_config_change():
+ return True
+ if self._dynamic_config._circular_deps_for_display:
+ return True
+ return False
+
def need_config_change(self):
"""
Returns true if backtracking should terminate due to a needed
@@ -9889,7 +9927,7 @@ def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, sp
elif backtracker:
backtracked += 1
- if not (success or mydepgraph.need_config_change()) and backtracked:
+ if backtracked and not success and not mydepgraph.need_display_problems():
if debug:
writemsg_level(