Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 521990 | Differences between
and this patch

Collapse All | Expand All

(-)a/pym/_emerge/depgraph.py (-15 / +85 lines)
Lines 647-672 class depgraph(object): Link Here
647
		# Go through all slot operator deps and check if one of these deps
647
		# Go through all slot operator deps and check if one of these deps
648
		# has a parent that is matched by one of the atoms from above.
648
		# has a parent that is matched by one of the atoms from above.
649
		forced_rebuilds = {}
649
		forced_rebuilds = {}
650
		for (root, slot_atom), deps in self._dynamic_config._slot_operator_deps.items():
651
			rebuild_atoms = atoms.get(root, set())
652
650
653
			for dep in deps:
651
		for root, rebuild_atoms in atoms.items():
654
				if not isinstance(dep.parent, Package):
655
					continue
656
652
657
				if dep.parent.installed or dep.child.installed or \
653
			for slot_atom in rebuild_atoms:
658
					dep.parent.slot_atom not in rebuild_atoms:
654
659
					continue
655
				inst_pkg, reinst_pkg = \
656
					self._select_pkg_from_installed(root, slot_atom)
660
657
661
				# Make sure the child's slot/subslot has changed. If it hasn't,
658
				if inst_pkg is reinst_pkg or reinst_pkg is None:
662
				# then another child has forced this rebuild.
663
				installed_pkg = self._select_pkg_from_installed(root, dep.child.slot_atom)[0]
664
				if installed_pkg and installed_pkg.slot == dep.child.slot and \
665
					installed_pkg.sub_slot == dep.child.sub_slot:
666
					continue
659
					continue
667
660
668
				# The child has forced a rebuild of the parent
661
				# Generate pseudo-deps for any slot-operator deps of
669
				forced_rebuilds.setdefault(root, {}).setdefault(dep.child, set()).add(dep.parent)
662
				# inst_pkg. Its deps aren't in _slot_operator_deps
663
				# because it hasn't been added to the graph, but we
664
				# are interested in any rebuilds that it triggered.
665
				built_slot_op_atoms = []
666
				if inst_pkg is not None:
667
					selected_atoms = self._select_atoms_probe(
668
						inst_pkg.root, inst_pkg)
669
					for atom in selected_atoms:
670
						if atom.slot_operator_built:
671
							built_slot_op_atoms.append(atom)
672
673
					if not built_slot_op_atoms:
674
						continue
675
676
				# Use a cloned list, since we may append to it below.
677
				deps = self._dynamic_config._slot_operator_deps.get(
678
					(root, slot_atom), [])[:]
679
680
				if built_slot_op_atoms and reinst_pkg is not None:
681
					for child in self._dynamic_config.digraph.child_nodes(
682
						reinst_pkg):
683
684
						if child.installed:
685
							continue
686
687
						for atom in built_slot_op_atoms:
688
							# NOTE: Since atom comes from inst_pkg, and
689
							# reinst_pkg is the replacement parent, there's
690
							# no guarantee that atom will completely match
691
							# child. So, simply use atom.cp and atom.slot
692
							# for matching.
693
							if atom.cp != child.cp:
694
								continue
695
							if atom.slot and atom.slot != child.slot:
696
								continue
697
							deps.append(Dependency(atom=atom, child=child,
698
								root=child.root, parent=reinst_pkg))
699
700
				for dep in deps:
701
					if dep.child.installed:
702
						# Find the replacement child.
703
						child = next((pkg for pkg in
704
							self._dynamic_config._package_tracker.match(
705
							dep.root, dep.child.slot_atom)
706
							if not pkg.installed), None)
707
708
						if child is None:
709
							continue
710
711
						inst_child = dep.child.installed
712
713
					else:
714
						child = dep.child
715
						inst_child = self._select_pkg_from_installed(
716
							child.root, child.slot_atom)[0]
717
718
					# Make sure the child's slot/subslot has changed. If it
719
					# hasn't, then another child has forced this rebuild.
720
					if inst_child and inst_child.slot == child.slot and \
721
						inst_child.sub_slot == child.sub_slot:
722
						continue
723
724
					if dep.parent.installed:
725
						# Find the replacement parent.
726
						parent = next((pkg for pkg in
727
							self._dynamic_config._package_tracker.match(
728
							dep.parent.root, dep.parent.slot_atom)
729
							if not pkg.installed), None)
730
731
						if parent is None:
732
							continue
733
734
					else:
735
						parent = dep.parent
736
737
					# The child has forced a rebuild of the parent
738
					forced_rebuilds.setdefault(root, {}
739
						).setdefault(child, set()).add(parent)
670
740
671
		if debug:
741
		if debug:
672
			writemsg_level("slot operator dependencies:\n",
742
			writemsg_level("slot operator dependencies:\n",
(-)a/pym/portage/tests/resolver/ResolverPlayground.py (-1 / +14 lines)
Lines 668-673 class ResolverPlaygroundTestCase(object): Link Here
668
				"unsatisfied_deps") and expected is not None:
668
				"unsatisfied_deps") and expected is not None:
669
				expected = set(expected)
669
				expected = set(expected)
670
670
671
			elif key == "forced_rebuilds" and expected is not None:
672
				expected = dict((k, set(v)) for k, v in expected.items())
673
671
			if got != expected:
674
			if got != expected:
672
				fail_msgs.append("atoms: (" + ", ".join(result.atoms) + "), key: " + \
675
				fail_msgs.append("atoms: (" + ", ".join(result.atoms) + "), key: " + \
673
					key + ", expected: " + str(expected) + ", got: " + str(got))
676
					key + ", expected: " + str(expected) + ", got: " + str(got))
Lines 681-689 class ResolverPlaygroundResult(object): Link Here
681
684
682
	checks = (
685
	checks = (
683
		"success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
686
		"success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
684
		"circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps",
687
		"circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps", "forced_rebuilds"
685
		)
688
		)
686
	optional_checks = (
689
	optional_checks = (
690
		"forced_rebuilds",
687
		"unsatisfied_deps"
691
		"unsatisfied_deps"
688
		)
692
		)
689
693
Lines 700-705 class ResolverPlaygroundResult(object): Link Here
700
		self.slot_collision_solutions = None
704
		self.slot_collision_solutions = None
701
		self.circular_dependency_solutions = None
705
		self.circular_dependency_solutions = None
702
		self.unsatisfied_deps = frozenset()
706
		self.unsatisfied_deps = frozenset()
707
		self.forced_rebuilds = None
703
708
704
		if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
709
		if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
705
			self.mergelist = []
710
			self.mergelist = []
Lines 763-768 class ResolverPlaygroundResult(object): Link Here
763
			self.unsatisfied_deps = set(dep_info[0][1]
768
			self.unsatisfied_deps = set(dep_info[0][1]
764
				for dep_info in self.depgraph._dynamic_config._unsatisfied_deps_for_display)
769
				for dep_info in self.depgraph._dynamic_config._unsatisfied_deps_for_display)
765
770
771
		if self.depgraph._forced_rebuilds:
772
			self.forced_rebuilds = dict(self._iter_forced_rebuilds())
773
774
	def _iter_forced_rebuilds(self):
775
		for child_dict in self.depgraph._forced_rebuilds.values():
776
			for child, parents in child_dict.items():
777
				yield child.cpv, set(parent.cpv for parent in parents)
778
766
class ResolverPlaygroundDepcleanResult(object):
779
class ResolverPlaygroundDepcleanResult(object):
767
780
768
	checks = (
781
	checks = (
(-)a/pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py (-1 / +84 lines)
Line 0 Link Here
0
- 
1
# Copyright 2014 Gentoo Foundation
2
# Distributed under the terms of the GNU General Public License v2
3
4
from portage.tests import TestCase
5
from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
6
	ResolverPlaygroundTestCase)
7
8
class SlotConflictForceRebuildTestCase(TestCase):
9
10
	def testSlotConflictForceRebuild(self):
11
12
		ebuilds = {
13
14
			"app-misc/A-1" : {
15
				"EAPI": "5",
16
				"SLOT": "0/1"
17
			},
18
19
			"app-misc/A-2" : {
20
				"EAPI": "5",
21
				"SLOT": "0/2"
22
			},
23
24
			"app-misc/B-0" : {
25
				"EAPI": "5",
26
				"RDEPEND": "app-misc/A:="
27
			},
28
29
			"app-misc/C-0" : {
30
				"EAPI": "5",
31
				"RDEPEND": "app-misc/A"
32
			},
33
34
		}
35
36
		installed = {
37
38
			"app-misc/A-1" : {
39
				"EAPI": "5",
40
				"SLOT": "0/1"
41
			},
42
43
			"app-misc/B-0" : {
44
				"EAPI": "5",
45
				"RDEPEND": "app-misc/A:0/1="
46
			},
47
48
			"app-misc/C-0" : {
49
				"EAPI": "5",
50
				"RDEPEND": "app-misc/A:0/1="
51
			},
52
53
		}
54
55
		world = ["app-misc/B", "app-misc/C"]
56
57
		test_cases = (
58
59
			# Test bug #521990, where forced_rebuilds omits ebuilds that
60
			# had have had their slot operator atoms removed from the
61
			# ebuilds, even though the corresponding installed
62
			# instances had really forced rebuilds due to being built
63
			# with slot-operators in their deps.
64
			ResolverPlaygroundTestCase(
65
				["app-misc/A"],
66
				options = {},
67
				success = True,
68
				ambiguous_merge_order = True,
69
				mergelist = ['app-misc/A-2', ('app-misc/B-0', 'app-misc/C-0')],
70
				forced_rebuilds = {
71
					'app-misc/A-2': ['app-misc/B-0', 'app-misc/C-0']
72
				}
73
			),
74
75
		)
76
77
		playground = ResolverPlayground(ebuilds=ebuilds,
78
			installed=installed, world=world, debug=False)
79
		try:
80
			for test_case in test_cases:
81
				playground.run_TestCase(test_case)
82
				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
83
		finally:
84
			playground.cleanup()

Return to bug 521990