summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2013-02-11 18:50:36 -0800
committerZac Medico <zmedico@gentoo.org>2013-02-11 18:50:36 -0800
commit69ea5d7b2a166a8d1085af77a72e827080edaee4 (patch)
treec3970f39b359bbf451da87a29a9054d2278cf6cd
parentAdd test case for bug #456340. (diff)
downloadportage-69ea5d7b2a166a8d1085af77a72e827080edaee4.tar.gz
portage-69ea5d7b2a166a8d1085af77a72e827080edaee4.tar.bz2
portage-69ea5d7b2a166a8d1085af77a72e827080edaee4.zip
Backtrack unsatisfied slot-operator, bug #456340.
-rw-r--r--pym/_emerge/depgraph.py98
-rw-r--r--pym/portage/tests/resolver/test_slot_operator_unsolved.py27
2 files changed, 115 insertions, 10 deletions
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 085ac9bb6..eb88357e1 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1273,6 +1273,100 @@ class depgraph(object):
return None
+ def _slot_operator_unsatisfied_probe(self, dep):
+
+ if dep.parent.installed and \
+ self._frozen_config.excluded_pkgs.findAtomForPackage(dep.parent,
+ modified_use=self._pkg_use_enabled(dep.parent)):
+ return False
+
+ debug = "--debug" in self._frozen_config.myopts
+
+ for replacement_parent in self._iter_similar_available(dep.parent,
+ dep.parent.slot_atom):
+
+ for atom in replacement_parent.validated_atoms:
+ if not atom.slot_operator == "=" or \
+ atom.blocker or \
+ atom.cp != dep.atom.cp:
+ continue
+
+ # Discard USE deps, we're only searching for an approximate
+ # pattern, and dealing with USE states is too complex for
+ # this purpose.
+ atom = atom.without_use
+
+ pkg, existing_node = self._select_package(dep.root, atom,
+ onlydeps=dep.onlydeps)
+
+ if pkg is not None:
+
+ if debug:
+ msg = []
+ msg.append("")
+ msg.append("")
+ msg.append("slot_operator_unsatisfied_probe:")
+ msg.append(" existing parent package: %s" % dep.parent)
+ msg.append(" existing parent atom: %s" % dep.atom)
+ msg.append(" new parent package: %s" % replacement_parent)
+ msg.append(" new child package: %s" % pkg)
+ msg.append("")
+ writemsg_level("\n".join(msg),
+ noiselevel=-1, level=logging.DEBUG)
+
+ return True
+
+ if debug:
+ msg = []
+ msg.append("")
+ msg.append("")
+ msg.append("slot_operator_unsatisfied_probe:")
+ msg.append(" existing parent package: %s" % dep.parent)
+ msg.append(" existing parent atom: %s" % dep.atom)
+ msg.append(" new parent package: %s" % None)
+ msg.append(" new child package: %s" % None)
+ msg.append("")
+ writemsg_level("\n".join(msg),
+ noiselevel=-1, level=logging.DEBUG)
+
+ return False
+
+ def _slot_operator_unsatisfied_backtrack(self, dep):
+
+ parent = dep.parent
+
+ if "--debug" in self._frozen_config.myopts:
+ msg = []
+ msg.append("")
+ msg.append("")
+ msg.append("backtracking due to unsatisfied "
+ "built slot-operator dep:")
+ msg.append(" parent package: %s" % parent)
+ msg.append(" atom: %s" % dep.atom)
+ msg.append("")
+ writemsg_level("\n".join(msg),
+ noiselevel=-1, level=logging.DEBUG)
+
+ backtrack_infos = self._dynamic_config._backtrack_infos
+ config = backtrack_infos.setdefault("config", {})
+
+ # mask unwanted binary packages if necessary
+ masks = {}
+ if not parent.installed:
+ masks.setdefault(parent, {})["slot_operator_mask_built"] = None
+ if masks:
+ config.setdefault("slot_operator_mask_built", {}).update(masks)
+
+ # trigger replacement of installed packages if necessary
+ reinstalls = set()
+ if parent.installed:
+ reinstalls.add((parent.root, parent.slot_atom))
+ if reinstalls:
+ config.setdefault("slot_operator_replace_installed",
+ set()).update(reinstalls)
+
+ self._dynamic_config._need_restart = True
+
def _downgrade_probe(self, pkg):
"""
Detect cases where a downgrade of the given package is considered
@@ -1529,6 +1623,10 @@ class depgraph(object):
(dep.parent,
self._dynamic_config._runtime_pkg_mask[
dep.parent]), noiselevel=-1)
+ elif dep.atom.slot_operator_built and \
+ self._slot_operator_unsatisfied_probe(dep):
+ self._slot_operator_unsatisfied_backtrack(dep)
+ return 1
elif not self.need_restart():
# Do not backtrack if only USE have to be changed in
# order to satisfy the dependency.
diff --git a/pym/portage/tests/resolver/test_slot_operator_unsolved.py b/pym/portage/tests/resolver/test_slot_operator_unsolved.py
index a4962523f..7ae3d9e28 100644
--- a/pym/portage/tests/resolver/test_slot_operator_unsolved.py
+++ b/pym/portage/tests/resolver/test_slot_operator_unsolved.py
@@ -9,11 +9,6 @@ class SlotOperatorUnsolvedTestCase(TestCase):
"""
Demonstrate bug #456340, where an unsolved circular dependency
interacts with an unsatisfied built slot-operator dep.
-
- The problem here results from poor handling of the unsatisfied built
- slot operator dep inside _add_dep, where it aborts the graph and tries
- to backtrack immediately. We really want it to queue a rebuild here,
- and continue filling out the graph.
"""
def __init__(self, *args, **kwargs):
super(SlotOperatorUnsolvedTestCase, self).__init__(*args, **kwargs)
@@ -31,12 +26,14 @@ class SlotOperatorUnsolvedTestCase(TestCase):
},
"dev-ruby/rdoc-3.12.1" : {
"EAPI": "5",
- "DEPEND": ">=dev-ruby/hoe-2.7.0",
+ "IUSE": "test",
+ "DEPEND": "test? ( >=dev-ruby/hoe-2.7.0 )",
},
"dev-ruby/hoe-2.13.0" : {
"EAPI": "5",
- "DEPEND": ">=dev-ruby/rdoc-3.10",
- "RDEPEND": ">=dev-ruby/rdoc-3.10",
+ "IUSE": "test",
+ "DEPEND": "test? ( >=dev-ruby/rdoc-3.10 )",
+ "RDEPEND": "test? ( >=dev-ruby/rdoc-3.10 )",
},
}
@@ -52,6 +49,10 @@ class SlotOperatorUnsolvedTestCase(TestCase):
},
}
+ user_config = {
+ "make.conf" : ("FEATURES=test",)
+ }
+
world = ["net-libs/webkit-gtk", "dev-ruby/hoe"]
test_cases = (
@@ -59,12 +60,18 @@ class SlotOperatorUnsolvedTestCase(TestCase):
ResolverPlaygroundTestCase(
["@world"],
options = {"--update": True, "--deep": True},
- success = False),
+ circular_dependency_solutions = {
+ 'dev-ruby/hoe-2.13.0': frozenset([frozenset([('test', False)])]),
+ 'dev-ruby/rdoc-3.12.1': frozenset([frozenset([('test', False)])])
+ },
+ success = False
+ ),
)
playground = ResolverPlayground(ebuilds=ebuilds,
- installed=installed, world=world, debug=False)
+ installed=installed, user_config=user_config,
+ world=world, debug=False)
try:
for test_case in test_cases:
playground.run_TestCase(test_case)