From d8a00c0d246115a5ae0738078bb900918309b0d2 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sun, 10 Feb 2013 17:58:16 -0800 Subject: [PATCH] Trigger rebuild for sub-slot change, bug #456208. If sub-slot changes without a revbump, trigger a rebuild so that dependent packages will have the new sub-slot recorded in their slot-operator deps. Hopefully this will fix bug #456208. --- pym/_emerge/depgraph.py | 78 ++++++++++++++++++- .../test_slot_change_without_revbump.py | 62 +++++++++++++++ 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 pym/portage/tests/resolver/test_slot_change_without_revbump.py diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 27104e17e..34a4604c8 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -1034,6 +1034,71 @@ class depgraph(object): return found_update + def _slot_change_probe(self, dep): + """ + @rtype: bool + @return: True if dep.child should be rebuilt due to a change + in sub-slot (without revbump, as in bug #456208). + """ + if not (isinstance(dep.parent, Package) and \ + not dep.parent.built and dep.child.built): + return None + + root_config = self._frozen_config.roots[dep.root] + try: + unbuilt_child = self._pkg(dep.child.cpv, "ebuild", + root_config, myrepo=dep.child.repo) + except PackageNotFound: + for unbuilt_child in self._iter_match_pkgs(root_config, + "ebuild", Atom("=%s" % (dep.child.cpv,))): + break + else: + return None + + if unbuilt_child.slot == dep.child.slot and \ + unbuilt_child.sub_slot == dep.child.sub_slot: + return None + + return unbuilt_child + + def _slot_change_backtrack(self, dep, new_child_slot): + child = dep.child + if "--debug" in self._frozen_config.myopts: + msg = [] + msg.append("") + msg.append("") + msg.append("backtracking due to slot/sub-slot change:") + msg.append(" child package: %s" % child) + msg.append(" child slot: %s/%s" % + (child.slot, child.sub_slot)) + msg.append(" new child: %s" % new_child_slot) + msg.append(" new child slot: %s/%s" % + (new_child_slot.slot, new_child_slot.sub_slot)) + msg.append(" parent package: %s" % dep.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 child.installed: + masks.setdefault(dep.child, {})["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 child.installed: + reinstalls.add((child.root, child.slot_atom)) + if reinstalls: + config.setdefault("slot_operator_replace_installed", + set()).update(reinstalls) + + self._dynamic_config._need_restart = True + def _slot_operator_update_backtrack(self, dep, new_child_slot=None): if new_child_slot is None: child = dep.child @@ -1241,6 +1306,17 @@ class depgraph(object): for slot_key, slot_info in self._dynamic_config._slot_operator_deps.items(): for dep in slot_info: + + atom = dep.atom + if atom.slot_operator is None: + continue + + if not atom.slot_operator_built: + new_child_slot = self._slot_change_probe(dep) + if new_child_slot is not None: + self._slot_change_backtrack(dep, new_child_slot) + continue + if not (dep.parent and isinstance(dep.parent, Package) and dep.parent.built): continue @@ -1669,7 +1745,7 @@ class depgraph(object): dep.child = pkg if (not pkg.onlydeps and - dep.atom and dep.atom.slot_operator_built): + dep.atom and dep.atom.slot_operator is not None): self._add_slot_operator_dep(dep) recurse = deep is True or depth + 1 <= deep diff --git a/pym/portage/tests/resolver/test_slot_change_without_revbump.py b/pym/portage/tests/resolver/test_slot_change_without_revbump.py new file mode 100644 index 000000000..dbd78dc66 --- /dev/null +++ b/pym/portage/tests/resolver/test_slot_change_without_revbump.py @@ -0,0 +1,62 @@ +# Copyright 2013 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +from portage.tests import TestCase +from portage.tests.resolver.ResolverPlayground import (ResolverPlayground, + ResolverPlaygroundTestCase) + +class SlotChangeWithoutRevBumpTestCase(TestCase): + + def testSlotChangeWithoutRevBump(self): + + ebuilds = { + "app-arch/libarchive-3.1.1" : { + "EAPI": "5", + "SLOT": "0/13" + }, + "app-arch/libarchive-3.0.4-r1" : { + "EAPI": "5", + "SLOT": "0" + }, + "kde-base/ark-4.10.0" : { + "EAPI": "5", + "DEPEND": "app-arch/libarchive:=", + "RDEPEND": "app-arch/libarchive:=" + }, + } + + installed = { + "app-arch/libarchive-3.1.1" : { + "EAPI": "5", + "SLOT": "0" + }, + + "kde-base/ark-4.10.0" : { + "EAPI": "5", + "DEPEND": "app-arch/libarchive:0/0=", + "RDEPEND": "app-arch/libarchive:0/0=" + }, + } + + world = ["kde-base/ark"] + + test_cases = ( + + # Demonstrate bug #456208, where a sub-slot change + # without revbump needs to trigger a rebuild. + ResolverPlaygroundTestCase( + ["kde-base/ark"], + options = {"--oneshot": True}, + success = True, + mergelist = ['app-arch/libarchive-3.1.1', "kde-base/ark-4.10.0"]), + + ) + + playground = ResolverPlayground(ebuilds=ebuilds, + installed=installed, world=world, debug=False) + try: + for test_case in test_cases: + playground.run_TestCase(test_case) + self.assertEqual(test_case.test_success, True, test_case.fail_msg) + finally: + playground.cleanup() -- 2.26.2