From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 8EEA413838B for ; Wed, 17 Sep 2014 16:35:24 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id A374DE0930; Wed, 17 Sep 2014 16:35:23 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 409B2E0930 for ; Wed, 17 Sep 2014 16:35:23 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 435253400A0 for ; Wed, 17 Sep 2014 16:35:22 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id EC5825D0C for ; Wed, 17 Sep 2014 16:35:20 +0000 (UTC) From: "Zac Medico" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Zac Medico" Message-ID: <1410971347.3f0799054b4e5ef88feb59d20d262668ca79df33.zmedico@gentoo> Subject: [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/ X-VCS-Repository: proj/portage X-VCS-Files: pym/_emerge/depgraph.py pym/portage/tests/resolver/ResolverPlayground.py pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py X-VCS-Directories: pym/portage/tests/resolver/ pym/_emerge/ X-VCS-Committer: zmedico X-VCS-Committer-Name: Zac Medico X-VCS-Revision: 3f0799054b4e5ef88feb59d20d262668ca79df33 X-VCS-Branch: master Date: Wed, 17 Sep 2014 16:35:20 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 9d310259-35cc-43a3-a978-31c46aaeb622 X-Archives-Hash: ac5466a3c43df5e9673a9273c2046ab8 commit: 3f0799054b4e5ef88feb59d20d262668ca79df33 Author: Zac Medico gentoo org> AuthorDate: Fri Sep 12 07:07:13 2014 +0000 Commit: Zac Medico gentoo org> CommitDate: Wed Sep 17 16:29:07 2014 +0000 URL: http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=3f079905 _compute_abi_rebuild_info: fix bug #521990 Since self._dynamic_config._slot_operator_deps only contains deps for packages added to the graph, it doesn't contain potentially relevant deps of installed packages that have not been added to the graph. Therefore, generate pseudo-deps for such installed packages, and use those to generate the rebuild info. X-Gentoo-Bug: 521990 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=521990 --- pym/_emerge/depgraph.py | 100 +++++++++++++++++---- pym/portage/tests/resolver/ResolverPlayground.py | 15 +++- .../resolver/test_slot_conflict_force_rebuild.py | 84 +++++++++++++++++ 3 files changed, 183 insertions(+), 16 deletions(-) diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index d85494a..6332733 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -647,26 +647,96 @@ class depgraph(object): # Go through all slot operator deps and check if one of these deps # has a parent that is matched by one of the atoms from above. forced_rebuilds = {} - for (root, slot_atom), deps in self._dynamic_config._slot_operator_deps.items(): - rebuild_atoms = atoms.get(root, set()) - for dep in deps: - if not isinstance(dep.parent, Package): - continue + for root, rebuild_atoms in atoms.items(): - if dep.parent.installed or dep.child.installed or \ - dep.parent.slot_atom not in rebuild_atoms: - continue + for slot_atom in rebuild_atoms: + + inst_pkg, reinst_pkg = \ + self._select_pkg_from_installed(root, slot_atom) - # Make sure the child's slot/subslot has changed. If it hasn't, - # then another child has forced this rebuild. - installed_pkg = self._select_pkg_from_installed(root, dep.child.slot_atom)[0] - if installed_pkg and installed_pkg.slot == dep.child.slot and \ - installed_pkg.sub_slot == dep.child.sub_slot: + if inst_pkg is reinst_pkg or reinst_pkg is None: continue - # The child has forced a rebuild of the parent - forced_rebuilds.setdefault(root, {}).setdefault(dep.child, set()).add(dep.parent) + # Generate pseudo-deps for any slot-operator deps of + # inst_pkg. Its deps aren't in _slot_operator_deps + # because it hasn't been added to the graph, but we + # are interested in any rebuilds that it triggered. + built_slot_op_atoms = [] + if inst_pkg is not None: + selected_atoms = self._select_atoms_probe( + inst_pkg.root, inst_pkg) + for atom in selected_atoms: + if atom.slot_operator_built: + built_slot_op_atoms.append(atom) + + if not built_slot_op_atoms: + continue + + # Use a cloned list, since we may append to it below. + deps = self._dynamic_config._slot_operator_deps.get( + (root, slot_atom), [])[:] + + if built_slot_op_atoms and reinst_pkg is not None: + for child in self._dynamic_config.digraph.child_nodes( + reinst_pkg): + + if child.installed: + continue + + for atom in built_slot_op_atoms: + # NOTE: Since atom comes from inst_pkg, and + # reinst_pkg is the replacement parent, there's + # no guarantee that atom will completely match + # child. So, simply use atom.cp and atom.slot + # for matching. + if atom.cp != child.cp: + continue + if atom.slot and atom.slot != child.slot: + continue + deps.append(Dependency(atom=atom, child=child, + root=child.root, parent=reinst_pkg)) + + for dep in deps: + if dep.child.installed: + # Find the replacement child. + child = next((pkg for pkg in + self._dynamic_config._package_tracker.match( + dep.root, dep.child.slot_atom) + if not pkg.installed), None) + + if child is None: + continue + + inst_child = dep.child.installed + + else: + child = dep.child + inst_child = self._select_pkg_from_installed( + child.root, child.slot_atom)[0] + + # Make sure the child's slot/subslot has changed. If it + # hasn't, then another child has forced this rebuild. + if inst_child and inst_child.slot == child.slot and \ + inst_child.sub_slot == child.sub_slot: + continue + + if dep.parent.installed: + # Find the replacement parent. + parent = next((pkg for pkg in + self._dynamic_config._package_tracker.match( + dep.parent.root, dep.parent.slot_atom) + if not pkg.installed), None) + + if parent is None: + continue + + else: + parent = dep.parent + + # The child has forced a rebuild of the parent + forced_rebuilds.setdefault(root, {} + ).setdefault(child, set()).add(parent) if debug: writemsg_level("slot operator dependencies:\n", diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py index b1974d7..646987d 100644 --- a/pym/portage/tests/resolver/ResolverPlayground.py +++ b/pym/portage/tests/resolver/ResolverPlayground.py @@ -677,6 +677,9 @@ class ResolverPlaygroundTestCase(object): "unsatisfied_deps") and expected is not None: expected = set(expected) + elif key == "forced_rebuilds" and expected is not None: + expected = dict((k, set(v)) for k, v in expected.items()) + if got != expected: fail_msgs.append("atoms: (" + ", ".join(result.atoms) + "), key: " + \ key + ", expected: " + str(expected) + ", got: " + str(got)) @@ -690,9 +693,10 @@ class ResolverPlaygroundResult(object): checks = ( "success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions", - "circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps", + "circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps", "forced_rebuilds" ) optional_checks = ( + "forced_rebuilds", "unsatisfied_deps" ) @@ -709,6 +713,7 @@ class ResolverPlaygroundResult(object): self.slot_collision_solutions = None self.circular_dependency_solutions = None self.unsatisfied_deps = frozenset() + self.forced_rebuilds = None if self.depgraph._dynamic_config._serialized_tasks_cache is not None: self.mergelist = [] @@ -772,6 +777,14 @@ class ResolverPlaygroundResult(object): self.unsatisfied_deps = set(dep_info[0][1] for dep_info in self.depgraph._dynamic_config._unsatisfied_deps_for_display) + if self.depgraph._forced_rebuilds: + self.forced_rebuilds = dict(self._iter_forced_rebuilds()) + + def _iter_forced_rebuilds(self): + for child_dict in self.depgraph._forced_rebuilds.values(): + for child, parents in child_dict.items(): + yield child.cpv, set(parent.cpv for parent in parents) + class ResolverPlaygroundDepcleanResult(object): checks = ( diff --git a/pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py new file mode 100644 index 0000000..4170bfd --- /dev/null +++ b/pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py @@ -0,0 +1,84 @@ +# Copyright 2014 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 SlotConflictForceRebuildTestCase(TestCase): + + def testSlotConflictForceRebuild(self): + + ebuilds = { + + "app-misc/A-1" : { + "EAPI": "5", + "SLOT": "0/1" + }, + + "app-misc/A-2" : { + "EAPI": "5", + "SLOT": "0/2" + }, + + "app-misc/B-0" : { + "EAPI": "5", + "RDEPEND": "app-misc/A:=" + }, + + "app-misc/C-0" : { + "EAPI": "5", + "RDEPEND": "app-misc/A" + }, + + } + + installed = { + + "app-misc/A-1" : { + "EAPI": "5", + "SLOT": "0/1" + }, + + "app-misc/B-0" : { + "EAPI": "5", + "RDEPEND": "app-misc/A:0/1=" + }, + + "app-misc/C-0" : { + "EAPI": "5", + "RDEPEND": "app-misc/A:0/1=" + }, + + } + + world = ["app-misc/B", "app-misc/C"] + + test_cases = ( + + # Test bug #521990, where forced_rebuilds omits ebuilds that + # had have had their slot operator atoms removed from the + # ebuilds, even though the corresponding installed + # instances had really forced rebuilds due to being built + # with slot-operators in their deps. + ResolverPlaygroundTestCase( + ["app-misc/A"], + options = {}, + success = True, + ambiguous_merge_order = True, + mergelist = ['app-misc/A-2', ('app-misc/B-0', 'app-misc/C-0')], + forced_rebuilds = { + 'app-misc/A-2': ['app-misc/B-0', 'app-misc/C-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()