@@ -, +, @@ --- pym/_emerge/depgraph.py | 24 +++++++++ pym/portage/tests/resolver/test_virtual_slot.py | 66 +++++++++++++++++++++++++ 2 files changed, 90 insertions(+) --- a/pym/_emerge/depgraph.py +++ a/pym/_emerge/depgraph.py @@ -527,6 +527,8 @@ class depgraph(object): self._event_loop = (portage._internal_caller and global_event_loop() or EventLoop(main=False)) + self._select_atoms_parent = None + self.query = UserQuery(myopts).query def _load_vdb(self): @@ -4062,11 +4064,13 @@ class depgraph(object): self._dynamic_config._autounmask = False # backup state for restoration, in case of recursive # calls to this method + backup_parent = self._select_atoms_parent backup_state = mytrees.copy() try: # clear state from previous call, in case this # call is recursive (we have a backup, that we # will use to restore it later) + self._select_atoms_parent = None mytrees.pop("pkg_use_enabled", None) mytrees.pop("parent", None) mytrees.pop("atom_graph", None) @@ -4074,6 +4078,7 @@ class depgraph(object): mytrees["pkg_use_enabled"] = self._pkg_use_enabled if parent is not None: + self._select_atoms_parent = parent mytrees["parent"] = parent mytrees["atom_graph"] = atom_graph if priority is not None: @@ -4085,6 +4090,7 @@ class depgraph(object): finally: # restore state self._dynamic_config._autounmask = _autounmask_backup + self._select_atoms_parent = backup_parent mytrees.pop("pkg_use_enabled", None) mytrees.pop("parent", None) mytrees.pop("atom_graph", None) @@ -8529,6 +8535,24 @@ class _dep_check_composite_db(dbapi): elif not self._depgraph._equiv_ebuild_visible(pkg): return False + if pkg.cp.startswith("virtual/"): + # Force virtual updates to be pulled in when appropriate + # for bug #526160. + want_update = False + if self._depgraph._select_atoms_parent is not None: + want_update = \ + self._depgraph._want_update_pkg( + self._depgraph._select_atoms_parent, pkg) + + if want_update: + for new_child in self._depgraph._iter_similar_available( + pkg, next(iter(atom_set))): + if not self._depgraph._virt_deps_visible( + new_child, ignore_use=True): + continue + if pkg < new_child: + return False + in_graph = next(self._depgraph._dynamic_config._package_tracker.match( self._root, pkg.slot_atom, installed=False), None) --- a/pym/portage/tests/resolver/test_virtual_slot.py +++ a/pym/portage/tests/resolver/test_virtual_slot.py @@ -92,6 +92,72 @@ class VirtualSlotResolverTestCase(TestCase): finally: playground.cleanup() + def testVirtualSubslotUpdate(self): + + ebuilds = { + "virtual/pypy-2.3.1" : { + "EAPI": "5", + "SLOT": "0/2.3", + "RDEPEND": "|| ( >=dev-python/pypy-2.3.1:0/2.3 >=dev-python/pypy-bin-2.3.1:0/2.3 ) " + }, + "virtual/pypy-2.4.0" : { + "EAPI": "5", + "SLOT": "0/2.4", + "RDEPEND": "|| ( >=dev-python/pypy-2.4.0:0/2.4 >=dev-python/pypy-bin-2.4.0:0/2.4 ) " + }, + "dev-python/pypy-2.3.1": { + "EAPI": "5", + "SLOT": "0/2.3" + }, + "dev-python/pypy-2.4.0": { + "EAPI": "5", + "SLOT": "0/2.4" + }, + "dev-python/pygments-1.6_p20140324-r1": { + "EAPI": "5", + "DEPEND": "virtual/pypy:=" + } + } + + installed = { + "virtual/pypy-2.3.1" : { + "EAPI": "5", + "SLOT": "0/2.3", + "RDEPEND": "|| ( >=dev-python/pypy-2.3.1:0/2.3 >=dev-python/pypy-bin-2.3.1:0/2.3 ) " + }, + "dev-python/pypy-2.3.1": { + "EAPI": "5", + "SLOT": "0/2.3" + }, + "dev-python/pygments-1.6_p20140324-r1": { + "EAPI": "5", + "DEPEND": "virtual/pypy:0/2.3=", + "RDEPEND": "virtual/pypy:0/2.3=", + } + } + + world = ["dev-python/pygments"] + + test_cases = ( + # bug 526160 - test for missed pypy sub-slot update + ResolverPlaygroundTestCase( + ["@world"], + options = {"--update": True, "--deep": True}, + success=True, + mergelist = ['dev-python/pypy-2.4.0', + 'virtual/pypy-2.4.0', + 'dev-python/pygments-1.6_p20140324-r1']), + ) + + playground = ResolverPlayground(debug=False, ebuilds=ebuilds, + installed=installed, world=world) + 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() + def testVirtualSlotDepclean(self): ebuilds = { --