public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2019-11-26 20:35 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2019-11-26 20:35 UTC (permalink / raw
  To: gentoo-commits

commit:     1b3131db0e22085dba7d0fb9fc6e5ec70c8c577d
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Nov 26 18:05:47 2019 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue Nov 26 20:34:53 2019 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=1b3131db

emerge --buildpkgonly: respect buildtime hard blockers

Bug: https://bugs.gentoo.org/689226
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                    | 24 ++++++---
 lib/portage/tests/resolver/test_blocker.py | 87 +++++++++++++++++++++++++++++-
 2 files changed, 102 insertions(+), 9 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 68b5bdb2e..1127a6234 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -2791,7 +2791,6 @@ class depgraph(object):
 
 	def _add_dep(self, dep, allow_unsatisfied=False):
 		debug = "--debug" in self._frozen_config.myopts
-		buildpkgonly = "--buildpkgonly" in self._frozen_config.myopts
 		nodeps = "--nodeps" in self._frozen_config.myopts
 		if dep.blocker:
 
@@ -2799,8 +2798,7 @@ class depgraph(object):
 			# blocker validation is only able to account for one package per slot.
 			is_slot_conflict_parent = any(dep.parent in conflict.pkgs[1:] for conflict in \
 				self._dynamic_config._package_tracker.slot_conflicts())
-			if not buildpkgonly and \
-				not nodeps and \
+			if not nodeps and \
 				not dep.collapsed_priority.ignored and \
 				not dep.collapsed_priority.optional and \
 				not is_slot_conflict_parent:
@@ -6805,8 +6803,7 @@ class depgraph(object):
 			for depclean and prune removal operations)
 		@type required_sets: dict
 		"""
-		if "--buildpkgonly" in self._frozen_config.myopts or \
-			"recurse" not in self._dynamic_config.myparams:
+		if "recurse" not in self._dynamic_config.myparams:
 			return 1
 
 		complete_if_new_use = self._dynamic_config.myparams.get(
@@ -7061,8 +7058,7 @@ class depgraph(object):
 		# has been called before it, by checking that it is not None.
 		self._dynamic_config._blocked_pkgs = digraph()
 
-		if "--buildpkgonly" in self._frozen_config.myopts or \
-			"--nodeps" in self._frozen_config.myopts:
+		if "--nodeps" in self._frozen_config.myopts:
 			return True
 
 		if True:
@@ -7338,6 +7334,10 @@ class depgraph(object):
 					# so apparently this one is unresolvable.
 					unresolved_blocks = True
 
+				if "--buildpkgonly" in self._frozen_config.myopts and not (
+					blocker.priority.buildtime and blocker.atom.blocker.overlap.forbid):
+					depends_on_order.clear()
+
 				# Make sure we don't unmerge any package that have been pulled
 				# into the graph.
 				if not unresolved_blocks and depends_on_order:
@@ -8292,9 +8292,17 @@ class depgraph(object):
 		retlist.extend(unsolvable_blockers)
 		retlist = tuple(retlist)
 
+		buildtime_blockers = []
+		if unsolvable_blockers and "--buildpkgonly" in self._frozen_config.myopts:
+			for blocker in unsolvable_blockers:
+				if blocker.priority.buildtime and blocker.atom.blocker.overlap.forbid:
+					buildtime_blockers.append(blocker)
+
 		if unsolvable_blockers and \
+			not buildtime_blockers and \
 			not self._accept_blocker_conflicts():
-			self._dynamic_config._unsatisfied_blockers_for_display = unsolvable_blockers
+			self._dynamic_config._unsatisfied_blockers_for_display = (tuple(buildtime_blockers)
+				if buildtime_blockers else unsolvable_blockers)
 			self._dynamic_config._serialized_tasks_cache = retlist
 			self._dynamic_config._scheduler_graph = scheduler_graph
 			# Blockers don't trigger the _skip_restart flag, since

diff --git a/lib/portage/tests/resolver/test_blocker.py b/lib/portage/tests/resolver/test_blocker.py
index 94a88b8b4..6534f99e6 100644
--- a/lib/portage/tests/resolver/test_blocker.py
+++ b/lib/portage/tests/resolver/test_blocker.py
@@ -1,4 +1,4 @@
-# Copyright 2014 Gentoo Foundation
+# Copyright 2014-2019 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -46,3 +46,88 @@ class SlotConflictWithBlockerTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+	def testBlockerBuildpkgonly(self):
+		ebuilds = {
+			'dev-libs/A-1': {
+				'EAPI': '7',
+				'DEPEND': '!!dev-libs/X'
+			},
+
+			'dev-libs/B-1': {
+				'EAPI': '7',
+				'BDEPEND': '!!dev-libs/X'
+			},
+
+			'dev-libs/C-1': {
+				'EAPI': '7',
+				'BDEPEND': '!dev-libs/X'
+			},
+
+			'dev-libs/D-1': {
+				'EAPI': '7',
+				'DEPEND': '!dev-libs/X'
+			},
+
+			'dev-libs/E-1': {
+				'EAPI': '7',
+				'RDEPEND': '!dev-libs/X !!dev-libs/X'
+			},
+
+			'dev-libs/F-1': {
+				'EAPI': '7',
+				'PDEPEND': '!dev-libs/X !!dev-libs/X'
+			},
+		}
+
+		installed = {
+			'dev-libs/X-1': {},
+		}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				['dev-libs/A'],
+				success = False,
+				options = {'--buildpkgonly': True},
+				mergelist = ['dev-libs/A-1', '!!dev-libs/X']),
+
+			ResolverPlaygroundTestCase(
+				['dev-libs/B'],
+				success = False,
+				options = {'--buildpkgonly': True},
+				mergelist = ['dev-libs/B-1', '!!dev-libs/X']),
+
+			ResolverPlaygroundTestCase(
+				['dev-libs/C'],
+				success = True,
+				options = {'--buildpkgonly': True},
+				mergelist = ['dev-libs/C-1']),
+
+			ResolverPlaygroundTestCase(
+				['dev-libs/D'],
+				success = True,
+				options = {'--buildpkgonly': True},
+				mergelist = ['dev-libs/D-1']),
+
+			ResolverPlaygroundTestCase(
+				['dev-libs/E'],
+				success = True,
+				options = {'--buildpkgonly': True},
+				mergelist = ['dev-libs/E-1']),
+
+			ResolverPlaygroundTestCase(
+				['dev-libs/F'],
+				success = True,
+				options = {'--buildpkgonly': True},
+				mergelist = ['dev-libs/F-1']),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, 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.debug = False
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2019-12-06  4:06 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2019-12-06  4:06 UTC (permalink / raw
  To: gentoo-commits

commit:     fa7b6ea6ecdc135a01a65e249276e6d75b92791e
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Thu Dec  5 07:11:47 2019 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Dec  6 04:03:28 2019 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=fa7b6ea6

_queue_disjunctive_deps: group disjunctions (bug 701996)

When disjunctive dependencies are queued, group together disjunctions
from the same dependency string so that any overlap between them will
trigger expansion to DNF.

Bug: https://bugs.gentoo.org/701996
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                            |  8 +++--
 .../resolver/test_virtual_minimize_children.py     | 39 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index f80b077bc..78226a3ea 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -3850,10 +3850,11 @@ class depgraph(object):
 		Yields non-disjunctive deps. Raises InvalidDependString when
 		necessary.
 		"""
+		disjunctions = []
 		for x in dep_struct:
 			if isinstance(x, list):
 				if x and x[0] == "||":
-					self._queue_disjunction(pkg, dep_root, dep_priority, [x])
+					disjunctions.append(x)
 				else:
 					for y in self._queue_disjunctive_deps(
 						pkg, dep_root, dep_priority, x):
@@ -3863,10 +3864,13 @@ class depgraph(object):
 				# or whatever other metadata gets implemented for this
 				# purpose.
 				if x.cp.startswith('virtual/'):
-					self._queue_disjunction(pkg, dep_root, dep_priority, [x])
+					disjunctions.append(x)
 				else:
 					yield x
 
+		if disjunctions:
+			self._queue_disjunction(pkg, dep_root, dep_priority, disjunctions)
+
 	def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct):
 		self._dynamic_config._dep_disjunctive_stack.append(
 			(pkg, dep_root, dep_priority, dep_struct))

diff --git a/lib/portage/tests/resolver/test_virtual_minimize_children.py b/lib/portage/tests/resolver/test_virtual_minimize_children.py
index b566cb592..720fbe57b 100644
--- a/lib/portage/tests/resolver/test_virtual_minimize_children.py
+++ b/lib/portage/tests/resolver/test_virtual_minimize_children.py
@@ -285,3 +285,42 @@ class VirtualMinimizeChildrenTestCase(TestCase):
 		finally:
 			playground.debug = False
 			playground.cleanup()
+
+
+	def testVirtualWine(self):
+		ebuilds = {
+			'virtual/wine-0-r6': {
+				'RDEPEND': '|| ( app-emulation/wine-staging app-emulation/wine-any ) '
+					'|| ( app-emulation/wine-vanilla app-emulation/wine-staging app-emulation/wine-any )'
+			},
+			'app-emulation/wine-staging-4': {},
+			'app-emulation/wine-any-4': {},
+			'app-emulation/wine-vanilla-4': {},
+		}
+
+		test_cases = (
+			# Test bug 701996, where separate disjunctions where not
+			# converted to DNF, causing both wine-vanilla and
+			# wine-staging to be pulled in.
+			ResolverPlaygroundTestCase(
+				[
+					'virtual/wine',
+				],
+				success=True,
+				mergelist=(
+					'app-emulation/wine-staging-4',
+					'virtual/wine-0-r6',
+				),
+			),
+		)
+
+		playground = ResolverPlayground(debug=False, ebuilds=ebuilds)
+
+		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.debug = False
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2019-12-26 23:00 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2019-12-26 23:00 UTC (permalink / raw
  To: gentoo-commits

commit:     680276cc4d4faa653203366cbe3c896ac3883cf2
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Dec 25 08:37:18 2019 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Dec 26 22:56:39 2019 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=680276cc

_serialize_tasks: limit scope of dropped circular dependencies

Ensure that all members of a buildtime dependency cycle are merged
as a group, such that packages which depend on one or more members
of the group will only be merged *after* the entire group has been
merged.

This extends runtime cycle handling to also handle buildtime cycles
in cases where the buildtime dependencies happen to be satisfied by
installed packages. In situations when this is necessary, it is
desirable to rely on the old installed instances of these packages
as little as possible, since they might have been broken by the
upgrade of a package that is a member of the dependency cycle.
Upgrading members of the cycle as a group effectively minimizes
reliance on the old installed package instances, avoiding some cases
of bug 199856. For example, it should avoid bug 703676, where
libspectre reportedly failed to build against an old installed
instance of ghostscript-gpl.

Bug: https://bugs.gentoo.org/199856
Bug: https://bugs.gentoo.org/689644
Bug: https://bugs.gentoo.org/690436
Bug: https://bugs.gentoo.org/703676
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                        | 94 +++++++++++++++-----------
 lib/portage/tests/resolver/test_merge_order.py | 25 ++++++-
 2 files changed, 78 insertions(+), 41 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 0ee50d5de..bf8882774 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -7640,21 +7640,6 @@ class depgraph(object):
 				break
 			removed_nodes.clear()
 		self._merge_order_bias(mygraph)
-		def cmp_circular_bias(n1, n2):
-			"""
-			RDEPEND is stronger than PDEPEND and this function
-			measures such a strength bias within a circular
-			dependency relationship.
-			"""
-			n1_n2_medium = n2 in mygraph.child_nodes(n1,
-				ignore_priority=priority_range.ignore_medium_soft)
-			n2_n1_medium = n1 in mygraph.child_nodes(n2,
-				ignore_priority=priority_range.ignore_medium_soft)
-			if n1_n2_medium == n2_n1_medium:
-				return 0
-			elif n1_n2_medium:
-				return 1
-			return -1
 		myblocker_uninstalls = self._dynamic_config._blocker_uninstalls.copy()
 		retlist=[]
 		# Contains uninstall tasks that have been scheduled to
@@ -7815,7 +7800,8 @@ class depgraph(object):
 			self._spinner_update()
 			selected_nodes = None
 			ignore_priority = None
-			if drop_satisfied or (prefer_asap and asap_nodes):
+			cycle_digraph = None
+			if prefer_asap and asap_nodes:
 				priority_range = DepPrioritySatisfiedRange
 			else:
 				priority_range = DepPriorityNormalRange
@@ -7897,11 +7883,12 @@ class depgraph(object):
 							break
 
 			if not selected_nodes:
-				nodes = get_nodes(ignore_priority=priority_range.ignore_medium)
-				if nodes:
-					mergeable_nodes = set(nodes)
+
+				def find_smallest_cycle(mergeable_nodes, priority_ranges):
 					if prefer_asap and asap_nodes:
 						nodes = asap_nodes
+					else:
+						nodes = mergeable_nodes
 					# When gathering the nodes belonging to a runtime cycle,
 					# we want to minimize the number of nodes gathered, since
 					# this tends to produce a more optimal merge order.
@@ -7912,21 +7899,44 @@ class depgraph(object):
 					# that depend on them. Therefore, we search for the
 					# smallest cycle in order to try and identify and prefer
 					# these smaller independent cycles.
-					ignore_priority = priority_range.ignore_medium_soft
 					smallest_cycle = None
+					ignore_priority = None
 					for node in nodes:
 						if not mygraph.parent_nodes(node):
 							continue
-						selected_nodes = set()
-						if gather_deps(ignore_priority,
-							mergeable_nodes, selected_nodes, node):
-							if smallest_cycle is None or \
-								len(selected_nodes) < len(smallest_cycle):
-								smallest_cycle = selected_nodes
+						for local_priority_range in priority_ranges:
+							selected_nodes = set()
+							if gather_deps(local_priority_range.ignore_medium_soft,
+								mergeable_nodes, selected_nodes, node):
+								if smallest_cycle is None or \
+									len(selected_nodes) < len(smallest_cycle):
+									smallest_cycle = selected_nodes
+									ignore_priority = local_priority_range.ignore_medium_soft
+								break
+
+					return smallest_cycle, ignore_priority
 
-					selected_nodes = smallest_cycle
+				priority_ranges = []
+				if priority_range is not DepPriorityNormalRange:
+					priority_ranges.append(DepPriorityNormalRange)
+				priority_ranges.append(priority_range)
+				if drop_satisfied and priority_range is not DepPrioritySatisfiedRange:
+					priority_ranges.append(DepPrioritySatisfiedRange)
 
-					if selected_nodes is not None:
+				for local_priority_range in priority_ranges:
+					mergeable_nodes = set(get_nodes(ignore_priority=local_priority_range.ignore_medium))
+					if mergeable_nodes:
+						selected_nodes, ignore_priority = find_smallest_cycle(mergeable_nodes, priority_ranges)
+						if selected_nodes:
+							break
+
+				if not selected_nodes:
+					if prefer_asap and asap_nodes:
+						# We failed to find any asap nodes to merge, so ignore
+						# them for the next iteration.
+						prefer_asap = False
+						continue
+				else:
 						cycle_digraph = mygraph.copy()
 						cycle_digraph.difference_update([x for x in
 							cycle_digraph if x not in selected_nodes])
@@ -7953,12 +7963,6 @@ class depgraph(object):
 								writemsg("runtime cycle leaf: %s\n\n" %
 									(selected_nodes[0],), noiselevel=-1)
 
-					if prefer_asap and asap_nodes and not selected_nodes:
-						# We failed to find any asap nodes to merge, so ignore
-						# them for the next iteration.
-						prefer_asap = False
-						continue
-
 			if selected_nodes and ignore_priority is not None:
 				# Try to merge ignored medium_soft deps as soon as possible
 				# if they're not satisfied by installed packages.
@@ -7980,10 +7984,24 @@ class depgraph(object):
 						# Merge PDEPEND asap for bug #180045.
 						asap_nodes.append(child)
 
-			if selected_nodes and len(selected_nodes) > 1:
-				if not isinstance(selected_nodes, list):
-					selected_nodes = list(selected_nodes)
-				selected_nodes.sort(key=cmp_sort_key(cmp_circular_bias))
+			if selected_nodes and len(selected_nodes) > 1 and cycle_digraph is not None:
+				# Sort nodes to account for direct circular relationships. Relevant
+				# priorities here are: runtime < buildtime < buildtime slot operator
+				ignore_priorities = list(filter(None, chain(
+					DepPriorityNormalRange.ignore_priority,
+					DepPrioritySatisfiedRange.ignore_priority,
+				)))
+				selected_nodes = []
+				while cycle_digraph:
+					for ignore_priority in ignore_priorities:
+						leaves = cycle_digraph.leaf_nodes(ignore_priority=ignore_priority)
+						if leaves:
+							cycle_digraph.difference_update(leaves)
+							selected_nodes.extend(leaves)
+							break
+					else:
+						selected_nodes.extend(cycle_digraph)
+						break
 
 			if not selected_nodes and myblocker_uninstalls:
 				# An Uninstall task needs to be executed in order to

diff --git a/lib/portage/tests/resolver/test_merge_order.py b/lib/portage/tests/resolver/test_merge_order.py
index 74e826661..11752d71e 100644
--- a/lib/portage/tests/resolver/test_merge_order.py
+++ b/lib/portage/tests/resolver/test_merge_order.py
@@ -81,6 +81,13 @@ class MergeOrderTestCase(TestCase):
 				"DEPEND": "app-misc/circ-satisfied-a",
 				"RDEPEND": "app-misc/circ-satisfied-a",
 			},
+			"app-misc/circ-direct-a-1": {
+				"RDEPEND": "app-misc/circ-direct-b",
+			},
+			"app-misc/circ-direct-b-1": {
+				"RDEPEND": "app-misc/circ-direct-a",
+				"DEPEND": "app-misc/circ-direct-a",
+			},
 			"app-misc/circ-smallest-a-1": {
 				"RDEPEND": "app-misc/circ-smallest-b",
 			},
@@ -220,6 +227,13 @@ class MergeOrderTestCase(TestCase):
 		}
 
 		installed = {
+			"app-misc/circ-direct-a-1": {
+				"RDEPEND": "app-misc/circ-direct-b",
+			},
+			"app-misc/circ-direct-b-1": {
+				"RDEPEND": "app-misc/circ-direct-a",
+				"DEPEND": "app-misc/circ-direct-a",
+			},
 			"app-misc/circ-buildtime-a-0": {},
 			"app-misc/circ-satisfied-a-0": {
 				"RDEPEND": "app-misc/circ-satisfied-b",
@@ -295,6 +309,12 @@ class MergeOrderTestCase(TestCase):
 		}
 
 		test_cases = (
+			ResolverPlaygroundTestCase(
+				["app-misc/circ-direct-a", "app-misc/circ-direct-b"],
+				success = True,
+				all_permutations = True,
+				mergelist = ["app-misc/circ-direct-a-1", "app-misc/circ-direct-b-1"],
+			),
 			ResolverPlaygroundTestCase(
 				["app-misc/some-app-a"],
 				success = True,
@@ -321,9 +341,8 @@ class MergeOrderTestCase(TestCase):
 				ambiguous_merge_order = True,
 				# The following merge order assertion reflects optimal order for
 				# a circular relationship which is DEPEND in one direction and
-				# RDEPEND in the other. The assertion currently fails, and the
-				# patch for bug 690436 will fix it.
-				#merge_order_assertions = (("app-misc/circ-buildtime-a-1", "app-misc/circ-buildtime-c-1"),),
+				# RDEPEND in the other.
+				merge_order_assertions = (("app-misc/circ-buildtime-a-1", "app-misc/circ-buildtime-c-1"),),
 				mergelist = [("app-misc/circ-buildtime-b-1", "app-misc/circ-buildtime-c-1", "app-misc/circ-buildtime-a-1"), "app-misc/some-app-c-1"]),
 			# Test optimal merge order for a circular dep that is
 			# RDEPEND in one direction and PDEPEND in the other.


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2020-02-15  0:58 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2020-02-15  0:58 UTC (permalink / raw
  To: gentoo-commits

commit:     b3a945a9dad98a6d2064a9120206ad3cc9d46675
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Feb 15 00:53:00 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat Feb 15 00:56:45 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=b3a945a9

_expand_set_args: un-reverse nested set traversal

Un-reverse traversal order for @profile @selected @system.

Bug: https://bugs.gentoo.org/649622
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                       | 6 ++----
 lib/portage/tests/resolver/test_or_choices.py | 4 ++--
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 27696ad40..a8ccd270d 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -2788,10 +2788,8 @@ class depgraph(object):
 
 				# Traverse nested sets and add them to the stack
 				# if they're not already in the graph. Also, graph
-				# edges between parent and nested sets. Traverse in
-				# sorted order for consistent results, using reverse
-				# sort since we pop these sets from a stack.
-				for token in sorted(arg.pset.getNonAtoms(), reverse=True):
+				# edges between parent and nested sets.
+				for token in sorted(arg.pset.getNonAtoms()):
 					if not token.startswith(SETPREFIX):
 						continue
 					s = token[len(SETPREFIX):]

diff --git a/lib/portage/tests/resolver/test_or_choices.py b/lib/portage/tests/resolver/test_or_choices.py
index 5c6803784..f9d9687f3 100644
--- a/lib/portage/tests/resolver/test_or_choices.py
+++ b/lib/portage/tests/resolver/test_or_choices.py
@@ -676,7 +676,7 @@ class OrChoicesTestCase(TestCase):
 				options = {'--update': True, '--deep': True},
 				success = True,
 				mergelist=['virtual/w3m-0'],
-				graph_order=['@world', '@system', '@selected', '@profile', '[nomerge]app-misc/neofetch-6.1.0', '[nomerge]mail-client/neomutt-20191207', '[nomerge]www-client/lynx-2.9.0_pre4', '[nomerge]x11-base/xorg-server-1.20.7', '[nomerge]app-text/xmlto-0.0.28-r1', '[nomerge]www-client/w3m-0.5.3_p20190105', 'virtual/w3m-0'],
+				graph_order=['@world', '@profile', '@selected', '@system', '[nomerge]app-misc/neofetch-6.1.0', '[nomerge]mail-client/neomutt-20191207', '[nomerge]www-client/lynx-2.9.0_pre4', '[nomerge]x11-base/xorg-server-1.20.7', '[nomerge]app-text/xmlto-0.0.28-r1', '[nomerge]www-client/w3m-0.5.3_p20190105', 'virtual/w3m-0'],
 			),
 
 		)
@@ -715,7 +715,7 @@ class OrChoicesTestCase(TestCase):
 				options={'--depclean': True},
 				success=True,
 				cleanlist=[],
-				graph_order=['@world', '@system', '@selected', '@profile', '@____depclean_protected_set____', '[nomerge]app-misc/neofetch-6.1.0', '[nomerge]mail-client/neomutt-20191207', '[nomerge]www-client/lynx-2.9.0_pre4', '[nomerge]x11-base/xorg-server-1.20.7', '[nomerge]app-text/xmlto-0.0.28-r1', '[nomerge]www-client/w3m-0.5.3_p20190105', '[nomerge]virtual/w3m-0'],
+				graph_order=['@world', '@____depclean_protected_set____', '@profile', '@selected', '@system', '[nomerge]app-misc/neofetch-6.1.0', '[nomerge]mail-client/neomutt-20191207', '[nomerge]www-client/lynx-2.9.0_pre4', '[nomerge]x11-base/xorg-server-1.20.7', '[nomerge]app-text/xmlto-0.0.28-r1', '[nomerge]www-client/w3m-0.5.3_p20190105', '[nomerge]virtual/w3m-0'],
 			),
 
 		)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2020-03-14 20:57 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2020-03-14 20:57 UTC (permalink / raw
  To: gentoo-commits

commit:     3e7d37b7cec0978363fc99b089bd69caefe1b826
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Mar 14 19:59:22 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat Mar 14 20:35:35 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=3e7d37b7

depgraph: respect --deep=<depth> with --update (bug 712298)

Fix the _wrapped_select_pkg_highest_available_imp method to select an
installed package when appropriate for the current --deep=<depth>
setting, even with --update enabled. This prevents violation of the
current --deep=<depth> setting in cases where an installed package
which satisfies a dependency is masked for any reason.

Bug: https://bugs.gentoo.org/712298
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                  |  8 ++++++--
 lib/portage/tests/resolver/test_depth.py | 18 ++++++++++++++++--
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index a8ccd270d..6d1f62178 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2019 Gentoo Authors
+# Copyright 1999-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import division, print_function, unicode_literals
@@ -6371,7 +6371,11 @@ class depgraph(object):
 					cpv = pkg.cpv
 					reinstall_for_flags = None
 
-					if not pkg.installed or \
+					if pkg.installed and parent is not None and not self._want_update_pkg(parent, pkg):
+						# Ensure that --deep=<depth> is respected even when the
+						# installed package is masked and --update is enabled.
+						pass
+					elif not pkg.installed or \
 						(matched_packages and not avoid_update):
 						# Only enforce visibility on installed packages
 						# if there is at least one other visible package

diff --git a/lib/portage/tests/resolver/test_depth.py b/lib/portage/tests/resolver/test_depth.py
index cb1e2dd5d..ea7c803bb 100644
--- a/lib/portage/tests/resolver/test_depth.py
+++ b/lib/portage/tests/resolver/test_depth.py
@@ -1,4 +1,4 @@
-# Copyright 2011 Gentoo Foundation
+# Copyright 2011-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -9,6 +9,17 @@ class ResolverDepthTestCase(TestCase):
 
 	def testResolverDepth(self):
 
+		profile = {
+			"package.mask":
+				(
+					# Mask an installed package (for which an update is
+					# available) in order to test for bug 712298, where
+					# --update caused --deep=<depth> to be violated for
+					# such a package.
+					"<dev-libs/B-2",
+				),
+		}
+
 		ebuilds = {
 			"dev-libs/A-1": {"RDEPEND" : "dev-libs/B"},
 			"dev-libs/A-2": {"RDEPEND" : "dev-libs/B"},
@@ -65,6 +76,9 @@ class ResolverDepthTestCase(TestCase):
 		world = ["dev-libs/A"]
 
 		test_cases = (
+			# Test for bug 712298, where --update caused --deep=<depth>
+			# to be violated for dependencies that were masked. In this
+			# case, the installed dev-libs/B-1 dependency is masked.
 			ResolverPlaygroundTestCase(
 				["dev-libs/A"],
 				options = {"--update": True, "--deep": 0},
@@ -243,7 +257,7 @@ class ResolverDepthTestCase(TestCase):
 			)
 
 		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed,
-			world=world)
+			profile=profile, world=world)
 		try:
 			for test_case in test_cases:
 				playground.run_TestCase(test_case)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2020-04-12  1:52 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2020-04-12  1:52 UTC (permalink / raw
  To: gentoo-commits

commit:     9b755b46f9e88f25fecada0a32095ea614a73b57
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Apr 12 00:01:05 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Apr 12 00:56:43 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=9b755b46

depgraph: respect <foo-version:= for slot operator rebuild (bug 717140)

When searching for slot operator rebuilds, respect non slot-operator
components of parent dependencies, so that a <foo-version:= dependency
like the <dev-libs/libgit2-1:0=[ssh?] dependency from bug 717140 will
not be completely ignored. This will prevent erroneous attempts to
trigger slot operator rebuilds for upgrades that would break
<foo-version:= dependencies (which triggered upgrade/downgrade loops
when backtracking tried to resolve the breakage).

Fixes: d569a2d7275c ("_slot_operator_update_probe: fix bug #508762")
Bug: https://bugs.gentoo.org/717140
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                                      | 12 +++++++++---
 .../tests/resolver/test_slot_operator_reverse_deps.py        |  3 +--
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 6d1f62178..ec90e59df 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -2068,9 +2068,15 @@ class depgraph(object):
 			for parent, atom in self._dynamic_config._parent_atoms.get(existing_pkg, []):
 				if isinstance(parent, Package):
 					if parent in built_slot_operator_parents:
-						# This parent may need to be rebuilt, so its
-						# dependencies aren't necessarily relevant.
-						continue
+						# This parent may need to be rebuilt, therefore
+						# discard its soname and built slot operator
+						# dependency components which are not necessarily
+						# relevant.
+						if atom.soname:
+							continue
+						elif atom.package and atom.slot_operator_built:
+							# This discards the slot/subslot component.
+							atom = atom.with_slot("=")
 
 					if replacement_parent is not None and \
 						(replacement_parent.slot_atom == parent.slot_atom

diff --git a/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py b/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py
index 5c5295510..6641e9987 100644
--- a/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py
+++ b/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py
@@ -1,4 +1,4 @@
-# Copyright 2020 Gentoo Authors
+# Copyright 2016-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -122,7 +122,6 @@ class SlotOperatorReverseDepsLibGit2TestCase(TestCase):
 		trigger an upgrade to dev-libs/libgit2-1.0.0-r1, ultimately
 		resulting in an undesirable downgrade to dev-libs/libgit2-0.28.4-r1.
 		"""
-		self.todo = True
 
 		ebuilds = {
 


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2020-08-31  6:22 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2020-08-31  6:22 UTC (permalink / raw
  To: gentoo-commits

commit:     67423a3606db72f45ffe4dec325253a30508bd9d
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Aug 30 23:21:25 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Aug 30 23:39:41 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=67423a36

dephgraph: Allow elimination of highest version after slot conflict (bug 439688)

After a slot conflict occurs, allow the highest version to be eliminated
from the graph when appropriate. This is needed for correct behavior in
cases the highest version cannot be installed because an older version
is required by some package. This reverts a change related to bug 531656
from commit a9064d08ef4c92a5d0d1bfb3dc8a01b7850812b0, and that change
no longer appears to be necessary, since the unit tests related to bug
531656 now pass without it.

Due to this change in slot conflict handling, the --changed-slot test
case related to bug 456208 will now fail unless we use an @world update to
trigger rebuilds, therefore fix it to do so.

Bug: https://bugs.gentoo.org/439688
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                                        | 9 ---------
 lib/portage/tests/resolver/test_slot_change_without_revbump.py | 4 ++--
 lib/portage/tests/resolver/test_slot_conflict_rebuild.py       | 3 ---
 3 files changed, 2 insertions(+), 14 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index e071be8df..3f864aefc 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -1501,15 +1501,6 @@ class depgraph:
 
 				matched = []
 				for pkg in conflict:
-					if (pkg is highest_pkg and
-						not highest_pkg.installed and
-						inst_pkg is not None and
-						inst_pkg.sub_slot != highest_pkg.sub_slot and
-						not self._downgrade_probe(highest_pkg)):
-						# If an upgrade is desired, force the highest
-						# version into the graph (bug #531656).
-						non_matching_forced.add(highest_pkg)
-
 					if atom.match(pkg.with_use(
 						self._pkg_use_enabled(pkg))) and \
 						not (is_arg_parent and pkg.installed):

diff --git a/lib/portage/tests/resolver/test_slot_change_without_revbump.py b/lib/portage/tests/resolver/test_slot_change_without_revbump.py
index 5cd8c53d1..e05705671 100644
--- a/lib/portage/tests/resolver/test_slot_change_without_revbump.py
+++ b/lib/portage/tests/resolver/test_slot_change_without_revbump.py
@@ -71,8 +71,8 @@ class SlotChangeWithoutRevBumpTestCase(TestCase):
 
 			# Test --changed-slot
 			ResolverPlaygroundTestCase(
-				["app-arch/libarchive"],
-				options = {"--changed-slot": True, "--usepkg": True},
+				["@world"],
+				options = {"--changed-slot": True, "--usepkg": True, "--update": True, "--deep": True},
 				success = True,
 				mergelist = ["app-arch/libarchive-3.1.1", "kde-base/ark-4.10.0"]),
 

diff --git a/lib/portage/tests/resolver/test_slot_conflict_rebuild.py b/lib/portage/tests/resolver/test_slot_conflict_rebuild.py
index b3bcf44d0..d650d42ae 100644
--- a/lib/portage/tests/resolver/test_slot_conflict_rebuild.py
+++ b/lib/portage/tests/resolver/test_slot_conflict_rebuild.py
@@ -454,10 +454,7 @@ class SlotConflictRebuildTestCase(TestCase):
 		finally:
 			playground.cleanup()
 
-class SlotConflictRebuildGolangTestCase(TestCase):
-
 	def testSlotConflictRebuildGolang(self):
-		self.todo = True
 
 		ebuilds = {
 


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2020-12-02  8:32 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2020-12-02  8:32 UTC (permalink / raw
  To: gentoo-commits

commit:     07a604537e746814613dc171a5c09072ef0266af
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Dec  2 07:08:04 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Dec  2 08:06:27 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=07a60453

find_smallest_cycle: don't merge satisfied PDEPEND too early

After PDEPENDs have been neglected by the find_smallest_cycle function,
do not try to merge them too early if they are already satisfied by
an installed package. This fixes incorrect merge order for PDEPEND
cycles involving xorg-server and xorg-drivers, which was triggered
by commit 5095c2023595a75e2848f1ad3dbe25b5fb451a44 because it gave
PDEPEND higher priority than satisfied buildtime dependencies.

Fixes: 5095c2023595 ("find_smallest_cycle: enhance search prioritization")
Reported-by: josef64 in #gentoo-portage
Bug: https://bugs.gentoo.org/754903
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/DepPrioritySatisfiedRange.py       |  1 +
 lib/_emerge/depgraph.py                        |  8 ++++----
 lib/portage/tests/resolver/test_merge_order.py | 27 ++++++++++++++++++++++++--
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/lib/_emerge/DepPrioritySatisfiedRange.py b/lib/_emerge/DepPrioritySatisfiedRange.py
index fb0d7db4e..f546590e0 100644
--- a/lib/_emerge/DepPrioritySatisfiedRange.py
+++ b/lib/_emerge/DepPrioritySatisfiedRange.py
@@ -93,6 +93,7 @@ class DepPrioritySatisfiedRange:
 	ignore_medium      = _ignore_runtime
 	ignore_medium_soft = _ignore_satisfied_buildtime_slot_op
 	ignore_medium_post = _ignore_runtime_post
+	ignore_medium_post_satisifed = _ignore_satisfied_runtime_post
 	ignore_soft        = _ignore_optional
 
 

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 1271bda3e..0450291d4 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -8052,18 +8052,18 @@ class depgraph:
 									(selected_nodes[0],), noiselevel=-1)
 
 			if selected_nodes and ignore_priority is not None:
-				# Try to merge ignored medium_post deps as soon as possible
+				# Try to merge neglected medium_post deps as soon as possible
 				# if they're not satisfied by installed packages.
 				for node in selected_nodes:
 					children = set(mygraph.child_nodes(node))
-					soft = children.difference(
+					medium_post_satisifed = children.difference(
 						mygraph.child_nodes(node,
 							ignore_priority = \
-							DepPrioritySatisfiedRange.ignore_soft))
+							DepPrioritySatisfiedRange.ignore_medium_post_satisifed))
 					medium_post = children.difference(
 						mygraph.child_nodes(node,
 						ignore_priority=DepPrioritySatisfiedRange.ignore_medium_post))
-					medium_post -= soft
+					medium_post -= medium_post_satisifed
 					for child in medium_post:
 						if child in selected_nodes:
 							continue

diff --git a/lib/portage/tests/resolver/test_merge_order.py b/lib/portage/tests/resolver/test_merge_order.py
index f81fd2f6f..0510a0636 100644
--- a/lib/portage/tests/resolver/test_merge_order.py
+++ b/lib/portage/tests/resolver/test_merge_order.py
@@ -217,12 +217,23 @@ class MergeOrderTestCase(TestCase):
 				"IUSE" : "X +encode",
 				"RDEPEND" : "|| ( >=media-video/ffmpeg-0.6.90_rc0-r2[X=,encode=] >=media-video/libav-0.6.90_rc[X=,encode=] )",
 			},
+			"x11-base/xorg-drivers-1.20-r2": {
+				"EAPI": "7",
+				"IUSE": "+video_cards_fbdev",
+				"PDEPEND": "x11-base/xorg-server video_cards_fbdev? ( x11-drivers/xf86-video-fbdev )",
+			},
 			"x11-base/xorg-server-1.14.1" : {
 				"EAPI" : "5",
 				"SLOT": "0/1.14.1",
 				"DEPEND" : "media-libs/mesa",
 				"RDEPEND" : "media-libs/mesa",
+				"PDEPEND": "x11-base/xorg-drivers",
 			},
+			"x11-drivers/xf86-video-fbdev-0.5.0-r1": {
+				"EAPI": "7",
+				"DEPEND": "x11-base/xorg-server:=",
+				"RDEPEND": "x11-base/xorg-server",
+			}
 		}
 
 		installed = {
@@ -299,12 +310,24 @@ class MergeOrderTestCase(TestCase):
 				"USE" : "encode",
 				"RDEPEND" : "|| ( >=media-video/ffmpeg-0.6.90_rc0-r2[X=,encode=] >=media-video/libav-0.6.90_rc[X=,encode=] )",
 			},
+			"x11-base/xorg-drivers-1.20-r2": {
+				"EAPI": "7",
+				"IUSE": "+video_cards_fbdev",
+				"USE": "video_cards_fbdev",
+				"PDEPEND": "x11-base/xorg-server x11-drivers/xf86-video-fbdev",
+			},
 			"x11-base/xorg-server-1.14.1" : {
 				"EAPI" : "5",
 				"SLOT": "0/1.14.1",
 				"DEPEND" : "media-libs/mesa",
 				"RDEPEND" : "media-libs/mesa",
+				"PDEPEND": "x11-base/xorg-drivers",
 			},
+			"x11-drivers/xf86-video-fbdev-0.5.0-r1": {
+				"EAPI": "7",
+				"DEPEND": "x11-base/xorg-server:0/1.14.1=",
+				"RDEPEND": "x11-base/xorg-server",
+			}
 		}
 
 		test_cases = (
@@ -486,10 +509,10 @@ class MergeOrderTestCase(TestCase):
 			# Both deps are already satisfied by installed packages, but
 			# the := dep is given higher priority in merge order.
 			ResolverPlaygroundTestCase(
-				["media-libs/mesa", "x11-base/xorg-server"],
+				["media-libs/mesa", "x11-drivers/xf86-video-fbdev", "x11-base/xorg-server"],
 				success=True,
 				all_permutations = True,
-				mergelist = ['x11-base/xorg-server-1.14.1', 'media-libs/mesa-9.1.3']),
+				mergelist = ['x11-base/xorg-server-1.14.1', 'media-libs/mesa-9.1.3', 'x11-drivers/xf86-video-fbdev-0.5.0-r1']),
 			# Test prioritization of the find_smallest_cycle function, which should
 			# minimize the use of installed packages to break cycles. If installed
 			# packages must be used to break cycles, then it should prefer to do this


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2021-01-11  7:27 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2021-01-11  7:27 UTC (permalink / raw
  To: gentoo-commits

commit:     4c25c0d7af7ad71fccbfafe1e5019116c691968e
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Jan 11 00:19:06 2021 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Jan 11 03:32:45 2021 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=4c25c0d7

check_reverse_dependencies: dereference virtual expansions (bug 764764)

If an atom is the result of virtual expansion, then derefrence it to
_orig_atom in check_reverse_dependencies so that it will be correctly
handled as a built slot operator dependency when appropriate. This
solves a case triggered in bug 764764 where a virtual expansion from
virtual/dist-kernel:0/5.10.5= to =virtual/dist-kernel-5.10.5 prevented
the atom from being handled as a built slot operator dependency, which
prevented rebuilds from being triggered.

Bug: https://bugs.gentoo.org/764764
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                            | 22 ++++++++++++++++++++++
 .../resolver/test_slot_operator_reverse_deps.py    |  2 +-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index f3e834a60..2bf04406f 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -2073,6 +2073,12 @@ class depgraph:
 			for parent, atom in self._dynamic_config._parent_atoms.get(existing_pkg, []):
 				if isinstance(parent, Package):
 					if parent in built_slot_operator_parents:
+						if hasattr(atom, '_orig_atom'):
+							# If atom is the result of virtual expansion, then
+							# derefrence it to _orig_atom so that it will be correctly
+							# handled as a built slot operator dependency when
+							# appropriate (see bug 764764).
+							atom = atom._orig_atom
 						# This parent may need to be rebuilt, therefore
 						# discard its soname and built slot operator
 						# dependency components which are not necessarily
@@ -2131,6 +2137,22 @@ class depgraph:
 					allow_repo=True)
 				if not atom_set.findAtomForPackage(candidate_pkg,
 					modified_use=self._pkg_use_enabled(candidate_pkg)):
+					if debug:
+						parent_atoms = []
+						for other_parent, other_atom in self._dynamic_config._parent_atoms.get(existing_pkg, []):
+							if other_parent is parent:
+								parent_atoms.append(other_atom)
+						msg = (
+							"",
+							"",
+							"check_reverse_dependencies:",
+							"   candidate package does not match atom '%s': %s" % (atom, candidate_pkg),
+							"   parent: %s" % parent,
+							"   parent atoms: %s" % " ".join(parent_atoms),
+							"",
+						)
+						writemsg_level("\n".join(msg),
+							noiselevel=-1, level=logging.DEBUG)
 					return False
 			return True
 

diff --git a/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py b/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py
index 6e7214043..ef884f8ca 100644
--- a/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py
+++ b/lib/portage/tests/resolver/test_slot_operator_reverse_deps.py
@@ -284,7 +284,7 @@ class SlotOperatorReverseDepsVirtualTestCase(TestCase):
 				["@world"],
 				options = {"--update": True, "--deep": True},
 				success = True,
-				mergelist = []
+				mergelist = ['sys-kernel/gentoo-kernel-5.10.6', 'virtual/dist-kernel-5.10.6', 'app-emulation/virtualbox-modules-6.1.16-r1', 'x11-drivers/nvidia-drivers-460.32.03']
 			),
 		)
 


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2023-11-25  6:30 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2023-11-25  6:30 UTC (permalink / raw
  To: gentoo-commits

commit:     cdc781349337fa755bc15773e2a87e4b41f5ff1e
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Nov 22 21:46:12 2023 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Nov 22 22:26:13 2023 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=cdc78134

Revert "find_smallest_cycle: Increase ignore_priority to find smaller cycles"

This reverts commit 9206d5a75ecd2d9ae0fe63e57d28aa8061b5927e.
The len(smallest_cycle) == 1 loop termination condition is
not optimal and it's too expensive as reported in bug 917660.

Bug: https://bugs.gentoo.org/917660
Bug: https://bugs.gentoo.org/917259
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                            |  7 +++----
 .../tests/resolver/test_alternatives_gzip.py       |  7 +++++--
 lib/portage/tests/resolver/test_merge_order.py     | 24 ++++++++++------------
 .../tests/resolver/test_rebuild_ghostscript.py     |  6 +++---
 4 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 0d3b37c698..e4305c18c9 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -9345,10 +9345,9 @@ class depgraph:
                                     smallest_cycle = selected_nodes
                                     ignore_priority = priority
 
-                        if smallest_cycle is not None and len(smallest_cycle) == 1:
-                            # The cycle can't get any smaller than this,
-                            # so there is no need to search further since
-                            # we try to minimize ignore_priority.
+                        # Exit this loop with the lowest possible priority, which
+                        # minimizes the use of installed packages to break cycles.
+                        if smallest_cycle is not None:
                             break
 
                     return smallest_cycle, ignore_priority

diff --git a/lib/portage/tests/resolver/test_alternatives_gzip.py b/lib/portage/tests/resolver/test_alternatives_gzip.py
index 7cd1da25f1..602ed1756f 100644
--- a/lib/portage/tests/resolver/test_alternatives_gzip.py
+++ b/lib/portage/tests/resolver/test_alternatives_gzip.py
@@ -1,6 +1,8 @@
 # Copyright 2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
+import pytest
+
 from portage.tests import TestCase
 from portage.tests.resolver.ResolverPlayground import (
     ResolverPlayground,
@@ -8,6 +10,7 @@ from portage.tests.resolver.ResolverPlayground import (
 )
 
 
+@pytest.mark.xfail()
 class AlternativesGzipTestCase(TestCase):
     def testAlternativesGzip(self):
         """
@@ -16,8 +19,8 @@ class AlternativesGzipTestCase(TestCase):
         find_smallest_cycle selects a large cycle and the topological
         sort produces poor results when leaf_nodes returns
         app-alternatives/gzip as part of a large group of nodes.
-        This problem was solved by increasing ignore_priority in order
-        to find a smaller cycle.
+        This problem might be solved by implementing a finer-grained
+        ignore_priority for leaf_nodes calls.
         """
         ebuilds = {
             "app-alternatives/gzip-1": {

diff --git a/lib/portage/tests/resolver/test_merge_order.py b/lib/portage/tests/resolver/test_merge_order.py
index 671543ca29..940eb3bbbe 100644
--- a/lib/portage/tests/resolver/test_merge_order.py
+++ b/lib/portage/tests/resolver/test_merge_order.py
@@ -382,12 +382,10 @@ class MergeOrderTestCase(TestCase):
                 ambiguous_merge_order=True,
                 # The following merge order assertion reflects optimal order for
                 # a circular relationship which is DEPEND in one direction and
-                # RDEPEND in the other. However, it is not respected because
-                # it would result in a temporarily broken RDEPEND, so we instead
-                # rely on satisfied installed build-time dependencies.
-                # merge_order_assertions=(
-                #    ("app-misc/circ-buildtime-a-1", "app-misc/circ-buildtime-c-1"),
-                # ),
+                # RDEPEND in the other.
+                merge_order_assertions=(
+                    ("app-misc/circ-buildtime-a-1", "app-misc/circ-buildtime-c-1"),
+                ),
                 mergelist=[
                     (
                         "app-misc/circ-buildtime-b-1",
@@ -701,15 +699,15 @@ class MergeOrderTestCase(TestCase):
                     "!app-misc/installed-blocker-a",
                     "app-misc/circ-direct-a-1",
                     "app-misc/circ-direct-b-1",
-                    "app-misc/circ-satisfied-a-1",
-                    "app-misc/circ-satisfied-c-1",
-                    "app-misc/circ-satisfied-b-1",
-                    "app-misc/circ-buildtime-c-1",
-                    "app-misc/circ-buildtime-b-1",
-                    "app-misc/circ-buildtime-a-1",
-                    "app-misc/some-app-c-1",
                     "x11-base/xorg-server-1.14.1",
                     "media-libs/mesa-9.1.3",
+                    "app-misc/circ-buildtime-a-1",
+                    "app-misc/circ-buildtime-b-1",
+                    "app-misc/circ-buildtime-c-1",
+                    "app-misc/some-app-c-1",
+                    "app-misc/circ-satisfied-a-1",
+                    "app-misc/circ-satisfied-b-1",
+                    "app-misc/circ-satisfied-c-1",
                 ],
             ),
         )

diff --git a/lib/portage/tests/resolver/test_rebuild_ghostscript.py b/lib/portage/tests/resolver/test_rebuild_ghostscript.py
index e1d736610e..8d7cbb1f92 100644
--- a/lib/portage/tests/resolver/test_rebuild_ghostscript.py
+++ b/lib/portage/tests/resolver/test_rebuild_ghostscript.py
@@ -136,12 +136,12 @@ class RebuildGhostscriptTestCase(TestCase):
                 success=True,
                 mergelist=[
                     "sys-apps/dbus-1.15.6",
+                    "x11-libs/gtk+-3.24.38",
+                    "net-print/cups-2.4.6",
+                    "net-dns/avahi-0.8-r7",
                     "app-text/ghostscript-gpl-10.01.2",
                     "app-text/libspectre-0.2.12",
                     "x11-libs/goffice-0.10.55",
-                    "net-dns/avahi-0.8-r7",
-                    "net-print/cups-2.4.6",
-                    "x11-libs/gtk+-3.24.38",
                 ],
             ),
         )


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2023-11-29 19:55 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2023-11-29 19:55 UTC (permalink / raw
  To: gentoo-commits

commit:     31832c7faf5bffde25a596ce62ecf84c478fac45
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Nov 29 16:14:27 2023 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Nov 29 16:33:18 2023 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=31832c7f

Optimize runtime cycle ignore_priority leaf selection loop for topological sort

Since increasing ignore_priority can only lead to a larger
selection of leaf nodes, there is no need to increase ignore_priority
to search for smaller groups of leaf nodes.

It was the "only harvest one node at a time" part of commit
3487594cd8f4 that caused the test case to succeed.

Fixes: 3487594cd8f4 ("Increase ignore_priority during topological sort for runtime cycle")
Bug: https://bugs.gentoo.org/917259
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/depgraph.py                        | 31 ++++++++++----------------
 lib/portage/tests/resolver/test_merge_order.py |  8 +++----
 2 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 9f041f83a9..15c3e3ca7b 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -9478,36 +9478,29 @@ class depgraph:
                 )
                 selected_nodes = []
                 while cycle_digraph:
-                    # Increase ignore_priority in order to find
-                    # smaller groups of leaf nodes. This solves
-                    # bug 917259 which happened because too many
-                    # leaves were selected at once.
-                    smallest_leaves = None
+                    leaves = None
                     for ignore_priority in ignore_priorities:
                         leaves = cycle_digraph.leaf_nodes(
                             ignore_priority=ignore_priority
                         )
-                        if leaves and (
-                            smallest_leaves is None
-                            or len(leaves) < len(smallest_leaves)
-                        ):
-                            smallest_leaves = leaves
-                            if len(smallest_leaves) == 1:
-                                break
+                        if leaves:
+                            # Select leaves with minimum ignore_priority,
+                            # in order to ingore as few deps as possible.
+                            break
 
-                    if smallest_leaves is None:
-                        smallest_leaves = [cycle_digraph.order[-1]]
+                    if leaves is None:
+                        leaves = [cycle_digraph.order[-1]]
 
                     # Prefer installed leaves, in order to avoid
-                    # merging something too early.
-                    installed_leaves = [pkg for pkg in smallest_leaves if pkg.installed]
+                    # merging something too early as in bug 917259.
+                    installed_leaves = [pkg for pkg in leaves if pkg.installed]
                     if installed_leaves:
-                        smallest_leaves = installed_leaves
+                        leaves = installed_leaves
 
                     # Only harvest one node at a time, in order to
                     # minimize the number of ignored dependencies.
-                    cycle_digraph.remove(smallest_leaves[0])
-                    selected_nodes.append(smallest_leaves[0])
+                    cycle_digraph.remove(leaves[0])
+                    selected_nodes.append(leaves[0])
 
             if not selected_nodes and myblocker_uninstalls:
                 # An Uninstall task needs to be executed in order to

diff --git a/lib/portage/tests/resolver/test_merge_order.py b/lib/portage/tests/resolver/test_merge_order.py
index e6d45c847b..a6c236a207 100644
--- a/lib/portage/tests/resolver/test_merge_order.py
+++ b/lib/portage/tests/resolver/test_merge_order.py
@@ -385,9 +385,9 @@ class MergeOrderTestCase(TestCase):
                 # RDEPEND in the other. However, it is not respected because
                 # it would result in a temporarily broken RDEPEND, so we instead
                 # rely on satisfied installed build-time dependencies.
-                # merge_order_assertions=(
-                #    ("app-misc/circ-buildtime-a-1", "app-misc/circ-buildtime-c-1"),
-                # ),
+                merge_order_assertions=(
+                    ("app-misc/circ-buildtime-a-1", "app-misc/circ-buildtime-c-1"),
+                ),
                 mergelist=[
                     (
                         "app-misc/circ-buildtime-b-1",
@@ -703,9 +703,9 @@ class MergeOrderTestCase(TestCase):
                     "app-misc/circ-direct-b-1",
                     "x11-base/xorg-server-1.14.1",
                     "media-libs/mesa-9.1.3",
+                    "app-misc/circ-buildtime-a-1",
                     "app-misc/circ-buildtime-c-1",
                     "app-misc/circ-buildtime-b-1",
-                    "app-misc/circ-buildtime-a-1",
                     "app-misc/some-app-c-1",
                     "app-misc/circ-satisfied-a-1",
                     "app-misc/circ-satisfied-c-1",


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2023-12-26 21:05 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2023-12-26 21:05 UTC (permalink / raw
  To: gentoo-commits

commit:     64b16b76611e14ff0b38b762486f073039f21a05
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Dec 25 02:53:57 2023 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue Dec 26 21:04:25 2023 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=64b16b76

depclean: Strengthen IDEPEND in unmerge order

Increase priority of IDEPEND so that it is stronger
than RDEPEND in unmerge order calculations. This
causes IDEPEND to be unmerged afterwards when
packages are involved in RDEPEND cycles.

Bug: https://bugs.gentoo.org/916135
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/AbstractDepPriority.py                |  3 +-
 lib/_emerge/UnmergeDepPriority.py                 | 35 +++++++------
 lib/_emerge/actions.py                            |  5 +-
 lib/_emerge/depgraph.py                           |  4 +-
 lib/portage/tests/resolver/test_depclean_order.py | 63 +++++++++++++++++++++++
 5 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/lib/_emerge/AbstractDepPriority.py b/lib/_emerge/AbstractDepPriority.py
index a9616c1094..3af262cd79 100644
--- a/lib/_emerge/AbstractDepPriority.py
+++ b/lib/_emerge/AbstractDepPriority.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2013 Gentoo Foundation
+# Copyright 1999-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import copy
@@ -9,6 +9,7 @@ class AbstractDepPriority(SlotObject):
     __slots__ = (
         "buildtime",
         "buildtime_slot_op",
+        "installtime",
         "runtime",
         "runtime_post",
         "runtime_slot_op",

diff --git a/lib/_emerge/UnmergeDepPriority.py b/lib/_emerge/UnmergeDepPriority.py
index d818bad1b8..b14f8b84eb 100644
--- a/lib/_emerge/UnmergeDepPriority.py
+++ b/lib/_emerge/UnmergeDepPriority.py
@@ -12,18 +12,19 @@ class UnmergeDepPriority(AbstractDepPriority):
         "satisfied",
     )
     """
-	Combination of properties           Priority  Category
-
-	runtime_slot_op                        0       HARD
-	runtime                               -1       HARD
-	runtime_post                          -2       HARD
-	buildtime                             -3       SOFT
-	(none of the above)                   -3       SOFT
-	"""
+    Combination of properties           Priority  Category
+
+    installtime                            0       HARD
+    runtime_slot_op                       -1       HARD
+    runtime                               -2       HARD
+    runtime_post                          -3       HARD
+    buildtime                             -4       SOFT
+    (none of the above)                   -4       SOFT
+    """
 
     MAX = 0
-    SOFT = -3
-    MIN = -3
+    SOFT = -4
+    MIN = -4
 
     def __init__(self, **kwargs):
         AbstractDepPriority.__init__(self, **kwargs)
@@ -31,19 +32,23 @@ class UnmergeDepPriority(AbstractDepPriority):
             self.optional = True
 
     def __int__(self):
-        if self.runtime_slot_op:
+        if self.installtime:
             return 0
-        if self.runtime:
+        if self.runtime_slot_op:
             return -1
-        if self.runtime_post:
+        if self.runtime:
             return -2
-        if self.buildtime:
+        if self.runtime_post:
             return -3
-        return -3
+        if self.buildtime:
+            return -4
+        return -4
 
     def __str__(self):
         if self.ignored:
             return "ignored"
+        if self.installtime:
+            return "install time"
         if self.runtime_slot_op:
             return "hard slot op"
         myvalue = self.__int__()

diff --git a/lib/_emerge/actions.py b/lib/_emerge/actions.py
index 13bb75931c..20f3978f77 100644
--- a/lib/_emerge/actions.py
+++ b/lib/_emerge/actions.py
@@ -1568,11 +1568,12 @@ def _calc_depclean(settings, trees, ldpath_mtimes, myopts, action, args_set, spi
         graph = digraph()
         del cleanlist[:]
 
+        installtime = UnmergeDepPriority(installtime=True, runtime=True)
         runtime = UnmergeDepPriority(runtime=True)
         runtime_post = UnmergeDepPriority(runtime_post=True)
         buildtime = UnmergeDepPriority(buildtime=True)
         priority_map = {
-            "IDEPEND": runtime,
+            "IDEPEND": installtime,
             "RDEPEND": runtime,
             "PDEPEND": runtime_post,
             "BDEPEND": buildtime,
@@ -1683,6 +1684,8 @@ def _calc_depclean(settings, trees, ldpath_mtimes, myopts, action, args_set, spi
                         break
                 if not nodes:
                     raise AssertionError("no root nodes")
+                # Sort nodes for deterministic results.
+                nodes.sort(reverse=True)
                 if ignore_priority is not None:
                     # Some deps have been dropped due to circular dependencies,
                     # so only pop one node in order to minimize the number that

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index e92c6962ac..6ee4471bbe 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -4007,7 +4007,9 @@ class depgraph:
             (
                 self._frozen_config._running_root.root,
                 edepend["IDEPEND"],
-                self._priority(cross=self._cross(pkg.root), runtime=True),
+                self._priority(
+                    cross=self._cross(pkg.root), installtime=True, runtime=True
+                ),
             ),
             (
                 myroot,

diff --git a/lib/portage/tests/resolver/test_depclean_order.py b/lib/portage/tests/resolver/test_depclean_order.py
index 23b5e755c3..36d60d44e9 100644
--- a/lib/portage/tests/resolver/test_depclean_order.py
+++ b/lib/portage/tests/resolver/test_depclean_order.py
@@ -109,3 +109,66 @@ class SimpleDepcleanTestCase(TestCase):
                 self.assertEqual(test_case.test_success, True, test_case.fail_msg)
         finally:
             playground.cleanup()
+
+    def testCircularDepclean(self):
+        """
+        Test for bug 916135, where an indirect circular dependency caused
+        the unmerge order to fail to account for IDEPEND.
+        """
+
+        ebuilds = {
+            "dev-util/A-1": {},
+            "dev-libs/B-1": {
+                "EAPI": "8",
+                "SLOT": "1",
+                "IDEPEND": "dev-util/A",
+                "RDEPEND": "dev-libs/B:=",
+            },
+            "dev-libs/B-2": {
+                "EAPI": "8",
+                "SLOT": "2",
+                "IDEPEND": "dev-util/A",
+                "RDEPEND": "dev-libs/B:=",
+            },
+            "dev-libs/C-1": {},
+        }
+
+        installed = {
+            "dev-util/A-1": {},
+            "dev-libs/B-1": {
+                "EAPI": "8",
+                "SLOT": "1",
+                "IDEPEND": "dev-util/A",
+                "RDEPEND": "dev-libs/B:2/2=",
+            },
+            "dev-libs/B-2": {
+                "EAPI": "8",
+                "SLOT": "2",
+                "IDEPEND": "dev-util/A",
+                "RDEPEND": "dev-libs/B:1/1=",
+            },
+            "dev-libs/C-1": {},
+        }
+
+        world = ("dev-libs/C",)
+
+        test_cases = (
+            # Remove dev-libs/B first because it IDEPENDs on dev-util/A
+            ResolverPlaygroundTestCase(
+                [],
+                options={"--depclean": True},
+                success=True,
+                ordered=True,
+                cleanlist=["dev-libs/B-2", "dev-libs/B-1", "dev-util/A-1"],
+            ),
+        )
+
+        playground = ResolverPlayground(
+            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()


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/
@ 2024-01-08  8:58 Zac Medico
  0 siblings, 0 replies; 13+ messages in thread
From: Zac Medico @ 2024-01-08  8:58 UTC (permalink / raw
  To: gentoo-commits

commit:     4b885b9ca063c990b1e218c73a786e9d434717e8
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Jan  8 06:04:37 2024 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Jan  8 08:08:51 2024 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=4b885b9c

_calc_depclean: add dep_check action

Add a dep_check action which can be used to check the
dependencies of all installed packages. The plan is for depgraph
to use this action to check for broken dependencies prior to the
merge order calculation. The new frozen_config parameter will
allow depgraph to pass a shared frozen config to _calc_depclean.

The result of the dep_check action becomes stale as soon as there
is any change to the installed packages. So, in order to account
for dependencies that may become broken or satisfied during the
process of updating installed packages, the merge order
calculation will need to refresh the dep_check calculation for
every merge order choice that it makes. This refresh will need
to be optimized to identify the portion of the graph that would
become stale due to a given change, so that it can avoid
unnecessary repetition of work.

Bug: https://bugs.gentoo.org/921333
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/actions.py                           | 21 ++++++-
 lib/_emerge/depgraph.py                          |  7 ++-
 lib/portage/tests/resolver/ResolverPlayground.py | 43 ++++++++++++--
 lib/portage/tests/resolver/meson.build           |  1 +
 lib/portage/tests/resolver/test_broken_deps.py   | 76 ++++++++++++++++++++++++
 5 files changed, 138 insertions(+), 10 deletions(-)

diff --git a/lib/_emerge/actions.py b/lib/_emerge/actions.py
index 20f3978f77..2710c4856c 100644
--- a/lib/_emerge/actions.py
+++ b/lib/_emerge/actions.py
@@ -909,7 +909,16 @@ _depclean_result = collections.namedtuple(
 )
 
 
-def _calc_depclean(settings, trees, ldpath_mtimes, myopts, action, args_set, spinner):
+def _calc_depclean(
+    settings,
+    trees,
+    ldpath_mtimes,
+    myopts,
+    action,
+    args_set,
+    spinner,
+    frozen_config=None,
+):
     allow_missing_deps = bool(args_set)
 
     debug = "--debug" in myopts
@@ -988,12 +997,14 @@ def _calc_depclean(settings, trees, ldpath_mtimes, myopts, action, args_set, spi
 
     writemsg_level("\nCalculating dependencies  ")
     resolver_params = create_depgraph_params(myopts, "remove")
-    resolver = depgraph(settings, trees, myopts, resolver_params, spinner)
+    resolver = depgraph(
+        settings, trees, myopts, resolver_params, spinner, frozen_config=frozen_config
+    )
     resolver._load_vdb()
     vardb = resolver._frozen_config.trees[eroot]["vartree"].dbapi
     real_vardb = trees[eroot]["vartree"].dbapi
 
-    if action == "depclean":
+    if action in ("dep_check", "depclean"):
         if args_set:
             if deselect:
                 # Start with an empty set.
@@ -1002,6 +1013,7 @@ def _calc_depclean(settings, trees, ldpath_mtimes, myopts, action, args_set, spi
                 # Pull in any sets nested within the selected set.
                 selected_set.update(psets["selected"].getNonAtoms())
 
+        if args_set or action == "dep_check":
             # Pull in everything that's installed but not matched
             # by an argument atom since we don't want to clean any
             # package if something depends on it.
@@ -1098,6 +1110,9 @@ def _calc_depclean(settings, trees, ldpath_mtimes, myopts, action, args_set, spi
     if not success:
         return _depclean_result(1, [], False, 0, resolver)
 
+    if action == "dep_check":
+        return _depclean_result(0, [], False, 0, resolver)
+
     def unresolved_deps():
         soname_deps = set()
         unresolvable = set()

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index a2865cad23..b859e68224 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -11723,6 +11723,7 @@ def backtrack_depgraph(
     myaction: Optional[str],
     myfiles: list[str],
     spinner: "_emerge.stdout_spinner.stdout_spinner",
+    frozen_config: Optional[_frozen_depgraph_config] = None,
 ) -> tuple[Any, depgraph, list[str]]:
     """
 
@@ -11747,6 +11748,7 @@ def _backtrack_depgraph(
     myaction: Optional[str],
     myfiles: list[str],
     spinner: "_emerge.stdout_spinner.stdout_spinner",
+    frozen_config: Optional[_frozen_depgraph_config] = None,
 ) -> tuple[Any, depgraph, list[str], int, int]:
     debug = "--debug" in myopts
     mydepgraph = None
@@ -11756,7 +11758,10 @@ def _backtrack_depgraph(
     backtracker = Backtracker(max_depth)
     backtracked = 0
 
-    frozen_config = _frozen_depgraph_config(settings, trees, myopts, myparams, spinner)
+    if frozen_config is None:
+        frozen_config = _frozen_depgraph_config(
+            settings, trees, myopts, myparams, spinner
+        )
 
     while backtracker:
         if debug and mydepgraph is not None:

diff --git a/lib/portage/tests/resolver/ResolverPlayground.py b/lib/portage/tests/resolver/ResolverPlayground.py
index 592f5cc5dc..2d26012873 100644
--- a/lib/portage/tests/resolver/ResolverPlayground.py
+++ b/lib/portage/tests/resolver/ResolverPlayground.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2023 Gentoo Authors
+# Copyright 2010-2024 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import bz2
@@ -33,7 +33,11 @@ from _emerge.actions import _calc_depclean
 from _emerge.Blocker import Blocker
 from _emerge.create_depgraph_params import create_depgraph_params
 from _emerge.DependencyArg import DependencyArg
-from _emerge.depgraph import backtrack_depgraph
+from _emerge.depgraph import (
+    _frozen_depgraph_config,
+    backtrack_depgraph,
+)
+from _emerge.Package import Package
 from _emerge.RootConfig import RootConfig
 
 
@@ -732,7 +736,16 @@ class ResolverPlayground:
                 portage.util.noiselimit = -2
             _emerge.emergelog._disable = True
 
-            if action in ("depclean", "prune"):
+            # NOTE: frozen_config could be cached and reused if options and params were constant.
+            params_action = (
+                "remove" if action in ("dep_check", "depclean", "prune") else action
+            )
+            params = create_depgraph_params(options, params_action)
+            frozen_config = _frozen_depgraph_config(
+                self.settings, self.trees, options, params, None
+            )
+
+            if params_action == "remove":
                 depclean_result = _calc_depclean(
                     self.settings,
                     self.trees,
@@ -741,6 +754,7 @@ class ResolverPlayground:
                     action,
                     InternalPackageSet(initial_atoms=atoms, allow_wildcard=True),
                     None,
+                    frozen_config=frozen_config,
                 )
                 result = ResolverPlaygroundDepcleanResult(
                     atoms,
@@ -751,9 +765,15 @@ class ResolverPlayground:
                     depclean_result.depgraph,
                 )
             else:
-                params = create_depgraph_params(options, action)
                 success, depgraph, favorites = backtrack_depgraph(
-                    self.settings, self.trees, options, params, action, atoms, None
+                    self.settings,
+                    self.trees,
+                    options,
+                    params,
+                    action,
+                    atoms,
+                    None,
+                    frozen_config=frozen_config,
                 )
                 depgraph._show_merge_list()
                 depgraph.display_problems()
@@ -939,7 +959,8 @@ class ResolverPlaygroundTestCase:
                 )
                 and expected is not None
             ):
-                expected = set(expected)
+                # unsatisfied_deps can be a dict for depclean-like actions
+                expected = expected if isinstance(expected, dict) else set(expected)
 
             elif key == "forced_rebuilds" and expected is not None:
                 expected = {k: set(v) for k, v in expected.items()}
@@ -1109,11 +1130,14 @@ class ResolverPlaygroundDepcleanResult:
         "ordered",
         "req_pkg_count",
         "graph_order",
+        "unsatisfied_deps",
     )
     optional_checks = (
+        "cleanlist",
         "ordered",
         "req_pkg_count",
         "graph_order",
+        "unsatisfied_deps",
     )
 
     def __init__(self, atoms, rval, cleanlist, ordered, req_pkg_count, depgraph):
@@ -1125,3 +1149,10 @@ class ResolverPlaygroundDepcleanResult:
         self.graph_order = [
             _mergelist_str(node, depgraph) for node in depgraph._dynamic_config.digraph
         ]
+        self.unsatisfied_deps = {}
+        for dep in depgraph._dynamic_config._initially_unsatisfied_deps:
+            if isinstance(dep.parent, Package):
+                parent_repr = dep.parent.cpv
+            else:
+                parent_repr = dep.parent.arg
+            self.unsatisfied_deps.setdefault(parent_repr, set()).add(dep.atom)

diff --git a/lib/portage/tests/resolver/meson.build b/lib/portage/tests/resolver/meson.build
index 77c65a511e..8892c78131 100644
--- a/lib/portage/tests/resolver/meson.build
+++ b/lib/portage/tests/resolver/meson.build
@@ -15,6 +15,7 @@ py.install_sources(
         'test_bdeps.py',
         'test_binary_pkg_ebuild_visibility.py',
         'test_blocker.py',
+        'test_broken_deps.py',
         'test_changed_deps.py',
         'test_circular_choices.py',
         'test_circular_choices_rust.py',

diff --git a/lib/portage/tests/resolver/test_broken_deps.py b/lib/portage/tests/resolver/test_broken_deps.py
new file mode 100644
index 0000000000..8ca7809d34
--- /dev/null
+++ b/lib/portage/tests/resolver/test_broken_deps.py
@@ -0,0 +1,76 @@
+# Copyright 2024 Gentoo Authors
+# 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 BrokenDepsTestCase(TestCase):
+    def testBrokenDeps(self):
+        """
+        Test the _calc_depclean "dep_check" action which will eventually
+        be used to check for unsatisfied deps of installed packages
+        for bug 921333.
+        """
+        ebuilds = {
+            "dev-qt/qtcore-5.15.12": {
+                "EAPI": "8",
+            },
+            "dev-qt/qtcore-5.15.11-r1": {
+                "EAPI": "8",
+            },
+            "dev-qt/qtxmlpatterns-5.15.12": {
+                "EAPI": "8",
+                "DEPEND": "=dev-qt/qtcore-5.15.12*",
+                "RDEPEND": "=dev-qt/qtcore-5.15.12*",
+            },
+            "dev-qt/qtxmlpatterns-5.15.11": {
+                "EAPI": "8",
+                "DEPEND": "=dev-qt/qtcore-5.15.11*",
+                "RDEPEND": "=dev-qt/qtcore-5.15.11*",
+            },
+            "kde-frameworks/syntax-highlighting-5.113.0": {
+                "EAPI": "8",
+                "DEPEND": ">=dev-qt/qtxmlpatterns-5.15.9:5",
+            },
+        }
+        installed = {
+            "dev-qt/qtcore-5.15.12": {
+                "EAPI": "8",
+            },
+            "dev-qt/qtxmlpatterns-5.15.11": {
+                "EAPI": "8",
+                "DEPEND": "=dev-qt/qtcore-5.15.11*",
+                "RDEPEND": "=dev-qt/qtcore-5.15.11*",
+            },
+            "kde-frameworks/syntax-highlighting-5.113.0": {
+                "EAPI": "8",
+                "DEPEND": ">=dev-qt/qtxmlpatterns-5.15.9:5",
+            },
+        }
+
+        world = ("kde-frameworks/syntax-highlighting",)
+
+        test_cases = (
+            ResolverPlaygroundTestCase(
+                [],
+                action="dep_check",
+                success=True,
+                unsatisfied_deps={
+                    "dev-qt/qtxmlpatterns-5.15.11": {"=dev-qt/qtcore-5.15.11*"}
+                },
+            ),
+        )
+
+        playground = ResolverPlayground(
+            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()


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-01-08  8:58 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-11-26 20:35 [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/_emerge/ Zac Medico
  -- strict thread matches above, loose matches on Subject: below --
2019-12-06  4:06 Zac Medico
2019-12-26 23:00 Zac Medico
2020-02-15  0:58 Zac Medico
2020-03-14 20:57 Zac Medico
2020-04-12  1:52 Zac Medico
2020-08-31  6:22 Zac Medico
2020-12-02  8:32 Zac Medico
2021-01-11  7:27 Zac Medico
2023-11-25  6:30 Zac Medico
2023-11-29 19:55 Zac Medico
2023-12-26 21:05 Zac Medico
2024-01-08  8:58 Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox