public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-03-05  0:56 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-03-05  0:56 UTC (permalink / raw
  To: gentoo-commits

commit:     ef125a7885f4f5a614265f3f8a97803f6a8c1264
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Mar  5 00:56:28 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue Mar  5 00:56:28 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=ef125a78

Fix bug #460304.

---
 pym/_emerge/depgraph.py                     |   26 +++++++++++++++++++++++++
 pym/portage/tests/resolver/test_slot_abi.py |   28 ++++++++++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index dddada0..9033285 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1189,6 +1189,8 @@ class depgraph(object):
 		for replacement_parent in self._iter_similar_available(dep.parent,
 			dep.parent.slot_atom):
 
+			selected_atoms = None
+
 			for atom in replacement_parent.validated_atoms:
 				if not atom.slot_operator == "=" or \
 					atom.blocker or \
@@ -1198,6 +1200,7 @@ class depgraph(object):
 				# Discard USE deps, we're only searching for an approximate
 				# pattern, and dealing with USE states is too complex for
 				# this purpose.
+				unevaluated_atom = atom.unevaluated_atom
 				atom = atom.without_use
 
 				if replacement_parent.built and \
@@ -1247,6 +1250,17 @@ class depgraph(object):
 						# slot conflict).
 						insignificant = True
 
+					if not insignificant:
+						# Evaluate USE conditionals and || deps, in order
+						# to see if this atom is really desirable, since
+						# otherwise we may trigger an undesirable rebuild
+						# as in bug #460304.
+						if selected_atoms is None:
+							selected_atoms = self._select_atoms_probe(
+								dep.child.root, replacement_parent)
+						if unevaluated_atom not in selected_atoms:
+							continue
+
 					if debug:
 						msg = []
 						msg.append("")
@@ -1393,6 +1407,18 @@ class depgraph(object):
 
 		return available_pkg is not None
 
+	def _select_atoms_probe(self, root, pkg):
+		selected_atoms = []
+		use = self._pkg_use_enabled(pkg)
+		for k in pkg._dep_keys:
+			v = pkg._metadata.get(k)
+			if not v:
+				continue
+			selected_atoms.extend(self._select_atoms(
+				root, v, myuse=use, parent=pkg)[pkg])
+		return frozenset(x.unevaluated_atom for
+			x in selected_atoms)
+
 	def _iter_similar_available(self, graph_pkg, atom):
 		"""
 		Given a package that's in the graph, do a rough check to

diff --git a/pym/portage/tests/resolver/test_slot_abi.py b/pym/portage/tests/resolver/test_slot_abi.py
index ca3662d..7263504 100644
--- a/pym/portage/tests/resolver/test_slot_abi.py
+++ b/pym/portage/tests/resolver/test_slot_abi.py
@@ -290,7 +290,33 @@ class SlotAbiTestCase(TestCase):
 				["@world"],
 				options = {"--update": True, "--deep": True},
 				success = True,
-				mergelist = ["net-misc/networkmanager-0.9.6.4-r1"]),
+				mergelist = []),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, user_config=user_config, world=world,
+			debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()
+
+		user_config = {
+			"make.conf" : ("USE=\"-wimax\"",)
+		}
+
+		test_cases = (
+
+			# Demonstrate bug #460304 again, but with inverted USE
+			# settings this time.
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True},
+				success = True,
+				mergelist = ['dev-libs/libnl-3.2.14', 'net-misc/networkmanager-0.9.6.4-r1']),
 
 		)
 


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2018-05-04 17:12 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2018-05-04 17:12 UTC (permalink / raw
  To: gentoo-commits

commit:     ce150da22e351a7ba52a6390b9cb7aa076c0c8ce
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri May  4 03:21:40 2018 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri May  4 17:11:07 2018 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=ce150da2

depgraph.autounmask_breakage_detected: ignore REQUIRED_USE violations (bug 654782)

When autounmask USE changes violate REQUIRED_USE, rather than
recalculate with autounmask disabled, display the autounmask USE
changes along with the REQUIRED_USE violation. Adjust unit tests
to allow for the autounmask USE changes that were previously
discarded. For the case reported in bug 654782, the output will
appear as follows:

The following keyword changes are necessary to proceed:
 (see "package.accept_keywords" in the portage(5) man page for more details)
# required by =retext-7.0.1-r1 (argument)
=app-editors/retext-7.0.1-r1 ~amd64

The following USE changes are necessary to proceed:
 (see "package.use" in the portage(5) man page for more details)
# required by app-editors/retext-7.0.1-r1::gentoo
# required by =retext-7.0.1-r1 (argument)
>=dev-python/PyQt5-5.9.2 printsupport webengine network gui widgets

!!! The ebuild selected to satisfy "dev-python/PyQt5[gui,network,printsupport,webengine,widgets,python_targets_python3_4(-)?,python_targets_python3_5(-)?,python_targets_python3_6(-)?,-python_single_target_python3_4(-),-python_single_target_python3_5(-),-python_single_target_python3_6(-)]" has unmet requirements.
- dev-python/PyQt5-5.9.2::gentoo USE="-bluetooth -dbus -debug -declarative -designer -examples -gles2 -gui -help -location -multimedia -network -opengl -positioning -printsupport -sensors -serialport -sql -svg -testlib -webchannel -webengine -webkit -websockets -widgets -x11extras -xmlpatterns" PYTHON_TARGETS="python2_7 python3_4 python3_6 -python3_5"

  The following REQUIRED_USE flag constraints are unsatisfied:
    webengine? ( widgets? ( webchannel ) )

  The above constraints are a subset of the following complete expression:
    any-of ( python_targets_python2_7 python_targets_python3_4 python_targets_python3_5 python_targets_python3_6 ) bluetooth? ( gui ) declarative? ( gui network ) designer? ( widgets ) help? ( gui widgets ) location? ( positioning ) multimedia? ( gui network ) opengl? ( gui widgets ) positioning? ( gui ) printsupport? ( gui widgets ) sensors? ( gui ) serialport? ( gui ) sql? ( widgets ) svg? ( gui widgets ) testlib? ( widgets ) webchannel? ( network ) webengine? ( network widgets? ( printsupport webchannel ) ) webkit? ( gui network printsupport widgets ) websockets? ( network ) widgets? ( gui ) xmlpatterns? ( network )

(dependency required by "app-editors/retext-7.0.1-r1::gentoo" [ebuild])
(dependency required by "=retext-7.0.1-r1" [argument])

Bug: https://bugs.gentoo.org/654782
Reviewed-by: M. J. Everitt <m.j.everitt <AT> iee.org>

 pym/_emerge/depgraph.py                            |  8 ++--
 pym/portage/tests/resolver/test_autounmask.py      | 48 ++++++++++++++++++++--
 pym/portage/tests/resolver/test_slot_collisions.py | 20 +++++----
 3 files changed, 61 insertions(+), 15 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index fbd16ad98..429d8871c 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3009,6 +3009,10 @@ class depgraph(object):
 					{"myparent" : dep.parent, "show_req_use" : pkg}))
 				self._dynamic_config._required_use_unsatisfied = True
 				self._dynamic_config._skip_restart = True
+				# Add pkg to digraph in order to enable autounmask messages
+				# for this package, which is useful when autounmask USE
+				# changes have violated REQUIRED_USE.
+				self._dynamic_config.digraph.add(pkg, dep.parent, priority=priority)
 				return 0
 
 		if not pkg.onlydeps:
@@ -9428,10 +9432,6 @@ class depgraph(object):
 		return self._dynamic_config._need_config_reload
 
 	def autounmask_breakage_detected(self):
-		# Check for REQUIRED_USE violations.
-		for changes in self._dynamic_config._needed_use_config_changes.values():
-			if getattr(changes, 'required_use_satisfied', None) is False:
-				return True
 		try:
 			for pargs, kwargs in self._dynamic_config._unsatisfied_deps_for_display:
 				self._show_unsatisfied_dep(

diff --git a/pym/portage/tests/resolver/test_autounmask.py b/pym/portage/tests/resolver/test_autounmask.py
index 9042349ea..809d42104 100644
--- a/pym/portage/tests/resolver/test_autounmask.py
+++ b/pym/portage/tests/resolver/test_autounmask.py
@@ -251,15 +251,42 @@ class AutounmaskTestCase(TestCase):
 					use_changes={ "dev-util/R-1": { "bar": True } }),
 
 				#Test interaction with REQUIRED_USE.
+				# Some of these cases trigger USE change(s) that violate
+				# REQUIRED_USE, so the USE changes are shown along with
+				# the REQUIRED_USE violation that they would trigger.
+
+				# The following USE changes are necessary to proceed:
+				#  (see "package.use" in the portage(5) man page for more details)
+				# # required by app-portage/A-1::test_repo
+				# # required by =app-portage/A-1 (argument)
+				# >=app-portage/B-1 foo
+				#
+				# !!! The ebuild selected to satisfy "app-portage/B[foo]" has unmet requirements.
+				# - app-portage/B-1::test_repo USE="bar (forced-flag) -foo"
+				#
+				#   The following REQUIRED_USE flag constraints are unsatisfied:
+				#     exactly-one-of ( foo bar )
 				ResolverPlaygroundTestCase(
 					["=app-portage/A-1"],
 					options={ "--autounmask": True },
-					use_changes=None,
+					use_changes={"app-portage/B-1": {"foo": True}},
 					success=False),
+
+				# The following USE changes are necessary to proceed:
+				#  (see "package.use" in the portage(5) man page for more details)
+				# # required by app-portage/A-2::test_repo
+				# # required by =app-portage/A-2 (argument)
+				# >=app-portage/B-1 foo
+				#
+				# !!! The ebuild selected to satisfy "app-portage/B[foo=]" has unmet requirements.
+				# - app-portage/B-1::test_repo USE="bar (forced-flag) -foo"
+				#
+				#   The following REQUIRED_USE flag constraints are unsatisfied:
+				#     exactly-one-of ( foo bar )
 				ResolverPlaygroundTestCase(
 					["=app-portage/A-2"],
 					options={ "--autounmask": True },
-					use_changes=None,
+					use_changes={"app-portage/B-1": {"foo": True}},
 					success=False),
 				ResolverPlaygroundTestCase(
 					["=app-portage/C-1"],
@@ -269,10 +296,25 @@ class AutounmaskTestCase(TestCase):
 
 				# Test bug 622462, where it inappropriately unmasked a newer
 				# version rather than report unsatisfied REQUIRED_USE.
+				#
+				# The following USE changes are necessary to proceed:
+				#  (see "package.use" in the portage(5) man page for more details)
+				# # required by sci-mathematics/octave-4.2.2::test_repo
+				# # required by sci-mathematics/octave (argument)
+				# >=x11-libs/qscintilla-2.9.4 qt5
+				#
+				# !!! The ebuild selected to satisfy ">=x11-libs/qscintilla-2.9.3-r2:=[qt5(+)]" has unmet requirements.
+				# - x11-libs/qscintilla-2.9.4::test_repo USE="qt4 -qt5"
+				#
+				#   The following REQUIRED_USE flag constraints are unsatisfied:
+				#     exactly-one-of ( qt4 qt5 )
+				#
+				# (dependency required by "sci-mathematics/octave-4.2.2::test_repo" [ebuild])
+				# (dependency required by "sci-mathematics/octave" [argument])
 				ResolverPlaygroundTestCase(
 					["sci-mathematics/octave"],
 					options={"--autounmask": True},
-					use_changes=None,
+					use_changes={"x11-libs/qscintilla-2.9.4": {"qt5": True}},
 					success=False),
 
 				#Make sure we don't change masked/forced flags.

diff --git a/pym/portage/tests/resolver/test_slot_collisions.py b/pym/portage/tests/resolver/test_slot_collisions.py
index 9fcd5294a..430ccaad6 100644
--- a/pym/portage/tests/resolver/test_slot_collisions.py
+++ b/pym/portage/tests/resolver/test_slot_collisions.py
@@ -136,15 +136,19 @@ class SlotCollisionTestCase(TestCase):
 				slot_collision_solutions = [{"sci-libs/Q-1": {"foo": True}, "sci-libs/P-1": {"foo": True}}]
 				),
 
-			#Conflict with REQUIRED_USE
-			ResolverPlaygroundTestCase(
-				["=app-misc/C-1", "=app-misc/B-1"],
-				all_permutations = True,
-				slot_collision_solutions = [],
-				mergelist = ["app-misc/A-1", "app-misc/C-1", "app-misc/B-1"],
-				ignore_mergelist_order = True,
-				success = False),
 			)
+			# NOTE: For this test case, ResolverPlaygroundTestCase attributes
+			# vary randomly between runs, so it's expected to fail randomly.
+			#Conflict with REQUIRED_USE
+			#ResolverPlaygroundTestCase(
+			#	["=app-misc/C-1", "=app-misc/B-1"],
+			#	all_permutations = True,
+			#	slot_collision_solutions = None,
+			#	use_changes={"app-misc/A-1": {"foo": True}},
+			#	mergelist = ["app-misc/A-1", "app-misc/C-1", "app-misc/B-1"],
+			#	ignore_mergelist_order = True,
+			#	success = False),
+			#)
 
 		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
 		try:


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2018-04-12  2:45 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2018-04-12  2:45 UTC (permalink / raw
  To: gentoo-commits

commit:     600b329949f8770fe2962987ee97567b65393c7e
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Apr 10 21:29:44 2018 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Apr 12 02:43:47 2018 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=600b3299

_slot_operator.._reinstalls: probe binpkg rebuild (bug 652938)

If the parent is not installed, check if it needs to be rebuilt against
an installed instance, since otherwise it could trigger downgrade of
an installed instance.

Bug: https://bugs.gentoo.org/652938
Reviewed-by: Manuel Rüger <mrueg <AT> gentoo.org>

 pym/_emerge/depgraph.py                            | 10 ++++-
 .../tests/resolver/test_slot_operator_rebuild.py   | 45 +++++++++++++++++++++-
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 160ea5e94..67f912f5e 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -2571,17 +2571,23 @@ class depgraph(object):
 					isinstance(dep.parent, Package) and dep.parent.built):
 					continue
 
+				# If the parent is not installed, check if it needs to be
+				# rebuilt against an installed instance, since otherwise
+				# it could trigger downgrade of an installed instance as
+				# in bug #652938.
+				want_update_probe = dep.want_update or not dep.parent.installed
+
 				# Check for slot update first, since we don't want to
 				# trigger reinstall of the child package when a newer
 				# slot will be used instead.
-				if rebuild_if_new_slot and dep.want_update:
+				if rebuild_if_new_slot and want_update_probe:
 					new_dep = self._slot_operator_update_probe(dep,
 						new_child_slot=True)
 					if new_dep is not None:
 						self._slot_operator_update_backtrack(dep,
 							new_child_slot=new_dep.child)
 
-				if dep.want_update:
+				if want_update_probe:
 					if self._slot_operator_update_probe(dep):
 						self._slot_operator_update_backtrack(dep)
 

diff --git a/pym/portage/tests/resolver/test_slot_operator_rebuild.py b/pym/portage/tests/resolver/test_slot_operator_rebuild.py
index 42512aad8..381683331 100644
--- a/pym/portage/tests/resolver/test_slot_operator_rebuild.py
+++ b/pym/portage/tests/resolver/test_slot_operator_rebuild.py
@@ -1,4 +1,4 @@
-# Copyright 2014 Gentoo Foundation
+# Copyright 2014-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -31,6 +31,32 @@ class SlotOperatorRebuildTestCase(TestCase):
 				"RDEPEND": "|| ( app-misc/X app-misc/A:= )"
 			},
 
+			"app-misc/D-1" : {
+				"EAPI": "6",
+				"RDEPEND": "app-misc/E",
+			},
+
+			"app-misc/E-1" : {
+				"EAPI": "6",
+				"RDEPEND": "app-misc/F:=",
+			},
+
+			"app-misc/F-1" : {
+				"EAPI": "6",
+				"SLOT": "0/1"
+			},
+
+			"app-misc/F-2" : {
+				"EAPI": "6",
+				"SLOT": "0/2"
+			},
+		}
+
+		binpkgs = {
+			"app-misc/E-1" : {
+				"EAPI": "6",
+				"RDEPEND": "app-misc/F:0/1=",
+			},
 		}
 
 		installed = {
@@ -50,6 +76,10 @@ class SlotOperatorRebuildTestCase(TestCase):
 				"RDEPEND": "|| ( app-misc/X app-misc/A:0/1= )"
 			},
 
+			"app-misc/F-2" : {
+				"EAPI": "6",
+				"SLOT": "0/2"
+			},
 		}
 
 		world = ["app-misc/B", "app-misc/C"]
@@ -68,9 +98,20 @@ class SlotOperatorRebuildTestCase(TestCase):
 				mergelist = ['app-misc/A-2', ('app-misc/B-0', 'app-misc/C-0')]
 			),
 
+			# Test bug #652938, where a binary package built against an
+			# older subslot triggered downgrade of an installed package.
+			# In this case we want to reject the app-misc/E-1 binary
+			# package, and rebuild it against the installed instance of
+			# app-misc/F.
+			ResolverPlaygroundTestCase(
+				["app-misc/D"],
+				options = {'--usepkg': True},
+				success = True,
+				mergelist = ['app-misc/E-1', 'app-misc/D-1']
+			),
 		)
 
-		playground = ResolverPlayground(ebuilds=ebuilds,
+		playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
 			installed=installed, world=world, debug=False)
 		try:
 			for test_case in test_cases:


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2017-09-29 17:24 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2017-09-29 17:24 UTC (permalink / raw
  To: gentoo-commits

commit:     5a65670ec2b0850c278b85c6417c20d8a4ca7734
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Sep 29 07:02:27 2017 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Sep 29 17:22:27 2017 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=5a65670e

_solve_..slot_conflicts: make "forced" set recursive (bug 632210)

When the slot conflict solver decides that it is "forced"
to choose a particular package, recursively force the
dependencies as well. Prior to this fix, substitution of
@world in the arguments for SlotConflictMaskUpdateTestCase
caused the test to fail because the solver removed
boost-build-1.53.0 from the graph event though it had
added the parent boost-1.53.0 package to the "forced"
set.

X-Gentoo-bug: 632210
X-Gentoo-bug-url: https://bugs.gentoo.org/632210
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 pym/_emerge/depgraph.py                                 | 13 +++++++++++++
 pym/portage/tests/resolver/test_slot_conflict_update.py |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 785c036b8..3b81c5c76 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1457,6 +1457,19 @@ class depgraph(object):
 
 		# Remove 'non_conflict_node' and or_tuples from 'forced'.
 		forced = set(pkg for pkg in forced if isinstance(pkg, Package))
+
+		# Add dependendencies of forced packages.
+		stack = list(forced)
+		traversed = set()
+		while stack:
+			pkg = stack.pop()
+			traversed.add(pkg)
+			for child in conflict_graph.child_nodes(pkg):
+				if (isinstance(child, Package) and
+					child not in traversed):
+					forced.add(child)
+					stack.append(child)
+
 		non_forced = set(pkg for pkg in conflict_pkgs if pkg not in forced)
 
 		if debug:

diff --git a/pym/portage/tests/resolver/test_slot_conflict_update.py b/pym/portage/tests/resolver/test_slot_conflict_update.py
index 331e5788b..f251d01f1 100644
--- a/pym/portage/tests/resolver/test_slot_conflict_update.py
+++ b/pym/portage/tests/resolver/test_slot_conflict_update.py
@@ -80,7 +80,7 @@ class SlotConflictUpdateTestCase(TestCase):
 			# this behavior makes SlotConflictMaskUpdateTestCase
 			# fail.
 			ResolverPlaygroundTestCase(
-				world,
+				['@world'],
 				all_permutations = True,
 				options = {"--update": True, "--deep": True},
 				success = True,


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2017-06-02  5:41 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2017-06-02  5:41 UTC (permalink / raw
  To: gentoo-commits

commit:     60af7e2696b96b47b0cd9e70caabd10546206b8b
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon May 29 08:22:40 2017 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Jun  2 05:38:02 2017 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=60af7e26

depgraph: prune unnecessary rebuilds for --autounmask-continue (bug 619626)

When there are autounmask USE changes, avoid unnecessary rebuilds
by accepting binary packages that were rejected due to the preexisting
USE configuration. This reuses the prune_rebuilds backtracker support
which was added for bug 439688.

X-Gentoo-bug: 619626
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=619626
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 pym/_emerge/depgraph.py                            | 96 ++++++++++++++++++----
 .../tests/resolver/test_autounmask_binpkg_use.py   | 64 +++++++++++++++
 2 files changed, 142 insertions(+), 18 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 2dc432431..abe2cb1bd 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5,6 +5,7 @@ from __future__ import division, print_function, unicode_literals
 
 import collections
 import errno
+import functools
 import io
 import logging
 import stat
@@ -856,17 +857,11 @@ class depgraph(object):
 				for parent in self._forced_rebuilds[root][child]:
 					writemsg_stdout("    %s\n" % (parent,), noiselevel=-1)
 
-	def _show_ignored_binaries(self):
+	def _eliminate_ignored_binaries(self):
 		"""
-		Show binaries that have been ignored because their USE didn't
-		match the user's config.
+		Eliminate any package from self._dynamic_config.ignored_binaries
+		for which a more optimal alternative exists.
 		"""
-		if not self._dynamic_config.ignored_binaries \
-			or '--quiet' in self._frozen_config.myopts:
-			return
-
-		ignored_binaries = {}
-
 		for pkg in list(self._dynamic_config.ignored_binaries):
 
 			for selected_pkg in self._dynamic_config._package_tracker.match(
@@ -894,10 +889,67 @@ class depgraph(object):
 					self._dynamic_config.ignored_binaries.pop(pkg)
 					break
 
-			else:
-				for reason, info in self._dynamic_config.\
-					ignored_binaries[pkg].items():
-					ignored_binaries.setdefault(reason, {})[pkg] = info
+	def _ignored_binaries_autounmask_backtrack(self):
+		"""
+		Check if there are ignored binaries that would have been
+		accepted with the current autounmask USE changes.
+
+		@rtype: bool
+		@return: True if there are unnecessary rebuilds that
+			can be avoided by backtracking
+		"""
+		if not all([
+			self._dynamic_config._allow_backtracking,
+			self._dynamic_config._needed_use_config_changes,
+			self._dynamic_config.ignored_binaries]):
+			return False
+
+		self._eliminate_ignored_binaries()
+
+		# _eliminate_ignored_binaries may have eliminated
+		# all of the ignored binaries
+		if not self._dynamic_config.ignored_binaries:
+			return False
+
+		use_changes = collections.defaultdict(
+			functools.partial(collections.defaultdict, dict))
+		for pkg, (new_use, changes) in self._dynamic_config._needed_use_config_changes.items():
+			if pkg in self._dynamic_config.digraph:
+				use_changes[pkg.root][pkg.slot_atom] = (pkg, new_use)
+
+		for pkg in self._dynamic_config.ignored_binaries:
+			selected_pkg, new_use = use_changes[pkg.root].get(
+				pkg.slot_atom, (None, None))
+			if new_use is None:
+				continue
+
+			if new_use != pkg.use.enabled:
+				continue
+
+			if selected_pkg > pkg:
+				continue
+
+			return True
+
+		return False
+
+	def _show_ignored_binaries(self):
+		"""
+		Show binaries that have been ignored because their USE didn't
+		match the user's config.
+		"""
+		if not self._dynamic_config.ignored_binaries \
+			or '--quiet' in self._frozen_config.myopts:
+			return
+
+		self._eliminate_ignored_binaries()
+
+		ignored_binaries = {}
+
+		for pkg in self._dynamic_config.ignored_binaries:
+			for reason, info in self._dynamic_config.\
+				ignored_binaries[pkg].items():
+				ignored_binaries.setdefault(reason, {})[pkg] = info
 
 		if self._dynamic_config.myparams.get(
 			"binpkg_respect_use") in ("y", "n"):
@@ -4254,6 +4306,13 @@ class depgraph(object):
 				self._dynamic_config._skip_restart = True
 				return False, myfavorites
 
+		if (not self._dynamic_config._prune_rebuilds and
+			self._ignored_binaries_autounmask_backtrack()):
+			config = self._dynamic_config._backtrack_infos.setdefault("config", {})
+			config["prune_rebuilds"] = True
+			self._dynamic_config._need_restart = True
+			return False, myfavorites
+
 		# Any failures except those due to autounmask *alone* should return
 		# before this point, since the success_without_autounmask flag that's
 		# set below is reserved for cases where there are *zero* other
@@ -6233,13 +6292,14 @@ class depgraph(object):
 							iuses = pkg.iuse.all
 							old_use = self._pkg_use_enabled(pkg)
 							if myeb:
-								pkgsettings.setcpv(myeb)
+								now_use = self._pkg_use_enabled(myeb)
+								forced_flags = set(chain(
+									myeb.use.force, myeb.use.mask))
 							else:
 								pkgsettings.setcpv(pkg)
-							now_use = pkgsettings["PORTAGE_USE"].split()
-							forced_flags = set()
-							forced_flags.update(pkgsettings.useforce)
-							forced_flags.update(pkgsettings.usemask)
+								now_use = pkgsettings["PORTAGE_USE"].split()
+								forced_flags = set(chain(
+									pkgsettings.useforce, pkgsettings.usemask))
 							cur_iuse = iuses
 							if myeb and not usepkgonly and not useoldpkg:
 								cur_iuse = myeb.iuse.all

diff --git a/pym/portage/tests/resolver/test_autounmask_binpkg_use.py b/pym/portage/tests/resolver/test_autounmask_binpkg_use.py
new file mode 100644
index 000000000..1ca4bf3d9
--- /dev/null
+++ b/pym/portage/tests/resolver/test_autounmask_binpkg_use.py
@@ -0,0 +1,64 @@
+# Copyright 2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class AutounmaskBinpkgUseTestCase(TestCase):
+
+	def testAutounmaskBinpkgUse(self):
+		ebuilds = {
+			"dev-libs/A-1": {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/B[foo]",
+				"RDEPEND": "dev-libs/B[foo]",
+			},
+			"dev-libs/B-1": {
+				"EAPI": "6",
+				"IUSE": "foo",
+			},
+		}
+		binpkgs = {
+			"dev-libs/A-1": {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/B[foo]",
+				"RDEPEND": "dev-libs/B[foo]",
+			},
+			"dev-libs/B-1": {
+				"EAPI": "6",
+				"IUSE": "foo",
+				"USE": "foo",
+			},
+		}
+		installed = {
+		}
+
+		test_cases = (
+			# Bug 619626: Test for unnecessary rebuild due
+			# to rejection of binary packages that would
+			# be acceptable after appplication of autounmask
+			# USE changes.
+			ResolverPlaygroundTestCase(
+				["dev-libs/A"],
+				all_permutations = True,
+				success = True,
+				options = {
+					"--usepkg": True,
+				},
+				mergelist = [
+				    "[binary]dev-libs/B-1",
+				    "[binary]dev-libs/A-1",
+				],
+				use_changes = {"dev-libs/B-1": {"foo": True}}
+			),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			binpkgs=binpkgs, 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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2017-04-01  5:48 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2017-04-01  5:48 UTC (permalink / raw
  To: gentoo-commits

commit:     a83bb83909c5a6ac232c8eb5931b28027f4175af
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Apr  1 03:53:03 2017 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat Apr  1 05:46:26 2017 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=a83bb839

depgraph: trigger slot operator rebuilds via _complete_graph (bug 614390)

Fix _complete_graph to trigger rebuilds of parent packages when they
pull in installed packages that had already been scheduled for rebuild
by the previous calculation.

X-Gentoo-bug: 614390
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=614390
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 pym/_emerge/depgraph.py                            |  15 +++
 .../resolver/test_slot_operator_complete_graph.py  | 141 +++++++++++++++++++++
 2 files changed, 156 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 04e724d8d..8a614c495 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -6649,6 +6649,21 @@ class depgraph(object):
 				# will be appropriately reported as a slot collision
 				# (possibly solvable via backtracking).
 				pkg = matches[-1] # highest match
+
+				if (self._dynamic_config._allow_backtracking and
+					not self._want_installed_pkg(pkg) and (dep.atom.soname or (
+					dep.atom.package and dep.atom.slot_operator_built))):
+					# If pkg was already scheduled for rebuild by the previous
+					# calculation, then pulling in the installed instance will
+					# trigger a slot conflict that may go unsolved. Therefore,
+					# trigger a rebuild of the parent if appropriate.
+					dep.child = pkg
+					new_dep = self._slot_operator_update_probe(dep)
+					if new_dep is not None:
+						self._slot_operator_update_backtrack(
+							dep, new_dep=new_dep)
+						continue
+
 				if not self._add_pkg(pkg, dep):
 					return 0
 				if not self._create_graph(allow_unsatisfied=True):

diff --git a/pym/portage/tests/resolver/test_slot_operator_complete_graph.py b/pym/portage/tests/resolver/test_slot_operator_complete_graph.py
new file mode 100644
index 000000000..1d59bcef1
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_complete_graph.py
@@ -0,0 +1,141 @@
+# Copyright 2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+	ResolverPlayground,
+	ResolverPlaygroundTestCase,
+)
+
+class SlotOperatorCompleteGraphTestCase(TestCase):
+
+	def testSlotOperatorCompleteGraph(self):
+
+		ebuilds = {
+			"app-misc/meta-pkg-2" : {
+				"EAPI": "6",
+				"DEPEND": "=app-misc/B-2 =app-misc/C-1  =app-misc/D-1 =dev-libs/foo-2",
+				"RDEPEND": "=app-misc/B-2 =app-misc/C-1 =app-misc/D-1 =dev-libs/foo-2",
+			},
+
+			"app-misc/meta-pkg-1" : {
+				"EAPI": "6",
+				"DEPEND": "=app-misc/B-1 =app-misc/C-1  =app-misc/D-1 =dev-libs/foo-1",
+				"RDEPEND": "=app-misc/B-1 =app-misc/C-1 =app-misc/D-1 =dev-libs/foo-1",
+			},
+
+			"app-misc/B-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/B-2" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/C-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:= app-misc/B",
+				"RDEPEND": "dev-libs/foo:= app-misc/B",
+			},
+
+			"app-misc/C-2" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:= app-misc/B",
+				"RDEPEND": "dev-libs/foo:= app-misc/B",
+			},
+
+			"app-misc/D-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/D-2" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"dev-libs/foo-1" : {
+				"EAPI": "6",
+				"SLOT": "0/1",
+			},
+
+			"dev-libs/foo-2" : {
+				"EAPI": "6",
+				"SLOT": "0/2",
+			},
+		}
+
+		installed = {
+			"app-misc/meta-pkg-1" : {
+				"EAPI": "6",
+				"DEPEND": "=app-misc/B-1 =app-misc/C-1  =app-misc/D-1 =dev-libs/foo-1",
+				"RDEPEND": "=app-misc/B-1 =app-misc/C-1 =app-misc/D-1 =dev-libs/foo-1",
+			},
+
+			"app-misc/B-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:0/1=",
+				"RDEPEND": "dev-libs/foo:0/1=",
+			},
+
+			"app-misc/C-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:0/1= app-misc/B",
+				"RDEPEND": "dev-libs/foo:0/1= app-misc/B",
+			},
+
+			"app-misc/D-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:0/1=",
+				"RDEPEND": "dev-libs/foo:0/1=",
+			},
+
+			"dev-libs/foo-1" : {
+				"EAPI": "6",
+				"SLOT": "0/1",
+			},
+		}
+
+		world = (
+			"app-misc/meta-pkg",
+		)
+
+		test_cases = (
+			# Test bug 614390, where the depgraph._complete_graph
+			# method pulled in an installed package that had been
+			# scheduled for rebuild by the previous calculation,
+			# triggering an unsolved slot conflict and preventing
+			# slot operator rebuilds.
+			ResolverPlaygroundTestCase(
+				["=app-misc/meta-pkg-2", "app-misc/C"],
+				options = {
+					"--backtrack": 5,
+				},
+				success = True,
+				ambiguous_merge_order = True,
+				mergelist = [
+					'dev-libs/foo-2',
+					('app-misc/D-1', 'app-misc/C-1', 'app-misc/B-2'),
+					'app-misc/meta-pkg-2',
+				]
+			),
+		)
+
+		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:
+			# Disable debug so that cleanup works.
+			playground.debug = False
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2017-03-22  8:59 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2017-03-22  8:59 UTC (permalink / raw
  To: gentoo-commits

commit:     82bfd91325b052a4c9250a04939641c15b3d2a20
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Mar 20 23:13:42 2017 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Mar 22 08:58:44 2017 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=82bfd913

emerge: fix --usepkg when ebuild is not available (bug 613360)

Fix emerge --usepkg to use a binary package when the corresponding
ebuild is not available (and --use-ebuild-visibility is not enabled),
in cases when no other package is available to satisfy the dependency.
This reverts an unintended behavior change from commit
e309323f156528a8a79a1f755e1326e8880346b7.

Fixes: e309323f1565 ("emerge: fix --use-ebuild-visibility to reject binary packages (bug 612960)")
X-Gentoo-bug: 613360
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=613360
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 pym/_emerge/depgraph.py                            |  3 ++-
 .../resolver/test_binary_pkg_ebuild_visibility.py  | 26 ++++++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 543f4dc78..7c9130b38 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -6062,7 +6062,8 @@ class depgraph(object):
 										identical_binary = True
 										break
 
-						if not identical_binary and pkg.built:
+						if (not identical_binary and pkg.built and
+							(use_ebuild_visibility or matched_packages)):
 								# If the ebuild no longer exists or it's
 								# keywords have been dropped, reject built
 								# instances (installed or binary).

diff --git a/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py b/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py
index ea65abded..0d01d0696 100644
--- a/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py
+++ b/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py
@@ -104,6 +104,32 @@ class BinaryPkgEbuildVisibilityTestCase(TestCase):
 					'[binary]app-misc/foo-3',
 				],
 			),
+
+			# The default behavior is to enforce ebuild visibility as
+			# long as a visible package is available to satisfy the
+			# current atom. In the following test case, ebuild visibility
+			# is ignored in order to satisfy the =app-misc/foo-3 atom.
+			ResolverPlaygroundTestCase(
+				["=app-misc/foo-3"],
+				options = {
+					"--usepkg": True,
+				},
+				success = True,
+				mergelist = [
+					'[binary]app-misc/foo-3',
+				],
+			),
+
+			# Verify that --use-ebuild-visibility works with --usepkg
+			# when no other visible package is available.
+			ResolverPlaygroundTestCase(
+				["=app-misc/foo-3"],
+				options = {
+					"--use-ebuild-visibility": "y",
+					"--usepkg": True,
+				},
+				success = False,
+			),
 		)
 
 		playground = ResolverPlayground(binpkgs=binpkgs, ebuilds=ebuilds,


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2017-03-16  4:51 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2017-03-16  4:51 UTC (permalink / raw
  To: gentoo-commits

commit:     15e67f5516e0779d2cba37704c15b42193808197
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Mar 15 21:34:37 2017 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Mar 16 04:47:41 2017 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=15e67f55

depgraph: fix slot operator rebuild for llvm:0 to llvm:4 upgrade (bug 612772)

Fix check_reverse_dependencies to ignore dependencies of parent packages
that could be uninstalled in order to solve a blocker conflict. This case
is similar to the one from bug 584626, except that the relevant parent
package is in an older slot which is blocked by a newer slot. In this
case, the _upgrade_available method returns False, because the package
in the older slot is the highest version version available for its
slot. Therefore, a new _in_blocker_conflict method is needed to detect
parent packages that could be uninstalled. The included unit test fails
without this fix.

Since the _in_blocker_conflict method requires information that is
collected by the _validate_blockers method, the _validate_blockers
method now has to be called before the _process_slot_conflict and
_slot_operator_trigger_reinstalls methods.

X-Gentoo-bug: 612772
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=612772
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 pym/_emerge/depgraph.py                            |  59 ++++++++---
 .../resolver/test_slot_operator_exclusive_slots.py | 109 +++++++++++++++++++++
 2 files changed, 155 insertions(+), 13 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 1379b0563..ad94fb70f 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -387,7 +387,10 @@ class _dynamic_depgraph_config(object):
 		# Contains only unsolvable Package -> Blocker edges
 		self._unsolvable_blockers = digraph()
 		# Contains all Blocker -> Blocked Package edges
-		self._blocked_pkgs = digraph()
+		# Do not initialize this until the depgraph _validate_blockers
+		# method is called, so that the _in_blocker_conflict method can
+		# assert that _validate_blockers has been called first.
+		self._blocked_pkgs = None
 		# Contains world packages that have been protected from
 		# uninstallation but may not have been added to the graph
 		# if the graph is not complete yet.
@@ -1466,9 +1469,22 @@ class depgraph(object):
 
 		self._solve_non_slot_operator_slot_conflicts()
 
+		if not self._validate_blockers():
+			# Blockers don't trigger the _skip_restart flag, since
+			# backtracking may solve blockers when it solves slot
+			# conflicts (or by blind luck).
+			raise self._unknown_internal_error()
+
+		# Both _process_slot_conflict and _slot_operator_trigger_reinstalls
+		# can call _slot_operator_update_probe, which requires that
+		# self._dynamic_config._blocked_pkgs has been initialized by a
+		# call to the _validate_blockers method.
 		for conflict in self._dynamic_config._package_tracker.slot_conflicts():
 			self._process_slot_conflict(conflict)
 
+		if self._dynamic_config._allow_backtracking:
+			self._slot_operator_trigger_reinstalls()
+
 	def _process_slot_conflict(self, conflict):
 		"""
 		Process slot conflict data to identify specific atoms which
@@ -1829,9 +1845,12 @@ class depgraph(object):
 						not self._frozen_config.excluded_pkgs.
 						findAtomForPackage(parent,
 						modified_use=self._pkg_use_enabled(parent)) and
-						self._upgrade_available(parent)):
+						(self._upgrade_available(parent) or
+						(parent.installed and self._in_blocker_conflict(parent)))):
 						# This parent may be irrelevant, since an
-						# update is available (see bug 584626).
+						# update is available (see bug 584626), or
+						# it could be uninstalled in order to solve
+						# a blocker conflict (bug 612772).
 						continue
 
 				atom_set = InternalPackageSet(initial_atoms=(atom,),
@@ -2125,6 +2144,24 @@ class depgraph(object):
 
 		self._dynamic_config._need_restart = True
 
+	def _in_blocker_conflict(self, pkg):
+		"""
+		Check if pkg is involved in a blocker conflict. This method
+		only works after the _validate_blockers method has been called.
+		"""
+
+		if self._dynamic_config._blocked_pkgs is None:
+			raise AssertionError(
+				'_in_blocker_conflict called before _validate_blockers')
+
+		if pkg in self._dynamic_config._blocked_pkgs:
+			return True
+
+		if pkg in self._dynamic_config._blocker_parents:
+			return True
+
+		return False
+
 	def _upgrade_available(self, pkg):
 		"""
 		Detect cases where an upgrade of the given package is available
@@ -2925,7 +2962,8 @@ class depgraph(object):
 		self._dynamic_config._blocker_parents.discard(pkg)
 		self._dynamic_config._irrelevant_blockers.discard(pkg)
 		self._dynamic_config._unsolvable_blockers.discard(pkg)
-		self._dynamic_config._blocked_pkgs.discard(pkg)
+		if self._dynamic_config._blocked_pkgs is not None:
+			self._dynamic_config._blocked_pkgs.discard(pkg)
 		self._dynamic_config._blocked_world_pkgs.pop(pkg, None)
 
 		for child in children:
@@ -6619,6 +6657,10 @@ class depgraph(object):
 		installed simultaneously. Also add runtime blockers from all installed
 		packages if any of them haven't been added already (bug 128809)."""
 
+		# The _in_blocker_conflict method needs to assert that this method
+		# 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:
 			return True
@@ -7106,15 +7148,6 @@ class depgraph(object):
 
 		self._process_slot_conflicts()
 
-		if self._dynamic_config._allow_backtracking:
-			self._slot_operator_trigger_reinstalls()
-
-		if not self._validate_blockers():
-			# Blockers don't trigger the _skip_restart flag, since
-			# backtracking may solve blockers when it solves slot
-			# conflicts (or by blind luck).
-			raise self._unknown_internal_error()
-
 	def _serialize_tasks(self):
 
 		debug = "--debug" in self._frozen_config.myopts

diff --git a/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py b/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py
new file mode 100644
index 000000000..2ab379cce
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py
@@ -0,0 +1,109 @@
+# Copyright 2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+	ResolverPlayground,
+	ResolverPlaygroundTestCase,
+)
+
+class SlotOperatorExclusiveSlotsTestCase(TestCase):
+
+	def testSlotOperatorExclusiveSlots(self):
+
+		ebuilds = {
+
+			"media-libs/mesa-17.0.1" : {
+				"EAPI": "6",
+				"SLOT": "0",
+				"RDEPEND": "<sys-devel/llvm-5:="
+			},
+
+			"sys-devel/clang-4.0.0" : {
+				"EAPI": "6",
+				"SLOT": "4",
+				"RDEPEND": ("~sys-devel/llvm-4.0.0:4= "
+					"!sys-devel/llvm:0 !sys-devel/clang:0"),
+			},
+
+			"sys-devel/clang-3.9.1-r100" : {
+				"EAPI": "6",
+				"SLOT": "0/3.9.1",
+				"RDEPEND": "~sys-devel/llvm-3.9.1",
+			},
+
+			"sys-devel/llvm-4.0.0" : {
+				"EAPI": "6",
+				"SLOT": "4",
+				"RDEPEND": "!sys-devel/llvm:0",
+			},
+
+			"sys-devel/llvm-3.9.1" : {
+				"EAPI": "6",
+				"SLOT": "0/3.91",
+				"RDEPEND": "!sys-devel/llvm:0",
+				"PDEPEND": "=sys-devel/clang-3.9.1-r100",
+			},
+
+		}
+
+		installed = {
+
+			"media-libs/mesa-17.0.1" : {
+				"EAPI": "6",
+				"SLOT": "0",
+				"RDEPEND": "<sys-devel/llvm-5:0/3.9.1="
+			},
+
+			"sys-devel/clang-3.9.1-r100" : {
+				"EAPI": "6",
+				"SLOT": "0/3.9.1",
+				"RDEPEND": "~sys-devel/llvm-3.9.1",
+			},
+
+			"sys-devel/llvm-3.9.1" : {
+				"EAPI": "6",
+				"SLOT": "0/3.9.1",
+				"RDEPEND": "!sys-devel/llvm:0",
+				"PDEPEND": "=sys-devel/clang-3.9.1-r100",
+			},
+
+		}
+
+		world = ["sys-devel/clang", "media-libs/mesa"]
+
+		test_cases = (
+
+			# Test bug #612772, where slot operator rebuilds are not
+			# properly triggered (for things like mesa) during a
+			# llvm:0 to llvm:4 upgrade with clang, resulting in
+			# unsolved blockers.
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True},
+				success = True,
+				ambiguous_merge_order = True,
+				mergelist = [
+					'sys-devel/llvm-4.0.0',
+					'media-libs/mesa-17.0.1',
+					(
+						'sys-devel/clang-4.0.0',
+						'[uninstall]sys-devel/llvm-3.9.1',
+						'!sys-devel/llvm:0',
+						'[uninstall]sys-devel/clang-3.9.1-r100',
+						'!sys-devel/clang:0',
+					)
+				],
+			),
+
+		)
+
+		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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2017-03-09 19:36 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2017-03-09 19:36 UTC (permalink / raw
  To: gentoo-commits

commit:     c01f3fbd23def329eb1d1b0fc8f79959119a8a82
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Mar  8 22:25:56 2017 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Mar  9 19:33:54 2017 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=c01f3fbd

depgraph: fix runtime package mask interaction with slot operator rebuilds (bug 612094)

In some cases the backtracking runtime package mask can interact badly
with slot operator rebuilds, preventing a solution from being found.
This patch fixes the problem, which is demonstrated by the included
unit test.

X-Gentoo-bug: 612094
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=612094
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 pym/_emerge/depgraph.py                            |  28 +++--
 .../test_slot_operator_runtime_pkg_mask.py         | 136 +++++++++++++++++++++
 2 files changed, 152 insertions(+), 12 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index bb3e307f0..1379b0563 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1597,9 +1597,6 @@ class depgraph(object):
 				atom.package and atom.slot_operator_built):
 				continue
 
-			if pkg not in conflict_pkgs:
-				continue
-
 			for other_pkg in slot_nodes:
 				if other_pkg in conflict_pkgs:
 					continue
@@ -2569,18 +2566,25 @@ class depgraph(object):
 			# runtime_pkg_mask, since that would trigger an
 			# infinite backtracking loop.
 			if self._dynamic_config._allow_backtracking:
-				if dep.parent in self._dynamic_config._runtime_pkg_mask:
-					if debug:
-						writemsg(
-							"!!! backtracking loop detected: %s %s\n" % \
-							(dep.parent,
-							self._dynamic_config._runtime_pkg_mask[
-							dep.parent]), noiselevel=-1)
-				elif dep.atom.package and dep.atom.slot_operator_built and \
-					self._slot_operator_unsatisfied_probe(dep):
+				if (dep.parent not in self._dynamic_config._runtime_pkg_mask and
+					dep.atom.package and dep.atom.slot_operator_built and
+					self._slot_operator_unsatisfied_probe(dep)):
 					self._slot_operator_unsatisfied_backtrack(dep)
 					return 1
 				else:
+					# This is for backward-compatibility with previous
+					# behavior, so that installed packages with unsatisfied
+					# dependencies trigger an error message but do not
+					# cause the dependency calculation to fail. Only do
+					# this if the parent is already in the runtime package
+					# mask, since otherwise we need to backtrack.
+					if (dep.parent.installed and
+						dep.parent in self._dynamic_config._runtime_pkg_mask and
+						not any(self._iter_match_pkgs_any(
+						dep.parent.root_config, dep.atom))):
+						self._dynamic_config._initially_unsatisfied_deps.append(dep)
+						return 1
+
 					# Do not backtrack if only USE have to be changed in
 					# order to satisfy the dependency. Note that when
 					# want_restart_for_use_change sets the need_restart

diff --git a/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py b/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py
new file mode 100644
index 000000000..0a5a7fa78
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py
@@ -0,0 +1,136 @@
+# Copyright 2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+	ResolverPlayground,
+	ResolverPlaygroundTestCase,
+)
+
+class SlotOperatorRuntimePkgMaskTestCase(TestCase):
+
+	def testSlotOperatorRuntimePkgMask(self):
+
+		ebuilds = {
+			"app-misc/meta-pkg-2" : {
+				"EAPI": "6",
+				"DEPEND": "=app-misc/B-2 =app-misc/C-1  =app-misc/D-1 =dev-libs/foo-2",
+				"RDEPEND": "=app-misc/B-2 =app-misc/C-1 =app-misc/D-1 =dev-libs/foo-2",
+			},
+
+			"app-misc/meta-pkg-1" : {
+				"EAPI": "6",
+				"DEPEND": "=app-misc/B-1 =app-misc/C-1  =app-misc/D-1 =dev-libs/foo-1",
+				"RDEPEND": "=app-misc/B-1 =app-misc/C-1 =app-misc/D-1 =dev-libs/foo-1",
+			},
+
+			"app-misc/B-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/B-2" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/C-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/C-2" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/D-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"app-misc/D-2" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:=",
+				"RDEPEND": "dev-libs/foo:=",
+			},
+
+			"dev-libs/foo-1" : {
+				"EAPI": "6",
+				"SLOT": "0/1",
+			},
+
+			"dev-libs/foo-2" : {
+				"EAPI": "6",
+				"SLOT": "0/2",
+			},
+		}
+
+		installed = {
+			"app-misc/meta-pkg-1" : {
+				"EAPI": "6",
+				"DEPEND": "=app-misc/B-1 =app-misc/C-1  =app-misc/D-1 =dev-libs/foo-1",
+				"RDEPEND": "=app-misc/B-1 =app-misc/C-1 =app-misc/D-1 =dev-libs/foo-1",
+			},
+
+			"app-misc/B-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:0/1=",
+				"RDEPEND": "dev-libs/foo:0/1=",
+			},
+
+			"app-misc/C-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:0/1=",
+				"RDEPEND": "dev-libs/foo:0/1=",
+			},
+
+			"app-misc/D-1" : {
+				"EAPI": "6",
+				"DEPEND": "dev-libs/foo:0/1=",
+				"RDEPEND": "dev-libs/foo:0/1=",
+			},
+
+			"dev-libs/foo-1" : {
+				"EAPI": "6",
+				"SLOT": "0/1",
+			},
+		}
+
+		world = (
+			"app-misc/meta-pkg",
+		)
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["=app-misc/meta-pkg-2"],
+				options = {
+					"--backtrack": 5,
+				},
+				success = True,
+				ambiguous_merge_order = True,
+				mergelist = [
+					'dev-libs/foo-2',
+					('app-misc/D-1', 'app-misc/C-1', 'app-misc/B-2'),
+					'app-misc/meta-pkg-2',
+				]
+			),
+		)
+
+		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:
+			# Disable debug so that cleanup works.
+			playground.debug = False
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2016-08-07 17:55 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2016-08-07 17:55 UTC (permalink / raw
  To: gentoo-commits

commit:     6412205462671735f6e8b3196a780bc4b0d6a077
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Aug  5 02:15:14 2016 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Aug  7 17:44:20 2016 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=64122054

depgraph._serialize_tasks: improve runtime cycle handling (bug 590514)

Previously, it was possible for _serialize_tasks to count some
dependencies of a runtime cycle as part of that cycle, leading to
sub-optimal merge order for these dependencies because they got
grouped together with the cycle in the overall merge order. Fix
it to separate these dependencies from the cycle, and merge them
earlier.

X-Gentoo-Bug: 590514
X-Gentoo-Bug-url: https://bugs.gentoo.org/show_bug.cgi?id=590514
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 pym/_emerge/depgraph.py                            | 50 +++++++--------
 .../resolver/test_runtime_cycle_merge_order.py     | 72 ++++++++++++++++++++++
 2 files changed, 98 insertions(+), 24 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index fc957f5..26037ad 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -7415,36 +7415,38 @@ class depgraph(object):
 						selected_nodes = set()
 						if gather_deps(ignore_priority,
 							mergeable_nodes, selected_nodes, node):
-							# When selecting asap_nodes, we need to ensure
-							# that we haven't selected a large runtime cycle
-							# that is obviously sub-optimal. This will be
-							# obvious if any of the non-asap selected_nodes
-							# is a leaf node when medium_soft deps are
-							# ignored.
-							if prefer_asap and asap_nodes and \
-								len(selected_nodes) > 1:
-								for node in selected_nodes.difference(
-									asap_nodes):
-									if not mygraph.child_nodes(node,
-										ignore_priority =
-										DepPriorityNormalRange.ignore_medium_soft):
-										selected_nodes = None
-										break
-							if selected_nodes:
-								if smallest_cycle is None or \
-									len(selected_nodes) < len(smallest_cycle):
-									smallest_cycle = selected_nodes
+							if smallest_cycle is None or \
+								len(selected_nodes) < len(smallest_cycle):
+								smallest_cycle = selected_nodes
 
 					selected_nodes = smallest_cycle
 
-					if selected_nodes and debug:
-						writemsg("\nruntime cycle digraph (%s nodes):\n\n" %
-							(len(selected_nodes),), noiselevel=-1)
+					if selected_nodes is not None:
 						cycle_digraph = mygraph.copy()
 						cycle_digraph.difference_update([x for x in
 							cycle_digraph if x not in selected_nodes])
-						cycle_digraph.debug_print()
-						writemsg("\n", noiselevel=-1)
+
+						leaves = cycle_digraph.leaf_nodes()
+						if leaves:
+							# NOTE: This case should only be triggered when
+							# prefer_asap is True, since otherwise these
+							# leaves would have been selected to merge
+							# before this point. Since these "leaves" may
+							# actually have some low-priority dependencies
+							# that we have intentionally ignored, select
+							# only one node here, so that merge order
+							# accounts for as many dependencies as possible.
+							selected_nodes = [leaves[0]]
+
+						if debug:
+							writemsg("\nruntime cycle digraph (%s nodes):\n\n" %
+								(len(selected_nodes),), noiselevel=-1)
+							cycle_digraph.debug_print()
+							writemsg("\n", noiselevel=-1)
+
+							if leaves:
+								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

diff --git a/pym/portage/tests/resolver/test_runtime_cycle_merge_order.py b/pym/portage/tests/resolver/test_runtime_cycle_merge_order.py
new file mode 100644
index 0000000..438d9cb
--- /dev/null
+++ b/pym/portage/tests/resolver/test_runtime_cycle_merge_order.py
@@ -0,0 +1,72 @@
+# Copyright 2016 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+
+class RuntimeCycleMergeOrderTestCase(TestCase):
+
+	def testRuntimeCycleMergeOrder(self):
+		ebuilds = {
+			'app-misc/plugins-consumer-1' : {
+				'EAPI': '6',
+				'DEPEND' : 'app-misc/plugin-b:=',
+				'RDEPEND' : 'app-misc/plugin-b:=',
+			},
+			'app-misc/plugin-b-1' : {
+				'EAPI': '6',
+				'RDEPEND' : 'app-misc/runtime-cycle-b',
+				'PDEPEND': 'app-misc/plugins-consumer',
+			},
+			'app-misc/runtime-cycle-b-1' : {
+				'RDEPEND' : 'app-misc/plugin-b app-misc/branch-b',
+			},
+			'app-misc/branch-b-1' : {
+				'RDEPEND' : 'app-misc/leaf-b app-misc/branch-c',
+			},
+			'app-misc/leaf-b-1' : {},
+			'app-misc/branch-c-1' : {
+				'RDEPEND' : 'app-misc/runtime-cycle-c app-misc/runtime-c',
+			},
+			'app-misc/runtime-cycle-c-1' : {
+				'RDEPEND' : 'app-misc/branch-c',
+			},
+			'app-misc/runtime-c-1' : {
+				'RDEPEND' : 'app-misc/branch-d',
+			},
+			'app-misc/branch-d-1' : {
+				'RDEPEND' : 'app-misc/leaf-d app-misc/branch-e',
+			},
+			'app-misc/branch-e-1' : {
+				'RDEPEND' : 'app-misc/leaf-e',
+			},
+			'app-misc/leaf-d-1' : {},
+			'app-misc/leaf-e-1' : {},
+		}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				['app-misc/plugin-b'],
+				success = True,
+				ambiguous_merge_order = True,
+				mergelist = [
+					('app-misc/leaf-b-1', 'app-misc/leaf-d-1', 'app-misc/leaf-e-1'),
+					('app-misc/branch-d-1', 'app-misc/branch-e-1'),
+					'app-misc/runtime-c-1',
+					('app-misc/runtime-cycle-c-1', 'app-misc/branch-c-1'),
+					'app-misc/branch-b-1',
+					('app-misc/runtime-cycle-b-1', 'app-misc/plugin-b-1'),
+					'app-misc/plugins-consumer-1',
+				],
+			),
+		)
+
+		playground = ResolverPlayground(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.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2015-11-24 16:45 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2015-11-24 16:45 UTC (permalink / raw
  To: gentoo-commits

commit:     0c00530c92ecca3499c7d98fedae41a9ab559d17
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Nov 24 09:14:41 2015 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue Nov 24 16:43:58 2015 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=0c00530c

depgraph: autounmask for conditional USE deps (bug 566704)

For parents with unsatisfied conditional dependencies, translate
USE change suggestions into autounmask changes.

X-Gentoo-Bug: 566704
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=566704
Acked-by: Alexander Berntsen <bernalex <AT> gentoo.org>

 pym/_emerge/depgraph.py                            | 35 +++++++++++++++++-
 .../tests/resolver/test_autounmask_parent.py       | 43 ++++++++++++++++++++++
 2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 57040ab..f659b0a 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -4075,6 +4075,7 @@ class depgraph(object):
 		# Now that the root packages have been added to the graph,
 		# process the dependencies.
 		if not self._create_graph():
+			self._apply_parent_use_changes()
 			return 0, myfavorites
 
 		try:
@@ -4162,6 +4163,24 @@ class depgraph(object):
 		# We're true here unless we are missing binaries.
 		return (True, myfavorites)
 
+	def _apply_parent_use_changes(self):
+		"""
+		For parents with unsatisfied conditional dependencies, translate
+		USE change suggestions into autounmask changes.
+		"""
+		if (self._dynamic_config._unsatisfied_deps_for_display and
+			self._dynamic_config._autounmask):
+			remaining_items = []
+			for item in self._dynamic_config._unsatisfied_deps_for_display:
+				pargs, kwargs = item
+				kwargs = kwargs.copy()
+				kwargs['collect_use_changes'] = True
+				if not self._show_unsatisfied_dep(*pargs,
+					**portage._native_kwargs(kwargs)):
+					remaining_items.append(item)
+			if len(remaining_items) != len(self._dynamic_config._unsatisfied_deps_for_display):
+				self._dynamic_config._unsatisfied_deps_for_display = remaining_items
+
 	def _set_args(self, args):
 		"""
 		Create the "__non_set_args__" package set from atoms and packages given as
@@ -4718,7 +4737,8 @@ class depgraph(object):
 
 
 	def _show_unsatisfied_dep(self, root, atom, myparent=None, arg=None,
-		check_backtrack=False, check_autounmask_breakage=False, show_req_use=None):
+		check_backtrack=False, check_autounmask_breakage=False, show_req_use=None,
+		collect_use_changes=False):
 		"""
 		When check_backtrack=True, no output is produced and
 		the method either returns or raises _backtrack_mask if
@@ -4962,15 +4982,28 @@ class depgraph(object):
 									"defined by %s: '%s'" % (myparent.cpv, \
 									human_readable_required_use(required_use))
 
+					target_use = {}
 					for flag in involved_flags:
 						if flag in self._pkg_use_enabled(myparent):
+							target_use[flag] = False
 							changes.append(colorize("blue", "-" + flag))
 						else:
+							target_use[flag] = True
 							changes.append(colorize("red", "+" + flag))
+
+					if collect_use_changes and not required_use_warning:
+						previous_changes = self._dynamic_config._needed_use_config_changes.get(myparent)
+						self._pkg_use_enabled(myparent, target_use=target_use)
+						if previous_changes is not self._dynamic_config._needed_use_config_changes.get(myparent):
+							return True
+
 					mreasons.append("Change USE: %s" % " ".join(changes) + required_use_warning)
 					if (myparent, mreasons) not in missing_use_reasons:
 						missing_use_reasons.append((myparent, mreasons))
 
+		if collect_use_changes:
+			return False
+
 		unmasked_use_reasons = [(pkg, mreasons) for (pkg, mreasons) \
 			in missing_use_reasons if pkg not in masked_pkg_instances]
 

diff --git a/pym/portage/tests/resolver/test_autounmask_parent.py b/pym/portage/tests/resolver/test_autounmask_parent.py
new file mode 100644
index 0000000..042acab
--- /dev/null
+++ b/pym/portage/tests/resolver/test_autounmask_parent.py
@@ -0,0 +1,43 @@
+# Copyright 2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+	ResolverPlayground,
+	ResolverPlaygroundTestCase,
+)
+
+class AutounmaskParentTestCase(TestCase):
+
+	def testAutounmaskParentUse(self):
+
+		ebuilds = {
+			"dev-libs/B-1": {
+				"EAPI": "5",
+				"DEPEND": "dev-libs/D[foo(-)?,bar(-)?]",
+				"IUSE": "+bar +foo",
+			},
+			"dev-libs/D-1": {},
+		}
+
+		test_cases = (
+			# Test bug 566704
+			ResolverPlaygroundTestCase(
+				["=dev-libs/B-1"],
+				options={"--autounmask": True},
+				success=False,
+				use_changes={
+					"dev-libs/B-1": {
+						"foo": False,
+						"bar": False,
+					}
+				}),
+		)
+
+		playground = ResolverPlayground(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.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-11-16  9:04 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2014-11-16  9:04 UTC (permalink / raw
  To: gentoo-commits

commit:     390f90c2bee92ee5c845cdd765824b48ed6718ad
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Nov 16 04:32:43 2014 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Nov 16 08:58:53 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=390f90c2

_slot_operator_update_probe: fix bug #528610

This fixes a case inside _slot_operator_update_probe where it would
select an inappropriate replacement_parent of a lower version than
desired. The problem is solved by rejecting replacement_parent if its
version is lower than the existing parent, and a downgrade is not
desired.

X-Gentoo-Bug: 528610
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=528610
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

---
 pym/_emerge/depgraph.py                            |  8 +++
 ..._slot_operator_update_probe_parent_downgrade.py | 68 ++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 94eaed8..2a839d0 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1659,6 +1659,7 @@ class depgraph(object):
 		debug = "--debug" in self._frozen_config.myopts
 		selective = "selective" in self._dynamic_config.myparams
 		want_downgrade = None
+		want_downgrade_parent = None
 
 		def check_reverse_dependencies(existing_pkg, candidate_pkg,
 			replacement_parent=None):
@@ -1706,6 +1707,13 @@ class depgraph(object):
 		for replacement_parent in self._iter_similar_available(dep.parent,
 			dep.parent.slot_atom, autounmask_level=autounmask_level):
 
+			if replacement_parent < dep.parent:
+				if want_downgrade_parent is None:
+					want_downgrade_parent = self._downgrade_probe(
+						dep.parent)
+				if not want_downgrade_parent:
+					continue
+
 			if not check_reverse_dependencies(dep.parent, replacement_parent):
 				continue
 

diff --git a/pym/portage/tests/resolver/test_slot_operator_update_probe_parent_downgrade.py b/pym/portage/tests/resolver/test_slot_operator_update_probe_parent_downgrade.py
new file mode 100644
index 0000000..2ec15b6
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_update_probe_parent_downgrade.py
@@ -0,0 +1,68 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import \
+	ResolverPlayground, ResolverPlaygroundTestCase
+
+class SlotOperatorUpdateProbeParentDowngradeTestCase(TestCase):
+
+	def testSlotOperatorUpdateProbeParentDowngrade(self):
+
+		ebuilds = {
+			"net-nds/openldap-2.4.40-r3": {
+				"EAPI": "5",
+				"RDEPEND": "<sys-libs/db-6.0:= " + \
+					"|| ( sys-libs/db:5.3 sys-libs/db:5.1 )"
+			},
+			"net-nds/openldap-2.4.40": {
+				"EAPI": "5",
+				"RDEPEND": "sys-libs/db"
+			},
+			"sys-libs/db-6.0": {
+				"SLOT": "6.0",
+			},
+			"sys-libs/db-5.3": {
+				"SLOT": "5.3",
+			},
+		}
+
+		installed = {
+			"net-nds/openldap-2.4.40-r3": {
+				"EAPI": "5",
+				"RDEPEND": "<sys-libs/db-6.0:5.3/5.3= " + \
+					"|| ( sys-libs/db:5.3 sys-libs/db:5.1 )"
+			},
+			"sys-libs/db-6.0": {
+				"SLOT": "6.0",
+			},
+			"sys-libs/db-5.3": {
+				"SLOT": "5.3",
+			},
+		}
+
+		world = (
+			"net-nds/openldap",
+		)
+
+		test_cases = (
+			# bug 528610 - openldap rebuild was triggered
+			# inappropriately, due to slot_operator_update_probe
+			# selecting an inappropriate replacement parent of
+			# a lower version than desired.
+			ResolverPlaygroundTestCase(
+				["@world"],
+				success = True,
+				options = { "--update": True, "--deep": True },
+				mergelist = []),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success,
+					True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-10-27  9:26 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2014-10-27  9:26 UTC (permalink / raw
  To: gentoo-commits

commit:     d3be49fe6827aa1974856dffe6d5a1aca80a7bed
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Oct 27 00:32:36 2014 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Oct 27 09:21:06 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=d3be49fe

depgraph: fix bug #526160

This fixes _dep_check_composite_db to mask packages that aren't the
highest visible match, but only if an update is desirable. This causes
desirable updates to get pulled in for cases like bug #526160. The
included unit test simulates the virtual/pypy update that triggered
the bug.

X-Gentoo-Bug: 526160
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=526160
Acked-by: Alexander Berntsen <bernalex <AT> gentoo.org>

---
 pym/_emerge/depgraph.py                         | 24 +++++++++
 pym/portage/tests/resolver/test_virtual_slot.py | 66 +++++++++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 5180db5..78b9236 100644
--- a/pym/_emerge/depgraph.py
+++ b/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)
 

diff --git a/pym/portage/tests/resolver/test_virtual_slot.py b/pym/portage/tests/resolver/test_virtual_slot.py
index 1b19d77..2e5ca7f 100644
--- a/pym/portage/tests/resolver/test_virtual_slot.py
+++ b/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 = {


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-09-19  9:28 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2014-09-19  9:28 UTC (permalink / raw
  To: gentoo-commits

commit:     c81f3f4586b7b6164f5038ac778098911fef9404
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Sep 19 09:24:58 2014 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Sep 19 09:26:15 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=c81f3f45

_solve_..slot_conflicts: fix bug #522084

Fix _solve_non_slot_operator_slot_conflicts to add all parents to the
conflict_graph, even for parents where the atom matches all relevant
nodes. Otherwise, we risk removing all of the matched nodes from the
graph, which would cause a missed update.

X-Gentoo-Bug: 522084
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=522084
Reviewed-by: Alexander Berntsen <bernalex <AT> gentoo.org>

---
 pym/_emerge/depgraph.py                            | 14 ++--
 .../test_solve_non_slot_operator_slot_conflicts.py | 75 ++++++++++++++++++++++
 2 files changed, 82 insertions(+), 7 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index e7ae720..f4e5a1b 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1172,12 +1172,15 @@ class depgraph(object):
 					for match in matched:
 						writemsg_level("         match: %s\n" % match, level=logging.DEBUG, noiselevel=-1)
 
-				if len(matched) == len(conflict):
-					# All packages match.
-					continue
+				if len(matched) > 1:
+					# Even if all packages match, this parent must still
+					# be added to the conflict_graph. Otherwise, we risk
+					# removing all of these packages from the depgraph,
+					# which could cause a missed update (bug #522084).
+					conflict_graph.add(or_tuple(matched), parent)
 				elif len(matched) == 1:
 					conflict_graph.add(matched[0], parent)
-				elif len(matched) == 0:
+				else:
 					# This typically means that autounmask broke a
 					# USE-dep, but it could also be due to the slot
 					# not matching due to multislot (bug #220341).
@@ -1189,9 +1192,6 @@ class depgraph(object):
 						for pkg in conflict:
 							writemsg_level("         non-match: %s\n" % pkg,
 								level=logging.DEBUG, noiselevel=-1)
-				else:
-					# More than one packages matched, but not all.
-					conflict_graph.add(or_tuple(matched), parent)
 
 		for pkg in indirect_conflict_pkgs:
 			for parent, atom in self._dynamic_config._parent_atoms.get(pkg, []):

diff --git a/pym/portage/tests/resolver/test_solve_non_slot_operator_slot_conflicts.py b/pym/portage/tests/resolver/test_solve_non_slot_operator_slot_conflicts.py
new file mode 100644
index 0000000..c6024f4
--- /dev/null
+++ b/pym/portage/tests/resolver/test_solve_non_slot_operator_slot_conflicts.py
@@ -0,0 +1,75 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SolveNonSlotOperatorSlotConflictsTestCase(TestCase):
+
+	def testSolveNonSlotOperatorSlotConflicts(self):
+
+		ebuilds = {
+
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1",
+				"PDEPEND": "app-misc/B"
+			},
+
+			"app-misc/A-2" : {
+				"EAPI": "5",
+				"SLOT": "0/2",
+				"PDEPEND": "app-misc/B"
+			},
+
+			"app-misc/B-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A:="
+			},
+
+		}
+
+		installed = {
+
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1",
+				"PDEPEND": "app-misc/B"
+			},
+
+			"app-misc/B-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A:0/1="
+			},
+
+		}
+
+		world = ["app-misc/A"]
+
+		test_cases = (
+
+			# bug 522084
+			# In this case, _solve_non_slot_operator_slot_conflicts
+			# removed both versions of app-misc/A from the graph, since
+			# they didn't have any non-conflict parents (except for
+			# @selected which matched both instances). The result was
+			# a missed update.
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True},
+				success = True,
+				mergelist = ['app-misc/A-2', 'app-misc/B-0']
+			),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True,
+					test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-09-19  9:17 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2014-09-19  9:17 UTC (permalink / raw
  To: gentoo-commits

commit:     beecd610f21497609679a08f867fd88090c71fb7
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Sep 19 09:16:32 2014 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Sep 19 09:16:32 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=beecd610

_backtrack_depgraph: fix bug #523048

This fixes _backtrack_depgraph to immediately report necessary
REQUIRED_USE changes instead of discarding the graph. This is
accomplished by replacing the depgraph.success_without_autounmask
method with a new need_config_change method that accounts for both
autounmask and REQUIRED_USE changes.

X-Gentoo-Bug: 523048
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=523048
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>
Acked-by: Alexander Berntsen <bernalex <AT> gentoo.org>

---
 pym/_emerge/depgraph.py                            | 11 ++--
 pym/portage/tests/resolver/ResolverPlayground.py   | 19 +++++-
 .../resolver/test_slot_operator_required_use.py    | 72 ++++++++++++++++++++++
 3 files changed, 95 insertions(+), 7 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 6332733..e7ae720 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -421,6 +421,7 @@ class _dynamic_depgraph_config(object):
 		self._buildpkgonly_deps_unsatisfied = False
 		self._autounmask = depgraph._frozen_config.myopts.get('--autounmask') != 'n'
 		self._success_without_autounmask = False
+		self._required_use_unsatisfied = False
 		self._traverse_ignored_deps = False
 		self._complete_mode = False
 		self._slot_operator_deps = {}
@@ -2461,6 +2462,7 @@ class depgraph(object):
 				self._dynamic_config._unsatisfied_deps_for_display.append(
 					((pkg.root, atom),
 					{"myparent" : dep.parent, "show_req_use" : pkg}))
+				self._dynamic_config._required_use_unsatisfied = True
 				self._dynamic_config._skip_restart = True
 				return 0
 
@@ -8390,8 +8392,9 @@ class depgraph(object):
 		return self._dynamic_config._need_restart and \
 			not self._dynamic_config._skip_restart
 
-	def success_without_autounmask(self):
-		return self._dynamic_config._success_without_autounmask
+	def need_config_change(self):
+		return self._dynamic_config._success_without_autounmask or \
+			self._dynamic_config._required_use_unsatisfied
 
 	def autounmask_breakage_detected(self):
 		try:
@@ -8665,7 +8668,7 @@ def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, sp
 			backtrack_parameters=backtrack_parameters)
 		success, favorites = mydepgraph.select_files(myfiles)
 
-		if success or mydepgraph.success_without_autounmask():
+		if success or mydepgraph.need_config_change():
 			break
 		elif not allow_backtracking:
 			break
@@ -8677,7 +8680,7 @@ def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, sp
 		else:
 			break
 
-	if not (success or mydepgraph.success_without_autounmask()) and backtracked:
+	if not (success or mydepgraph.need_config_change()) and backtracked:
 
 		if debug:
 			writemsg_level(

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index d74a410..2d16251 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -674,7 +674,8 @@ class ResolverPlaygroundTestCase(object):
 						expected = x
 						break
 			elif key in ("unstable_keywords", "needed_p_mask_changes",
-				"unsatisfied_deps") and expected is not None:
+				"unsatisfied_deps", "required_use_unsatisfied") and \
+				expected is not None:
 				expected = set(expected)
 
 			elif key == "forced_rebuilds" and expected is not None:
@@ -692,11 +693,14 @@ class ResolverPlaygroundTestCase(object):
 class ResolverPlaygroundResult(object):
 
 	checks = (
-		"success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
-		"circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps", "forced_rebuilds"
+		"success", "mergelist", "use_changes", "license_changes",
+		"unstable_keywords", "slot_collision_solutions",
+		"circular_dependency_solutions", "needed_p_mask_changes",
+		"unsatisfied_deps", "forced_rebuilds", "required_use_unsatisfied"
 		)
 	optional_checks = (
 		"forced_rebuilds",
+		"required_use_unsatisfied",
 		"unsatisfied_deps"
 		)
 
@@ -714,6 +718,7 @@ class ResolverPlaygroundResult(object):
 		self.circular_dependency_solutions = None
 		self.unsatisfied_deps = frozenset()
 		self.forced_rebuilds = None
+		self.required_use_unsatisfied = None
 
 		if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
 			self.mergelist = []
@@ -783,6 +788,14 @@ class ResolverPlaygroundResult(object):
 				for child_dict in self.depgraph._forced_rebuilds.values()
 				for child, parents in child_dict.items())
 
+		required_use_unsatisfied = []
+		for pargs, kwargs in \
+			self.depgraph._dynamic_config._unsatisfied_deps_for_display:
+			if "show_req_use" in kwargs:
+				required_use_unsatisfied.append(pargs[1])
+		if required_use_unsatisfied:
+			self.required_use_unsatisfied = set(required_use_unsatisfied)
+
 class ResolverPlaygroundDepcleanResult(object):
 
 	checks = (

diff --git a/pym/portage/tests/resolver/test_slot_operator_required_use.py b/pym/portage/tests/resolver/test_slot_operator_required_use.py
new file mode 100644
index 0000000..9cc6dba
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_required_use.py
@@ -0,0 +1,72 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SlotOperatorRequiredUseTestCase(TestCase):
+
+	def testSlotOperatorRequiredUse(self):
+
+		ebuilds = {
+
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1"
+			},
+
+			"app-misc/A-2" : {
+				"EAPI": "5",
+				"SLOT": "0/2"
+			},
+
+			"app-misc/B-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A:=",
+				"IUSE": "x y",
+				"REQUIRED_USE": "|| ( x y )"
+			},
+
+		}
+
+		installed = {
+
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1"
+			},
+
+			"app-misc/B-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A:0/1=",
+				"IUSE": "x y",
+				"USE": "x"
+			},
+
+		}
+
+		world = ["app-misc/B"]
+
+		test_cases = (
+
+			# bug 523048
+			# Ensure that unsatisfied REQUIRED_USE is reported when
+			# it blocks necessary slot-operator rebuilds.
+			ResolverPlaygroundTestCase(
+				["app-misc/A"],
+				success = False,
+				required_use_unsatisfied = ['app-misc/B:0']
+			),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True,
+					test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-09-17 16:35 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2014-09-17 16:35 UTC (permalink / raw
  To: gentoo-commits

commit:     3f0799054b4e5ef88feb59d20d262668ca79df33
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Sep 12 07:07:13 2014 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Sep 17 16:29:07 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=3f079905

_compute_abi_rebuild_info: fix bug #521990

Since self._dynamic_config._slot_operator_deps only contains deps for
packages added to the graph, it doesn't contain potentially relevant
deps of installed packages that have not been added to the graph.
Therefore, generate pseudo-deps for such installed packages, and use
those to generate the rebuild info.

X-Gentoo-Bug: 521990
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=521990

---
 pym/_emerge/depgraph.py                            | 100 +++++++++++++++++----
 pym/portage/tests/resolver/ResolverPlayground.py   |  15 +++-
 .../resolver/test_slot_conflict_force_rebuild.py   |  84 +++++++++++++++++
 3 files changed, 183 insertions(+), 16 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index d85494a..6332733 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -647,26 +647,96 @@ class depgraph(object):
 		# Go through all slot operator deps and check if one of these deps
 		# has a parent that is matched by one of the atoms from above.
 		forced_rebuilds = {}
-		for (root, slot_atom), deps in self._dynamic_config._slot_operator_deps.items():
-			rebuild_atoms = atoms.get(root, set())
 
-			for dep in deps:
-				if not isinstance(dep.parent, Package):
-					continue
+		for root, rebuild_atoms in atoms.items():
 
-				if dep.parent.installed or dep.child.installed or \
-					dep.parent.slot_atom not in rebuild_atoms:
-					continue
+			for slot_atom in rebuild_atoms:
+
+				inst_pkg, reinst_pkg = \
+					self._select_pkg_from_installed(root, slot_atom)
 
-				# Make sure the child's slot/subslot has changed. If it hasn't,
-				# then another child has forced this rebuild.
-				installed_pkg = self._select_pkg_from_installed(root, dep.child.slot_atom)[0]
-				if installed_pkg and installed_pkg.slot == dep.child.slot and \
-					installed_pkg.sub_slot == dep.child.sub_slot:
+				if inst_pkg is reinst_pkg or reinst_pkg is None:
 					continue
 
-				# The child has forced a rebuild of the parent
-				forced_rebuilds.setdefault(root, {}).setdefault(dep.child, set()).add(dep.parent)
+				# Generate pseudo-deps for any slot-operator deps of
+				# inst_pkg. Its deps aren't in _slot_operator_deps
+				# because it hasn't been added to the graph, but we
+				# are interested in any rebuilds that it triggered.
+				built_slot_op_atoms = []
+				if inst_pkg is not None:
+					selected_atoms = self._select_atoms_probe(
+						inst_pkg.root, inst_pkg)
+					for atom in selected_atoms:
+						if atom.slot_operator_built:
+							built_slot_op_atoms.append(atom)
+
+					if not built_slot_op_atoms:
+						continue
+
+				# Use a cloned list, since we may append to it below.
+				deps = self._dynamic_config._slot_operator_deps.get(
+					(root, slot_atom), [])[:]
+
+				if built_slot_op_atoms and reinst_pkg is not None:
+					for child in self._dynamic_config.digraph.child_nodes(
+						reinst_pkg):
+
+						if child.installed:
+							continue
+
+						for atom in built_slot_op_atoms:
+							# NOTE: Since atom comes from inst_pkg, and
+							# reinst_pkg is the replacement parent, there's
+							# no guarantee that atom will completely match
+							# child. So, simply use atom.cp and atom.slot
+							# for matching.
+							if atom.cp != child.cp:
+								continue
+							if atom.slot and atom.slot != child.slot:
+								continue
+							deps.append(Dependency(atom=atom, child=child,
+								root=child.root, parent=reinst_pkg))
+
+				for dep in deps:
+					if dep.child.installed:
+						# Find the replacement child.
+						child = next((pkg for pkg in
+							self._dynamic_config._package_tracker.match(
+							dep.root, dep.child.slot_atom)
+							if not pkg.installed), None)
+
+						if child is None:
+							continue
+
+						inst_child = dep.child.installed
+
+					else:
+						child = dep.child
+						inst_child = self._select_pkg_from_installed(
+							child.root, child.slot_atom)[0]
+
+					# Make sure the child's slot/subslot has changed. If it
+					# hasn't, then another child has forced this rebuild.
+					if inst_child and inst_child.slot == child.slot and \
+						inst_child.sub_slot == child.sub_slot:
+						continue
+
+					if dep.parent.installed:
+						# Find the replacement parent.
+						parent = next((pkg for pkg in
+							self._dynamic_config._package_tracker.match(
+							dep.parent.root, dep.parent.slot_atom)
+							if not pkg.installed), None)
+
+						if parent is None:
+							continue
+
+					else:
+						parent = dep.parent
+
+					# The child has forced a rebuild of the parent
+					forced_rebuilds.setdefault(root, {}
+						).setdefault(child, set()).add(parent)
 
 		if debug:
 			writemsg_level("slot operator dependencies:\n",

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index b1974d7..646987d 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -677,6 +677,9 @@ class ResolverPlaygroundTestCase(object):
 				"unsatisfied_deps") and expected is not None:
 				expected = set(expected)
 
+			elif key == "forced_rebuilds" and expected is not None:
+				expected = dict((k, set(v)) for k, v in expected.items())
+
 			if got != expected:
 				fail_msgs.append("atoms: (" + ", ".join(result.atoms) + "), key: " + \
 					key + ", expected: " + str(expected) + ", got: " + str(got))
@@ -690,9 +693,10 @@ class ResolverPlaygroundResult(object):
 
 	checks = (
 		"success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
-		"circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps",
+		"circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps", "forced_rebuilds"
 		)
 	optional_checks = (
+		"forced_rebuilds",
 		"unsatisfied_deps"
 		)
 
@@ -709,6 +713,7 @@ class ResolverPlaygroundResult(object):
 		self.slot_collision_solutions = None
 		self.circular_dependency_solutions = None
 		self.unsatisfied_deps = frozenset()
+		self.forced_rebuilds = None
 
 		if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
 			self.mergelist = []
@@ -772,6 +777,14 @@ class ResolverPlaygroundResult(object):
 			self.unsatisfied_deps = set(dep_info[0][1]
 				for dep_info in self.depgraph._dynamic_config._unsatisfied_deps_for_display)
 
+		if self.depgraph._forced_rebuilds:
+			self.forced_rebuilds = dict(self._iter_forced_rebuilds())
+
+	def _iter_forced_rebuilds(self):
+		for child_dict in self.depgraph._forced_rebuilds.values():
+			for child, parents in child_dict.items():
+				yield child.cpv, set(parent.cpv for parent in parents)
+
 class ResolverPlaygroundDepcleanResult(object):
 
 	checks = (

diff --git a/pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py
new file mode 100644
index 0000000..4170bfd
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_conflict_force_rebuild.py
@@ -0,0 +1,84 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SlotConflictForceRebuildTestCase(TestCase):
+
+	def testSlotConflictForceRebuild(self):
+
+		ebuilds = {
+
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1"
+			},
+
+			"app-misc/A-2" : {
+				"EAPI": "5",
+				"SLOT": "0/2"
+			},
+
+			"app-misc/B-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A:="
+			},
+
+			"app-misc/C-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A"
+			},
+
+		}
+
+		installed = {
+
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1"
+			},
+
+			"app-misc/B-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A:0/1="
+			},
+
+			"app-misc/C-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/A:0/1="
+			},
+
+		}
+
+		world = ["app-misc/B", "app-misc/C"]
+
+		test_cases = (
+
+			# Test bug #521990, where forced_rebuilds omits ebuilds that
+			# had have had their slot operator atoms removed from the
+			# ebuilds, even though the corresponding installed
+			# instances had really forced rebuilds due to being built
+			# with slot-operators in their deps.
+			ResolverPlaygroundTestCase(
+				["app-misc/A"],
+				options = {},
+				success = True,
+				ambiguous_merge_order = True,
+				mergelist = ['app-misc/A-2', ('app-misc/B-0', 'app-misc/C-0')],
+				forced_rebuilds = {
+					'app-misc/A-2': ['app-misc/B-0', 'app-misc/C-0']
+				}
+			),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-09-16 21:04 Brian Dolbec
  0 siblings, 0 replies; 56+ messages in thread
From: Brian Dolbec @ 2014-09-16 21:04 UTC (permalink / raw
  To: gentoo-commits

commit:     38d9d0d3aa260c29b0a49ad0933e425e8e729b07
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Sep 16 17:57:49 2014 +0000
Commit:     Brian Dolbec <brian.dolbec <AT> gmail <DOT> com>
CommitDate: Tue Sep 16 20:25:13 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=38d9d0d3

_solve_..slot_conflicts: fix bug #510270

This fixes an IndexError in _solve_non_slot_operator_slot_conflicts
which occurs when none of the conflict packages matched a particular
atom. This typically means that autounmask broke a USE-dep, but it could
also be due to the slot not matching due to multislot (bug #220341).
Either way, don't try to solve this conflict. Instead, force all of the
associated conflict nodes into the graph so that they are protected from
removal by the conflict solver.

X-Gentoo-Bug: 510270
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=510270

---
 pym/_emerge/depgraph.py                            | 14 +++++
 pym/portage/tests/resolver/ResolverPlayground.py   |  9 ++++
 .../tests/resolver/test_autounmask_use_breakage.py | 63 ++++++++++++++++++++++
 3 files changed, 86 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index cc87d9f..d85494a 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1059,6 +1059,7 @@ class depgraph(object):
 			def __str__(self):
 				return "(%s)" % ",".join(str(pkg) for pkg in self)
 
+		non_matching_forced = set()
 		for conflict in conflicts:
 			if debug:
 				writemsg_level("   conflict:\n", level=logging.DEBUG, noiselevel=-1)
@@ -1105,6 +1106,18 @@ class depgraph(object):
 					continue
 				elif len(matched) == 1:
 					conflict_graph.add(matched[0], parent)
+				elif len(matched) == 0:
+					# This typically means that autounmask broke a
+					# USE-dep, but it could also be due to the slot
+					# not matching due to multislot (bug #220341).
+					# Either way, don't try to solve this conflict.
+					# Instead, force them all into the graph so that
+					# they are protected from removal.
+					non_matching_forced.update(conflict)
+					if debug:
+						for pkg in conflict:
+							writemsg_level("         non-match: %s\n" % pkg,
+								level=logging.DEBUG, noiselevel=-1)
 				else:
 					# More than one packages matched, but not all.
 					conflict_graph.add(or_tuple(matched), parent)
@@ -1125,6 +1138,7 @@ class depgraph(object):
 		# Now select required packages. Collect them in the
 		# 'forced' set.
 		forced = set([non_conflict_node])
+		forced.update(non_matching_forced)
 		unexplored = set([non_conflict_node])
 		# or_tuples get special handling. We first explore
 		# all packages in the hope of having forced one of

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index 77a5b5c..b1974d7 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -549,6 +549,7 @@ class ResolverPlaygroundTestCase(object):
 		self.all_permutations = kwargs.pop("all_permutations", False)
 		self.ignore_mergelist_order = kwargs.pop("ignore_mergelist_order", False)
 		self.ambiguous_merge_order = kwargs.pop("ambiguous_merge_order", False)
+		self.ambiguous_slot_collision_solutions = kwargs.pop("ambiguous_slot_collision_solutions", False)
 		self.check_repo_names = kwargs.pop("check_repo_names", False)
 		self.merge_order_assertions = kwargs.pop("merge_order_assertions", False)
 
@@ -664,6 +665,14 @@ class ResolverPlaygroundTestCase(object):
 									str((node1, node2))) + \
 									", got: " + str(got))
 
+			elif key == "slot_collision_solutions" and \
+				self.ambiguous_slot_collision_solutions:
+				# Tests that use all_permutations can have multiple
+				# outcomes here.
+				for x in expected:
+					if x == got:
+						expected = x
+						break
 			elif key in ("unstable_keywords", "needed_p_mask_changes",
 				"unsatisfied_deps") and expected is not None:
 				expected = set(expected)

diff --git a/pym/portage/tests/resolver/test_autounmask_use_breakage.py b/pym/portage/tests/resolver/test_autounmask_use_breakage.py
new file mode 100644
index 0000000..3654aa6
--- /dev/null
+++ b/pym/portage/tests/resolver/test_autounmask_use_breakage.py
@@ -0,0 +1,63 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class AutounmaskUseBreakageTestCase(TestCase):
+
+	def testAutounmaskUseBreakage(self):
+
+		ebuilds = {
+
+			"app-misc/A-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/D[-foo]",
+			},
+
+			"app-misc/B-0" : {
+				"EAPI": "5",
+				"RDEPEND": "app-misc/D[foo]"
+			},
+
+			"app-misc/C-0" : {
+				"EAPI": "5",
+				"RDEPEND": ">=app-misc/D-1"
+			},
+
+			"app-misc/D-0" : {
+				"EAPI": "5",
+				"IUSE": "foo"
+			},
+
+			"app-misc/D-1" : {
+				"EAPI": "5",
+				"IUSE": "bar"
+			},
+
+		}
+
+		test_cases = (
+
+			# Bug 510270
+			# _solve_non_slot_operator_slot_conflicts throws
+			# IndexError: tuple index out of range
+			# due to autounmask USE breakage.
+			ResolverPlaygroundTestCase(
+				["app-misc/C", "app-misc/B", "app-misc/A"],
+				all_permutations = True,
+				success = False,
+				ambiguous_slot_collision_solutions = True,
+				slot_collision_solutions = [None, []]
+			),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-09-11 21:37 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2014-09-11 21:37 UTC (permalink / raw
  To: gentoo-commits

commit:     336ab90212c80ce9548362bf4fbdafd388c3515c
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Sep  7 05:19:46 2014 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Sep 11 21:36:08 2014 +0000
URL:        http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=336ab902

depgraph._add_dep: fix bug #520950

This handles a case which occurs when
_solve_non_slot_operator_slot_conflicts calls _create_graph. In this
case, ignore unsatisfied deps for installed packages only if their depth
is beyond the depth requested by the user and the dep was initially
unsatisfied (not broken by a slot conflict in the current graph).

Since depth is meaningless for packages that are not reachable as deep
dependencies of arguments, the _UNREACHABLE_DEPTH constant is used as
the depth value for any packages added via _complete_graph. Also, any
sets added via _complete_graph have their reset_depth attribute set to
False.

The sys.stderr -> writemsg changes are necessary to ensure that the test
cases do not output unwanted error messages.

X-Gentoo-Bug: 520950
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=520950

---
 pym/_emerge/depgraph.py                            | 128 ++++++++++++++++-----
 pym/portage/tests/resolver/ResolverPlayground.py   |  11 +-
 .../test_slot_conflict_unsatisfied_deep_deps.py    | 115 ++++++++++++++++++
 3 files changed, 226 insertions(+), 28 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index d6cd24d..cc87d9f 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -107,7 +107,7 @@ def _wildcard_set(atoms):
 
 class _frozen_depgraph_config(object):
 
-	def __init__(self, settings, trees, myopts, spinner):
+	def __init__(self, settings, trees, myopts, params, spinner):
 		self.settings = settings
 		self.target_root = settings["EROOT"]
 		self.myopts = myopts
@@ -115,6 +115,7 @@ class _frozen_depgraph_config(object):
 		if settings.get("PORTAGE_DEBUG", "") == "1":
 			self.edebug = 1
 		self.spinner = spinner
+		self.requested_depth = params.get("deep", 0)
 		self._running_root = trees[trees._running_eroot]["root_config"]
 		self.pkgsettings = {}
 		self.trees = {}
@@ -502,13 +503,18 @@ class _dynamic_depgraph_config(object):
 
 class depgraph(object):
 
+	# Represents the depth of a node that is unreachable from explicit
+	# user arguments (or their deep dependencies). Such nodes are pulled
+	# in by the _complete_graph method.
+	_UNREACHABLE_DEPTH = object()
+
 	pkg_tree_map = RootConfig.pkg_tree_map
 
 	def __init__(self, settings, trees, myopts, myparams, spinner,
 		frozen_config=None, backtrack_parameters=BacktrackParameter(), allow_backtracking=False):
 		if frozen_config is None:
 			frozen_config = _frozen_depgraph_config(settings, trees,
-			myopts, spinner)
+			myopts, myparams, spinner)
 		self._frozen_config = frozen_config
 		self._dynamic_config = _dynamic_depgraph_config(self, myparams,
 			allow_backtracking, backtrack_parameters)
@@ -2095,6 +2101,13 @@ class depgraph(object):
 				arg = arg_stack.pop()
 				if arg in traversed_set_args:
 					continue
+
+				# If a node with the same hash already exists in
+				# the digraph, preserve the existing instance which
+				# may have a different reset_depth attribute
+				# (distiguishes user arguments from sets added for
+				# another reason such as complete mode).
+				arg = self._dynamic_config.digraph.get(arg, arg)
 				traversed_set_args.add(arg)
 
 				if add_to_digraph:
@@ -2114,8 +2127,16 @@ class depgraph(object):
 					if nested_set is None:
 						nested_set = root_config.sets.get(s)
 					if nested_set is not None:
+						# Propagate the reset_depth attribute from
+						# parent set to nested set.
 						nested_arg = SetArg(arg=token, pset=nested_set,
+							reset_depth=arg.reset_depth,
 							root_config=root_config)
+
+						# Preserve instances already in the graph (same
+						# reason as for the "arg" variable above).
+						nested_arg = self._dynamic_config.digraph.get(
+							nested_arg, nested_arg)
 						arg_stack.append(nested_arg)
 						if add_to_digraph:
 							self._dynamic_config.digraph.add(nested_arg, arg,
@@ -2164,9 +2185,42 @@ class depgraph(object):
 				dep.collapsed_priority.ignored):
 				# This is an unnecessary build-time dep.
 				return 1
+
+			# NOTE: For removal actions, allow_unsatisfied is always
+			# True since all existing removal actions traverse all
+			# installed deps deeply via the _complete_graph method,
+			# which calls _create_graph with allow_unsatisfied = True.
 			if allow_unsatisfied:
 				self._dynamic_config._unsatisfied_deps.append(dep)
 				return 1
+
+			# The following case occurs when
+			# _solve_non_slot_operator_slot_conflicts calls
+			# _create_graph. In this case, ignore unsatisfied deps for
+			# installed packages only if their depth is beyond the depth
+			# requested by the user and the dep was initially
+			# unsatisfied (not broken by a slot conflict in the current
+			# graph). See bug #520950.
+			# NOTE: The value of dep.parent.depth is guaranteed to be
+			# either an integer or _UNREACHABLE_DEPTH, where
+			# _UNREACHABLE_DEPTH indicates that the parent has been
+			# pulled in by the _complete_graph method (rather than by
+			# explicit arguments or their deep dependencies). These
+			# cases must be distinguished because depth is meaningless
+			# for packages that are not reachable as deep dependencies
+			# of arguments.
+			if (self._dynamic_config._complete_mode and
+				isinstance(dep.parent, Package) and
+				dep.parent.installed and
+				(dep.parent.depth is self._UNREACHABLE_DEPTH or
+				(self._frozen_config.requested_depth is not True and
+				dep.parent.depth >= self._frozen_config.requested_depth))):
+				inst_pkg, in_graph = \
+					self._select_pkg_from_installed(dep.root, dep.atom)
+				if inst_pkg is None:
+					self._dynamic_config._initially_unsatisfied_deps.append(dep)
+					return 1
+
 			self._dynamic_config._unsatisfied_deps_for_display.append(
 				((dep.root, dep.atom), {"myparent":dep.parent}))
 
@@ -2411,14 +2465,23 @@ class depgraph(object):
 		# Installing package A, we need to make sure package A's deps are met.
 		# emerge --deep <pkgspec>; we need to recursively check dependencies of pkgspec
 		# If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies.
-		if arg_atoms and depth > 0:
+		if arg_atoms and depth != 0:
 			for parent, atom in arg_atoms:
 				if parent.reset_depth:
 					depth = 0
 					break
 
-		if previously_added and pkg.depth is not None:
-			depth = min(pkg.depth, depth)
+		if previously_added and depth != 0 and \
+			isinstance(pkg.depth, int):
+			# Use pkg.depth if it is less than depth.
+			if isinstance(depth, int):
+				depth = min(pkg.depth, depth)
+			else:
+				# depth is _UNREACHABLE_DEPTH and pkg.depth is
+				# an int, so use the int because it's considered
+				# to be less than _UNREACHABLE_DEPTH.
+				depth = pkg.depth
+
 		pkg.depth = depth
 		deep = self._dynamic_config.myparams.get("deep", 0)
 		update = "--update" in self._frozen_config.myopts
@@ -2716,7 +2779,11 @@ class depgraph(object):
 
 	def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
 		dep_string, allow_unsatisfied):
-		depth = pkg.depth + 1
+		if isinstance(pkg.depth, int):
+			depth = pkg.depth + 1
+		else:
+			depth = pkg.depth
+
 		deep = self._dynamic_config.myparams.get("deep", 0)
 		recurse_satisfied = deep is True or depth <= deep
 		debug = "--debug" in self._frozen_config.myopts
@@ -3544,9 +3611,9 @@ class depgraph(object):
 						if not self._add_pkg(arg.package, dep) or \
 							not self._create_graph():
 							if not self.need_restart():
-								sys.stderr.write(("\n\n!!! Problem " + \
+								writemsg(("\n\n!!! Problem " + \
 									"resolving dependencies for %s\n") % \
-									arg.arg)
+									arg.arg, noiselevel=-1)
 							return 0, myfavorites
 						continue
 					if debug:
@@ -3947,10 +4014,14 @@ class depgraph(object):
 			# Recursively traversed virtual dependencies, and their
 			# direct dependencies, are considered to have the same
 			# depth as direct dependencies.
-			if parent.depth is None:
-				virt_depth = None
-			else:
+			if isinstance(parent.depth, int):
 				virt_depth = parent.depth + 1
+			else:
+				# The depth may be None when called via
+				# _select_atoms_probe, or it may be
+				# _UNREACHABLE_DEPTH for complete mode.
+				virt_depth = parent.depth
+
 			chosen_atom_ids = frozenset(id(atom) for atom in mycheck[1])
 			selected_atoms = OrderedDict()
 			node_stack = [(parent, None, None)]
@@ -5833,14 +5904,14 @@ class depgraph(object):
 					pset = root_config.sets[s]
 				atom = SETPREFIX + s
 				args.append(SetArg(arg=atom, pset=pset,
-					root_config=root_config))
+					reset_depth=False, root_config=root_config))
 
 		self._set_args(args)
 		for arg in self._expand_set_args(args, add_to_digraph=True):
 			for atom in arg.pset.getAtoms():
 				self._dynamic_config._dep_stack.append(
 					Dependency(atom=atom, root=arg.root_config.root,
-						parent=arg))
+						parent=arg, depth=self._UNREACHABLE_DEPTH))
 
 		if True:
 			if self._dynamic_config._ignored_deps:
@@ -7786,18 +7857,23 @@ class depgraph(object):
 						break
 
 			if world_problems:
-				sys.stderr.write("\n!!! Problems have been " + \
-					"detected with your world file\n")
-				sys.stderr.write("!!! Please run " + \
-					green("emaint --check world")+"\n\n")
+				writemsg("\n!!! Problems have been " + \
+					"detected with your world file\n",
+					noiselevel=-1)
+				writemsg("!!! Please run " + \
+					green("emaint --check world")+"\n\n",
+					noiselevel=-1)
 
 		if self._dynamic_config._missing_args:
-			sys.stderr.write("\n" + colorize("BAD", "!!!") + \
-				" Ebuilds for the following packages are either all\n")
-			sys.stderr.write(colorize("BAD", "!!!") + \
-				" masked or don't exist:\n")
-			sys.stderr.write(" ".join(str(atom) for arg, atom in \
-				self._dynamic_config._missing_args) + "\n")
+			writemsg("\n" + colorize("BAD", "!!!") + \
+				" Ebuilds for the following packages are either all\n",
+				noiselevel=-1)
+			writemsg(colorize("BAD", "!!!") + \
+				" masked or don't exist:\n",
+				noiselevel=-1)
+			writemsg(" ".join(str(atom) for arg, atom in \
+				self._dynamic_config._missing_args) + "\n",
+				noiselevel=-1)
 
 		if self._dynamic_config._pprovided_args:
 			arg_refs = {}
@@ -7837,7 +7913,7 @@ class depgraph(object):
 				msg.append("  C) Remove offending entries from package.provided.\n\n")
 				msg.append("The best course of action depends on the reason that an offending\n")
 				msg.append("package.provided entry exists.\n\n")
-			sys.stderr.write("".join(msg))
+			writemsg("".join(msg), noiselevel=-1)
 
 		masked_packages = []
 		for pkg in self._dynamic_config._masked_license_updates:
@@ -8487,7 +8563,7 @@ def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, sp
 	backtracked = 0
 
 	frozen_config = _frozen_depgraph_config(settings, trees,
-		myopts, spinner)
+		myopts, myparams, spinner)
 
 	while backtracker:
 
@@ -8569,7 +8645,7 @@ def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
 	mergelist = mtimedb["resume"]["mergelist"]
 	dropped_tasks = {}
 	frozen_config = _frozen_depgraph_config(settings, trees,
-		myopts, spinner)
+		myopts, myparams, spinner)
 	while True:
 		mydepgraph = depgraph(settings, trees,
 			myopts, myparams, spinner, frozen_config=frozen_config)

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index 9ee1d5e..3476aba 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -662,7 +662,8 @@ class ResolverPlaygroundTestCase(object):
 									str((node1, node2))) + \
 									", got: " + str(got))
 
-			elif key in ("unstable_keywords", "needed_p_mask_changes") and expected is not None:
+			elif key in ("unstable_keywords", "needed_p_mask_changes",
+				"unsatisfied_deps") and expected is not None:
 				expected = set(expected)
 
 			if got != expected:
@@ -678,9 +679,10 @@ class ResolverPlaygroundResult(object):
 
 	checks = (
 		"success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
-		"circular_dependency_solutions", "needed_p_mask_changes",
+		"circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps",
 		)
 	optional_checks = (
+		"unsatisfied_deps"
 		)
 
 	def __init__(self, atoms, success, mydepgraph, favorites):
@@ -695,6 +697,7 @@ class ResolverPlaygroundResult(object):
 		self.needed_p_mask_changes = None
 		self.slot_collision_solutions = None
 		self.circular_dependency_solutions = None
+		self.unsatisfied_deps = frozenset()
 
 		if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
 			self.mergelist = []
@@ -754,6 +757,10 @@ class ResolverPlaygroundResult(object):
 			sol = handler.solutions
 			self.circular_dependency_solutions = dict(zip([x.cpv for x in sol.keys()], sol.values()))
 
+		if self.depgraph._dynamic_config._unsatisfied_deps_for_display:
+			self.unsatisfied_deps = set(dep_info[0][1]
+				for dep_info in self.depgraph._dynamic_config._unsatisfied_deps_for_display)
+
 class ResolverPlaygroundDepcleanResult(object):
 
 	checks = (

diff --git a/pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py b/pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py
new file mode 100644
index 0000000..13f7e67
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py
@@ -0,0 +1,115 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class SlotConflictUnsatisfiedDeepDepsTestCase(TestCase):
+
+	def testSlotConflictUnsatisfiedDeepDeps(self):
+
+		ebuilds = {
+			"dev-libs/A-1": { },
+			"dev-libs/A-2": { "KEYWORDS": "~x86" },
+			"dev-libs/B-1": { "DEPEND": "dev-libs/A" },
+			"dev-libs/C-1": { "DEPEND": ">=dev-libs/A-2" },
+			"dev-libs/D-1": { "DEPEND": "dev-libs/A" },
+		}
+
+		installed = {
+			"dev-libs/broken-1": {
+				"RDEPEND": "dev-libs/A dev-libs/initially-unsatisfied"
+			},
+		}
+
+		world = (
+			"dev-libs/A",
+			"dev-libs/B",
+			"dev-libs/C",
+			"dev-libs/D",
+			"dev-libs/broken"
+		)
+
+		test_cases = (
+			# Test bug #520950, where unsatisfied deps of installed
+			# packages are supposed to be ignored when they are beyond
+			# the depth requested by the user.
+			ResolverPlaygroundTestCase(
+				["dev-libs/B", "dev-libs/C", "dev-libs/D"],
+				all_permutations=True,
+				options={
+					"--autounmask": "y",
+					"--complete-graph": True
+				},
+				mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+				ignore_mergelist_order=True,
+				unstable_keywords=["dev-libs/A-2"],
+				unsatisfied_deps=[],
+				success=False),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options={
+					"--autounmask": "y",
+					"--complete-graph": True
+				},
+				mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+				ignore_mergelist_order=True,
+				unstable_keywords=["dev-libs/A-2"],
+				unsatisfied_deps=["dev-libs/broken"],
+				success=False),
+
+			# Test --selective with --deep = 0
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options={
+					"--autounmask": "y",
+					"--complete-graph": True,
+					"--selective": True,
+					"--deep": 0
+				},
+				mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+				ignore_mergelist_order=True,
+				unstable_keywords=["dev-libs/A-2"],
+				unsatisfied_deps=[],
+				success=False),
+
+			# Test --deep = 1
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options={
+					"--autounmask": "y",
+					"--complete-graph": True,
+					"--selective": True,
+					"--deep": 1
+				},
+				mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+				ignore_mergelist_order=True,
+				unstable_keywords=["dev-libs/A-2"],
+				unsatisfied_deps=["dev-libs/initially-unsatisfied"],
+				success=False),
+
+			# Test --deep = True
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options={
+					"--autounmask": "y",
+					"--complete-graph": True,
+					"--selective": True,
+					"--deep": True
+				},
+				mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+				ignore_mergelist_order=True,
+				unstable_keywords=["dev-libs/A-2"],
+				unsatisfied_deps=["dev-libs/initially-unsatisfied"],
+				success=False),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed,
+			world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-04-26 19:44 Sebastian Luther
  0 siblings, 0 replies; 56+ messages in thread
From: Sebastian Luther @ 2014-04-26 19:44 UTC (permalink / raw
  To: gentoo-commits

commit:     de71f70eac5f8f82d739c2d6e5da8e7680e89efe
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Sat Apr 26 19:21:04 2014 +0000
Commit:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de >
CommitDate: Sat Apr 26 19:43:56 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=de71f70e

Prevent rebuild code from performing unwanted repo changes

---
 pym/_emerge/depgraph.py                            |  2 ++
 .../tests/resolver/test_slot_conflict_rebuild.py   | 41 ++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 737ed66..28d4026 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1631,6 +1631,8 @@ class depgraph(object):
 							# different slot_operator is an older version
 							if not want_downgrade:
 								continue
+						if pkg.version == dep.child.version and not dep.child.built:
+							continue
 
 					insignificant = False
 					if not slot_conflict and \

diff --git a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
index 17737cf..b39eaf0 100644
--- a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
+++ b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
@@ -406,3 +406,44 @@ class SlotConflictRebuildTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+	def testSlotConflictMultiRepoUpdates(self):
+		"""
+		Bug 508236 (similar to testSlotConflictMultiRepo)
+		Different repositories contain the same cpv with different sub-slots for
+		a slot operator child. For both the installed version and an updated version.
+
+		"""
+		ebuilds = {
+			"net-firewall/iptables-1.4.21::overlay" : { "EAPI": "5", "SLOT": "0/10" },
+			"net-firewall/iptables-1.4.21-r1::overlay" : { "EAPI": "5", "SLOT": "0/10" },
+			"sys-apps/iproute2-3.11.0::overlay" : { "EAPI": "5", "RDEPEND": "net-firewall/iptables:=" },
+
+			"net-firewall/iptables-1.4.21" : { "EAPI": "5", "SLOT": "0" },
+			"net-firewall/iptables-1.4.21-r1" : { "EAPI": "5", "SLOT": "0" },
+			"sys-apps/iproute2-3.12.0": { "EAPI": "5", "RDEPEND": "net-firewall/iptables:=" },
+		}
+
+		installed = {
+			"net-firewall/iptables-1.4.21::overlay" : { "EAPI": "5", "SLOT": "0/10" },
+			"sys-apps/iproute2-3.12.0": { "EAPI": "5", "RDEPEND": "net-firewall/iptables:0/10=" },
+		}
+
+		world = ["sys-apps/iproute2"]
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--deep": True, "--update": True, "--verbose": True},
+				success = True,
+				mergelist = ["net-firewall/iptables-1.4.21-r1::overlay"]),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-02-16 17:25 Sebastian Luther
  0 siblings, 0 replies; 56+ messages in thread
From: Sebastian Luther @ 2014-02-16 17:25 UTC (permalink / raw
  To: gentoo-commits

commit:     292633baa2cc5091b1cc4b8d8a89f5c2fe28ca9e
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Sun Feb 16 16:14:14 2014 +0000
Commit:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de >
CommitDate: Sun Feb 16 16:14:14 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=292633ba

Fix crash in depgraph._remove_pkg

Make sure we don't try to remove a packages twice. This happened in the
past when a package was its own digraph-child.

One way to trigger this is a DEPEND on itself as in the test case.

This bug was reported by slyfox on IRC. In his case the cause for the
self-edge is unknown. Unfortunately the system state is lost.

---
 pym/_emerge/depgraph.py                            |  9 ++++++-
 pym/portage/tests/resolver/test_slot_collisions.py | 31 ++++++++++++++++++++++
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 2ed7aeb..9698607 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -2388,8 +2388,15 @@ class depgraph(object):
 		Remove a package and all its then parentless digraph
 		children from all depgraph datastructures.
 		"""
+		debug = "--debug" in self._frozen_config.myopts
+		if debug:
+			writemsg_level(
+				"Removing package: %s\n" % pkg,
+				level=logging.DEBUG, noiselevel=-1)
+
 		try:
-			children = self._dynamic_config.digraph.child_nodes(pkg)
+			children = [child for child in self._dynamic_config.digraph.child_nodes(pkg) \
+				if child is not pkg]
 			self._dynamic_config.digraph.remove(pkg)
 		except KeyError:
 			children = []

diff --git a/pym/portage/tests/resolver/test_slot_collisions.py b/pym/portage/tests/resolver/test_slot_collisions.py
index fdd6dd6..85afc09 100644
--- a/pym/portage/tests/resolver/test_slot_collisions.py
+++ b/pym/portage/tests/resolver/test_slot_collisions.py
@@ -226,3 +226,34 @@ class SlotCollisionTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+
+	def testSelfDEPENDRemovalCrash(self):
+		"""
+		Make sure we don't try to remove a packages twice. This happened
+		in the past when a package had a DEPEND on itself.
+		"""
+		ebuilds = {
+			"dev-libs/A-1": { "RDEPEND": "=dev-libs/X-1" },
+			"dev-libs/B-1": { "RDEPEND": "dev-libs/X" },
+
+			"dev-libs/X-1": { },
+			"dev-libs/X-2": { "DEPEND": ">=dev-libs/X-2" },
+			}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["dev-libs/A", "dev-libs/B"],
+				all_permutations = True,
+				success = True,
+				ignore_mergelist_order = True,
+				mergelist = ["dev-libs/X-1", "dev-libs/A-1", "dev-libs/B-1"]),
+			)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-02-15 12:40 Sebastian Luther
  0 siblings, 0 replies; 56+ messages in thread
From: Sebastian Luther @ 2014-02-15 12:40 UTC (permalink / raw
  To: gentoo-commits

commit:     9a21e1f08be692598a203de88f3bcef23e0dcc7a
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Sat Feb 15 12:37:05 2014 +0000
Commit:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de >
CommitDate: Sat Feb 15 12:37:05 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=9a21e1f0

Only use Atoms with package_tracker.match (bug 501360)

---
 pym/_emerge/depgraph.py                     |  2 +-
 pym/portage/tests/resolver/test_onlydeps.py | 34 +++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index ae6b883..2ed7aeb 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5817,7 +5817,7 @@ class depgraph(object):
 		if pkg is None and onlydeps and not installed:
 			# Maybe it already got pulled in as a "merge" node.
 			for candidate in self._dynamic_config._package_tracker.match(
-				root_config.root, cpv):
+				root_config.root, Atom("="+cpv)):
 				if candidate.type_name == type_name and \
 					candidate.repo_name == myrepo and \
 					candidate.root_config is root_config and \

diff --git a/pym/portage/tests/resolver/test_onlydeps.py b/pym/portage/tests/resolver/test_onlydeps.py
new file mode 100644
index 0000000..986769a
--- /dev/null
+++ b/pym/portage/tests/resolver/test_onlydeps.py
@@ -0,0 +1,34 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class OnlydepsTestCase(TestCase):
+
+	def testOnlydeps(self):
+		ebuilds = {
+			"dev-libs/A-1": { "DEPEND": "dev-libs/B" },
+			"dev-libs/B-1": { },
+			}
+		installed = {
+			"dev-libs/B-1": { },
+		}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["dev-libs/A", "dev-libs/B"],
+				all_permutations = True,
+				success = True,
+				options = { "--onlydeps": True },
+				mergelist = ["dev-libs/B-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.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-02-05 19:42 Sebastian Luther
  0 siblings, 0 replies; 56+ messages in thread
From: Sebastian Luther @ 2014-02-05 19:42 UTC (permalink / raw
  To: gentoo-commits

commit:     a862cc5dd1a56114fa579c5fb01b518b243666d9
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Tue Jan 28 21:32:25 2014 +0000
Commit:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de >
CommitDate: Wed Feb  5 19:39:21 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=a862cc5d

Solve some slot conflicts without backtracking

---
 pym/_emerge/depgraph.py                            | 345 ++++++++++++++++++++-
 pym/portage/tests/resolver/test_backtracking.py    |  13 +-
 pym/portage/tests/resolver/test_blocker.py         |  48 +++
 pym/portage/tests/resolver/test_slot_collisions.py |  75 ++++-
 4 files changed, 457 insertions(+), 24 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 1bb086b..ae6b883 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3,6 +3,7 @@
 
 from __future__ import print_function, unicode_literals
 
+import collections
 import errno
 import io
 import logging
@@ -78,7 +79,7 @@ from _emerge.resolver.backtracking import Backtracker, BacktrackParameter
 from _emerge.resolver.package_tracker import PackageTracker, PackageTrackerDbapiWrapper
 from _emerge.resolver.slot_collision import slot_conflict_handler
 from _emerge.resolver.circular_dependency import circular_dependency_handler
-from _emerge.resolver.output import Display
+from _emerge.resolver.output import Display, format_unmatched_atom
 
 if sys.hexversion >= 0x3000000:
 	basestring = str
@@ -423,6 +424,8 @@ class _dynamic_depgraph_config(object):
 		self._complete_mode = False
 		self._slot_operator_deps = {}
 		self._package_tracker = PackageTracker()
+		# Track missed updates caused by solved conflicts.
+		self._conflict_missed_update = collections.defaultdict(dict)
 
 		for myroot in depgraph._frozen_config.trees:
 			self.sets[myroot] = _depgraph_sets()
@@ -769,7 +772,8 @@ class depgraph(object):
 		# missed update from each SLOT.
 		missed_updates = {}
 		for pkg, mask_reasons in \
-			self._dynamic_config._runtime_pkg_mask.items():
+			chain(self._dynamic_config._runtime_pkg_mask.items(),
+				self._dynamic_config._conflict_missed_update.items()):
 			if pkg.installed:
 				# Exclude installed here since we only
 				# want to show available updates.
@@ -779,7 +783,8 @@ class depgraph(object):
 			for chosen_pkg in self._dynamic_config._package_tracker.match(
 				pkg.root, pkg.slot_atom):
 				any_selected = True
-				if chosen_pkg >= pkg:
+				if chosen_pkg > pkg or (not chosen_pkg.installed and \
+					chosen_pkg.version == pkg.version):
 					missed_update = False
 					break
 			if any_selected and missed_update:
@@ -869,7 +874,7 @@ class depgraph(object):
 
 		self._show_merge_list()
 		msg = []
-		msg.append("\nWARNING: One or more updates have been " + \
+		msg.append("\nWARNING: One or more updates/rebuilds have been " + \
 			"skipped due to a dependency conflict:\n\n")
 
 		indent = "  "
@@ -879,22 +884,29 @@ class depgraph(object):
 				msg.append(" for %s" % (pkg.root,))
 			msg.append("\n\n")
 
-			for parent, atom in parent_atoms:
-				msg.append(indent)
-				msg.append(str(pkg))
+			msg.append(indent)
+			msg.append(str(pkg))
+			msg.append(" conflicts with\n")
 
-				msg.append(" conflicts with\n")
-				msg.append(2*indent)
+			for parent, atom in parent_atoms:
 				if isinstance(parent,
 					(PackageArg, AtomArg)):
 					# For PackageArg and AtomArg types, it's
 					# redundant to display the atom attribute.
+					msg.append(2*indent)
 					msg.append(str(parent))
+					msg.append("\n")
 				else:
 					# Display the specific atom from SetArg or
 					# Package types.
-					msg.append("%s required by %s" % (atom, parent))
-				msg.append("\n")
+					atom, marker = format_unmatched_atom(
+						pkg, atom, self._pkg_use_enabled)
+
+					msg.append(2*indent)
+					msg.append("%s required by %s\n" % (atom, parent))
+					msg.append(2*indent)
+					msg.append(marker)
+					msg.append("\n")
 			msg.append("\n")
 
 		writemsg("".join(msg), noiselevel=-1)
@@ -956,6 +968,239 @@ class depgraph(object):
 			writemsg(line + '\n', noiselevel=-1)
 		writemsg('\n', noiselevel=-1)
 
+	def _solve_non_slot_operator_slot_conflicts(self):
+		"""
+		This function solves slot conflicts which can
+		be solved by simply choosing one of the conflicting
+		and removing all the other ones.
+		It is able to solve somewhat more complex cases where
+		conflicts can only be solved simultaniously.
+		"""
+		debug = "--debug" in self._frozen_config.myopts
+
+		# List all conflicts. Ignore those that involve slot operator rebuilds
+		# as the logic there needs special slot conflict behavior which isn't
+		# provided by this function.
+		conflicts = []
+		for conflict in self._dynamic_config._package_tracker.slot_conflicts():
+			slot_key = conflict.root, conflict.atom
+			if slot_key not in self._dynamic_config._slot_operator_replace_installed:
+				conflicts.append(conflict)
+
+		if not conflicts:
+			return
+
+		# Get a set of all conflicting packages.
+		conflict_pkgs = set()
+		for conflict in conflicts:
+			conflict_pkgs.update(conflict)
+
+		# Get the list of other packages which are only
+		# required by conflict packages.
+		indirect_conflict_candidates = set()
+		for pkg in conflict_pkgs:
+			indirect_conflict_candidates.update(self._dynamic_config.digraph.child_nodes(pkg))
+		indirect_conflict_candidates.difference_update(conflict_pkgs)
+
+		indirect_conflict_pkgs = set()
+		while indirect_conflict_candidates:
+			pkg = indirect_conflict_candidates.pop()
+
+			only_conflict_parents = True
+			for parent, atom in self._dynamic_config._parent_atoms.get(pkg, []):
+				if parent not in conflict_pkgs and parent not in indirect_conflict_pkgs:
+					only_conflict_parents = False
+					break
+			if not only_conflict_parents:
+				continue
+
+			indirect_conflict_pkgs.add(pkg)
+			for child in self._dynamic_config.digraph.child_nodes(pkg):
+				if child in conflict_pkgs or child in indirect_conflict_pkgs:
+					continue
+				indirect_conflict_candidates.add(child)
+
+		# Create a graph containing the conflict packages
+		# and a special 'non_conflict_node' that represents
+		# all non-conflict packages.
+		conflict_graph = digraph()
+
+		non_conflict_node = "(non-conflict package)"
+		conflict_graph.add(non_conflict_node, None)
+
+		for pkg in chain(conflict_pkgs, indirect_conflict_pkgs):
+			conflict_graph.add(pkg, None)
+
+		# Add parent->child edges for each conflict package.
+		# Parents, which aren't conflict packages are represented
+		# by 'non_conflict_node'.
+		# If several conflicting packages are matched, but not all,
+		# add a tuple with the matched packages to the graph.
+		class or_tuple(tuple):
+			"""
+			Helper class for debug printing.
+			"""
+			def __str__(self):
+				return "(%s)" % ",".join(str(pkg) for pkg in self)
+
+		for conflict in conflicts:
+			all_parent_atoms = set()
+			for pkg in conflict:
+				all_parent_atoms.update(
+					self._dynamic_config._parent_atoms.get(pkg, []))
+
+			for parent, atom in all_parent_atoms:
+				is_arg_parent = isinstance(parent, AtomArg)
+
+				if parent not in conflict_pkgs and \
+					parent not in indirect_conflict_pkgs:
+					parent = non_conflict_node
+
+				atom_set = InternalPackageSet(
+					initial_atoms=(atom,), allow_repo=True)
+
+				matched = []
+				for pkg in conflict:
+					if atom_set.findAtomForPackage(pkg, \
+						modified_use=self._pkg_use_enabled(pkg)) and \
+						not (is_arg_parent and pkg.installed):
+						matched.append(pkg)
+				if len(matched) == len(conflict):
+					# All packages match.
+					continue
+				elif len(matched) == 1:
+					conflict_graph.add(matched[0], parent)
+				else:
+					# More than one packages matched, but not all.
+					conflict_graph.add(or_tuple(matched), parent)
+
+		for pkg in indirect_conflict_pkgs:
+			for parent, atom in self._dynamic_config._parent_atoms.get(pkg, []):
+				if parent not in conflict_pkgs and \
+					parent not in indirect_conflict_pkgs:
+					parent = non_conflict_node
+				conflict_graph.add(pkg, parent)
+
+		if debug:
+			writemsg_level(
+				"\n!!! Slot conflict graph:\n",
+				level=logging.DEBUG, noiselevel=-1)
+			conflict_graph.debug_print()
+
+		# Now select required packages. Collect them in the
+		# 'forced' set.
+		forced = set([non_conflict_node])
+		unexplored = set([non_conflict_node])
+		# or_tuples get special handling. We first explore
+		# all packages in the hope of having forced one of
+		# the packages in the tuple. This way we don't have
+		# to choose one.
+		unexplored_tuples = set()
+
+		while unexplored:
+			# Handle all unexplored packages.
+			while unexplored:
+				node = unexplored.pop()
+				for child in conflict_graph.child_nodes(node):
+					if child in forced:
+						continue
+					forced.add(child)
+					if isinstance(child, Package):
+						unexplored.add(child)
+					else:
+						unexplored_tuples.add(child)
+
+			# Now handle unexplored or_tuples. Move on with packages
+			# once we had to choose one.
+			while unexplored_tuples:
+				nodes = unexplored_tuples.pop()
+				if any(node in forced for node in nodes):
+					# At least one of the packages in the
+					# tuple is already forced, which means the
+					# dependency represented by this tuple
+					# is satisfied.
+					continue
+
+				# We now have to choose one of packages in the tuple.
+				# In theory one could solve more conflicts if we'd be
+				# able to try different choices here, but that has lots
+				# of other problems. For now choose the package that was
+				# pulled first, as this should be the most desirable choice
+				# (otherwise it wouldn't have been the first one).
+				forced.add(nodes[0])
+				unexplored.add(nodes[0])
+				break
+
+		# Remove 'non_conflict_node' and or_tuples from 'forced'.
+		forced = set(pkg for pkg in forced if isinstance(pkg, Package))
+		non_forced = set(pkg for pkg in conflict_pkgs if pkg not in forced)
+
+		if debug:
+			writemsg_level(
+				"\n!!! Slot conflict solution:\n",
+				level=logging.DEBUG, noiselevel=-1)
+			for conflict in conflicts:
+				writemsg_level(
+					"   Conflict: (%s, %s)\n" % (conflict.root, conflict.atom),
+					level=logging.DEBUG, noiselevel=-1)
+				for pkg in conflict:
+					if pkg in forced:
+						writemsg_level(
+							"      keep:   %s\n" % pkg,
+							level=logging.DEBUG, noiselevel=-1)
+					else:
+						writemsg_level(
+							"      remove: %s\n" % pkg,
+							level=logging.DEBUG, noiselevel=-1)
+
+		broken_packages = set()
+		for pkg in non_forced:
+			for parent, atom in self._dynamic_config._parent_atoms.get(pkg, []):
+				if isinstance(parent, Package) and parent not in non_forced:
+					# Non-forcing set args are expected to be a parent of all
+					# packages in the conflict.
+					broken_packages.add(parent)
+			self._remove_pkg(pkg)
+
+		# Process the dependencies of choosen conflict packages
+		# again to  properly account for blockers.
+		broken_packages.update(forced)
+
+		# Filter out broken packages which have been removed during
+		# recursive removal in self._remove_pkg.
+		broken_packages = list(pkg for pkg in broken_packages if pkg in broken_packages \
+			if self._dynamic_config._package_tracker.contains(pkg, installed=False))
+
+		self._dynamic_config._dep_stack.extend(broken_packages)
+
+		if broken_packages:
+			# Process dependencies. This cannot fail because we just ensured that
+			# the remaining packages satisfy all dependencies.
+			self._create_graph()
+
+		# Record missed updates.
+		for conflict in conflicts:
+			if not any(pkg in non_forced for pkg in conflict):
+				continue
+			for pkg in conflict:
+				if pkg not in non_forced:
+					continue
+
+				for other in conflict:
+					if other is pkg:
+						continue
+
+					for parent, atom in self._dynamic_config._parent_atoms.get(other, []):
+						atom_set = InternalPackageSet(
+							initial_atoms=(atom,), allow_repo=True)
+						if not atom_set.findAtomForPackage(pkg,
+							modified_use=self._pkg_use_enabled(pkg)):
+							self._dynamic_config._conflict_missed_update[pkg].setdefault(
+								"slot conflict", set())
+							self._dynamic_config._conflict_missed_update[pkg]["slot conflict"].add(
+								(parent, atom))
+
+
 	def _process_slot_conflicts(self):
 		"""
 		If there are any slot conflicts and backtracking is enabled,
@@ -963,6 +1208,9 @@ class depgraph(object):
 		is called, so that all relevant reverse dependencies are
 		available for use in backtracking decisions.
 		"""
+
+		self._solve_non_slot_operator_slot_conflicts()
+
 		for conflict in self._dynamic_config._package_tracker.slot_conflicts():
 			self._process_slot_conflict(conflict)
 
@@ -1286,9 +1534,29 @@ class depgraph(object):
 		selective = "selective" in self._dynamic_config.myparams
 		want_downgrade = None
 
+		def check_reverse_dependencies(existing_pkg, candidate_pkg):
+			"""
+			Check if candidate_pkg satisfies all of existing_pkg's non-
+			slot operator parents.
+			"""
+			for parent, atom in self._dynamic_config._parent_atoms.get(existing_pkg, []):
+				if atom.slot_operator == "=" and parent.built:
+					continue
+
+				atom_set = InternalPackageSet(initial_atoms=(atom,),
+					allow_repo=True)
+				if not atom_set.findAtomForPackage(candidate_pkg,
+					modified_use=self._pkg_use_enabled(candidate_pkg)):
+					return False
+			return True
+
+
 		for replacement_parent in self._iter_similar_available(dep.parent,
 			dep.parent.slot_atom, autounmask_level=autounmask_level):
 
+			if not check_reverse_dependencies(dep.parent, replacement_parent):
+				continue
+
 			selected_atoms = None
 
 			atoms = set()
@@ -1389,10 +1657,11 @@ class depgraph(object):
 						if unevaluated_atom not in selected_atoms:
 							continue
 
-					if not insignificant:
+					if not insignificant and \
+						check_reverse_dependencies(dep.child, pkg):
+
 						candidate_pkg_atoms.append((pkg, unevaluated_atom))
 						candidate_pkgs.append(pkg)
-
 				replacement_candidates.append(candidate_pkg_atoms)
 				if all_candidate_pkgs is None:
 					all_candidate_pkgs = set(candidate_pkgs)
@@ -2113,6 +2382,56 @@ class depgraph(object):
 			dep_stack.append(pkg)
 		return 1
 
+
+	def _remove_pkg(self, pkg):
+		"""
+		Remove a package and all its then parentless digraph
+		children from all depgraph datastructures.
+		"""
+		try:
+			children = self._dynamic_config.digraph.child_nodes(pkg)
+			self._dynamic_config.digraph.remove(pkg)
+		except KeyError:
+			children = []
+
+		self._dynamic_config._package_tracker.discard_pkg(pkg)
+
+		self._dynamic_config._parent_atoms.pop(pkg, None)
+		self._dynamic_config._set_nodes.discard(pkg)
+
+		for child in children:
+			try:
+				self._dynamic_config._parent_atoms[child] = set((parent, atom) \
+					for (parent, atom) in self._dynamic_config._parent_atoms[child] \
+					if parent is not pkg)
+			except KeyError:
+				pass
+
+		# Remove slot operator dependencies.
+		slot_key = (pkg.root, pkg.slot_atom)
+		if slot_key in self._dynamic_config._slot_operator_deps:
+			self._dynamic_config._slot_operator_deps[slot_key] = \
+				[dep for dep in self._dynamic_config._slot_operator_deps[slot_key] \
+				if dep.child is not pkg]
+			if not self._dynamic_config._slot_operator_deps[slot_key]:
+				del self._dynamic_config._slot_operator_deps[slot_key]
+
+		# Remove blockers.
+		self._dynamic_config._blocker_parents.discard(pkg)
+		self._dynamic_config._irrelevant_blockers.discard(pkg)
+		self._dynamic_config._unsolvable_blockers.discard(pkg)
+		self._dynamic_config._blocked_pkgs.discard(pkg)
+		self._dynamic_config._blocked_world_pkgs.pop(pkg, None)
+
+		for child in children:
+			if not self._dynamic_config.digraph.parent_nodes(child):
+				self._remove_pkg(child)
+
+		# Clear caches.
+		self._dynamic_config._filtered_trees[pkg.root]["porttree"].dbapi._clear_cache()
+		self._dynamic_config._highest_pkg_cache.clear()
+
+
 	def _check_masks(self, pkg):
 
 		slot_key = (pkg.root, pkg.slot_atom)

diff --git a/pym/portage/tests/resolver/test_backtracking.py b/pym/portage/tests/resolver/test_backtracking.py
index 9dc37ac..3b69eda 100644
--- a/pym/portage/tests/resolver/test_backtracking.py
+++ b/pym/portage/tests/resolver/test_backtracking.py
@@ -1,4 +1,4 @@
-# Copyright 2010 Gentoo Foundation
+# Copyright 2010-2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -31,7 +31,7 @@ class BacktrackingTestCase(TestCase):
 			playground.cleanup()
 
 
-	def testHittingTheBacktrackLimit(self):
+	def testBacktrackNotNeeded(self):
 		ebuilds = {
 			"dev-libs/A-1": {},
 			"dev-libs/A-2": {},
@@ -45,17 +45,10 @@ class BacktrackingTestCase(TestCase):
 				ResolverPlaygroundTestCase(
 					["dev-libs/C", "dev-libs/D"],
 					all_permutations = True,
+					options = { "--backtrack": 1 },
 					mergelist = ["dev-libs/A-1", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
 					ignore_mergelist_order = True,
 					success = True),
-				#This one hits the backtrack limit. Be aware that this depends on the argument order.
-				ResolverPlaygroundTestCase(
-					["dev-libs/D", "dev-libs/C"],
-					options = { "--backtrack": 1 },
-					mergelist = ["dev-libs/A-1", "dev-libs/B-1", "dev-libs/A-2", "dev-libs/B-2", "dev-libs/C-1", "dev-libs/D-1"],
-					ignore_mergelist_order = True,
-					slot_collision_solutions = [],
-					success = False),
 			)
 
 		playground = ResolverPlayground(ebuilds=ebuilds)

diff --git a/pym/portage/tests/resolver/test_blocker.py b/pym/portage/tests/resolver/test_blocker.py
new file mode 100644
index 0000000..94a88b8
--- /dev/null
+++ b/pym/portage/tests/resolver/test_blocker.py
@@ -0,0 +1,48 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class SlotConflictWithBlockerTestCase(TestCase):
+
+	def testBlocker(self):
+		ebuilds = {
+			"dev-libs/A-1": { "DEPEND": "dev-libs/X" },
+			"dev-libs/B-1": { "DEPEND": "<dev-libs/X-2" },
+			"dev-libs/C-1": { "DEPEND": "<dev-libs/X-3" },
+
+			"dev-libs/X-1": { "EAPI": "2", "RDEPEND": "!=dev-libs/Y-1" },
+			"dev-libs/X-2": { "EAPI": "2", "RDEPEND": "!=dev-libs/Y-2" },
+			"dev-libs/X-3": { "EAPI": "2", "RDEPEND": "!=dev-libs/Y-3" },
+
+			"dev-libs/Y-1": { "SLOT": "1" },
+			"dev-libs/Y-2": { "SLOT": "2" },
+			"dev-libs/Y-3": { "SLOT": "3" },
+			}
+
+		installed = {
+			"dev-libs/Y-1": { "SLOT": "1" },
+			"dev-libs/Y-2": { "SLOT": "2" },
+			"dev-libs/Y-3": { "SLOT": "3" },
+			}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["dev-libs/A", "dev-libs/B", "dev-libs/C"],
+				options = { "--backtrack": 0 },
+				all_permutations = True,
+				success = True,
+				ambiguous_merge_order = True,
+				mergelist = ["dev-libs/X-1", "[uninstall]dev-libs/Y-1", "!=dev-libs/Y-1", \
+					("dev-libs/A-1", "dev-libs/B-1", "dev-libs/C-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.cleanup()

diff --git a/pym/portage/tests/resolver/test_slot_collisions.py b/pym/portage/tests/resolver/test_slot_collisions.py
index 95d68fe..fdd6dd6 100644
--- a/pym/portage/tests/resolver/test_slot_collisions.py
+++ b/pym/portage/tests/resolver/test_slot_collisions.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2011 Gentoo Foundation
+# Copyright 2010-2011,2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -153,3 +153,76 @@ class SlotCollisionTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+	def testConnectedCollision(self):
+		"""
+		Ensure that we are able to solve connected slot conflicts
+		which cannot be solved each on their own.
+		"""
+		ebuilds = {
+			"dev-libs/A-1": { "RDEPEND": "=dev-libs/X-1" },
+			"dev-libs/B-1": { "RDEPEND": "dev-libs/X" },
+
+			"dev-libs/X-1": { "RDEPEND": "=dev-libs/Y-1" },
+			"dev-libs/X-2": { "RDEPEND": "=dev-libs/Y-2" },
+
+			"dev-libs/Y-1": { "PDEPEND": "=dev-libs/X-1" },
+			"dev-libs/Y-2": { "PDEPEND": "=dev-libs/X-2" },
+			}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["dev-libs/A", "dev-libs/B"],
+				all_permutations = True,
+				options = { "--backtrack": 0 },
+				success = True,
+				ambiguous_merge_order = True,
+				mergelist = ["dev-libs/Y-1", "dev-libs/X-1", ("dev-libs/A-1", "dev-libs/B-1")]),
+			)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()
+
+
+	def testDeeplyConnectedCollision(self):
+		"""
+		Like testConnectedCollision, except that there is another
+		level of dependencies between the two conflicts.
+		"""
+		ebuilds = {
+			"dev-libs/A-1": { "RDEPEND": "=dev-libs/X-1" },
+			"dev-libs/B-1": { "RDEPEND": "dev-libs/X" },
+
+			"dev-libs/X-1": { "RDEPEND": "dev-libs/K" },
+			"dev-libs/X-2": { "RDEPEND": "dev-libs/L" },
+
+			"dev-libs/K-1": { "RDEPEND": "=dev-libs/Y-1" },
+			"dev-libs/L-1": { "RDEPEND": "=dev-libs/Y-2" },
+
+			"dev-libs/Y-1": { "PDEPEND": "=dev-libs/X-1" },
+			"dev-libs/Y-2": { "PDEPEND": "=dev-libs/X-2" },
+			}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["dev-libs/A", "dev-libs/B"],
+				all_permutations = True,
+				options = { "--backtrack": 0 },
+				success = True,
+				ignore_mergelist_order = True,
+				mergelist = ["dev-libs/Y-1", "dev-libs/X-1", "dev-libs/K-1", \
+					"dev-libs/A-1", "dev-libs/B-1"]),
+			)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2014-01-07 22:22 Arfrever Frehtes Taifersar Arahesis
  0 siblings, 0 replies; 56+ messages in thread
From: Arfrever Frehtes Taifersar Arahesis @ 2014-01-07 22:22 UTC (permalink / raw
  To: gentoo-commits

commit:     ecf817d1b1913ddff65fb020c6bc5558d550d2bd
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Tue Jan  7 22:21:40 2014 +0000
Commit:     Arfrever Frehtes Taifersar Arahesis <Arfrever <AT> Apache <DOT> Org>
CommitDate: Tue Jan  7 22:21:40 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=ecf817d1

Bug #497238: Fix unnecessary rebuild caused by equal versions in different repositories.

---
 pym/_emerge/depgraph.py                            |  4 +-
 .../tests/resolver/test_slot_conflict_rebuild.py   | 44 +++++++++++++++++++++-
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 763f3fd..83035c2 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2013 Gentoo Foundation
+# Copyright 1999-2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import print_function, unicode_literals
@@ -1376,7 +1376,7 @@ class depgraph(object):
 						selective and \
 						dep.parent.installed and \
 						dep.child.installed and \
-						dep.parent.cpv == replacement_parent.cpv and \
+						dep.parent >= replacement_parent and \
 						dep.child.cpv == pkg.cpv:
 						# Then can happen if the child's sub-slot changed
 						# without a revision bump. The sub-slot change is

diff --git a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
index 5acdadb..17737cf 100644
--- a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
+++ b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2013 Gentoo Foundation
+# Copyright 2012-2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -364,3 +364,45 @@ class SlotConflictRebuildTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+
+	def testSlotConflictMultiRepo(self):
+		"""
+		Bug 497238
+		Different repositories contain the same cpv with different sub-slots for
+		a slot operator child.
+		Downgrading the slot operator parent would result in a sub-slot change of
+		the installed package by changing the source repository.
+		Make sure we don't perform this undesirable rebuild.
+		"""
+		ebuilds = {
+			"net-firewall/iptables-1.4.21::overlay" : { "EAPI": "5", "SLOT": "0/10" },
+			"sys-apps/iproute2-3.11.0::overlay" : { "EAPI": "5", "RDEPEND": "net-firewall/iptables:=" },
+
+			"net-firewall/iptables-1.4.21" : { "EAPI": "5", "SLOT": "0" },
+			"sys-apps/iproute2-3.12.0": { "EAPI": "5", "RDEPEND": "net-firewall/iptables:=" },
+		}
+
+		installed = {
+			"net-firewall/iptables-1.4.21::overlay" : { "EAPI": "5", "SLOT": "0/10" },
+			"sys-apps/iproute2-3.12.0": { "EAPI": "5", "RDEPEND": "net-firewall/iptables:0/10=" },
+		}
+
+		world = ["sys-apps/iproute2"]
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--deep": True, "--update": True, "--verbose": True},
+				success = True,
+				mergelist = []),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-12-05 15:38 Brian Dolbec
  0 siblings, 0 replies; 56+ messages in thread
From: Brian Dolbec @ 2013-12-05 15:38 UTC (permalink / raw
  To: gentoo-commits

commit:     dee9512d2ffec94b4a9eb4ece5c8345e86d04d32
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Mon Dec  2 12:52:36 2013 +0000
Commit:     Brian Dolbec <brian.dolbec <AT> gmail <DOT> com>
CommitDate: Thu Dec  5 15:14:27 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=dee9512d

Fix unnecessary rebuild (bug 487198)

This one was caused by a mix of >= and < dependencies.
Rename the test as requested by Sebastian to testSlotConflictMixedDependencies

---
 pym/_emerge/depgraph.py                            | 92 +++++++++++++++++-----
 .../tests/resolver/test_slot_conflict_rebuild.py   | 66 ++++++++++++++++
 2 files changed, 139 insertions(+), 19 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 6600bc2..763f3fd 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1298,7 +1298,34 @@ class depgraph(object):
 
 			selected_atoms = None
 
-			for atom in replacement_parent.validated_atoms:
+			atoms = set()
+			invalid_metadata = False
+			for dep_key in ("DEPEND", "HDEPEND", "RDEPEND", "PDEPEND"):
+				dep_string = replacement_parent._metadata[dep_key]
+				if not dep_string:
+					continue
+
+				try:
+					dep_string = portage.dep.use_reduce(dep_string,
+						uselist=self._pkg_use_enabled(replacement_parent),
+						is_valid_flag=replacement_parent.iuse.is_valid_flag,
+						flat=True, token_class=Atom,
+						eapi=replacement_parent.eapi)
+				except portage.exception.InvalidDependString:
+					invalid_metadata = True
+					break
+
+				atoms.update(token for token in dep_string if isinstance(token, Atom))
+
+			if invalid_metadata:
+				continue
+
+			# List of list of child,atom pairs for each atom.
+			replacement_candidates = []
+			# Set of all packages all atoms can agree on.
+			all_candidate_pkgs = None
+
+			for atom in atoms:
 				if atom.blocker or \
 					atom.cp != dep.atom.cp:
 					continue
@@ -1316,6 +1343,8 @@ class depgraph(object):
 					# parent and search for another.
 					break
 
+				candidate_pkg_atoms = []
+				candidate_pkgs = []
 				for pkg in self._iter_similar_available(
 					dep.child, atom):
 					if pkg.slot == dep.child.slot and \
@@ -1367,26 +1396,51 @@ class depgraph(object):
 						if unevaluated_atom not in selected_atoms:
 							continue
 
-					if debug:
-						msg = []
-						msg.append("")
-						msg.append("")
-						msg.append("slot_operator_update_probe:")
-						msg.append("   existing child package:  %s" % dep.child)
-						msg.append("   existing parent package: %s" % dep.parent)
-						msg.append("   new child package:  %s" % pkg)
-						msg.append("   new parent package: %s" % replacement_parent)
-						if insignificant:
-							msg.append("insignificant changes detected")
-						msg.append("")
-						writemsg_level("\n".join(msg),
-							noiselevel=-1, level=logging.DEBUG)
+					if not insignificant:
+						candidate_pkg_atoms.append((pkg, unevaluated_atom))
+						candidate_pkgs.append(pkg)
+
+				replacement_candidates.append(candidate_pkg_atoms)
+				if all_candidate_pkgs is None:
+					all_candidate_pkgs = set(candidate_pkgs)
+				else:
+					all_candidate_pkgs.intersection_update(candidate_pkgs)
+
+			if not all_candidate_pkgs:
+				# If the atoms that connect parent and child can't agree on
+				# any replacement child, we can't do anything.
+				continue
+
+			# Now select one of the pkgs as replacement. This is as easy as
+			# selecting the highest version.
+			# The more complicated part is to choose an atom for the
+			# new Dependency object. Choose the one which ranked the selected
+			# parent highest.
+			selected = None
+			for candidate_pkg_atoms in replacement_candidates:
+				for i, (pkg, atom) in enumerate(candidate_pkg_atoms):
+					if pkg not in all_candidate_pkgs:
+						continue
+					if selected is None or \
+						selected[0] < pkg or \
+						(selected[0] is pkg and i < selected[2]):
+						selected = (pkg, atom, i)
 
-					if insignificant:
-						return None
+			if debug:
+				msg = []
+				msg.append("")
+				msg.append("")
+				msg.append("slot_operator_update_probe:")
+				msg.append("   existing child package:  %s" % dep.child)
+				msg.append("   existing parent package: %s" % dep.parent)
+				msg.append("   new child package:  %s" % selected[0])
+				msg.append("   new parent package: %s" % replacement_parent)
+				msg.append("")
+				writemsg_level("\n".join(msg),
+					noiselevel=-1, level=logging.DEBUG)
 
-					return Dependency(parent=replacement_parent,
-						child=pkg, atom=unevaluated_atom)
+			return Dependency(parent=replacement_parent,
+				child=selected[0], atom=selected[1])
 
 		if debug:
 			msg = []

diff --git a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
index c7c62dd..1950550 100644
--- a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
+++ b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
@@ -298,3 +298,69 @@ class SlotConflictRebuildTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+
+	def testSlotConflictMixedDependencies(self):
+		"""
+		Bug 487198
+		For parents with mixed >= and < dependencies, we scheduled rebuilds for the
+		>= atom, but in the end didn't install the child update becaue of the < atom.
+		"""
+		ebuilds = {
+			"cat/slotted-lib-1" : {
+				"EAPI": "5",
+				"SLOT": "1"
+			},
+			"cat/slotted-lib-2" : {
+				"EAPI": "5",
+				"SLOT": "2"
+			},
+			"cat/slotted-lib-3" : {
+				"EAPI": "5",
+				"SLOT": "3"
+			},
+			"cat/slotted-lib-4" : {
+				"EAPI": "5",
+				"SLOT": "4"
+			},
+			"cat/slotted-lib-5" : {
+				"EAPI": "5",
+				"SLOT": "5"
+			},
+			"cat/user-1" : {
+				"EAPI": "5",
+				"DEPEND": ">=cat/slotted-lib-2:= <cat/slotted-lib-4:=",
+				"RDEPEND": ">=cat/slotted-lib-2:= <cat/slotted-lib-4:=",
+			},
+		}
+
+		installed = {
+			"cat/slotted-lib-3" : {
+				"EAPI": "5",
+				"SLOT": "3"
+			},
+			"cat/user-1" : {
+				"EAPI": "5",
+				"DEPEND": ">=cat/slotted-lib-2:3/3= <cat/slotted-lib-4:3/3=",
+				"RDEPEND": ">=cat/slotted-lib-2:3/3= <cat/slotted-lib-4:3/3=",
+			},
+		}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["cat/user"],
+				options = {"--deep": True, "--update": True},
+				success = True,
+				mergelist = []),
+		)
+
+		world = []
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-12-01 10:19 Brian Dolbec
  0 siblings, 0 replies; 56+ messages in thread
From: Brian Dolbec @ 2013-12-01 10:19 UTC (permalink / raw
  To: gentoo-commits

commit:     8a23eb70eb289fc84d77754447b5f9a84b94b4e1
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Thu Nov 28 10:34:09 2013 +0000
Commit:     Brian Dolbec <brian.dolbec <AT> gmail <DOT> com>
CommitDate: Sun Dec  1 09:41:25 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=8a23eb70

Another slot operator bug (bug 486580, try 2)

This time rebuilds are scheduled properly, but we
might still forget to install the package that caused
the rebuild.

URL: https://bugs.gentoo.org/486580

---
 pym/_emerge/depgraph.py                            | 48 +++++++++++------
 .../tests/resolver/test_slot_conflict_rebuild.py   | 63 ++++++++++++++++++++++
 2 files changed, 95 insertions(+), 16 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index b02d3473..622d288 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -2266,6 +2266,36 @@ class depgraph(object):
 		finally:
 			self._dynamic_config._autounmask = _autounmask_backup
 
+	def _ignore_dependency(self, atom, pkg, child, dep, mypriority, recurse_satisfied):
+		"""
+		In some cases, dep_check will return deps that shouldn't
+		be proccessed any further, so they are identified and
+		discarded here. Try to discard as few as possible since
+		discarded dependencies reduce the amount of information
+		available for optimization of merge order.
+		Don't ignore dependencies if pkg has a slot operator dependency on the child
+		and the child has changed slot/sub_slot.
+		"""
+		slot_operator_rebuild = False
+		if atom.slot_operator == '=' and \
+			(pkg.root, pkg.slot_atom) in self._dynamic_config._slot_operator_replace_installed and \
+			mypriority.satisfied and \
+			mypriority.satisfied is not child and \
+			mypriority.satisfied.installed and \
+			not child.installed and \
+			(child.slot != mypriority.satisfied.slot or child.sub_slot != mypriority.satisfied.sub_slot):
+			slot_operator_rebuild = True
+
+		return not atom.blocker and \
+			not recurse_satisfied and \
+			mypriority.satisfied and \
+			mypriority.satisfied.visible and \
+			dep.child is not None and \
+			not dep.child.installed and \
+			self._dynamic_config._slot_pkg_map[dep.child.root].get(
+			dep.child.slot_atom) is None and \
+			not slot_operator_rebuild
+
 	def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
 		dep_string, allow_unsatisfied):
 		depth = pkg.depth + 1
@@ -2355,14 +2385,7 @@ class depgraph(object):
 			# discarded dependencies reduce the amount of information
 			# available for optimization of merge order.
 			ignored = False
-			if not atom.blocker and \
-				not recurse_satisfied and \
-				mypriority.satisfied and \
-				mypriority.satisfied.visible and \
-				dep.child is not None and \
-				not dep.child.installed and \
-				self._dynamic_config._slot_pkg_map[dep.child.root].get(
-				dep.child.slot_atom) is None:
+			if self._ignore_dependency(atom, pkg, child, dep, mypriority, recurse_satisfied):
 				myarg = None
 				try:
 					myarg = next(self._iter_atoms_for_pkg(dep.child), None)
@@ -2465,14 +2488,7 @@ class depgraph(object):
 					collapsed_parent=pkg, collapsed_priority=dep_priority)
 
 				ignored = False
-				if not atom.blocker and \
-					not recurse_satisfied and \
-					mypriority.satisfied and \
-					mypriority.satisfied.visible and \
-					dep.child is not None and \
-					not dep.child.installed and \
-					self._dynamic_config._slot_pkg_map[dep.child.root].get(
-					dep.child.slot_atom) is None:
+				if self._ignore_dependency(atom, pkg, child, dep, mypriority, recurse_satisfied):
 					myarg = None
 					try:
 						myarg = next(self._iter_atoms_for_pkg(dep.child), None)

diff --git a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
index 74f5cc1..e3c517d 100644
--- a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
+++ b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
@@ -181,6 +181,69 @@ class SlotConflictRebuildTestCase(TestCase):
 		finally:
 			playground.cleanup()
 
+	def testSlotConflictForgottenChild(self):
+		"""
+		Similar to testSlotConflictMassRebuild above, but this time the rebuilds are scheduled,
+		but the package causing the rebuild (the child) is not installed.
+		"""
+		ebuilds = {
+
+			"app-misc/A-2" : {
+				"EAPI": "5",
+				"DEPEND": "app-misc/B:= app-misc/C",
+				"RDEPEND": "app-misc/B:= app-misc/C",
+			},
+
+			"app-misc/B-2" : {
+				"EAPI": "5",
+				"SLOT": "2"
+			},
+
+			"app-misc/C-1": {
+				"EAPI": "5",
+				"DEPEND": "app-misc/B:=",
+				"RDEPEND": "app-misc/B:="
+			},
+		}
+
+		installed = {
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"DEPEND": "app-misc/B:1/1= app-misc/C",
+				"RDEPEND": "app-misc/B:1/1= app-misc/C",
+			},
+
+			"app-misc/B-1" : {
+				"EAPI": "5",
+				"SLOT": "1"
+			},
+
+			"app-misc/C-1": {
+				"EAPI": "5",
+				"DEPEND": "app-misc/B:1/1=",
+				"RDEPEND": "app-misc/B:1/1="
+			},
+		}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["app-misc/A"],
+				success = True,
+				mergelist = ['app-misc/B-2', 'app-misc/C-1', 'app-misc/A-2']),
+		)
+
+		world = []
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()
+
+
 	def testSlotConflictDepChange(self):
 		"""
 		Bug 490362


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-11-27  7:44 Mike Frysinger
  0 siblings, 0 replies; 56+ messages in thread
From: Mike Frysinger @ 2013-11-27  7:44 UTC (permalink / raw
  To: gentoo-commits

commit:     c752202d57a1e3163aded69301e2d71d1ea26ae7
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Tue Nov 26 20:06:23 2013 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Wed Nov 27 07:44:29 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=c752202d

Fix a missing rebuild

The dependency in the ebuild was changed from
slot operator to no slot operator. The vdb
contained the slot operator and emerge would
refuse to rebuild, causing a missed update.

URL: https://bugs.gentoo.org/490362

---
 pym/_emerge/depgraph.py                            |  3 +-
 .../tests/resolver/test_slot_conflict_rebuild.py   | 55 ++++++++++++++++++++++
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 033057b..da2e604 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1301,8 +1301,7 @@ class depgraph(object):
 			selected_atoms = None
 
 			for atom in replacement_parent.validated_atoms:
-				if not atom.slot_operator == "=" or \
-					atom.blocker or \
+				if atom.blocker or \
 					atom.cp != dep.atom.cp:
 					continue
 

diff --git a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
index 96cc8f1..9fd9164 100644
--- a/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
+++ b/pym/portage/tests/resolver/test_slot_conflict_rebuild.py
@@ -180,3 +180,58 @@ class SlotConflictRebuildTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+	def testSlotConflictDepChange(self):
+		"""
+		Bug 490362
+		The dependency in the ebuild was changed form slot operator to
+		no slot operator. The vdb contained the slot operator and emerge
+		would refuse to rebuild.
+		"""
+		ebuilds = {
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"DEPEND": "app-misc/B",
+				"RDEPEND": "app-misc/B"
+			},
+
+			"app-misc/B-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1"
+			},
+
+			"app-misc/B-2" : {
+				"EAPI": "5",
+				"SLOT": "0/2"
+			},
+		}
+
+		installed = {
+			"app-misc/A-1" : {
+				"EAPI": "5",
+				"DEPEND": "app-misc/B:0/1=",
+				"RDEPEND": "app-misc/B:0/1="
+			},
+			"app-misc/B-1" : {
+				"EAPI": "5",
+				"SLOT": "0/1"
+			},
+		}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["app-misc/B"],
+				success = True,
+				mergelist = ['app-misc/B-2', 'app-misc/A-1']),
+		)
+
+		world = ["app-misc/A"]
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-08-02  8:26 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-08-02  8:26 UTC (permalink / raw
  To: gentoo-commits

commit:     9b6f69e2a66c0f1d1d6545208edb3c45eacfd845
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Aug  2 08:24:32 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Aug  2 08:24:32 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=9b6f69e2

Avoid some missed updates when backtracking.

This avoids unnecessarily missed updates like the following:

WARNING: One or more updates have been skipped due to a dependency conflict:

dev-util/boost-build:0

  (dev-util/boost-build-1.53.0::gentoo, ebuild scheduled for merge) conflicts with
    =dev-util/boost-build-1.52.0-r1 required by (dev-libs/boost-1.52.0-r6::gentoo, installed)

!!! The following update(s) have been skipped due to unsatisfied dependencies
!!! triggered by backtracking:

dev-libs/boost:0

---
 pym/_emerge/depgraph.py                            | 15 +---
 pym/portage/tests/resolver/test_backtracking.py    | 31 -------
 .../resolver/test_slot_conflict_mask_update.py     | 41 +++++++++
 .../tests/resolver/test_slot_conflict_update.py    | 98 ++++++++++++++++++++++
 4 files changed, 143 insertions(+), 42 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 76fda2c..39ae3ea 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -6,6 +6,7 @@ from __future__ import print_function, unicode_literals
 import errno
 import io
 import logging
+import operator
 import stat
 import sys
 import textwrap
@@ -983,17 +984,9 @@ class depgraph(object):
 			backtrack_data.append((to_be_masked, conflict_atoms))
 
 		if len(backtrack_data) > 1:
-			# NOTE: Generally, we prefer to mask the higher
-			# version since this solves common cases in which a
-			# lower version is needed so that all dependencies
-			# will be satisfied (bug #337178). However, if
-			# existing_node happens to be installed then we
-			# mask that since this is a common case that is
-			# triggered when --update is not enabled.
-			if existing_node.installed:
-				pass
-			elif any(pkg > existing_node for pkg in conflict_pkgs):
-				backtrack_data.reverse()
+			# In order to avoid a missed update, first mask lower
+			# versions that conflict with higher versions.
+			backtrack_data.sort(key=operator.itemgetter(0), reverse=True)
 
 		to_be_masked = backtrack_data[-1][0]
 

diff --git a/pym/portage/tests/resolver/test_backtracking.py b/pym/portage/tests/resolver/test_backtracking.py
index 53899eb..9dc37ac 100644
--- a/pym/portage/tests/resolver/test_backtracking.py
+++ b/pym/portage/tests/resolver/test_backtracking.py
@@ -67,37 +67,6 @@ class BacktrackingTestCase(TestCase):
 		finally:
 			playground.cleanup()
 
-
-	def testBacktrackingGoodVersionFirst(self):
-		"""
-		When backtracking due to slot conflicts, we masked the version that has been pulled
-		in first. This is not always a good idea. Mask the highest version instead.
-		"""
-
-		ebuilds = {
-			"dev-libs/A-1": { "DEPEND": "=dev-libs/C-1 dev-libs/B" },
-			"dev-libs/B-1": { "DEPEND": "=dev-libs/C-1" },
-			"dev-libs/B-2": { "DEPEND": "=dev-libs/C-2" },
-			"dev-libs/C-1": { },
-			"dev-libs/C-2": { },
-			}
-
-		test_cases = (
-				ResolverPlaygroundTestCase(
-					["dev-libs/A"],
-					mergelist = ["dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1",],
-					success = True),
-			)
-
-		playground = ResolverPlayground(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.cleanup()
-
 	def testBacktrackWithoutUpdates(self):
 		"""
 		If --update is not given we might have to mask the old installed version later.

diff --git a/pym/portage/tests/resolver/test_slot_conflict_mask_update.py b/pym/portage/tests/resolver/test_slot_conflict_mask_update.py
new file mode 100644
index 0000000..a90eeac
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_conflict_mask_update.py
@@ -0,0 +1,41 @@
+# Copyright 2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SlotConflictMaskUpdateTestCase(TestCase):
+
+	def testBacktrackingGoodVersionFirst(self):
+		"""
+		When backtracking due to slot conflicts, we masked the version that has been pulled
+		in first. This is not always a good idea. Mask the highest version instead.
+		"""
+
+		
+		self.todo = True
+
+		ebuilds = {
+			"dev-libs/A-1": { "DEPEND": "=dev-libs/C-1 dev-libs/B" },
+			"dev-libs/B-1": { "DEPEND": "=dev-libs/C-1" },
+			"dev-libs/B-2": { "DEPEND": "=dev-libs/C-2" },
+			"dev-libs/C-1": { },
+			"dev-libs/C-2": { },
+			}
+
+		test_cases = (
+				ResolverPlaygroundTestCase(
+					["dev-libs/A"],
+					mergelist = ["dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1",],
+					success = True),
+			)
+
+		playground = ResolverPlayground(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.cleanup()

diff --git a/pym/portage/tests/resolver/test_slot_conflict_update.py b/pym/portage/tests/resolver/test_slot_conflict_update.py
new file mode 100644
index 0000000..331e578
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_conflict_update.py
@@ -0,0 +1,98 @@
+# Copyright 2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SlotConflictUpdateTestCase(TestCase):
+
+	def testSlotConflictUpdate(self):
+
+		ebuilds = {
+
+			"app-text/podofo-0.9.2" : {
+				"EAPI": "5",
+				"RDEPEND" : "dev-util/boost-build"
+			},
+
+			"dev-cpp/libcmis-0.3.1" : {
+				"EAPI": "5",
+				"RDEPEND" : "dev-libs/boost:="
+			},
+
+			"dev-libs/boost-1.53.0" : {
+				"EAPI": "5",
+				"SLOT": "0/1.53",
+				"RDEPEND" : "=dev-util/boost-build-1.53.0"
+			},
+
+			"dev-libs/boost-1.52.0" : {
+				"EAPI": "5",
+				"SLOT": "0/1.52",
+				"RDEPEND" : "=dev-util/boost-build-1.52.0"
+			},
+
+			"dev-util/boost-build-1.53.0" : {
+				"EAPI": "5",
+				"SLOT": "0"
+			},
+
+			"dev-util/boost-build-1.52.0" : {
+				"EAPI": "5",
+				"SLOT": "0"
+			},
+
+
+		}
+
+		installed = {
+
+			"app-text/podofo-0.9.2" : {
+				"EAPI": "5",
+				"RDEPEND" : "dev-util/boost-build"
+			},
+
+			"dev-cpp/libcmis-0.3.1" : {
+				"EAPI": "5",
+				"RDEPEND" : "dev-libs/boost:0/1.52="
+			},
+
+			"dev-util/boost-build-1.52.0" : {
+				"EAPI": "5",
+				"SLOT": "0"
+			},
+
+			"dev-libs/boost-1.52.0" : {
+				"EAPI": "5",
+				"SLOT": "0/1.52",
+				"RDEPEND" : "=dev-util/boost-build-1.52.0"
+			}
+
+		}
+
+		world = ["dev-cpp/libcmis", "dev-libs/boost", "app-text/podofo"]
+
+		test_cases = (
+
+			# In order to avoid a missed update, first mask lower
+			# versions that conflict with higher versions. Note that
+			# this behavior makes SlotConflictMaskUpdateTestCase
+			# fail.
+			ResolverPlaygroundTestCase(
+				world,
+				all_permutations = True,
+				options = {"--update": True, "--deep": True},
+				success = True,
+				mergelist = ['dev-util/boost-build-1.53.0', 'dev-libs/boost-1.53.0', 'dev-cpp/libcmis-0.3.1']),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-07-07 19:16 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-07-07 19:16 UTC (permalink / raw
  To: gentoo-commits

commit:     328ee458b0230d8288162a35c3b7472d85be8d67
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Jul  7 19:10:34 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Jul  7 19:14:54 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=328ee458

calc_depclean: use runtime_slot_op priorities

---
 pym/_emerge/UnmergeDepPriority.py                 |  2 +
 pym/_emerge/actions.py                            | 13 +++++-
 pym/portage/tests/resolver/test_depclean_order.py | 57 +++++++++++++++++++++++
 3 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/pym/_emerge/UnmergeDepPriority.py b/pym/_emerge/UnmergeDepPriority.py
index 0457ea9..ec44a67 100644
--- a/pym/_emerge/UnmergeDepPriority.py
+++ b/pym/_emerge/UnmergeDepPriority.py
@@ -37,6 +37,8 @@ class UnmergeDepPriority(AbstractDepPriority):
 	def __str__(self):
 		if self.ignored:
 			return "ignored"
+		if self.runtime_slot_op:
+			return "hard slot op"
 		myvalue = self.__int__()
 		if myvalue > self.SOFT:
 			return "hard"

diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
index 034613e..730868e 100644
--- a/pym/_emerge/actions.py
+++ b/pym/_emerge/actions.py
@@ -1147,7 +1147,8 @@ def calc_depclean(settings, trees, ldpath_mtimes,
 						"installed", root_config, installed=True)
 					if not resolver._add_pkg(pkg,
 						Dependency(parent=consumer_pkg,
-						priority=UnmergeDepPriority(runtime=True),
+						priority=UnmergeDepPriority(runtime=True,
+							runtime_slot_op=True),
 						root=pkg.root)):
 						resolver.display_problems()
 						return 1, [], False, 0
@@ -1235,7 +1236,15 @@ def calc_depclean(settings, trees, ldpath_mtimes,
 						continue
 					for child_node in matches:
 						if child_node in clean_set:
-							graph.add(child_node, node, priority=priority)
+
+							mypriority = priority.copy()
+							if atom.slot_operator_built:
+								if mypriority.buildtime:
+									mypriority.buildtime_slot_op = True
+								if mypriority.runtime:
+									mypriority.runtime_slot_op = True
+
+							graph.add(child_node, node, priority=mypriority)
 
 		if debug:
 			writemsg_level("\nunmerge digraph:\n\n",

diff --git a/pym/portage/tests/resolver/test_depclean_order.py b/pym/portage/tests/resolver/test_depclean_order.py
new file mode 100644
index 0000000..9511d29
--- /dev/null
+++ b/pym/portage/tests/resolver/test_depclean_order.py
@@ -0,0 +1,57 @@
+# Copyright 2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class SimpleDepcleanTestCase(TestCase):
+
+	def testSimpleDepclean(self):
+
+		ebuilds = {
+			"dev-libs/A-1": {
+				"EAPI": "5",
+				"RDEPEND": "dev-libs/B:=",
+			},
+			"dev-libs/B-1": {
+				"EAPI": "5",
+				"RDEPEND": "dev-libs/A",
+			},
+			"dev-libs/C-1": {},
+		}
+
+		installed = {
+			"dev-libs/A-1": {
+				"EAPI": "5",
+				"RDEPEND": "dev-libs/B:0/0=",
+			},
+			"dev-libs/B-1": {
+				"EAPI": "5",
+				"RDEPEND": "dev-libs/A",
+			},
+			"dev-libs/C-1": {},
+		}
+
+		world = (
+			"dev-libs/C",
+		)
+
+		test_cases = (
+			# Remove dev-libs/A-1 first because of dev-libs/B:0/0= (built
+			# slot-operator dep).
+			ResolverPlaygroundTestCase(
+				[],
+				options={"--depclean": True},
+				success=True,
+				ordered=True,
+				cleanlist=["dev-libs/A-1", "dev-libs/B-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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-07-06 21:45 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-07-06 21:45 UTC (permalink / raw
  To: gentoo-commits

commit:     92d9c95c83ddc6ac7b59395db92c0c8d81d7687a
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Jul  6 21:45:04 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat Jul  6 21:45:04 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=92d9c95c

depgraph: tweak slot-operator merge order

This handles circular DEPEND/RDEPEND with one := operator, so that when
both deps are already satisfied by installed packages, the := dep is
given higher priority in merge order.

---
 pym/_emerge/AbstractDepPriority.py             |  5 ++--
 pym/_emerge/DepPriority.py                     | 29 +++++++++++++--------
 pym/_emerge/DepPrioritySatisfiedRange.py       | 23 ++++++++++++-----
 pym/_emerge/UnmergeDepPriority.py              | 25 ++++++++++--------
 pym/_emerge/depgraph.py                        |  7 ++++++
 pym/portage/tests/resolver/test_merge_order.py | 35 +++++++++++++++++++++++++-
 6 files changed, 93 insertions(+), 31 deletions(-)

diff --git a/pym/_emerge/AbstractDepPriority.py b/pym/_emerge/AbstractDepPriority.py
index 94f26ef..1fcd043 100644
--- a/pym/_emerge/AbstractDepPriority.py
+++ b/pym/_emerge/AbstractDepPriority.py
@@ -1,11 +1,12 @@
-# Copyright 1999-2012 Gentoo Foundation
+# Copyright 1999-2013 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import copy
 from portage.util.SlotObject import SlotObject
 
 class AbstractDepPriority(SlotObject):
-	__slots__ = ("buildtime", "runtime", "runtime_post")
+	__slots__ = ("buildtime", "buildtime_slot_op",
+		"runtime", "runtime_post", "runtime_slot_op")
 
 	def __lt__(self, other):
 		return self.__int__() < other

diff --git a/pym/_emerge/DepPriority.py b/pym/_emerge/DepPriority.py
index 3c2256a..34fdb48 100644
--- a/pym/_emerge/DepPriority.py
+++ b/pym/_emerge/DepPriority.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2011 Gentoo Foundation
+# Copyright 1999-2013 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from _emerge.AbstractDepPriority import AbstractDepPriority
@@ -16,31 +16,38 @@ class DepPriority(AbstractDepPriority):
 
 		Attributes                            Hardness
 
-		buildtime                               0
-		runtime                                -1
-		runtime_post                           -2
-		optional                               -3
-		(none of the above)                    -4
+		buildtime_slot_op                       0
+		buildtime                              -1
+		runtime                                -2
+		runtime_post                           -3
+		optional                               -4
+		(none of the above)                    -5
 
 		"""
 
 		if self.optional:
-			return -3
-		if self.buildtime:
+			return -4
+		if self.buildtime_slot_op:
 			return 0
-		if self.runtime:
+		if self.buildtime:
 			return -1
-		if self.runtime_post:
+		if self.runtime:
 			return -2
-		return -4
+		if self.runtime_post:
+			return -3
+		return -5
 
 	def __str__(self):
 		if self.ignored:
 			return "ignored"
 		if self.optional:
 			return "optional"
+		if self.buildtime_slot_op:
+			return "buildtime_slot_op"
 		if self.buildtime:
 			return "buildtime"
+		if self.runtime_slot_op:
+			return "runtime_slot_op"
 		if self.runtime:
 			return "runtime"
 		if self.runtime_post:

diff --git a/pym/_emerge/DepPrioritySatisfiedRange.py b/pym/_emerge/DepPrioritySatisfiedRange.py
index edb29df..e5fdba9 100644
--- a/pym/_emerge/DepPrioritySatisfiedRange.py
+++ b/pym/_emerge/DepPrioritySatisfiedRange.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2011 Gentoo Foundation
+# Copyright 1999-2013 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from _emerge.DepPriority import DepPriority
@@ -7,17 +7,18 @@ class DepPrioritySatisfiedRange(object):
 	DepPriority                         Index      Category
 
 	not satisfied and buildtime                    HARD
-	not satisfied and runtime              6       MEDIUM
-	not satisfied and runtime_post         5       MEDIUM_SOFT
+	not satisfied and runtime              7       MEDIUM
+	not satisfied and runtime_post         6       MEDIUM_SOFT
+	satisfied and buildtime_slot_op        5       SOFT
 	satisfied and buildtime                4       SOFT
 	satisfied and runtime                  3       SOFT
 	satisfied and runtime_post             2       SOFT
 	optional                               1       SOFT
 	(none of the above)                    0       NONE
 	"""
-	MEDIUM      = 6
-	MEDIUM_SOFT = 5
-	SOFT        = 4
+	MEDIUM      = 7
+	MEDIUM_SOFT = 6
+	SOFT        = 5
 	NONE        = 0
 
 	@classmethod
@@ -50,6 +51,15 @@ class DepPrioritySatisfiedRange(object):
 	def _ignore_satisfied_buildtime(cls, priority):
 		if priority.__class__ is not DepPriority:
 			return False
+		if priority.buildtime_slot_op:
+			return False
+		return bool(priority.optional or \
+			priority.satisfied)
+
+	@classmethod
+	def _ignore_satisfied_buildtime_slot_op(cls, priority):
+		if priority.__class__ is not DepPriority:
+			return False
 		return bool(priority.optional or \
 			priority.satisfied)
 
@@ -80,6 +90,7 @@ DepPrioritySatisfiedRange.ignore_priority = (
 	DepPrioritySatisfiedRange._ignore_satisfied_runtime_post,
 	DepPrioritySatisfiedRange._ignore_satisfied_runtime,
 	DepPrioritySatisfiedRange._ignore_satisfied_buildtime,
+	DepPrioritySatisfiedRange._ignore_satisfied_buildtime_slot_op,
 	DepPrioritySatisfiedRange._ignore_runtime_post,
 	DepPrioritySatisfiedRange._ignore_runtime
 )

diff --git a/pym/_emerge/UnmergeDepPriority.py b/pym/_emerge/UnmergeDepPriority.py
index 4316600..0457ea9 100644
--- a/pym/_emerge/UnmergeDepPriority.py
+++ b/pym/_emerge/UnmergeDepPriority.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2011 Gentoo Foundation
+# Copyright 1999-2013 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from _emerge.AbstractDepPriority import AbstractDepPriority
@@ -7,15 +7,16 @@ class UnmergeDepPriority(AbstractDepPriority):
 	"""
 	Combination of properties           Priority  Category
 
-	runtime                                0       HARD
-	runtime_post                          -1       HARD
-	buildtime                             -2       SOFT
-	(none of the above)                   -2       SOFT
+	runtime_slot_op                        0       HARD
+	runtime                               -1       HARD
+	runtime_post                          -2       HARD
+	buildtime                             -3       SOFT
+	(none of the above)                   -3       SOFT
 	"""
 
 	MAX    =  0
-	SOFT   = -2
-	MIN    = -2
+	SOFT   = -3
+	MIN    = -3
 
 	def __init__(self, **kwargs):
 		AbstractDepPriority.__init__(self, **kwargs)
@@ -23,13 +24,15 @@ class UnmergeDepPriority(AbstractDepPriority):
 			self.optional = True
 
 	def __int__(self):
-		if self.runtime:
+		if self.runtime_slot_op:
 			return 0
-		if self.runtime_post:
+		if self.runtime:
 			return -1
-		if self.buildtime:
+		if self.runtime_post:
 			return -2
-		return -2
+		if self.buildtime:
+			return -3
+		return -3
 
 	def __str__(self):
 		if self.ignored:

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index b2d79a8..939adde 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -2254,6 +2254,13 @@ class depgraph(object):
 
 			mypriority = dep_priority.copy()
 			if not atom.blocker:
+
+				if atom.slot_operator == "=":
+					if mypriority.buildtime:
+						mypriority.buildtime_slot_op = True
+					if mypriority.runtime:
+						mypriority.runtime_slot_op = True
+
 				inst_pkgs = [inst_pkg for inst_pkg in
 					reversed(vardb.match_pkgs(atom))
 					if not reinstall_atoms.findAtomForPackage(inst_pkg,

diff --git a/pym/portage/tests/resolver/test_merge_order.py b/pym/portage/tests/resolver/test_merge_order.py
index 5b5709a..5d000d1 100644
--- a/pym/portage/tests/resolver/test_merge_order.py
+++ b/pym/portage/tests/resolver/test_merge_order.py
@@ -1,4 +1,4 @@
-# Copyright 2011 Gentoo Foundation
+# Copyright 2011-2013 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import portage
@@ -191,6 +191,12 @@ class MergeOrderTestCase(TestCase):
 				"DEPEND"  : "kde-base/libkdegames",
 				"RDEPEND" : "kde-base/libkdegames",
 			},
+			"media-libs/mesa-9.1.3" : {
+				"EAPI" : "5",
+				"IUSE" : "+xorg",
+				"DEPEND" : "xorg? ( x11-base/xorg-server:= )",
+				"RDEPEND" : "xorg? ( x11-base/xorg-server:= )",
+			},
 			"media-video/libav-0.7_pre20110327" : {
 				"EAPI" : "2",
 				"IUSE" : "X +encode",
@@ -205,6 +211,12 @@ 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-server-1.14.1" : {
+				"EAPI" : "5",
+				"SLOT": "0/1.14.1",
+				"DEPEND" : "media-libs/mesa",
+				"RDEPEND" : "media-libs/mesa",
+			},
 		}
 
 		installed = {
@@ -256,6 +268,13 @@ class MergeOrderTestCase(TestCase):
 				"RDEPEND": "",
 			},
 			"app-arch/xz-utils-5.0.1" : {},
+			"media-libs/mesa-9.1.3" : {
+				"EAPI" : "5",
+				"IUSE" : "+xorg",
+				"USE": "xorg",
+				"DEPEND" : "x11-base/xorg-server:0/1.14.1=",
+				"RDEPEND" : "x11-base/xorg-server:0/1.14.1=",
+			},
 			"media-video/ffmpeg-0.7_rc1" : {
 				"EAPI" : "2",
 				"IUSE" : "X +encode",
@@ -267,6 +286,12 @@ 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-server-1.14.1" : {
+				"EAPI" : "5",
+				"SLOT": "0/1.14.1",
+				"DEPEND" : "media-libs/mesa",
+				"RDEPEND" : "media-libs/mesa",
+			},
 		}
 
 		test_cases = (
@@ -434,6 +459,14 @@ class MergeOrderTestCase(TestCase):
 					('kde-base/libkdegames-3.5.7', 'kde-base/kmines-3.5.7'),
 				),
 				mergelist = [('kde-base/kdelibs-3.5.7', 'dev-util/pkgconfig-0.25-r2', 'kde-misc/kdnssd-avahi-0.1.2', 'app-arch/xz-utils-5.0.2', 'kde-base/libkdegames-3.5.7', 'kde-base/kdnssd-3.5.7', 'kde-base/kmines-3.5.7')]),
+			# Test satisfied circular DEPEND/RDEPEND with one := operator.
+			# 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"],
+				success=True,
+				all_permutations = True,
+				mergelist = ['x11-base/xorg-server-1.14.1', 'media-libs/mesa-9.1.3']),
 		)
 
 		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-03-19 21:06 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-03-19 21:06 UTC (permalink / raw
  To: gentoo-commits

commit:     af19f0ec16e635393ca0d1ac875d2873cff1608f
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Mar 19 21:05:57 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue Mar 19 21:05:57 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=af19f0ec

Use autounmask for subslot conflict, bug #461464.

---
 pym/_emerge/depgraph.py                            |   60 ++++++++---
 .../resolver/test_slot_operator_autounmask.py      |  120 ++++++++++++++++++++
 2 files changed, 165 insertions(+), 15 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index a17398c..308c583 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1032,8 +1032,11 @@ class depgraph(object):
 				dep = Dependency(atom=atom, child=other_pkg,
 					parent=parent, root=pkg.root)
 
-				if self._slot_operator_update_probe(dep, slot_conflict=True):
-					self._slot_operator_update_backtrack(dep)
+				new_dep = \
+					self._slot_operator_update_probe_slot_conflict(dep)
+				if new_dep is not None:
+					self._slot_operator_update_backtrack(dep,
+						new_dep=new_dep)
 					found_update = True
 
 		return found_update
@@ -1117,7 +1120,8 @@ class depgraph(object):
 
 		self._dynamic_config._need_restart = True
 
-	def _slot_operator_update_backtrack(self, dep, new_child_slot=None):
+	def _slot_operator_update_backtrack(self, dep, new_child_slot=None,
+		new_dep=None):
 		if new_child_slot is None:
 			child = dep.child
 		else:
@@ -1131,6 +1135,8 @@ class depgraph(object):
 			if new_child_slot is not None:
 				msg.append("   new child slot package:  %s" % new_child_slot)
 			msg.append("   parent package: %s" % dep.parent)
+			if new_dep is not None:
+				msg.append("   new parent pkg: %s" % new_dep.parent)
 			msg.append("   atom: %s" % dep.atom)
 			msg.append("")
 			writemsg_level("\n".join(msg),
@@ -1151,7 +1157,10 @@ class depgraph(object):
 		# trigger replacement of installed packages if necessary
 		abi_reinstalls = set()
 		if dep.parent.installed:
-			replacement_atom = self._replace_installed_atom(dep.parent)
+			if new_dep is not None:
+				replacement_atom = new_dep.parent.slot_atom
+			else:
+				replacement_atom = self._replace_installed_atom(dep.parent)
 			if replacement_atom is not None:
 				abi_reinstalls.add((dep.parent.root, replacement_atom))
 		if new_child_slot is None and child.installed:
@@ -1164,8 +1173,26 @@ class depgraph(object):
 
 		self._dynamic_config._need_restart = True
 
+	def _slot_operator_update_probe_slot_conflict(self, dep):
+		new_dep = self._slot_operator_update_probe(dep, slot_conflict=True)
+
+		if new_dep is not None:
+			return new_dep
+
+		if self._dynamic_config._autounmask is True:
+
+			for autounmask_level in self._autounmask_levels():
+
+				new_dep = self._slot_operator_update_probe(dep,
+					slot_conflict=True, autounmask_level=autounmask_level)
+
+				if new_dep is not None:
+					return new_dep
+
+		return None
+
 	def _slot_operator_update_probe(self, dep, new_child_slot=False,
-		slot_conflict=False):
+		slot_conflict=False, autounmask_level=None):
 		"""
 		slot/sub-slot := operators tend to prevent updates from getting pulled in,
 		since installed packages pull in packages with the slot/sub-slot that they
@@ -1191,7 +1218,7 @@ class depgraph(object):
 		want_downgrade = None
 
 		for replacement_parent in self._iter_similar_available(dep.parent,
-			dep.parent.slot_atom):
+			dep.parent.slot_atom, autounmask_level=autounmask_level):
 
 			selected_atoms = None
 
@@ -1283,7 +1310,8 @@ class depgraph(object):
 					if insignificant:
 						return None
 
-					return pkg
+					return Dependency(parent=replacement_parent,
+						child=pkg, atom=unevaluated_atom)
 
 		if debug:
 			msg = []
@@ -1423,7 +1451,7 @@ class depgraph(object):
 		return frozenset(x.unevaluated_atom for
 			x in selected_atoms)
 
-	def _iter_similar_available(self, graph_pkg, atom):
+	def _iter_similar_available(self, graph_pkg, atom, autounmask_level=None):
 		"""
 		Given a package that's in the graph, do a rough check to
 		see if a similar package is available to install. The given
@@ -1447,16 +1475,18 @@ class depgraph(object):
 			if self._frozen_config.excluded_pkgs.findAtomForPackage(pkg,
 				modified_use=self._pkg_use_enabled(pkg)):
 				continue
-			if not self._pkg_visibility_check(pkg):
+			if pkg.built and self._equiv_binary_installed(pkg):
 				continue
 			if pkg.built:
-				if self._equiv_binary_installed(pkg):
-					continue
 				if not (not use_ebuild_visibility and
 					(usepkgonly or useoldpkg_atoms.findAtomForPackage(
 					pkg, modified_use=self._pkg_use_enabled(pkg)))) and \
-					not self._equiv_ebuild_visible(pkg):
+					not self._equiv_ebuild_visible(pkg,
+					autounmask_level=autounmask_level):
 					continue
+			if not self._pkg_visibility_check(pkg,
+				autounmask_level=autounmask_level):
+				continue
 			yield pkg
 
 	def _replace_installed_atom(self, inst_pkg):
@@ -1521,11 +1551,11 @@ class depgraph(object):
 				# trigger reinstall of the child package when a newer
 				# slot will be used instead.
 				if rebuild_if_new_slot:
-					new_child = self._slot_operator_update_probe(dep,
+					new_dep = self._slot_operator_update_probe(dep,
 						new_child_slot=True)
-					if new_child:
+					if new_dep is not None:
 						self._slot_operator_update_backtrack(dep,
-							new_child_slot=new_child)
+							new_child_slot=new_dep.child)
 						break
 
 				if dep.want_update:

diff --git a/pym/portage/tests/resolver/test_slot_operator_autounmask.py b/pym/portage/tests/resolver/test_slot_operator_autounmask.py
new file mode 100644
index 0000000..624271b
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_autounmask.py
@@ -0,0 +1,120 @@
+# Copyright 2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SlotOperatorAutoUnmaskTestCase(TestCase):
+
+	def __init__(self, *args, **kwargs):
+		super(SlotOperatorAutoUnmaskTestCase, self).__init__(*args, **kwargs)
+
+	def testSubSlot(self):
+		ebuilds = {
+			"dev-libs/icu-49" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/49"
+			},
+			"dev-libs/icu-4.8" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/48"
+			},
+			"dev-libs/libxml2-2.7.8" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/icu:=",
+				"RDEPEND": "dev-libs/icu:=",
+				"KEYWORDS": "~x86"
+			},
+		}
+		binpkgs = {
+			"dev-libs/icu-49" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/49"
+			},
+			"dev-libs/icu-4.8" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/48"
+			},
+			"dev-libs/libxml2-2.7.8" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/icu:0/48=",
+				"RDEPEND": "dev-libs/icu:0/48="
+			},
+		}
+		installed = {
+			"dev-libs/icu-4.8" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/48"
+			},
+			"dev-libs/libxml2-2.7.8" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/icu:0/48=",
+				"RDEPEND": "dev-libs/icu:0/48="
+			},
+		}
+
+		world = ["dev-libs/libxml2"]
+
+		test_cases = (
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--autounmask": True, "--oneshot": True},
+				success = False,
+				mergelist = ["dev-libs/icu-49", "dev-libs/libxml2-2.7.8" ],
+				unstable_keywords = ['dev-libs/libxml2-2.7.8']),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True, "--ignore-built-slot-operator-deps": "y"},
+				success = True,
+				mergelist = ["dev-libs/icu-49"]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True, "--usepkg": True},
+				success = False,
+				mergelist = ["[binary]dev-libs/icu-49", "dev-libs/libxml2-2.7.8" ],
+				unstable_keywords = ['dev-libs/libxml2-2.7.8']),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True, "--usepkgonly": True},
+				success = True,
+				mergelist = ["[binary]dev-libs/icu-4.8"]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True, "--usepkgonly": True, "--ignore-built-slot-operator-deps": "y"},
+				success = True,
+				mergelist = ["[binary]dev-libs/icu-49"]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--ignore-built-slot-operator-deps": "y"},
+				success = True,
+				mergelist = ["dev-libs/icu-49"]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--usepkgonly": True},
+				success = True,
+				mergelist = []),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--usepkgonly": True, "--ignore-built-slot-operator-deps": "y"},
+				success = True,
+				mergelist = ["[binary]dev-libs/icu-49"]),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-02-14  4:45 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-02-14  4:45 UTC (permalink / raw
  To: gentoo-commits

commit:     468adcc31f8b97134a5a67a621e1d32a82bc6ffb
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Thu Feb 14 04:45:40 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Feb 14 04:45:40 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=468adcc3

slot_operator_replace_installed: check available

This fixes a case where it could try to pull in an unavailable SLOT.

---
 pym/_emerge/depgraph.py                            |   47 ++++++++++++++-
 .../test_regular_slot_change_without_revbump.py    |   59 ++++++++++++++++++++
 2 files changed, 102 insertions(+), 4 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index e0ea895..bab1c32 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1104,7 +1104,9 @@ class depgraph(object):
 		# trigger replacement of installed packages if necessary
 		reinstalls = set()
 		if child.installed:
-			reinstalls.add((child.root, child.slot_atom))
+			replacement_atom = self._replace_installed_atom(child)
+			if replacement_atom is not None:
+				reinstalls.add((child.root, replacement_atom))
 		if reinstalls:
 			config.setdefault("slot_operator_replace_installed",
 				set()).update(reinstalls)
@@ -1145,9 +1147,13 @@ class depgraph(object):
 		# trigger replacement of installed packages if necessary
 		abi_reinstalls = set()
 		if dep.parent.installed:
-			abi_reinstalls.add((dep.parent.root, dep.parent.slot_atom))
+			replacement_atom = self._replace_installed_atom(dep.parent)
+			if replacement_atom is not None:
+				abi_reinstalls.add((dep.parent.root, replacement_atom))
 		if new_child_slot is None and child.installed:
-			abi_reinstalls.add((child.root, child.slot_atom))
+			replacement_atom = self._replace_installed_atom(child)
+			if replacement_atom is not None:
+				abi_reinstalls.add((child.root, replacement_atom))
 		if abi_reinstalls:
 			config.setdefault("slot_operator_replace_installed",
 				set()).update(abi_reinstalls)
@@ -1363,7 +1369,9 @@ class depgraph(object):
 		# trigger replacement of installed packages if necessary
 		reinstalls = set()
 		if parent.installed:
-			reinstalls.add((parent.root, parent.slot_atom))
+			replacement_atom = self._replace_installed_atom(parent)
+			if replacement_atom is not None:
+				reinstalls.add((parent.root, replacement_atom))
 		if reinstalls:
 			config.setdefault("slot_operator_replace_installed",
 				set()).update(reinstalls)
@@ -1421,6 +1429,37 @@ class depgraph(object):
 					continue
 			yield pkg
 
+	def _replace_installed_atom(self, inst_pkg):
+		"""
+		Given an installed package, generate an atom suitable for
+		slot_operator_replace_installed backtracking info. The replacement
+		SLOT may differ from the installed SLOT, so first search by cpv.
+		"""
+		built_pkgs = []
+		for pkg in self._iter_similar_available(inst_pkg,
+			Atom("=%s" % inst_pkg.cpv)):
+			if not pkg.built:
+				return pkg.slot_atom
+			elif not pkg.installed:
+				# avoid using SLOT from a built instance
+				built_pkgs.append(pkg)
+
+		for pkg in self._iter_similar_available(inst_pkg, inst_pkg.slot_atom):
+			if not pkg.built:
+				return pkg.slot_atom
+			elif not pkg.installed:
+				# avoid using SLOT from a built instance
+				built_pkgs.append(pkg)
+
+		if built_pkgs:
+			best_version = None
+			for pkg in built_pkgs:
+				if best_version is None or pkg > best_version:
+					best_version = pkg
+			return best_version.slot_atom
+
+		return None
+
 	def _slot_operator_trigger_reinstalls(self):
 		"""
 		Search for packages with slot-operator deps on older slots, and schedule

diff --git a/pym/portage/tests/resolver/test_regular_slot_change_without_revbump.py b/pym/portage/tests/resolver/test_regular_slot_change_without_revbump.py
new file mode 100644
index 0000000..415277b
--- /dev/null
+++ b/pym/portage/tests/resolver/test_regular_slot_change_without_revbump.py
@@ -0,0 +1,59 @@
+# Copyright 2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class RegularSlotChangeWithoutRevBumpTestCase(TestCase):
+
+	def testRegularSlotChangeWithoutRevBumpTestCase(self):
+
+		ebuilds = {
+			"dev-libs/boost-1.52.0" : {
+				"SLOT": "0"
+			},
+			"app-office/libreoffice-4.0.0.2" : {
+				"EAPI": "5",
+				"DEPEND": ">=dev-libs/boost-1.46:=",
+				"RDEPEND": ">=dev-libs/boost-1.46:=",
+			},
+		}
+
+		binpkgs = {
+			"dev-libs/boost-1.52.0" : {
+				"SLOT": "1.52"
+			},
+		}
+
+		installed = {
+			"dev-libs/boost-1.52.0" : {
+				"SLOT": "1.52"
+			},
+		}
+
+		world = []
+
+		test_cases = (
+			# Test that @__auto_slot_operator_replace_installed__
+			# pulls in the available slot, even though it's
+			# different from the installed slot (0 instead of 1.52).
+			ResolverPlaygroundTestCase(
+				["app-office/libreoffice"],
+				options = {"--oneshot": True, "--usepkg": True},
+				success = True,
+				mergelist = [
+					'dev-libs/boost-1.52.0',
+					'app-office/libreoffice-4.0.0.2'
+				]
+			),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-02-12  2:50 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-02-12  2:50 UTC (permalink / raw
  To: gentoo-commits

commit:     69ea5d7b2a166a8d1085af77a72e827080edaee4
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Feb 12 02:50:36 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue Feb 12 02:50:36 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=69ea5d7b

Backtrack unsatisfied slot-operator, bug #456340.

---
 pym/_emerge/depgraph.py                            |   98 ++++++++++++++++++++
 .../tests/resolver/test_slot_operator_unsolved.py  |   27 ++++--
 2 files changed, 115 insertions(+), 10 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 085ac9b..eb88357 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1273,6 +1273,100 @@ class depgraph(object):
 
 		return None
 
+	def _slot_operator_unsatisfied_probe(self, dep):
+
+		if dep.parent.installed and \
+			self._frozen_config.excluded_pkgs.findAtomForPackage(dep.parent,
+			modified_use=self._pkg_use_enabled(dep.parent)):
+			return False
+
+		debug = "--debug" in self._frozen_config.myopts
+
+		for replacement_parent in self._iter_similar_available(dep.parent,
+			dep.parent.slot_atom):
+
+			for atom in replacement_parent.validated_atoms:
+				if not atom.slot_operator == "=" or \
+					atom.blocker or \
+					atom.cp != dep.atom.cp:
+					continue
+
+				# Discard USE deps, we're only searching for an approximate
+				# pattern, and dealing with USE states is too complex for
+				# this purpose.
+				atom = atom.without_use
+
+				pkg, existing_node = self._select_package(dep.root, atom,
+					onlydeps=dep.onlydeps)
+
+				if pkg is not None:
+
+					if debug:
+						msg = []
+						msg.append("")
+						msg.append("")
+						msg.append("slot_operator_unsatisfied_probe:")
+						msg.append("   existing parent package: %s" % dep.parent)
+						msg.append("   existing parent atom: %s" % dep.atom)
+						msg.append("   new parent package: %s" % replacement_parent)
+						msg.append("   new child package:  %s" % pkg)
+						msg.append("")
+						writemsg_level("\n".join(msg),
+							noiselevel=-1, level=logging.DEBUG)
+
+					return True
+
+		if debug:
+			msg = []
+			msg.append("")
+			msg.append("")
+			msg.append("slot_operator_unsatisfied_probe:")
+			msg.append("   existing parent package: %s" % dep.parent)
+			msg.append("   existing parent atom: %s" % dep.atom)
+			msg.append("   new parent package: %s" % None)
+			msg.append("   new child package:  %s" % None)
+			msg.append("")
+			writemsg_level("\n".join(msg),
+				noiselevel=-1, level=logging.DEBUG)
+
+		return False
+
+	def _slot_operator_unsatisfied_backtrack(self, dep):
+
+		parent = dep.parent
+
+		if "--debug" in self._frozen_config.myopts:
+			msg = []
+			msg.append("")
+			msg.append("")
+			msg.append("backtracking due to unsatisfied "
+				"built slot-operator dep:")
+			msg.append("   parent package: %s" % parent)
+			msg.append("   atom: %s" % dep.atom)
+			msg.append("")
+			writemsg_level("\n".join(msg),
+				noiselevel=-1, level=logging.DEBUG)
+
+		backtrack_infos = self._dynamic_config._backtrack_infos
+		config = backtrack_infos.setdefault("config", {})
+
+		# mask unwanted binary packages if necessary
+		masks = {}
+		if not parent.installed:
+			masks.setdefault(parent, {})["slot_operator_mask_built"] = None
+		if masks:
+			config.setdefault("slot_operator_mask_built", {}).update(masks)
+
+		# trigger replacement of installed packages if necessary
+		reinstalls = set()
+		if parent.installed:
+			reinstalls.add((parent.root, parent.slot_atom))
+		if reinstalls:
+			config.setdefault("slot_operator_replace_installed",
+				set()).update(reinstalls)
+
+		self._dynamic_config._need_restart = True
+
 	def _downgrade_probe(self, pkg):
 		"""
 		Detect cases where a downgrade of the given package is considered
@@ -1529,6 +1623,10 @@ class depgraph(object):
 							(dep.parent,
 							self._dynamic_config._runtime_pkg_mask[
 							dep.parent]), noiselevel=-1)
+				elif dep.atom.slot_operator_built and \
+					self._slot_operator_unsatisfied_probe(dep):
+					self._slot_operator_unsatisfied_backtrack(dep)
+					return 1
 				elif not self.need_restart():
 					# Do not backtrack if only USE have to be changed in
 					# order to satisfy the dependency.

diff --git a/pym/portage/tests/resolver/test_slot_operator_unsolved.py b/pym/portage/tests/resolver/test_slot_operator_unsolved.py
index a496252..7ae3d9e 100644
--- a/pym/portage/tests/resolver/test_slot_operator_unsolved.py
+++ b/pym/portage/tests/resolver/test_slot_operator_unsolved.py
@@ -9,11 +9,6 @@ class SlotOperatorUnsolvedTestCase(TestCase):
 	"""
 	Demonstrate bug #456340, where an unsolved circular dependency
 	interacts with an unsatisfied built slot-operator dep.
-
-	The problem here results from poor handling of the unsatisfied built
-	slot operator dep inside _add_dep, where it aborts the graph and tries
-	to backtrack immediately. We really want it to queue a rebuild here,
-	and continue filling out the graph.
 	"""
 	def __init__(self, *args, **kwargs):
 		super(SlotOperatorUnsolvedTestCase, self).__init__(*args, **kwargs)
@@ -31,12 +26,14 @@ class SlotOperatorUnsolvedTestCase(TestCase):
 			},
 			"dev-ruby/rdoc-3.12.1" : {
 				"EAPI": "5",
-				"DEPEND": ">=dev-ruby/hoe-2.7.0",
+				"IUSE": "test",
+				"DEPEND": "test? ( >=dev-ruby/hoe-2.7.0 )",
 			},
 			"dev-ruby/hoe-2.13.0" : {
 				"EAPI": "5",
-				"DEPEND": ">=dev-ruby/rdoc-3.10",
-				"RDEPEND": ">=dev-ruby/rdoc-3.10",
+				"IUSE": "test",
+				"DEPEND": "test? ( >=dev-ruby/rdoc-3.10 )",
+				"RDEPEND": "test? ( >=dev-ruby/rdoc-3.10 )",
 			},
 		}
 
@@ -52,6 +49,10 @@ class SlotOperatorUnsolvedTestCase(TestCase):
 			},
 		}
 
+		user_config = {
+			"make.conf" : ("FEATURES=test",)
+		}
+
 		world = ["net-libs/webkit-gtk", "dev-ruby/hoe"]
 
 		test_cases = (
@@ -59,12 +60,18 @@ class SlotOperatorUnsolvedTestCase(TestCase):
 			ResolverPlaygroundTestCase(
 				["@world"],
 				options = {"--update": True, "--deep": True},
-				success = False),
+				circular_dependency_solutions = {
+					'dev-ruby/hoe-2.13.0': frozenset([frozenset([('test', False)])]),
+					'dev-ruby/rdoc-3.12.1': frozenset([frozenset([('test', False)])])
+				},
+				success = False
+			),
 
 		)
 
 		playground = ResolverPlayground(ebuilds=ebuilds,
-			installed=installed, world=world, debug=False)
+			installed=installed, user_config=user_config,
+			world=world, debug=False)
 		try:
 			for test_case in test_cases:
 				playground.run_TestCase(test_case)


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-02-11 22:51 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-02-11 22:51 UTC (permalink / raw
  To: gentoo-commits

commit:     041f75fd030074d037458ade3462e0ed395e86c6
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Feb 11 22:51:09 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Feb 11 22:51:09 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=041f75fd

_add_pkg: fix existing_node early return

This fixes a case where it would return early, before calling
_add_slot_operator_dep, which could prevent slot-operator backtracking
from working properly. This makes SlotChangeWithoutRevBumpTestCase work
properly when we add an undesirable app-arch/libarchive-3.1.1 binary
package.

---
 pym/_emerge/depgraph.py                            |   52 +++++++++++--------
 .../resolver/test_slot_change_without_revbump.py   |   11 +++-
 2 files changed, 39 insertions(+), 24 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index c356010..7423ae0 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1653,24 +1653,25 @@ class depgraph(object):
 			if existing_node:
 				if existing_node_matches:
 					# The existing node can be reused.
-					if arg_atoms:
-						for parent_atom in arg_atoms:
-							parent, atom = parent_atom
-							self._dynamic_config.digraph.add(existing_node, parent,
-								priority=priority)
-							self._add_parent_atom(existing_node, parent_atom)
-					# If a direct circular dependency is not an unsatisfied
-					# buildtime dependency then drop it here since otherwise
-					# it can skew the merge order calculation in an unwanted
-					# way.
-					if existing_node != myparent or \
-						(priority.buildtime and not priority.satisfied):
-						self._dynamic_config.digraph.addnode(existing_node, myparent,
-							priority=priority)
-						if dep.atom is not None and dep.parent is not None:
-							self._add_parent_atom(existing_node,
-								(dep.parent, dep.atom))
-					return 1
+					if pkg != existing_node:
+						pkg = existing_node
+						previously_added = True
+						try:
+							arg_atoms = list(self._iter_atoms_for_pkg(pkg))
+						except InvalidDependString as e:
+							if not pkg.installed:
+								# should have been masked before
+								# it was selected
+								raise
+
+						if debug:
+							writemsg_level(
+								"%s%s %s\n" % ("Re-used Child:".ljust(15),
+								pkg, pkg_use_display(pkg,
+								self._frozen_config.myopts,
+								modified_use=self._pkg_use_enabled(pkg))),
+								level=logging.DEBUG, noiselevel=-1)
+
 				else:
 					self._add_slot_conflict(pkg)
 					if debug:
@@ -1721,12 +1722,19 @@ class depgraph(object):
 		if arg_atoms:
 			self._dynamic_config._set_nodes.add(pkg)
 
-		# Do this even when addme is False (--onlydeps) so that the
+		# Do this even for onlydeps, so that the
 		# parent/child relationship is always known in case
 		# self._show_slot_collision_notice() needs to be called later.
-		self._dynamic_config.digraph.add(pkg, myparent, priority=priority)
-		if dep.atom is not None and dep.parent is not None:
-			self._add_parent_atom(pkg, (dep.parent, dep.atom))
+		# If a direct circular dependency is not an unsatisfied
+		# buildtime dependency then drop it here since otherwise
+		# it can skew the merge order calculation in an unwanted
+		# way.
+		if pkg != dep.parent or \
+			(priority.buildtime and not priority.satisfied):
+			self._dynamic_config.digraph.add(pkg,
+				dep.parent, priority=priority)
+			if dep.atom is not None and dep.parent is not None:
+				self._add_parent_atom(pkg, (dep.parent, dep.atom))
 
 		if arg_atoms:
 			for parent_atom in arg_atoms:

diff --git a/pym/portage/tests/resolver/test_slot_change_without_revbump.py b/pym/portage/tests/resolver/test_slot_change_without_revbump.py
index dbd78dc..d85ff7e0 100644
--- a/pym/portage/tests/resolver/test_slot_change_without_revbump.py
+++ b/pym/portage/tests/resolver/test_slot_change_without_revbump.py
@@ -25,6 +25,13 @@ class SlotChangeWithoutRevBumpTestCase(TestCase):
 			},
 		}
 
+		binpkgs = {
+			"app-arch/libarchive-3.1.1" : {
+				"EAPI": "5",
+				"SLOT": "0"
+			},
+		}
+
 		installed = {
 			"app-arch/libarchive-3.1.1" : {
 				"EAPI": "5",
@@ -46,13 +53,13 @@ class SlotChangeWithoutRevBumpTestCase(TestCase):
 			# without revbump needs to trigger a rebuild.
 			ResolverPlaygroundTestCase(
 				["kde-base/ark"],
-				options = {"--oneshot": True},
+				options = {"--oneshot": True, "--usepkg": True},
 				success = True,
 				mergelist = ['app-arch/libarchive-3.1.1', "kde-base/ark-4.10.0"]),
 
 		)
 
-		playground = ResolverPlayground(ebuilds=ebuilds,
+		playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
 			installed=installed, world=world, debug=False)
 		try:
 			for test_case in test_cases:


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2013-02-11  1:58 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2013-02-11  1:58 UTC (permalink / raw
  To: gentoo-commits

commit:     d8a00c0d246115a5ae0738078bb900918309b0d2
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Feb 11 01:58:16 2013 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Feb 11 01:58:16 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=d8a00c0d

Trigger rebuild for sub-slot change, bug #456208.

If sub-slot changes without a revbump, trigger a rebuild so that
dependent packages will have the new sub-slot recorded in their
slot-operator deps. Hopefully this will fix bug #456208.

---
 pym/_emerge/depgraph.py                            |   78 +++++++++++++++++++-
 .../resolver/test_slot_change_without_revbump.py   |   62 ++++++++++++++++
 2 files changed, 139 insertions(+), 1 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 27104e1..34a4604 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1034,6 +1034,71 @@ class depgraph(object):
 
 		return found_update
 
+	def _slot_change_probe(self, dep):
+		"""
+		@rtype: bool
+		@return: True if dep.child should be rebuilt due to a change
+			in sub-slot (without revbump, as in bug #456208).
+		"""
+		if not (isinstance(dep.parent, Package) and \
+			not dep.parent.built and dep.child.built):
+			return None
+
+		root_config = self._frozen_config.roots[dep.root]
+		try:
+			unbuilt_child  = self._pkg(dep.child.cpv, "ebuild",
+				root_config, myrepo=dep.child.repo)
+		except PackageNotFound:
+			for unbuilt_child in self._iter_match_pkgs(root_config,
+				"ebuild", Atom("=%s" % (dep.child.cpv,))):
+				break
+			else:
+				return None
+
+		if unbuilt_child.slot == dep.child.slot and \
+			unbuilt_child.sub_slot == dep.child.sub_slot:
+			return None
+
+		return unbuilt_child
+
+	def _slot_change_backtrack(self, dep, new_child_slot):
+		child = dep.child
+		if "--debug" in self._frozen_config.myopts:
+			msg = []
+			msg.append("")
+			msg.append("")
+			msg.append("backtracking due to slot/sub-slot change:")
+			msg.append("   child package:  %s" % child)
+			msg.append("      child slot:  %s/%s" %
+				(child.slot, child.sub_slot))
+			msg.append("       new child:  %s" % new_child_slot)
+			msg.append("  new child slot:  %s/%s" %
+				(new_child_slot.slot, new_child_slot.sub_slot))
+			msg.append("   parent package: %s" % dep.parent)
+			msg.append("   atom: %s" % dep.atom)
+			msg.append("")
+			writemsg_level("\n".join(msg),
+				noiselevel=-1, level=logging.DEBUG)
+		backtrack_infos = self._dynamic_config._backtrack_infos
+		config = backtrack_infos.setdefault("config", {})
+
+		# mask unwanted binary packages if necessary
+		masks = {}
+		if not child.installed:
+			masks.setdefault(dep.child, {})["slot_operator_mask_built"] = None
+		if masks:
+			config.setdefault("slot_operator_mask_built", {}).update(masks)
+
+		# trigger replacement of installed packages if necessary
+		reinstalls = set()
+		if child.installed:
+			reinstalls.add((child.root, child.slot_atom))
+		if reinstalls:
+			config.setdefault("slot_operator_replace_installed",
+				set()).update(reinstalls)
+
+		self._dynamic_config._need_restart = True
+
 	def _slot_operator_update_backtrack(self, dep, new_child_slot=None):
 		if new_child_slot is None:
 			child = dep.child
@@ -1241,6 +1306,17 @@ class depgraph(object):
 		for slot_key, slot_info in self._dynamic_config._slot_operator_deps.items():
 
 			for dep in slot_info:
+
+				atom = dep.atom
+				if atom.slot_operator is None:
+					continue
+
+				if not atom.slot_operator_built:
+					new_child_slot = self._slot_change_probe(dep)
+					if new_child_slot is not None:
+						self._slot_change_backtrack(dep, new_child_slot)
+					continue
+
 				if not (dep.parent and
 					isinstance(dep.parent, Package) and dep.parent.built):
 					continue
@@ -1669,7 +1745,7 @@ class depgraph(object):
 
 		dep.child = pkg
 		if (not pkg.onlydeps and
-			dep.atom and dep.atom.slot_operator_built):
+			dep.atom and dep.atom.slot_operator is not None):
 			self._add_slot_operator_dep(dep)
 
 		recurse = deep is True or depth + 1 <= deep

diff --git a/pym/portage/tests/resolver/test_slot_change_without_revbump.py b/pym/portage/tests/resolver/test_slot_change_without_revbump.py
new file mode 100644
index 0000000..dbd78dc
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_change_without_revbump.py
@@ -0,0 +1,62 @@
+# Copyright 2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SlotChangeWithoutRevBumpTestCase(TestCase):
+
+	def testSlotChangeWithoutRevBump(self):
+
+		ebuilds = {
+			"app-arch/libarchive-3.1.1" : {
+				"EAPI": "5",
+				"SLOT": "0/13"
+			},
+			"app-arch/libarchive-3.0.4-r1" : {
+				"EAPI": "5",
+				"SLOT": "0"
+			},
+			"kde-base/ark-4.10.0" : {
+				"EAPI": "5",
+				"DEPEND": "app-arch/libarchive:=",
+				"RDEPEND": "app-arch/libarchive:="
+			},
+		}
+
+		installed = {
+			"app-arch/libarchive-3.1.1" : {
+				"EAPI": "5",
+				"SLOT": "0"
+			},
+
+			"kde-base/ark-4.10.0" : {
+				"EAPI": "5",
+				"DEPEND": "app-arch/libarchive:0/0=",
+				"RDEPEND": "app-arch/libarchive:0/0="
+			},
+		}
+
+		world = ["kde-base/ark"]
+
+		test_cases = (
+
+			# Demonstrate bug #456208, where a sub-slot change
+			# without revbump needs to trigger a rebuild.
+			ResolverPlaygroundTestCase(
+				["kde-base/ark"],
+				options = {"--oneshot": True},
+				success = True,
+				mergelist = ['app-arch/libarchive-3.1.1', "kde-base/ark-4.10.0"]),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2012-12-01 23:23 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2012-12-01 23:23 UTC (permalink / raw
  To: gentoo-commits

commit:     4b897286cf94c6ec2c556a75ea2e67798e1157cc
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Dec  1 23:22:59 2012 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat Dec  1 23:22:59 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=4b897286

emerge --depclean: rm unavailable slot bug 445506

---
 pym/_emerge/depgraph.py                            |    8 ++
 .../resolver/test_depclean_slot_unavailable.py     |   79 ++++++++++++++++++++
 2 files changed, 87 insertions(+), 0 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index f5fe435..65a94ab 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -4634,6 +4634,14 @@ class depgraph(object):
 					unmasked = [pkg for pkg in matches if not pkg.masks]
 					if unmasked:
 						matches = unmasked
+						if len(matches) > 1:
+							# Now account for packages for which existing
+							# ebuilds are masked or unavailable (bug #445506).
+							unmasked = [pkg for pkg in matches if
+								self._equiv_ebuild_visible(pkg)]
+							if unmasked:
+								matches = unmasked
+
 		pkg = matches[-1] # highest match
 		in_graph = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom)
 		return pkg, in_graph

diff --git a/pym/portage/tests/resolver/test_depclean_slot_unavailable.py b/pym/portage/tests/resolver/test_depclean_slot_unavailable.py
new file mode 100644
index 0000000..9d17189
--- /dev/null
+++ b/pym/portage/tests/resolver/test_depclean_slot_unavailable.py
@@ -0,0 +1,79 @@
+# Copyright 2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class DepcleanUnavailableSlotTestCase(TestCase):
+
+	def testDepcleanUnavailableSlot(self):
+		"""
+		Test bug #445506, where we want to remove the slot
+		for which the ebuild is no longer available, even
+		though its version is higher.
+		"""
+
+		ebuilds = {
+			"sys-kernel/gentoo-sources-3.0.53": {
+				"SLOT": "3.0.53",
+				"KEYWORDS": "x86"
+			},
+		}
+
+		installed = {
+			"sys-kernel/gentoo-sources-3.0.53": {
+				"SLOT": "3.0.53",
+				"KEYWORDS": "x86"
+			},
+			"sys-kernel/gentoo-sources-3.2.21": {
+				"SLOT": "3.2.21",
+				"KEYWORDS": "x86"
+			},
+		}
+
+		world = [ "sys-kernel/gentoo-sources" ]
+
+		test_cases = (
+
+			ResolverPlaygroundTestCase(
+				[],
+				options = {"--depclean": True},
+				success = True,
+				cleanlist = ["sys-kernel/gentoo-sources-3.2.21"]),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()
+
+		# Now make the newer version availale and verify that
+		# the lower version is depcleaned.
+		ebuilds.update({
+			"sys-kernel/gentoo-sources-3.2.21": {
+				"SLOT": "3.2.21",
+				"KEYWORDS": "x86"
+			},
+		})
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				[],
+				options = {"--depclean": True},
+				success = True,
+				cleanlist = ["sys-kernel/gentoo-sources-3.0.53"]),
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2012-10-26  6:06 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2012-10-26  6:06 UTC (permalink / raw
  To: gentoo-commits

commit:     cbe52a133e4480cefd22ca51dd0c133c09eb93f4
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Oct 26 06:06:17 2012 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Oct 26 06:06:17 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=cbe52a13

depgraph: trigger rebuild for unbuilt child

This will fix bug #439694, where built slot-operator deps failed
to trigger rebuilds if the deps were initially broken.

---
 pym/_emerge/depgraph.py                            |    4 ++--
 .../resolver/test_slot_operator_unsatisfied.py     |    7 +++++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 41bdc8e..e129a81 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1192,7 +1192,7 @@ class depgraph(object):
 		for slot_key, slot_info in self._dynamic_config._slot_operator_deps.items():
 
 			for dep in slot_info:
-				if not (dep.child.built and dep.parent and
+				if not (dep.parent and
 					isinstance(dep.parent, Package) and dep.parent.built):
 					continue
 
@@ -1619,7 +1619,7 @@ class depgraph(object):
 			not (deep is not True and depth > deep))
 
 		dep.child = pkg
-		if (not pkg.onlydeps and pkg.built and
+		if (not pkg.onlydeps and
 			dep.atom and dep.atom.slot_operator_built):
 			self._add_slot_operator_dep(dep)
 

diff --git a/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py b/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py
index 14631eb..e3b53d1 100644
--- a/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py
+++ b/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py
@@ -43,13 +43,16 @@ class SlotOperatorUnsatisfiedTestCase(TestCase):
 		test_cases = (
 
 			# Demonstrate bug #439694, where a broken slot-operator
-			# sub-slot dependency fails to trigger rebuild.
+			# sub-slot dependency needs to trigger a rebuild.
 			ResolverPlaygroundTestCase(
 				["@world"],
 				options = {"--update": True, "--deep": True},
 				success = True,
-				mergelist = ["app-misc/A-1"]),
+				mergelist = ["app-misc/B-0"]),
 
+			# This doesn't trigger a rebuild, since there's no version
+			# change to trigger complete graph mode, and initially
+			# unsatisfied deps are ignored in complete graph mode anyway.
 			ResolverPlaygroundTestCase(
 				["app-misc/A"],
 				options = {"--oneshot": True},


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2012-10-26  4:57 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2012-10-26  4:57 UTC (permalink / raw
  To: gentoo-commits

commit:     57604eaf869b544aac9e8ed2e270dcc6be3cf739
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Oct 26 04:57:01 2012 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Oct 26 04:57:01 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=57604eaf

depgraph: no multislot tweak for built slot op

The multislot tweak from bug #220341 (see commit
65a421ae35acd5639ad1258e220754a85e55de6e) triggered erroneous matches
for built slot-operator deps, causing the depgraph to treat unsatisfied
built slot-operator deps as if they were satisfied (one of the issues
uncovered in bug #439694).

---
 pym/_emerge/depgraph.py                            |    3 ++-
 .../resolver/test_slot_operator_unsatisfied.py     |    4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 0722fac..41bdc8e 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3804,7 +3804,8 @@ class depgraph(object):
 		# the newly built package still won't have the expected slot.
 		# Therefore, assume that such SLOT dependencies are already
 		# satisfied rather than forcing a rebuild.
-		if not matched_something and installed and atom.slot is not None:
+		if not matched_something and installed and \
+			atom.slot is not None and not atom.slot_operator_built:
 
 			if "remove" in self._dynamic_config.myparams:
 				# We need to search the portdbapi, which is not in our

diff --git a/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py b/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py
index fe8893f..14631eb 100644
--- a/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py
+++ b/pym/portage/tests/resolver/test_slot_operator_unsatisfied.py
@@ -43,12 +43,12 @@ class SlotOperatorUnsatisfiedTestCase(TestCase):
 		test_cases = (
 
 			# Demonstrate bug #439694, where a broken slot-operator
-			# sub-slot dependency fails to be recognized.
+			# sub-slot dependency fails to trigger rebuild.
 			ResolverPlaygroundTestCase(
 				["@world"],
 				options = {"--update": True, "--deep": True},
 				success = True,
-				mergelist = []),
+				mergelist = ["app-misc/A-1"]),
 
 			ResolverPlaygroundTestCase(
 				["app-misc/A"],


^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2012-07-05  3:16 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2012-07-05  3:16 UTC (permalink / raw
  To: gentoo-commits

commit:     02bcf332a88bbf25b9e0391b1a6d781ab4bbe0b9
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Thu Jul  5 03:16:40 2012 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Jul  5 03:16:40 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=02bcf332

Rebuild for slot-abi downgrades, bug #424651.

---
 pym/_emerge/depgraph.py                            |  109 +++++++---
 .../tests/resolver/test_slot_abi_downgrade.py      |  225 ++++++++++++++++++++
 2 files changed, 298 insertions(+), 36 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 480cb90..f819aef 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -24,7 +24,8 @@ from portage.dep import Atom, best_match_to_list, extract_affecting_use, \
 	_repo_separator
 from portage.dep._slot_abi import ignore_built_slot_abi_deps
 from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use
-from portage.exception import InvalidAtom, InvalidDependString, PortageException
+from portage.exception import (InvalidAtom, InvalidDependString,
+	PackageNotFound, PortageException)
 from portage.output import colorize, create_color_func, \
 	darkgreen, green
 bad = create_color_func("BAD")
@@ -1047,6 +1048,7 @@ class depgraph(object):
 			return None
 
 		debug = "--debug" in self._frozen_config.myopts
+		want_downgrade = None
 
 		for replacement_parent in self._iter_similar_available(dep.parent,
 			dep.parent.slot_atom):
@@ -1087,10 +1089,13 @@ class depgraph(object):
 						if pkg.slot != dep.child.slot:
 							continue
 						if pkg < dep.child:
+							if want_downgrade is None:
+								want_downgrade = self._downgrade_probe(dep.child)
 							# be careful not to trigger a rebuild when
 							# the only version available with a
 							# different slot_abi is an older version
-							continue
+							if not want_downgrade:
+								continue
 
 					if debug:
 						msg = []
@@ -1122,12 +1127,33 @@ class depgraph(object):
 
 		return None
 
+	def _downgrade_probe(self, pkg):
+		"""
+		Detect cases where a downgrade of the given package is considered
+		desirable due to the current version being masked or unavailable.
+		"""
+		available_pkg = None
+		for available_pkg in self._iter_similar_available(pkg,
+			pkg.slot_atom):
+			if available_pkg >= pkg:
+				# There's an available package of the same or higher
+				# version, so downgrade seems undesirable.
+				return False
+
+		return available_pkg is not None
+
 	def _iter_similar_available(self, graph_pkg, atom):
 		"""
 		Given a package that's in the graph, do a rough check to
 		see if a similar package is available to install. The given
 		graph_pkg itself may be yielded only if it's not installed.
 		"""
+
+		usepkgonly = "--usepkgonly" in self._frozen_config.myopts
+		useoldpkg_atoms = self._frozen_config.useoldpkg_atoms
+		use_ebuild_visibility = self._frozen_config.myopts.get(
+			'--use-ebuild-visibility', 'n') != 'n'
+
 		for pkg in self._iter_match_pkgs_any(
 			graph_pkg.root_config, atom):
 			if pkg.cp != graph_pkg.cp:
@@ -1142,6 +1168,14 @@ class depgraph(object):
 				continue
 			if not self._pkg_visibility_check(pkg):
 				continue
+			if pkg.built:
+				if self._equiv_binary_installed(pkg):
+					continue
+				if not (not use_ebuild_visibility and
+					(usepkgonly or useoldpkg_atoms.findAtomForPackage(
+					pkg, modified_use=self._pkg_use_enabled(pkg)))) and \
+					not self._equiv_ebuild_visible(pkg):
+					continue
 			yield pkg
 
 	def _slot_abi_trigger_reinstalls(self):
@@ -3811,6 +3845,38 @@ class depgraph(object):
 
 		return not arg
 
+	def _equiv_ebuild_visible(self, pkg, autounmask_level=None):
+		try:
+			pkg_eb = self._pkg(
+				pkg.cpv, "ebuild", pkg.root_config, myrepo=pkg.repo)
+		except portage.exception.PackageNotFound:
+			pkg_eb_visible = False
+			for pkg_eb in self._iter_match_pkgs(pkg.root_config,
+				"ebuild", Atom("=%s" % (pkg.cpv,))):
+				if self._pkg_visibility_check(pkg_eb, autounmask_level):
+					pkg_eb_visible = True
+					break
+			if not pkg_eb_visible:
+				return False
+		else:
+			if not self._pkg_visibility_check(pkg_eb, autounmask_level):
+				return False
+
+		return True
+
+	def _equiv_binary_installed(self, pkg):
+		build_time = pkg.metadata.get('BUILD_TIME')
+		if not build_time:
+			return False
+
+		try:
+			inst_pkg = self._pkg(pkg.cpv, "installed",
+				pkg.root_config, installed=True)
+		except PackageNotFound:
+			return False
+
+		return build_time == inst_pkg.metadata.get('BUILD_TIME')
+
 	class _AutounmaskLevel(object):
 		__slots__ = ("allow_use_changes", "allow_unstable_keywords", "allow_license_changes", \
 			"allow_missing_keywords", "allow_unmasks")
@@ -4241,22 +4307,9 @@ class depgraph(object):
 								if not use_ebuild_visibility and (usepkgonly or useoldpkg):
 									if pkg.installed and pkg.masks:
 										continue
-								else:
-									try:
-										pkg_eb = self._pkg(
-											pkg.cpv, "ebuild", root_config, myrepo=pkg.repo)
-									except portage.exception.PackageNotFound:
-										pkg_eb_visible = False
-										for pkg_eb in self._iter_match_pkgs(pkg.root_config,
-											"ebuild", Atom("=%s" % (pkg.cpv,))):
-											if self._pkg_visibility_check(pkg_eb, autounmask_level):
-												pkg_eb_visible = True
-												break
-										if not pkg_eb_visible:
-											continue
-									else:
-										if not self._pkg_visibility_check(pkg_eb, autounmask_level):
-											continue
+								elif not self._equiv_ebuild_visible(pkg,
+									autounmask_level=autounmask_level):
+									continue
 
 					# Calculation of USE for unbuilt ebuilds is relatively
 					# expensive, so it is only performed lazily, after the
@@ -7137,24 +7190,8 @@ class _dep_check_composite_db(dbapi):
 			if not avoid_update:
 				if not use_ebuild_visibility and usepkgonly:
 					return False
-				else:
-					try:
-						pkg_eb = self._depgraph._pkg(
-							pkg.cpv, "ebuild", pkg.root_config,
-							myrepo=pkg.repo)
-					except portage.exception.PackageNotFound:
-						pkg_eb_visible = False
-						for pkg_eb in self._depgraph._iter_match_pkgs(
-							pkg.root_config, "ebuild",
-							Atom("=%s" % (pkg.cpv,))):
-							if self._depgraph._pkg_visibility_check(pkg_eb):
-								pkg_eb_visible = True
-								break
-						if not pkg_eb_visible:
-							return False
-					else:
-						if not self._depgraph._pkg_visibility_check(pkg_eb):
-							return False
+				elif not self._depgraph._equiv_ebuild_visible(pkg):
+					return False
 
 		in_graph = self._depgraph._dynamic_config._slot_pkg_map[
 			self._root].get(pkg.slot_atom)

diff --git a/pym/portage/tests/resolver/test_slot_abi_downgrade.py b/pym/portage/tests/resolver/test_slot_abi_downgrade.py
new file mode 100644
index 0000000..45a7555
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_abi_downgrade.py
@@ -0,0 +1,225 @@
+# Copyright 2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class SlotAbiDowngradeTestCase(TestCase):
+
+	def __init__(self, *args, **kwargs):
+		super(SlotAbiDowngradeTestCase, self).__init__(*args, **kwargs)
+
+	def testSubSlot(self):
+		ebuilds = {
+			"dev-libs/icu-4.8" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/48"
+			},
+			"dev-libs/libxml2-2.7.8" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/icu:=",
+				"RDEPEND": "dev-libs/icu:="
+			},
+		}
+		binpkgs = {
+			"dev-libs/icu-49" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/49"
+			},
+			"dev-libs/icu-4.8" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/48"
+			},
+			"dev-libs/libxml2-2.7.8" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/icu:0/49=",
+				"RDEPEND": "dev-libs/icu:0/49="
+			},
+		}
+		installed = {
+			"dev-libs/icu-49" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "0/49"
+			},
+			"dev-libs/libxml2-2.7.8" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/icu:0/49=",
+				"RDEPEND": "dev-libs/icu:0/49="
+			},
+		}
+
+		world = ["dev-libs/libxml2"]
+
+		test_cases = (
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True},
+				success = True,
+				mergelist = ["dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True, "--ignore-built-slot-abi-deps": "y"},
+				success = True,
+				mergelist = ["dev-libs/icu-4.8"]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True, "--usepkg": True},
+				success = True,
+				mergelist = ["[binary]dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/icu"],
+				options = {"--oneshot": True, "--usepkgonly": True},
+				success = True,
+				mergelist = ["[binary]dev-libs/icu-49"]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True},
+				success = True,
+				mergelist = ["dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--ignore-built-slot-abi-deps": "y"},
+				success = True,
+				mergelist = ["dev-libs/icu-4.8"]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--usepkg": True},
+				success = True,
+				mergelist = ["[binary]dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--usepkgonly": True},
+				success = True,
+				mergelist = []),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()
+
+	def testWholeSlotSubSlotMix(self):
+		ebuilds = {
+			"dev-libs/glib-1.2.10" : {
+				"SLOT": "1"
+			},
+			"dev-libs/glib-2.30.2" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "2/2.30"
+			},
+			"dev-libs/dbus-glib-0.98" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/glib:2=",
+				"RDEPEND": "dev-libs/glib:2="
+			},
+		}
+		binpkgs = {
+			"dev-libs/glib-1.2.10" : {
+				"SLOT": "1"
+			},
+			"dev-libs/glib-2.30.2" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "2/2.30"
+			},
+			"dev-libs/glib-2.32.3" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "2/2.32"
+			},
+			"dev-libs/dbus-glib-0.98" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/glib:2/2.32=",
+				"RDEPEND": "dev-libs/glib:2/2.32="
+			},
+		}
+		installed = {
+			"dev-libs/glib-1.2.10" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "1"
+			},
+			"dev-libs/glib-2.32.3" : {
+				"EAPI": "4-slot-abi",
+				"SLOT": "2/2.32"
+			},
+			"dev-libs/dbus-glib-0.98" : {
+				"EAPI": "4-slot-abi",
+				"DEPEND":  "dev-libs/glib:2/2.32=",
+				"RDEPEND": "dev-libs/glib:2/2.32="
+			},
+		}
+
+		world = ["dev-libs/glib:1", "dev-libs/dbus-glib"]
+
+		test_cases = (
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/glib"],
+				options = {"--oneshot": True},
+				success = True,
+				mergelist = ["dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/glib"],
+				options = {"--oneshot": True, "--ignore-built-slot-abi-deps": "y"},
+				success = True,
+				mergelist = ["dev-libs/glib-2.30.2"]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/glib"],
+				options = {"--oneshot": True, "--usepkg": True},
+				success = True,
+				mergelist = ["[binary]dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/glib"],
+				options = {"--oneshot": True, "--usepkgonly": True},
+				success = True,
+				mergelist = ["[binary]dev-libs/glib-2.32.3"]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True},
+				success = True,
+				mergelist = ["dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--ignore-built-slot-abi-deps": "y"},
+				success = True,
+				mergelist = ["dev-libs/glib-2.30.2"]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--usepkg": True},
+				success = True,
+				mergelist = ["[binary]dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True, "--usepkgonly": True},
+				success = True,
+				mergelist = []),
+
+		)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
+			installed=installed, world=world, debug=False)
+		try:
+			for test_case in test_cases:
+				playground.run_TestCase(test_case)
+				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+		finally:
+			playground.cleanup()



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2012-06-15 23:04 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2012-06-15 23:04 UTC (permalink / raw
  To: gentoo-commits

commit:     b363b5342ac918f06e8752e702e68363d1388cdb
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Jun 15 23:03:59 2012 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Jun 15 23:03:59 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=b363b534

Add USE + license autounmask for bug #420847.

---
 pym/_emerge/depgraph.py                       |    9 +++++++--
 pym/portage/tests/resolver/test_autounmask.py |   12 ++++++------
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 2e98be8..5eece98 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3522,7 +3522,8 @@ class depgraph(object):
 		"""
 		Iterate over the different allowed things to unmask.
 
-		1. USE
+		0. USE
+		1. USE + license
 		2. USE + ~arch + license
 		3. USE + ~arch + license + missing keywords
 		4. USE + ~arch + license + masks
@@ -3541,8 +3542,12 @@ class depgraph(object):
 		autounmask_level = self._AutounmaskLevel()
 
 		autounmask_level.allow_use_changes = True
+		yield autounmask_level
 
-		for only_use_changes in (True, False):
+		autounmask_level.allow_license_changes = True
+		yield autounmask_level
+
+		for only_use_changes in (False,):
 
 			autounmask_level.allow_unstable_keywords = (not only_use_changes)
 			autounmask_level.allow_license_changes = (not only_use_changes)

diff --git a/pym/portage/tests/resolver/test_autounmask.py b/pym/portage/tests/resolver/test_autounmask.py
index c75a174..84182ba 100644
--- a/pym/portage/tests/resolver/test_autounmask.py
+++ b/pym/portage/tests/resolver/test_autounmask.py
@@ -321,12 +321,12 @@ class AutounmaskTestCase(TestCase):
 					license_changes = { "dev-libs/D-1": set(["TEST"]), "dev-libs/E-1": set(["TEST"]), "dev-libs/E-2": set(["TEST"]), "dev-libs/F-1": set(["TEST"]) }),
 
 				#Test license only for bug #420847
-				#ResolverPlaygroundTestCase(
-					#["dev-java/sun-jdk"],
-					#options = {"--autounmask": True},
-					#success = False,
-					#mergelist = ["dev-java/sun-jdk-1.6.0.31"],
-					#license_changes = { "dev-java/sun-jdk-1.6.0.31": set(["TEST"]) }),
+				ResolverPlaygroundTestCase(
+					["dev-java/sun-jdk"],
+					options = {"--autounmask": True},
+					success = False,
+					mergelist = ["dev-java/sun-jdk-1.6.0.31"],
+					license_changes = { "dev-java/sun-jdk-1.6.0.31": set(["TEST"]) }),
 			)
 
 		playground = ResolverPlayground(ebuilds=ebuilds)



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2012-02-26 10:00 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2012-02-26 10:00 UTC (permalink / raw
  To: gentoo-commits

commit:     b684a8d3a73da02423d090c58c0f1536c25b093b
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Sun Feb 26 09:34:31 2012 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Feb 26 09:59:00 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=b684a8d3

autounmask: Avoid unmasking live versions if possible

Before this patch the allowed changes were:

1. USE
2. USE + ~arch + license
3. USE + ~arch + license + missing keywords + masks

With this patch:

1. USE
2. USE + ~arch + license
3. USE + ~arch + license + missing keywords
4. USE + ~arch + license + masks
5. USE + ~arch + license + missing keywords + masks

This avoids unmasking live versions, which are typically masked
and have missing keywords to be avoided if there is a regular
masked version available.

---
 pym/_emerge/depgraph.py                       |   33 +++++++++++++----
 pym/portage/tests/resolver/test_autounmask.py |   47 ++++++++++++++++++++++++-
 2 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index a05c17e..e4310b4 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3505,15 +3505,31 @@ class depgraph(object):
 		return True
 
 	class _AutounmaskLevel(object):
-		__slots__ = ("allow_use_changes", "allow_unstable_keywords", "allow_license_changes", "allow_unmasks")
+		__slots__ = ("allow_use_changes", "allow_unstable_keywords", "allow_license_changes", \
+			"allow_missing_keywords", "allow_unmasks")
 
 		def __init__(self):
 			self.allow_use_changes = False
-			self.allow_unstable_keywords = False
 			self.allow_license_changes = False
+			self.allow_unstable_keywords = False
+			self.allow_missing_keywords = False
 			self.allow_unmasks = False
 
 	def _autounmask_levels(self):
+		"""
+		Iterate over the different allowed things to unmask.
+
+		1. USE
+		2. USE + ~arch + license
+		3. USE + ~arch + license + missing keywords
+		4. USE + ~arch + license + masks
+		5. USE + ~arch + license + missing keywords + masks
+
+		Some thoughts:
+			* Do least invasive changes first.
+			* Try unmasking alone before unmasking + missing keywords
+				to avoid -9999 versions if possible
+		"""
 
 		if self._dynamic_config._autounmask is not True:
 			return
@@ -3528,11 +3544,13 @@ class depgraph(object):
 			autounmask_level.allow_unstable_keywords = (not only_use_changes)
 			autounmask_level.allow_license_changes = (not only_use_changes)
 
-			for allow_unmasks in (False, True):
-				if allow_unmasks and (only_use_changes or autounmask_keep_masks):
-					continue
+			for missing_keyword, unmask in ((False,False), (True, False), (False, True), (True, True)):
+
+				if (only_use_changes or autounmask_keep_masks) and (missing_keyword or unmask):
+					break
 
-				autounmask_level.allow_unmasks = allow_unmasks
+				autounmask_level.allow_missing_keywords = missing_keyword
+				autounmask_level.allow_unmasks = unmask
 
 				yield autounmask_level
 
@@ -3634,9 +3652,8 @@ class depgraph(object):
 			#Package has already been unmasked.
 			return True
 
-		#We treat missing keywords in the same way as masks.
 		if (masked_by_unstable_keywords and not autounmask_level.allow_unstable_keywords) or \
-			(masked_by_missing_keywords and not autounmask_level.allow_unmasks) or \
+			(masked_by_missing_keywords and not autounmask_level.allow_missing_keywords) or \
 			(masked_by_p_mask and not autounmask_level.allow_unmasks) or \
 			(missing_licenses and not autounmask_level.allow_license_changes):
 			#We are not allowed to do the needed changes.

diff --git a/pym/portage/tests/resolver/test_autounmask.py b/pym/portage/tests/resolver/test_autounmask.py
index 3da1c25..46dbab1 100644
--- a/pym/portage/tests/resolver/test_autounmask.py
+++ b/pym/portage/tests/resolver/test_autounmask.py
@@ -391,7 +391,11 @@ class AutounmaskTestCase(TestCase):
 
 
 	def testAutounmaskKeepMasks(self):
-
+		"""
+		Ensure that we try to use a masked version with keywords before trying
+		masked version with missing keywords (prefer masked regular version
+		over -9999 version).
+		"""
 		ebuilds = {
 			"app-text/A-1": {},
 			}
@@ -427,3 +431,44 @@ class AutounmaskTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+
+	def testAutounmask9999(self):
+
+		ebuilds = {
+			"dev-libs/A-1": { },
+			"dev-libs/A-2": { },
+			"dev-libs/A-9999": { "KEYWORDS": "" },
+			"dev-libs/B-1": { "DEPEND": ">=dev-libs/A-2" },
+			"dev-libs/C-1": { "DEPEND": ">=dev-libs/A-3" },
+			}
+
+		profile = {
+			"package.mask":
+				(
+					">=dev-libs/A-2",
+				),
+		}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["dev-libs/B"],
+				success = False,
+				mergelist = ["dev-libs/A-2", "dev-libs/B-1"],
+				needed_p_mask_changes = set(["dev-libs/A-2"])),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/C"],
+				success = False,
+				mergelist = ["dev-libs/A-9999", "dev-libs/C-1"],
+				unstable_keywords = set(["dev-libs/A-9999"]),
+				needed_p_mask_changes = set(["dev-libs/A-9999"])),
+			)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, profile=profile)
+		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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-11-18  1:26 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-11-18  1:26 UTC (permalink / raw
  To: gentoo-commits

commit:     458ce208ed25f2d17666926585e14da6166eb9d7
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Nov 18 01:26:01 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Nov 18 01:26:01 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=458ce208

depgraph: don't merge portage asap

There's no need to do this anymore, because we don't restart since
commit d3f704a425a50b5cfa997a25866929b30f1b7d0f.

---
 pym/_emerge/depgraph.py                        |    9 ---------
 pym/portage/tests/resolver/test_merge_order.py |    8 --------
 2 files changed, 0 insertions(+), 17 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 65fe1fd..484206e 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -4996,15 +4996,6 @@ class depgraph(object):
 		if replacement_portage == running_portage:
 			replacement_portage = None
 
-		if replacement_portage is not None and \
-			(running_portage is None or \
-			running_portage.cpv != replacement_portage.cpv or \
-			'9999' in replacement_portage.cpv or \
-			'git' in replacement_portage.inherited or \
-			'git-2' in replacement_portage.inherited):
-			# update from running_portage to replacement_portage asap
-			asap_nodes.append(replacement_portage)
-
 		if running_portage is not None:
 			try:
 				portage_rdepend = self._select_atoms_highest_available(

diff --git a/pym/portage/tests/resolver/test_merge_order.py b/pym/portage/tests/resolver/test_merge_order.py
index 0a52c81..adff84d 100644
--- a/pym/portage/tests/resolver/test_merge_order.py
+++ b/pym/portage/tests/resolver/test_merge_order.py
@@ -410,14 +410,6 @@ class MergeOrderTestCase(TestCase):
 				["media-video/libav"],
 				success=True,
 				mergelist = ['media-video/libav-0.7_pre20110327', 'media-video/ffmpeg-0.7_rc1', '!media-video/ffmpeg']),
-			# Test that PORTAGE_PACKAGE_ATOM is merged asap. Optimally,
-			# satisfied deps are always merged after the asap nodes that
-			# depend on them.
-			ResolverPlaygroundTestCase(
-				["dev-lang/python", portage.const.PORTAGE_PACKAGE_ATOM],
-				success = True,
-				all_permutations = True,
-				mergelist = ['app-admin/eselect-python-20100321', 'sys-apps/portage-2.1.9.49', 'dev-lang/python-3.2']),
 			# Test that OS_HEADERS_PACKAGE_ATOM and LIBC_PACKAGE_ATOM
 			# are merged asap, in order to account for implicit
 			# dependencies. See bug #303567. Optimally, satisfied deps



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-09-30  8:30 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-09-30  8:30 UTC (permalink / raw
  To: gentoo-commits

commit:     d1a3c0f5ab81d1dbf70c0b8e5322cfb2d11b8ce7
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Sep 30 08:30:00 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Sep 30 08:30:00 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=d1a3c0f5

depgraph: pull in new-style virtuals more

This causes new-style virtuals to get pulled in for virtuals that are
already satisfied by installed old-style virtuals. This case is common,
due to PROVIDE being (removed without revision bump) from lots of
ebuilds.

---
 pym/_emerge/depgraph.py                            |    6 ++
 pym/portage/tests/resolver/ResolverPlayground.py   |    6 ++
 .../tests/resolver/test_virtual_transition.py      |   51 ++++++++++++++++++++
 3 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index da61709..9638ce9 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3953,6 +3953,12 @@ class depgraph(object):
 						e_pkg = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom)
 						if not e_pkg:
 							break
+
+						if e_pkg.cp != atom_cp and \
+							self._have_new_virt(root, atom_cp):
+							# pull in a new-style virtual instead
+							break
+
 						# Use PackageSet.findAtomForPackage()
 						# for PROVIDE support.
 						if atom_set.findAtomForPackage(e_pkg, modified_use=self._pkg_use_enabled(e_pkg)):

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index a73f632..9630008 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -142,6 +142,7 @@ class ResolverPlayground(object):
 			homepage = metadata.pop("HOMEPAGE", None)
 			src_uri = metadata.pop("SRC_URI", None)
 			iuse = metadata.pop("IUSE", "")
+			provide = metadata.pop("PROVIDE", None)
 			depend = metadata.pop("DEPEND", "")
 			rdepend = metadata.pop("RDEPEND", None)
 			pdepend = metadata.pop("PDEPEND", None)
@@ -174,6 +175,8 @@ class ResolverPlayground(object):
 			f.write('SLOT="' + str(slot) + '"\n')
 			f.write('KEYWORDS="' + str(keywords) + '"\n')
 			f.write('IUSE="' + str(iuse) + '"\n')
+			if provide is not None:
+				f.write('PROVIDE="%s"\n' % provide)
 			f.write('DEPEND="' + str(depend) + '"\n')
 			if rdepend is not None:
 				f.write('RDEPEND="' + str(rdepend) + '"\n')
@@ -224,6 +227,7 @@ class ResolverPlayground(object):
 			keywords = metadata.pop("KEYWORDS", "~x86")
 			iuse = metadata.pop("IUSE", "")
 			use = metadata.pop("USE", "")
+			provide = metadata.pop("PROVIDE", None)
 			depend = metadata.pop("DEPEND", "")
 			rdepend = metadata.pop("RDEPEND", None)
 			pdepend = metadata.pop("PDEPEND", None)
@@ -248,6 +252,8 @@ class ResolverPlayground(object):
 			write_key("KEYWORDS", keywords)
 			write_key("IUSE", iuse)
 			write_key("USE", use)
+			if provide is not None:
+				write_key("PROVIDE", provide)
 			write_key("DEPEND", depend)
 			if rdepend is not None:
 				write_key("RDEPEND", rdepend)

diff --git a/pym/portage/tests/resolver/test_virtual_transition.py b/pym/portage/tests/resolver/test_virtual_transition.py
new file mode 100644
index 0000000..3f4171e
--- /dev/null
+++ b/pym/portage/tests/resolver/test_virtual_transition.py
@@ -0,0 +1,51 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class VirtualTransitionTestCase(TestCase):
+
+	def testVirtualTransition(self):
+		ebuilds = {
+			"kde-base/kcron-4.7.1" : {"RDEPEND": "virtual/cron" },
+			"sys-process/vixie-cron-4.1-r11": {},
+			"virtual/cron-0" : {"RDEPEND": "sys-process/vixie-cron" },
+		}
+		installed = {
+			"kde-base/kcron-4.7.1" : {"RDEPEND": "virtual/cron" },
+			"sys-process/vixie-cron-4.1-r11" : {"PROVIDE" : "virtual/cron"},
+		}
+
+		world = ["kde-base/kcron", "sys-process/vixie-cron"]
+
+		test_cases = (
+
+			# Pull in a new-style virtual, even though there is an installed
+			# old-style virtual to satisfy the virtual/cron dep. This case
+			# is common, due to PROVIDE being removed (without revision bump)
+			# from lots of ebuilds.
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update": True, "--deep": True},
+				success = True,
+				mergelist = ["virtual/cron-0"]),
+
+			# Make sure that depclean is satisfied with the installed
+			# old-style virutal.
+			ResolverPlaygroundTestCase(
+				[],
+				options = {"--depclean": True},
+				success = True,
+				cleanlist = []),
+		)
+
+		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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-09-19  3:05 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-09-19  3:05 UTC (permalink / raw
  To: gentoo-commits

commit:     81e0f87b5c1da0ebc531d89846135b72743e71e0
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Sep 19 03:05:35 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Sep 19 03:05:35 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=81e0f87b

Test --prune with virtual slots.

---
 pym/_emerge/actions.py                           |    3 ++-
 pym/portage/tests/resolver/ResolverPlayground.py |   10 ++++++++--
 pym/portage/tests/resolver/test_virtual_slot.py  |    7 +++++++
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
index 82adca7..08f70df 100644
--- a/pym/_emerge/actions.py
+++ b/pym/_emerge/actions.py
@@ -706,7 +706,8 @@ def calc_depclean(settings, trees, ldpath_mtimes,
 		# that are also matched by argument atoms, but do not remove
 		# them if they match the highest installed version.
 		for pkg in vardb:
-			spinner.update()
+			if spinner is not None:
+				spinner.update()
 			pkgs_for_cp = vardb.match_pkgs(pkg.cp)
 			if not pkgs_for_cp or pkg not in pkgs_for_cp:
 				raise AssertionError("package expected in matches: " + \

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index adf03d2..a73f632 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -511,6 +511,12 @@ class ResolverPlayground(object):
 		if self.debug:
 			options["--debug"] = True
 
+		if action is None:
+			if options.get("--depclean"):
+				action = "depclean"
+			elif options.get("--prune"):
+				action = "prune"
+
 		global_noiselimit = portage.util.noiselimit
 		global_emergelog_disable = _emerge.emergelog._disable
 		try:
@@ -519,10 +525,10 @@ class ResolverPlayground(object):
 				portage.util.noiselimit = -2
 			_emerge.emergelog._disable = True
 
-			if options.get("--depclean"):
+			if action in ("depclean", "prune"):
 				rval, cleanlist, ordered, req_pkg_count = \
 					calc_depclean(self.settings, self.trees, None,
-					options, "depclean", InternalPackageSet(initial_atoms=atoms, allow_wildcard=True), None)
+					options, action, InternalPackageSet(initial_atoms=atoms, allow_wildcard=True), None)
 				result = ResolverPlaygroundDepcleanResult( \
 					atoms, rval, cleanlist, ordered, req_pkg_count)
 			else:

diff --git a/pym/portage/tests/resolver/test_virtual_slot.py b/pym/portage/tests/resolver/test_virtual_slot.py
index 4ea6677..1b19d77 100644
--- a/pym/portage/tests/resolver/test_virtual_slot.py
+++ b/pym/portage/tests/resolver/test_virtual_slot.py
@@ -123,6 +123,13 @@ class VirtualSlotResolverTestCase(TestCase):
 				options = {"--depclean" : True},
 				success = True,
 				cleanlist = []),
+
+			# Prune redundant lower slots, even if they are in world.
+			ResolverPlaygroundTestCase(
+				[],
+				options = {"--prune" : True},
+				success = True,
+				cleanlist = ['virtual/jdk-1.6.0', 'dev-java/icedtea-6.1.10.3']),
 		)
 
 		playground = ResolverPlayground(



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-09-18 20:08 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-09-18 20:08 UTC (permalink / raw
  To: gentoo-commits

commit:     57cc4e3e8991e7c4394d1dff7698aa62ed2a286b
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Sun Sep 18 19:30:46 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Sep 18 20:02:19 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=57cc4e3e

autounmask: Ensure a suitable parent is displayed in the dep chain

Fixes bug 375265.

---
 pym/_emerge/depgraph.py                       |   34 +++++++++++++-
 pym/portage/tests/resolver/test_autounmask.py |   64 +++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 1 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index fbbae1e..400207e 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -18,7 +18,8 @@ from portage import os, OrderedDict
 from portage import _unicode_decode, _unicode_encode, _encodings
 from portage.const import PORTAGE_PACKAGE_ATOM, USER_CONFIG_PATH
 from portage.dbapi import dbapi
-from portage.dep import Atom, extract_affecting_use, check_required_use, human_readable_required_use, _repo_separator
+from portage.dep import Atom, best_match_to_list, extract_affecting_use, \
+	check_required_use, human_readable_required_use, _repo_separator
 from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use
 from portage.exception import InvalidAtom, InvalidDependString, PortageException
 from portage.output import colorize, create_color_func, \
@@ -2694,6 +2695,37 @@ class depgraph(object):
 
 			dep_chain.append((pkg_name, node.type_name))
 
+
+		# To build a dep chain for the given package we take
+		# "random" parents form the digraph, except for the
+		# first package, because we want a parent that forced
+		# the corresponding change (i.e '>=foo-2', instead 'foo').
+
+		traversed_nodes.add(start_node)
+
+		start_node_parent_atoms = {}
+		for ppkg, patom in all_parents[node]:
+			# Get a list of suitable atoms. For use deps
+			# (aka unsatisfied_dependency is not None) we
+			# need that the start_node doesn't match the atom.
+			if not unsatisfied_dependency or \
+				not InternalPackageSet(initial_atoms=(patom,)).findAtomForPackage(start_node):
+				start_node_parent_atoms.setdefault(patom, []).append(ppkg)
+
+		if start_node_parent_atoms:
+			# If there are parents in all_parents then use one of them.
+			# If not, then this package got pulled in by an Arg and
+			# will be correctly handled by the code that handles later
+			# packages in the dep chain.
+			best_match = best_match_to_list(node.cpv, start_node_parent_atoms)
+
+			child = node
+			for ppkg in start_node_parent_atoms[best_match]:
+				node = ppkg
+				if ppkg in self._dynamic_config._initial_arg_list:
+					# Stop if reached the top level of the dep chain.
+					break
+
 		while node is not None:
 			traversed_nodes.add(node)
 

diff --git a/pym/portage/tests/resolver/test_autounmask.py b/pym/portage/tests/resolver/test_autounmask.py
index 54c435f..ff13789 100644
--- a/pym/portage/tests/resolver/test_autounmask.py
+++ b/pym/portage/tests/resolver/test_autounmask.py
@@ -1,6 +1,7 @@
 # Copyright 2010-2011 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+from portage.const import _ENABLE_SET_CONFIG
 from portage.tests import TestCase
 from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
 
@@ -324,3 +325,66 @@ class AutounmaskTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+
+	def testAutounmaskAndSets(self):
+
+		if not _ENABLE_SET_CONFIG:
+			return
+
+		ebuilds = {
+			#ebuilds to test use changes
+			"dev-libs/A-1": { },
+			"dev-libs/A-2": { "KEYWORDS": "~x86" },
+			"dev-libs/B-1": { "DEPEND": "dev-libs/A" },
+			"dev-libs/C-1": { "DEPEND": ">=dev-libs/A-2" },
+			"dev-libs/D-1": { "DEPEND": "dev-libs/A" },
+			}
+
+		world_sets = [ "@test-set" ]
+		sets = {
+			"test-set": (
+					"dev-libs/A", "dev-libs/B", "dev-libs/C", "dev-libs/D",
+				),
+			}
+
+		test_cases = (
+				#Test USE changes.
+				#The simple case.
+
+				ResolverPlaygroundTestCase(
+					["dev-libs/B", "dev-libs/C", "dev-libs/D"],
+					all_permutations=True,
+					options = {"--autounmask": "y"},
+					mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+					ignore_mergelist_order=True,
+					unstable_keywords = ["dev-libs/A-2"],
+					success = False),
+
+				ResolverPlaygroundTestCase(
+					["@test-set"],
+					all_permutations=True,
+					options = {"--autounmask": "y"},
+					mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+					ignore_mergelist_order=True,
+					unstable_keywords = ["dev-libs/A-2"],
+					success = False),
+
+				ResolverPlaygroundTestCase(
+					["@world"],
+					all_permutations=True,
+					options = {"--autounmask": "y"},
+					mergelist=["dev-libs/A-2", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+					ignore_mergelist_order=True,
+					unstable_keywords = ["dev-libs/A-2"],
+					success = False),
+			)
+
+
+		playground = ResolverPlayground(ebuilds=ebuilds, world_sets=world_sets, sets=sets)
+		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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-09-18 19:42 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-09-18 19:42 UTC (permalink / raw
  To: gentoo-commits

commit:     c7474fe52e1c52bb6b17bc56ae489d8efc3c0ef3
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Sep 18 19:42:38 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Sep 18 19:42:38 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=c7474fe5

depclean: don't remove new virtual slots

This provides depclean symmetry with the change in update behavior
from commit b95cbb6b78ad6d9b8e2d3edc5fafff122c3ce7c5, so that new
virtual slots won't be removed by depclean immediately after they
have been pulled in.

---
 pym/_emerge/depgraph.py                         |    3 +-
 pym/portage/tests/resolver/test_virtual_slot.py |   42 +++++++++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index f25a22d..fbbae1e 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -6595,7 +6595,8 @@ class _dep_check_composite_db(dbapi):
 		if pkg is not None and \
 			atom.slot is None and \
 			pkg.cp.startswith("virtual/") and \
-			("--update" not in self._depgraph._frozen_config.myopts or
+			(("remove" not in self._depgraph._dynamic_config.myparams and
+			"--update" not in self._depgraph._frozen_config.myopts) or
 			not ret or
 			not self._depgraph._virt_deps_visible(pkg, ignore_use=True)):
 			# For new-style virtual lookahead that occurs inside dep_check()

diff --git a/pym/portage/tests/resolver/test_virtual_slot.py b/pym/portage/tests/resolver/test_virtual_slot.py
index fb24201..4ea6677 100644
--- a/pym/portage/tests/resolver/test_virtual_slot.py
+++ b/pym/portage/tests/resolver/test_virtual_slot.py
@@ -91,3 +91,45 @@ class VirtualSlotResolverTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+	def testVirtualSlotDepclean(self):
+
+		ebuilds = {
+			"dev-java/oracle-jdk-bin-1.7.0" : {"SLOT": "1.7", "LICENSE": "TEST"},
+			"dev-java/sun-jdk-1.6.0" : {"SLOT": "1.6", "LICENSE": "TEST"},
+			"dev-java/icedtea-6.1.10.3" : {"SLOT": "6"},
+			"dev-java/icedtea-7" : {"SLOT": "7"},
+			"app-misc/java-app-1": {"RDEPEND": ">=virtual/jdk-1.6.0"},
+			"virtual/jdk-1.6.0": {"SLOT": "1.6", "RDEPEND": "|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )"},
+			"virtual/jdk-1.7.0": {"SLOT": "1.7", "RDEPEND": "|| ( =dev-java/icedtea-7* =dev-java/oracle-jdk-bin-1.7.0* )"},
+		}
+
+		installed = {
+			"app-misc/java-app-1": {"RDEPEND": ">=virtual/jdk-1.6.0"},
+			"dev-java/icedtea-6.1.10.3" : {"SLOT": "6"},
+			"dev-java/icedtea-7" : {"SLOT": "7"},
+			"virtual/jdk-1.6.0": {"SLOT" : "1.6", "RDEPEND": "|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )"},
+			"virtual/jdk-1.7.0": {"SLOT": "1.7", "RDEPEND": "|| ( =dev-java/icedtea-7* =dev-java/oracle-jdk-bin-1.7.0* )"},
+		}
+
+		world = ("virtual/jdk:1.6", "app-misc/java-app",)
+
+		test_cases = (
+			# Make sure that depclean doesn't remove a new slot even though
+			# it is redundant in the sense that the older slot will satisfy
+			# all dependencies.
+			ResolverPlaygroundTestCase(
+				[],
+				options = {"--depclean" : True},
+				success = True,
+				cleanlist = []),
+		)
+
+		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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-09-15  5:10 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-09-15  5:10 UTC (permalink / raw
  To: gentoo-commits

commit:     70e7107bfb01225c0aac74ce32f66b1c3b0d4d2d
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Thu Sep 15 05:09:04 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Thu Sep 15 05:09:04 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=70e7107b

Fix multislot handling for depclean (bug #382823)

---
 pym/_emerge/depgraph.py                      |   18 ++++++++++++++----
 pym/portage/tests/resolver/test_multislot.py |   16 +++++++++++++++-
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 1e311e8..f25a22d 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3263,11 +3263,20 @@ class depgraph(object):
 		# satisfied rather than forcing a rebuild.
 		installed = pkg_type == 'installed'
 		if installed and not cpv_list and atom.slot:
+
+			if "remove" in self._dynamic_config.myparams:
+				# We need to search the portdbapi, which is not in our
+				# normal dbs list, in order to find the real SLOT.
+				portdb = self._frozen_config.trees[root_config.root]["porttree"].dbapi
+				db_keys = list(portdb._aux_cache_keys)
+				dbs = [(portdb, "ebuild", False, False, db_keys)]
+			else:
+				dbs = self._dynamic_config._filtered_trees[root_config.root]["dbs"]
+
 			for cpv in db.match(atom.cp):
 				slot_available = False
 				for other_db, other_type, other_built, \
-					other_installed, other_keys in \
-					self._dynamic_config._filtered_trees[root_config.root]["dbs"]:
+					other_installed, other_keys in dbs:
 					try:
 						if atom.slot == \
 							other_db.aux_get(cpv, ["SLOT"])[0]:
@@ -4064,11 +4073,12 @@ class depgraph(object):
 		"""
 		Select packages that are installed.
 		"""
-		vardb = self._dynamic_config._graph_trees[root]["vartree"].dbapi
-		matches = vardb.match_pkgs(atom)
+		matches = list(self._iter_match_pkgs(self._frozen_config.roots[root],
+			"installed", atom))
 		if not matches:
 			return None, None
 		if len(matches) > 1:
+			matches.reverse() # ascending order
 			unmasked = [pkg for pkg in matches if \
 				self._pkg_visibility_check(pkg)]
 			if unmasked:

diff --git a/pym/portage/tests/resolver/test_multislot.py b/pym/portage/tests/resolver/test_multislot.py
index 8615419..1331edf 100644
--- a/pym/portage/tests/resolver/test_multislot.py
+++ b/pym/portage/tests/resolver/test_multislot.py
@@ -14,12 +14,18 @@ class MultSlotTestCase(TestCase):
 
 		ebuilds = {
 			"sys-devel/gcc-4.4.4": { "SLOT": "4.4" },
+			"dev-util/nvidia-cuda-toolkit-4.0" : { "RDEPEND": "sys-devel/gcc:4.4"},
 			}
 
 		installed = {
 			"sys-devel/gcc-4.4.4": { "SLOT": "i686-pc-linux-gnu-4.4.4" },
+			"dev-util/nvidia-cuda-toolkit-4.0" : { "RDEPEND": "sys-devel/gcc:4.4"},
 			}
 
+		world = (
+			"dev-util/nvidia-cuda-toolkit",
+		)
+
 		options = {'--update' : True, '--deep' : True, '--selective' : True}
 
 		test_cases = (
@@ -28,9 +34,17 @@ class MultSlotTestCase(TestCase):
 					options = options,
 					mergelist = [],
 					success = True),
+
+				# depclean test for bug #382823
+				ResolverPlaygroundTestCase(
+					[],
+					options = {"--depclean": True},
+					success = True,
+					cleanlist = []),
 			)
 
-		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed,
+			world=world)
 
 		try:
 			for test_case in test_cases:



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-09-11 20:43 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-09-11 20:43 UTC (permalink / raw
  To: gentoo-commits

commit:     b95cbb6b78ad6d9b8e2d3edc5fafff122c3ce7c5
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Sep 11 20:43:10 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Sep 11 20:43:10 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=b95cbb6b

depgraph: pull in new virtual slots with --update

This re-implements the fix from commit
21330075f07248765016e104b3ba8216903f1ecb, without introducing the
unwanted behavior reported in bug 382557. This involves checking the
direct dependencies of virtual slot updates to make sure they are all
visible, before pulling them in.

---
 pym/_emerge/depgraph.py                         |   69 +++++++++++++++++++----
 pym/portage/tests/resolver/test_virtual_slot.py |   47 +++++++++++++++
 2 files changed, 105 insertions(+), 11 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 6a04a79..1e311e8 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -2500,24 +2500,36 @@ class depgraph(object):
 			# account for masking and USE settings.
 			_autounmask_backup = self._dynamic_config._autounmask
 			self._dynamic_config._autounmask = False
-			mytrees["pkg_use_enabled"] = self._pkg_use_enabled
+			# backup state for restoration, in case of recursive
+			# calls to this method
+			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)
+				mytrees.pop("pkg_use_enabled", None)
+				mytrees.pop("parent", None)
+				mytrees.pop("atom_graph", None)
+				mytrees.pop("priority", None)
+
+				mytrees["pkg_use_enabled"] = self._pkg_use_enabled
 				if parent is not None:
-					trees[root]["parent"] = parent
-					trees[root]["atom_graph"] = atom_graph
+					mytrees["parent"] = parent
+					mytrees["atom_graph"] = atom_graph
 				if priority is not None:
-					trees[root]["priority"] = priority
+					mytrees["priority"] = priority
+
 				mycheck = portage.dep_check(depstring, None,
 					pkgsettings, myuse=myuse,
 					myroot=root, trees=trees)
 			finally:
+				# restore state
 				self._dynamic_config._autounmask = _autounmask_backup
-				del mytrees["pkg_use_enabled"]
-				if parent is not None:
-					trees[root].pop("parent")
-					trees[root].pop("atom_graph")
-				if priority is not None:
-					trees[root].pop("priority")
+				mytrees.pop("pkg_use_enabled", None)
+				mytrees.pop("parent", None)
+				mytrees.pop("atom_graph", None)
+				mytrees.pop("priority", None)
+				mytrees.update(backup_state)
 			if not mycheck[0]:
 				raise portage.exception.InvalidDependString(mycheck[1])
 		if parent is None:
@@ -2611,6 +2623,38 @@ class depgraph(object):
 					continue
 				yield atom
 
+	def _virt_deps_visible(self, pkg, ignore_use=False):
+		"""
+		Assumes pkg is a virtual package. Traverses virtual deps recursively
+		and returns True if all deps are visible, False otherwise. This is
+		useful for checking if it will be necessary to expand virtual slots,
+		for cases like bug #382557.
+		"""
+		try:
+			rdepend = self._select_atoms(
+				pkg.root, pkg.metadata.get("RDEPEND", ""),
+				myuse=self._pkg_use_enabled(pkg),
+				parent=pkg, priority=self._priority(runtime=True))
+		except InvalidDependString as e:
+			if not pkg.installed:
+				raise
+			writemsg_level("!!! Invalid RDEPEND in " + \
+				"'%svar/db/pkg/%s/RDEPEND': %s\n" % \
+				(pkg.root, pkg.cpv, e),
+				noiselevel=-1, level=logging.ERROR)
+			return False
+
+		for atoms in rdepend.values():
+			for atom in atoms:
+				if ignore_use:
+					atom = atom.without_use
+				pkg, existing = self._select_package(
+					pkg.root, atom)
+				if pkg is None or not self._pkg_visibility_check(pkg):
+					return False
+
+		return True
+
 	def _get_dep_chain(self, start_node, target_atom=None,
 		unsatisfied_dependency=False):
 		"""
@@ -6540,7 +6584,10 @@ class _dep_check_composite_db(dbapi):
 
 		if pkg is not None and \
 			atom.slot is None and \
-			pkg.cp.startswith("virtual/"):
+			pkg.cp.startswith("virtual/") and \
+			("--update" not in self._depgraph._frozen_config.myopts or
+			not ret or
+			not self._depgraph._virt_deps_visible(pkg, ignore_use=True)):
 			# For new-style virtual lookahead that occurs inside dep_check()
 			# for bug #141118, examine all slots. This is needed so that newer
 			# slots will not unnecessarily be pulled in when a satisfying lower

diff --git a/pym/portage/tests/resolver/test_virtual_slot.py b/pym/portage/tests/resolver/test_virtual_slot.py
index 40ed73b..fb24201 100644
--- a/pym/portage/tests/resolver/test_virtual_slot.py
+++ b/pym/portage/tests/resolver/test_virtual_slot.py
@@ -44,3 +44,50 @@ class VirtualSlotResolverTestCase(TestCase):
 				self.assertEqual(test_case.test_success, True, test_case.fail_msg)
 		finally:
 			playground.cleanup()
+
+	def testVirtualSlotUpdate(self):
+
+		ebuilds = {
+			"dev-java/oracle-jdk-bin-1.7.0" : {"SLOT": "1.7", "LICENSE": "TEST"},
+			"dev-java/sun-jdk-1.6.0" : {"SLOT": "1.6", "LICENSE": "TEST"},
+			"dev-java/icedtea-6.1.10.3" : {"SLOT": "6"},
+			"dev-java/icedtea-7" : {"SLOT": "7"},
+			"app-misc/java-app-1": {"RDEPEND": ">=virtual/jdk-1.6.0"},
+			"virtual/jdk-1.6.0": {"SLOT": "1.6", "RDEPEND": "|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )"},
+			"virtual/jdk-1.7.0": {"SLOT": "1.7", "RDEPEND": "|| ( =dev-java/icedtea-7* =dev-java/oracle-jdk-bin-1.7.0* )"},
+		}
+
+		installed = {
+			"app-misc/java-app-1": {"RDEPEND": ">=virtual/jdk-1.6.0"},
+			"dev-java/icedtea-6.1.10.3" : {"SLOT": "6"},
+			"virtual/jdk-1.6.0": {"SLOT" : "1.6", "RDEPEND": "|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )"},
+		}
+
+		world = ("app-misc/java-app",)
+
+		test_cases = (
+			# Pull in the virtual/jdk-1.7.0 slot update since its dependencies
+			# can only be satisfied by an unmasked package.
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--update" : True, "--deep" : True},
+				success = True,
+				mergelist = ["dev-java/icedtea-7", "virtual/jdk-1.7.0"]),
+
+			# Bug #275945 - Don't pull in the virtual/jdk-1.7.0 slot update
+			# unless --update is enabled.
+			ResolverPlaygroundTestCase(
+				["@world"],
+				options = {"--selective" : True, "--deep" : True},
+				success = True,
+				mergelist = []),
+		)
+
+		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] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-06-12 22:13 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-06-12 22:13 UTC (permalink / raw
  To: gentoo-commits

commit:     c754569663408e515fa134c52c7b3b8a1bb15181
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Jun 12 22:12:26 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Jun 12 22:12:26 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=c7545696

test_merge_order: test smallest runtime cycle

In the case of multiple runtime cycles, where some cycles
may depend on smaller independent cycles, it's optimal
to merge smaller independent cycles before other cycles
that depend on them. Therefore, we search for the
smallest cycle in order to try and identify and prefer
these smaller independent cycles.

---
 pym/_emerge/depgraph.py                        |    6 ++++
 pym/portage/tests/resolver/test_merge_order.py |   33 ++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 3b47c35..9ce199b 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5022,6 +5022,12 @@ class depgraph(object):
 					# we want to minimize the number of nodes gathered, since
 					# this tends to produce a more optimal merge order.
 					# Ignoring all medium_soft deps serves this purpose.
+					# In the case of multiple runtime cycles, where some cycles
+					# may depend on smaller independent cycles, it's optimal
+					# to merge smaller independent cycles before other cycles
+					# 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
 					for node in nodes:

diff --git a/pym/portage/tests/resolver/test_merge_order.py b/pym/portage/tests/resolver/test_merge_order.py
index e94b6c7..0a52c81 100644
--- a/pym/portage/tests/resolver/test_merge_order.py
+++ b/pym/portage/tests/resolver/test_merge_order.py
@@ -81,6 +81,27 @@ class MergeOrderTestCase(TestCase):
 				"DEPEND": "app-misc/circ-satisfied-a",
 				"RDEPEND": "app-misc/circ-satisfied-a",
 			},
+			"app-misc/circ-smallest-a-1": {
+				"RDEPEND": "app-misc/circ-smallest-b",
+			},
+			"app-misc/circ-smallest-b-1": {
+				"RDEPEND": "app-misc/circ-smallest-a",
+			},
+			"app-misc/circ-smallest-c-1": {
+				"RDEPEND": "app-misc/circ-smallest-d",
+			},
+			"app-misc/circ-smallest-d-1": {
+				"RDEPEND": "app-misc/circ-smallest-e",
+			},
+			"app-misc/circ-smallest-e-1": {
+				"RDEPEND": "app-misc/circ-smallest-c",
+			},
+			"app-misc/circ-smallest-f-1": {
+				"RDEPEND": "app-misc/circ-smallest-g app-misc/circ-smallest-a app-misc/circ-smallest-c",
+			},
+			"app-misc/circ-smallest-g-1": {
+				"RDEPEND": "app-misc/circ-smallest-f",
+			},
 			"app-misc/installed-blocker-a-1" : {
 				"EAPI"   : "2",
 				"DEPEND" : "!app-misc/blocker-buildtime-a",
@@ -294,6 +315,18 @@ class MergeOrderTestCase(TestCase):
 				ambiguous_merge_order = True,
 				merge_order_assertions = (("app-misc/circ-satisfied-a-1", "app-misc/circ-satisfied-c-1"),),
 				mergelist = [("app-misc/circ-satisfied-a-1", "app-misc/circ-satisfied-b-1", "app-misc/circ-satisfied-c-1")]),
+			# In the case of multiple runtime cycles, where some cycles
+			# may depend on smaller independent cycles, it's optimal
+			# to merge smaller independent cycles before other cycles
+			# that depend on them.
+			ResolverPlaygroundTestCase(
+				["app-misc/circ-smallest-a", "app-misc/circ-smallest-c", "app-misc/circ-smallest-f"],
+				success = True,
+				ambiguous_merge_order = True,
+				all_permutations = True,
+				mergelist = [('app-misc/circ-smallest-a-1', 'app-misc/circ-smallest-b-1'),
+				('app-misc/circ-smallest-c-1', 'app-misc/circ-smallest-d-1', 'app-misc/circ-smallest-e-1'),
+				('app-misc/circ-smallest-f-1', 'app-misc/circ-smallest-g-1')]),
 			# installed package has buildtime-only blocker
 			# that should be ignored
 			ResolverPlaygroundTestCase(



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-05-24 23:59 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-05-24 23:59 UTC (permalink / raw
  To: gentoo-commits

commit:     5181c9721add98ecb45d62f86c05fe59f1f35f40
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue May 24 23:59:13 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue May 24 23:59:13 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=5181c972

test_merge_order: test asap PDEPEND (bug #180045)

---
 pym/_emerge/depgraph.py                        |    1 +
 pym/portage/tests/resolver/test_merge_order.py |   33 ++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index ca1fe0d..3463925 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5025,6 +5025,7 @@ class depgraph(object):
 							continue
 						if child in asap_nodes:
 							continue
+						# Merge PDEPEND asap for bug #180045.
 						asap_nodes.append(child)
 
 			if selected_nodes and len(selected_nodes) > 1:

diff --git a/pym/portage/tests/resolver/test_merge_order.py b/pym/portage/tests/resolver/test_merge_order.py
index ba3d9b4..e00f820 100644
--- a/pym/portage/tests/resolver/test_merge_order.py
+++ b/pym/portage/tests/resolver/test_merge_order.py
@@ -150,6 +150,26 @@ class MergeOrderTestCase(TestCase):
 			},
 			"app-arch/xz-utils-5.0.1" : {},
 			"app-arch/xz-utils-5.0.2" : {},
+			"dev-util/pkgconfig-0.25-r2" : {},
+			"kde-base/kdelibs-3.5.7" : {
+				"PDEPEND" : "kde-misc/kdnssd-avahi",
+			},
+			"kde-misc/kdnssd-avahi-0.1.2" : {
+				"DEPEND"  : "kde-base/kdelibs app-arch/xz-utils dev-util/pkgconfig",
+				"RDEPEND" : "kde-base/kdelibs",
+			},
+			"kde-base/kdnssd-3.5.7" : {
+				"DEPEND"  : "kde-base/kdelibs",
+				"RDEPEND" : "kde-base/kdelibs",
+			},
+			"kde-base/libkdegames-3.5.7" : {
+				"DEPEND"  : "kde-base/kdelibs",
+				"RDEPEND" : "kde-base/kdelibs",
+			},
+			"kde-base/kmines-3.5.7" : {
+				"DEPEND"  : "kde-base/libkdegames",
+				"RDEPEND" : "kde-base/libkdegames",
+			}
 		}
 
 		installed = {
@@ -342,6 +362,19 @@ class MergeOrderTestCase(TestCase):
 				all_permutations = True,
 				ambiguous_merge_order = True,
 				mergelist = ['sys-kernel/linux-headers-2.6.39', 'sys-devel/gcc-4.5.2', 'sys-libs/glibc-2.13', ('app-arch/xz-utils-5.0.2', 'sys-devel/binutils-2.20.1')]),
+			# Test asap install of PDEPEND for bug #180045.
+			ResolverPlaygroundTestCase(
+				["kde-base/kmines", "kde-base/kdnssd", "kde-base/kdelibs", "app-arch/xz-utils"],
+				success = True,
+				all_permutations = True,
+				ambiguous_merge_order = True,
+				merge_order_assertions = (
+					('dev-util/pkgconfig-0.25-r2', 'kde-misc/kdnssd-avahi-0.1.2'),
+					('kde-misc/kdnssd-avahi-0.1.2', 'kde-base/libkdegames-3.5.7'),
+					('kde-misc/kdnssd-avahi-0.1.2', 'kde-base/kdnssd-3.5.7'),
+					('kde-base/libkdegames-3.5.7', 'kde-base/kmines-3.5.7'),
+				),
+				mergelist = [('kde-base/kdelibs-3.5.7', 'dev-util/pkgconfig-0.25-r2', 'kde-misc/kdnssd-avahi-0.1.2', 'app-arch/xz-utils-5.0.2', 'kde-base/libkdegames-3.5.7', 'kde-base/kdnssd-3.5.7', 'kde-base/kmines-3.5.7')]),
 		)
 
 		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-05-23  5:40 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-05-23  5:40 UTC (permalink / raw
  To: gentoo-commits

commit:     b84449fae4abf40ff3721002952dc37ccef24030
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon May 23 05:39:57 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon May 23 05:39:57 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=b84449fa

_serialize_tasks: prefer unsatisfied asap child

Optimally, satisfied deps are always merged after the asap nodes that
depend on them.

---
 pym/_emerge/depgraph.py                        |   28 ++++++++++++++++++-----
 pym/portage/tests/resolver/test_merge_order.py |    9 +++++--
 2 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 37fdeed..ca1fe0d 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -4931,6 +4931,7 @@ class depgraph(object):
 					if nodes:
 						# If there is a mixture of merges and uninstalls,
 						# do the uninstalls first.
+						good_uninstalls = None
 						if len(nodes) > 1:
 							good_uninstalls = []
 							for node in nodes:
@@ -4942,7 +4943,9 @@ class depgraph(object):
 							else:
 								nodes = nodes
 
-						if ignore_priority is None and not tree_mode:
+						if good_uninstalls or len(nodes) == 1 or \
+							(ignore_priority is None and \
+							not asap_nodes and not tree_mode):
 							# Greedily pop all of these nodes since no
 							# relationship has been ignored. This optimization
 							# destroys --tree output, so it's disabled in tree
@@ -4955,12 +4958,25 @@ class depgraph(object):
 							#    will not produce a leaf node, so avoid it.
 							#  * It's normal for a selected uninstall to be a
 							#    root node, so don't check them for parents.
-							for node in nodes:
-								if node.operation == "uninstall" or \
-									mygraph.parent_nodes(node):
-									selected_nodes = [node]
+							if asap_nodes:
+								prefer_asap_parents = (True, False)
+							else:
+								prefer_asap_parents = (False,)
+							for check_asap_parent in prefer_asap_parents:
+								if check_asap_parent:
+									for node in nodes:
+										parents = mygraph.parent_nodes(node,
+											ignore_priority=DepPrioritySatisfiedRange.ignore_soft)
+										if parents and set(parents).intersection(asap_nodes):
+											selected_nodes = [node]
+											break
+								else:
+									for node in nodes:
+										if mygraph.parent_nodes(node):
+											selected_nodes = [node]
+											break
+								if selected_nodes:
 									break
-
 						if selected_nodes:
 							break
 

diff --git a/pym/portage/tests/resolver/test_merge_order.py b/pym/portage/tests/resolver/test_merge_order.py
index ee3c786..1057300 100644
--- a/pym/portage/tests/resolver/test_merge_order.py
+++ b/pym/portage/tests/resolver/test_merge_order.py
@@ -112,12 +112,13 @@ class MergeOrderTestCase(TestCase):
 			"app-misc/some-app-c-1": {
 				"RDEPEND": "app-misc/circ-buildtime-a app-misc/circ-buildtime-b",
 			},
+			"app-admin/eselect-python-20100321" : {},
 			"sys-apps/portage-2.1.9.42" : {
 				"DEPEND"  : "dev-lang/python",
 				"RDEPEND" : "dev-lang/python",
 			},
 			"sys-apps/portage-2.1.9.49" : {
-				"DEPEND"  : "dev-lang/python",
+				"DEPEND"  : "dev-lang/python >=app-admin/eselect-python-20091230",
 				"RDEPEND" : "dev-lang/python",
 			},
 			"dev-lang/python-3.1" : {},
@@ -318,12 +319,14 @@ class MergeOrderTestCase(TestCase):
 				["app-misc/blocker-runtime-hard-a"],
 				success = False,
 				mergelist = ['app-misc/blocker-runtime-hard-a-1', '!!app-misc/blocker-runtime-hard-a']),
-			# Test that PORTAGE_PACKAGE_ATOM is merged asap.
+			# Test that PORTAGE_PACKAGE_ATOM is merged asap. Optimally,
+			# satisfied deps are always merged after the asap nodes that
+			# depend on them.
 			ResolverPlaygroundTestCase(
 				["dev-lang/python", portage.const.PORTAGE_PACKAGE_ATOM],
 				success = True,
 				all_permutations = True,
-				mergelist = ['sys-apps/portage-2.1.9.49', 'dev-lang/python-3.2']),
+				mergelist = ['app-admin/eselect-python-20100321', 'sys-apps/portage-2.1.9.49', 'dev-lang/python-3.2']),
 			# Test that OS_HEADERS_PACKAGE_ATOM and LIBC_PACKAGE_ATOM
 			# are merged asap, in order to account for implicit
 			# dependencies. See bug #303567.



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-05-22 23:49 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-05-22 23:49 UTC (permalink / raw
  To: gentoo-commits

commit:     6e6b9c5928e175af42615542866fc9b3aef694e6
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun May 22 23:48:42 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun May 22 23:48:42 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=6e6b9c59

_add_pkg_dep_string: handle satisfied virt_dep

This fixes a problem with the asap LIBC_PACKAGE_ATOM test case for
bug #303567.

---
 pym/_emerge/depgraph.py                        |   14 ++++++++++++++
 pym/portage/tests/resolver/test_merge_order.py |   10 +++++++---
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index caf150a..37fdeed 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1571,6 +1571,20 @@ class depgraph(object):
 
 			if not dep_priority.ignored or \
 				self._dynamic_config._traverse_ignored_deps:
+
+				inst_pkgs = [inst_pkg for inst_pkg in vardb.match_pkgs(virt_dep.atom)
+					if not reinstall_atoms.findAtomForPackage(inst_pkg,
+							modified_use=self._pkg_use_enabled(inst_pkg))]
+				if inst_pkgs:
+					for inst_pkg in inst_pkgs:
+						if self._pkg_visibility_check(inst_pkg):
+							# highest visible
+							virt_dep.priority.satisfied = inst_pkg
+							break
+					if not virt_dep.priority.satisfied:
+						# none visible, so use highest
+						virt_dep.priority.satisfied = inst_pkgs[0]
+
 				if not self._add_pkg(virt_pkg, virt_dep):
 					return 0
 

diff --git a/pym/portage/tests/resolver/test_merge_order.py b/pym/portage/tests/resolver/test_merge_order.py
index 1b7cddd..ee3c786 100644
--- a/pym/portage/tests/resolver/test_merge_order.py
+++ b/pym/portage/tests/resolver/test_merge_order.py
@@ -127,18 +127,22 @@ class MergeOrderTestCase(TestCase):
 			},
 			"sys-libs/glibc-2.11" : {
 				"DEPEND" : "virtual/os-headers",
+				"RDEPEND": "",
 			},
 			"sys-libs/glibc-2.13" : {
 				"DEPEND" : "virtual/os-headers",
+				"RDEPEND": "",
 			},
 			"virtual/os-headers-0" : {
 				"RDEPEND" : "sys-kernel/linux-headers",
 			},
 			"sys-kernel/linux-headers-2.6.38": {
 				"DEPEND" : "app-arch/xz-utils",
+				"RDEPEND": "",
 			},
 			"sys-kernel/linux-headers-2.6.39": {
 				"DEPEND" : "app-arch/xz-utils",
+				"RDEPEND": "",
 			},
 			"app-arch/xz-utils-5.0.1" : {},
 			"app-arch/xz-utils-5.0.2" : {},
@@ -182,12 +186,14 @@ class MergeOrderTestCase(TestCase):
 			},
 			"sys-libs/glibc-2.11" : {
 				"DEPEND" : "virtual/os-headers",
+				"RDEPEND": "",
 			},
 			"virtual/os-headers-0" : {
 				"RDEPEND" : "sys-kernel/linux-headers",
 			},
 			"sys-kernel/linux-headers-2.6.38": {
 				"DEPEND" : "app-arch/xz-utils",
+				"RDEPEND": "",
 			},
 			"app-arch/xz-utils-5.0.1" : {},
 		}
@@ -321,14 +327,12 @@ class MergeOrderTestCase(TestCase):
 			# Test that OS_HEADERS_PACKAGE_ATOM and LIBC_PACKAGE_ATOM
 			# are merged asap, in order to account for implicit
 			# dependencies. See bug #303567.
-			# TODO: optimize this to ensure that glibc comes before xz-utils
 			ResolverPlaygroundTestCase(
 				["app-arch/xz-utils", "sys-kernel/linux-headers", "sys-libs/glibc"],
 				options = {"--complete-graph" : True},
 				success = True,
 				all_permutations = True,
-				ambiguous_merge_order = True,
-				mergelist = ['sys-kernel/linux-headers-2.6.39', ('app-arch/xz-utils-5.0.2', 'sys-libs/glibc-2.13')]),
+				mergelist = ['sys-kernel/linux-headers-2.6.39', 'sys-libs/glibc-2.13', 'app-arch/xz-utils-5.0.2']),
 		)
 
 		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-05-21  3:49 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-05-21  3:49 UTC (permalink / raw
  To: gentoo-commits

commit:     037ef49ed8763eba774a8e69f9b060793cbb7d68
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat May 21 03:49:08 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat May 21 03:49:08 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=037ef49e

test_merge_order: test hard blocker resolution

---
 pym/_emerge/depgraph.py                        |    3 +--
 pym/portage/tests/resolver/test_merge_order.py |   16 +++++++++++++---
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 4789a0c..3ef47f8 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5531,8 +5531,7 @@ class depgraph(object):
 
 				msg.append("\n")
 
-			sys.stderr.write("".join(msg))
-			sys.stderr.flush()
+			writemsg("".join(msg), noiselevel=-1)
 
 		if "--quiet" not in self._frozen_config.myopts:
 			show_blocker_docs_link()

diff --git a/pym/portage/tests/resolver/test_merge_order.py b/pym/portage/tests/resolver/test_merge_order.py
index 6c929f7..e7f1aa4 100644
--- a/pym/portage/tests/resolver/test_merge_order.py
+++ b/pym/portage/tests/resolver/test_merge_order.py
@@ -11,6 +11,7 @@ class MergeOrderTestCase(TestCase):
 		ebuilds = {
 			"app-misc/blocker-buildtime-a-1" : {},
 			"app-misc/blocker-runtime-a-1" : {},
+			"app-misc/blocker-runtime-hard-a-1" : {},
 			"app-misc/circ-post-runtime-a-1": {
 				"PDEPEND": "app-misc/circ-post-runtime-b",
 			},
@@ -24,8 +25,9 @@ class MergeOrderTestCase(TestCase):
 				"RDEPEND": "app-misc/circ-runtime-a",
 			},
 			"app-misc/installed-blocker-a-1" : {
+				"EAPI"   : "2",
 				"DEPEND" : "!app-misc/blocker-buildtime-a",
-				"RDEPEND" : "!app-misc/blocker-runtime-a",
+				"RDEPEND" : "!app-misc/blocker-runtime-a !!app-misc/blocker-runtime-hard-a",
 			},
 			"app-misc/some-app-a-1": {
 				"RDEPEND": "app-misc/circ-runtime-a app-misc/circ-runtime-b",
@@ -37,9 +39,10 @@ class MergeOrderTestCase(TestCase):
 
 		installed = {
 			"app-misc/installed-blocker-a-1" : {
+				"EAPI"   : "2",
 				"DEPEND" : "!app-misc/blocker-buildtime-a",
-				"RDEPEND" : "!app-misc/blocker-runtime-a",
-			}
+				"RDEPEND" : "!app-misc/blocker-runtime-a !!app-misc/blocker-runtime-hard-a",
+			},
 		}
 
 		test_cases = (
@@ -72,6 +75,13 @@ class MergeOrderTestCase(TestCase):
 				["app-misc/blocker-runtime-a"],
 				success = True,
 				mergelist = ["app-misc/blocker-runtime-a-1", "app-misc/installed-blocker-a-1", "!app-misc/blocker-runtime-a"]),
+			# An installed package has a hard runtime blocker that
+			# will not resolve automatically (unless the option
+			# requested in bug 250286 is implemented).
+			ResolverPlaygroundTestCase(
+				["app-misc/blocker-runtime-hard-a"],
+				success = False,
+				mergelist = ['app-misc/blocker-runtime-hard-a-1', '!!app-misc/blocker-runtime-hard-a']),
 		)
 
 		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-05-03 22:59 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-05-03 22:59 UTC (permalink / raw
  To: gentoo-commits

commit:     5d26fe64b1f8b56f1f3e588921f33bc9df4da78d
Author:     David James <davidjames <AT> chromium <DOT> org>
AuthorDate: Tue May  3 20:10:28 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue May  3 22:47:25 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=5d26fe64

rebuild_config: propagate runtime deps to parents

Update rebuild option to propagate runtime deps to parents.

Suggested by SebastianLuther <AT> gmx.de

BUG=chromium-os:14858
TEST=Added unit test. Ran unit tests.

Change-Id: I7228a8558eddd1956c590de39430172476c66228

Review URL: http://gerrit.chromium.org/gerrit/202

---
 pym/_emerge/depgraph.py                    |   12 ++++++++----
 pym/portage/tests/resolver/test_rebuild.py |    9 +++++++--
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 8a76863..0de443b 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -267,15 +267,21 @@ class _rebuild_config(object):
 			# Remove our leaf node from the graph, keeping track of deps.
 			parents = graph.nodes[node][1].items()
 			graph.remove(node)
+			node_build_deps = build_deps.get(node, {})
+			node_runtime_deps = runtime_deps.get(node, {})
 			for parent, priorities in parents:
 				if parent == node:
 					# Ignore a direct cycle.
 					continue
+				parent_bdeps = build_deps.setdefault(parent, {})
+				parent_rdeps = runtime_deps.setdefault(parent, {})
 				for priority in priorities:
 					if priority.buildtime:
-						build_deps.setdefault(parent, {})[slot_atom] = node
+						parent_bdeps[slot_atom] = node
 					if priority.runtime:
-						runtime_deps.setdefault(parent, {})[slot_atom] = node
+						parent_rdeps[slot_atom] = node
+				if slot_atom in parent_bdeps and slot_atom in parent_rdeps:
+					parent_rdeps.update(node_runtime_deps)
 				if not graph.child_nodes(parent):
 					leaf_nodes.append(parent)
 
@@ -284,8 +290,6 @@ class _rebuild_config(object):
 			# completely filled in, and self.rebuild_list / self.reinstall_list
 			# will tell us whether any of our children need to be rebuilt or
 			# reinstalled.
-			node_build_deps = build_deps.get(node, {})
-			node_runtime_deps = runtime_deps.get(node, {})
 			if self._trigger_rebuild(node, node_build_deps, node_runtime_deps):
 				need_restart = True
 

diff --git a/pym/portage/tests/resolver/test_rebuild.py b/pym/portage/tests/resolver/test_rebuild.py
index 809dbed..fda289c 100644
--- a/pym/portage/tests/resolver/test_rebuild.py
+++ b/pym/portage/tests/resolver/test_rebuild.py
@@ -26,6 +26,8 @@ class RebuildTestCase(TestCase):
 			"sys-apps/d-2": { "RDEPEND" : "sys-libs/x"},
 			"sys-apps/e-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
 			"sys-apps/f-2": { "DEPEND"  : "sys-apps/a", "RDEPEND" : "sys-apps/a"},
+			"sys-apps/g-2": { "DEPEND"  : "sys-apps/b sys-libs/x",
+				"RDEPEND" : "sys-apps/b"},
 			}
 
 		installed = {
@@ -36,10 +38,12 @@ class RebuildTestCase(TestCase):
 			"sys-apps/d-1": { "RDEPEND" : "sys-libs/x"},
 			"sys-apps/e-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
 			"sys-apps/f-1": { "DEPEND"  : "sys-apps/a", "RDEPEND" : "sys-apps/a"},
+			"sys-apps/g-1": { "DEPEND"  : "sys-apps/b sys-libs/x",
+				"RDEPEND" : "sys-apps/b"},
 			}
 
 		world = ["sys-apps/a", "sys-apps/b", "sys-apps/c", "sys-apps/d",
-			"sys-apps/e", "sys-apps/f"]
+			"sys-apps/e", "sys-apps/f", "sys-apps/g"]
 
 		test_cases = (
 				ResolverPlaygroundTestCase(
@@ -53,7 +57,8 @@ class RebuildTestCase(TestCase):
 				ResolverPlaygroundTestCase(
 					["sys-libs/x"],
 					options = {"--rebuild" : True},
-					mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/b-2', 'sys-apps/e-2'],
+					mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/b-2',
+						'sys-apps/e-2', 'sys-apps/g-2'],
 					ignore_mergelist_order = True,
 					success = True),
 			)



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-04-27 20:40 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-04-27 20:40 UTC (permalink / raw
  To: gentoo-commits

commit:     9e813764e3056fe9a376af70d9bc80749980fe5e
Author:     Sebastian Luther <SebastianLuther <AT> gmx <DOT> de>
AuthorDate: Wed Apr 27 20:36:15 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Apr 27 20:36:15 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=9e813764

--autounmask: Don't change masked/forced flags

This will fix bug #364701.

---
 pym/_emerge/depgraph.py                          |    4 +++
 pym/portage/tests/resolver/ResolverPlayground.py |    2 +-
 pym/portage/tests/resolver/test_autounmask.py    |   31 +++++++++++++++++++++-
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 391c845..a0a4622 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3120,6 +3120,10 @@ class depgraph(object):
 				not check_required_use(required_use, new_use, pkg.iuse.is_valid_flag):
 				return old_use
 
+			if pkg.use.mask.intersection(new_changes) or \
+				pkg.use.force.intersection(new_changes):
+				return old_use
+
 			self._dynamic_config._needed_use_config_changes[pkg] = (new_use, new_changes)
 			backtrack_infos = self._dynamic_config._backtrack_infos
 			backtrack_infos.setdefault("config", {})

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index eb591bb..276b193 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -32,7 +32,7 @@ class ResolverPlayground(object):
 	"""
 
 	config_files = frozenset(("package.use", "package.mask", "package.keywords", \
-		"package.unmask", "package.properties", "package.license"))
+		"package.unmask", "package.properties", "package.license", "use.mask", "use.force"))
 
 	def __init__(self, ebuilds={}, installed={}, profile={}, repo_configs={}, \
 		user_config={}, sets={}, world=[], debug=False):

diff --git a/pym/portage/tests/resolver/test_autounmask.py b/pym/portage/tests/resolver/test_autounmask.py
index 9e50be7..bd3a5f9 100644
--- a/pym/portage/tests/resolver/test_autounmask.py
+++ b/pym/portage/tests/resolver/test_autounmask.py
@@ -16,6 +16,12 @@ class AutounmaskTestCase(TestCase):
 			"dev-libs/C-1": {},
 			"dev-libs/D-1": {},
 
+			#ebuilds to test if we allow changing of masked or forced flags
+			"dev-libs/E-1": { "SLOT": 1, "DEPEND": "dev-libs/F[masked-flag]", "EAPI": 2},
+			"dev-libs/E-2": { "SLOT": 2, "DEPEND": "dev-libs/G[-forced-flag]", "EAPI": 2},
+			"dev-libs/F-1": { "IUSE": "masked-flag"},
+			"dev-libs/G-1": { "IUSE": "forced-flag"},
+
 			#ebuilds to test keyword changes
 			"app-misc/Z-1": { "KEYWORDS": "~x86", "DEPEND": "app-misc/Y" },
 			"app-misc/Y-1": { "KEYWORDS": "~x86" },
@@ -185,9 +191,32 @@ class AutounmaskTestCase(TestCase):
 					options = { "--autounmask": True },
 					use_changes = None,
 					success = False),
+
+				#Make sure we don't change masked/forced flags.
+				ResolverPlaygroundTestCase(
+					["dev-libs/E:1"],
+					options = {"--autounmask": True},
+					use_changes = None,
+					success = False),
+				ResolverPlaygroundTestCase(
+					["dev-libs/E:2"],
+					options = {"--autounmask": True},
+					use_changes = None,
+					success = False),
 			)
 
-		playground = ResolverPlayground(ebuilds=ebuilds)
+		profile = {
+			"use.mask":
+				(
+					"masked-flag",
+				),
+			"use.force":
+				(
+					"forced-flag",
+				),
+		}
+
+		playground = ResolverPlayground(ebuilds=ebuilds, profile=profile)
 		try:
 			for test_case in test_cases:
 				playground.run_TestCase(test_case)



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-02-13 13:55 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-02-13 13:55 UTC (permalink / raw
  To: gentoo-commits

commit:     f5eaf39529393b0b68f656b06600920791d9bec0
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Feb 13 13:55:18 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Feb 13 13:55:18 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=f5eaf395

depgraph: fix and test depth control for virtuals

---
 pym/_emerge/depgraph.py                  |   50 +++++++++++++++++++++++++-----
 pym/portage/tests/resolver/test_depth.py |   33 +++++++++++++++-----
 2 files changed, 67 insertions(+), 16 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 1dba229..30e7046 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1238,6 +1238,7 @@ class depgraph(object):
 
 		root_config = self._frozen_config.roots[dep_root]
 		vardb = root_config.trees["vartree"].dbapi
+		traversed_virt_pkgs = set()
 
 		for atom, child in self._minimize_children(
 			pkg, dep_priority, root_config, selected_atoms[pkg]):
@@ -1278,7 +1279,6 @@ class depgraph(object):
 			# available for optimization of merge order.
 			ignored = False
 			if not atom.blocker and \
-				not is_virt and \
 				not recurse_satisfied and \
 				mypriority.satisfied and \
 				mypriority.satisfied.visible and \
@@ -1304,9 +1304,12 @@ class depgraph(object):
 					dep.child = None
 					self._dynamic_config._ignored_deps.append(dep)
 
-			if not ignored and not self._add_dep(dep,
-				allow_unsatisfied=allow_unsatisfied):
-				return 0
+			if not ignored:
+				if not self._add_dep(dep,
+					allow_unsatisfied=allow_unsatisfied):
+					return 0
+				if is_virt:
+					traversed_virt_pkgs.add(dep.child)
 
 		selected_atoms.pop(pkg)
 
@@ -1318,6 +1321,8 @@ class depgraph(object):
 		for virt_dep, atoms in selected_atoms.items():
 
 			virt_pkg = virt_dep.child
+			if virt_pkg not in traversed_virt_pkgs:
+				continue
 
 			if debug:
 				writemsg_level("Candidates: %s: %s\n" % \
@@ -1334,6 +1339,7 @@ class depgraph(object):
 				# from dep_check, map it back to the original, in
 				# order to avoid distortion in places like display
 				# or conflict resolution code.
+				is_virt = hasattr(atom, '_orig_atom')
 				atom = getattr(atom, '_orig_atom', atom)
 
 				# This is a GLEP 37 virtual, so its deps are all runtime.
@@ -1352,11 +1358,39 @@ class depgraph(object):
 
 				# Dependencies of virtuals are considered to have the
 				# same depth as the virtual itself.
-				if not self._add_dep(Dependency(atom=atom,
+				dep = Dependency(atom=atom,
 					blocker=atom.blocker, child=child, depth=virt_dep.depth,
-					parent=virt_pkg, priority=mypriority, root=dep_root),
-					allow_unsatisfied=allow_unsatisfied):
-					return 0
+					parent=virt_pkg, priority=mypriority, root=dep_root)
+
+				ignored = False
+				if not atom.blocker and \
+					not recurse_satisfied and \
+					mypriority.satisfied and \
+					mypriority.satisfied.visible and \
+					dep.child is not None and \
+					not dep.child.installed:
+					myarg = None
+					if dep.root == self._frozen_config.target_root:
+						try:
+								myarg = next(
+									self._iter_atoms_for_pkg(dep.child))
+						except StopIteration:
+								pass
+						except InvalidDependString:
+							if not dep.child.installed:
+								raise
+
+					if myarg is None:
+						ignored = True
+						dep.child = None
+						self._dynamic_config._ignored_deps.append(dep)
+
+				if not ignored:
+					if not self._add_dep(dep,
+						allow_unsatisfied=allow_unsatisfied):
+						return 0
+					if is_virt:
+						traversed_virt_pkgs.add(dep.child)
 
 		if debug:
 			writemsg_level("Exiting... %s\n" % (pkg,),

diff --git a/pym/portage/tests/resolver/test_depth.py b/pym/portage/tests/resolver/test_depth.py
index cecdd37..65cfac6 100644
--- a/pym/portage/tests/resolver/test_depth.py
+++ b/pym/portage/tests/resolver/test_depth.py
@@ -123,19 +123,28 @@ class ResolverDepthTestCase(TestCase):
 				["virtual/jre"],
 				options = {"--update" : True},
 				success = True,
+				mergelist = ['virtual/jre-1.6.0-r1', 'virtual/jre-1.5.0-r1']),
+
+			# Recursively traversed virtual dependencies, and their
+			# direct dependencies, are considered to have the same
+			# depth as direct dependencies.
+			ResolverPlaygroundTestCase(
+				["virtual/jre"],
+				options = {"--update" : True, "--deep" : 1},
+				success = True,
 				mergelist = ['dev-java/icedtea-6.1-r1', 'dev-java/gcj-jdk-4.5-r1', 'virtual/jdk-1.6.0-r1', 'virtual/jdk-1.5.0-r1', 'virtual/jre-1.6.0-r1', 'virtual/jre-1.5.0-r1']),
 
 			ResolverPlaygroundTestCase(
 				["virtual/jre:1.5"],
 				options = {"--update" : True},
 				success = True,
-				mergelist = ['dev-java/gcj-jdk-4.5-r1', 'virtual/jdk-1.5.0-r1', 'virtual/jre-1.5.0-r1']),
+				mergelist = ['virtual/jre-1.5.0-r1']),
 
 			ResolverPlaygroundTestCase(
 				["virtual/jre:1.6"],
 				options = {"--update" : True},
 				success = True,
-				mergelist = ['dev-java/icedtea-6.1-r1', 'virtual/jdk-1.6.0-r1', 'virtual/jre-1.6.0-r1']),
+				mergelist = ['virtual/jre-1.6.0-r1']),
 
 			# Test that we don't pull in any unnecessary updates
 			# when --update is not specified, even though we
@@ -146,12 +155,20 @@ class ResolverDepthTestCase(TestCase):
 				success = True,
 				mergelist = ["dev-java/ant-core-1.8"]),
 
-			# FIXME: pulls in unwanted updates without --deep: ['dev-java/icedtea-6.1-r1', 'virtual/jdk-1.6.0-r1', 'dev-java/ant-core-1.8']
-			#ResolverPlaygroundTestCase(
-			#	["dev-java/ant-core"],
-			#	options = {"--update" : True},
-			#	success = True,
-			#	mergelist = ["dev-java/ant-core-1.8"]),
+			ResolverPlaygroundTestCase(
+				["dev-java/ant-core"],
+				options = {"--update" : True},
+				success = True,
+				mergelist = ["dev-java/ant-core-1.8"]),
+
+			# Recursively traversed virtual dependencies, and their
+			# direct dependencies, are considered to have the same
+			# depth as direct dependencies.
+			ResolverPlaygroundTestCase(
+				["dev-java/ant-core"],
+				options = {"--update" : True, "--deep" : 1},
+				success = True,
+				mergelist = ['dev-java/icedtea-6.1-r1', 'virtual/jdk-1.6.0-r1', 'dev-java/ant-core-1.8']),
 
 			ResolverPlaygroundTestCase(
 				["dev-db/hsqldb"],



^ permalink raw reply related	[flat|nested] 56+ messages in thread
* [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/
@ 2011-02-13 10:23 Zac Medico
  0 siblings, 0 replies; 56+ messages in thread
From: Zac Medico @ 2011-02-13 10:23 UTC (permalink / raw
  To: gentoo-commits

commit:     5655b4dcfe5e9dae5e9d6352d791c3d04953baf7
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Feb 13 10:20:24 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Feb 13 10:20:24 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=5655b4dc

depgraph: fix and test --deep control of depth

Control over recursion depth hasn't behaved properly since commit
6503980e0e3bcfce9fbaff85c33d87f616e955a9. Now it is fixed and tested.

---
 pym/_emerge/depgraph.py                  |   44 +++++++++++++++++++++++--
 pym/portage/tests/resolver/test_depth.py |   53 ++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index bec9ffd..72fc1ae 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -18,7 +18,7 @@ from portage.const import PORTAGE_PACKAGE_ATOM
 from portage.dbapi import dbapi
 from portage.dep import Atom, extract_affecting_use, check_required_use, human_readable_required_use, _repo_separator
 from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use
-from portage.exception import InvalidAtom
+from portage.exception import InvalidAtom, InvalidDependString
 from portage.output import colorize, create_color_func, \
 	darkgreen, green
 bad = create_color_func("BAD")
@@ -1206,6 +1206,8 @@ class depgraph(object):
 	def _add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string,
 		allow_unsatisfied, ignore_blockers=False):
 		depth = pkg.depth + 1
+		deep = self._dynamic_config.myparams.get("deep", 0)
+		recurse_satisfied = deep is True or depth <= deep
 		debug = "--debug" in self._frozen_config.myopts
 		strict = pkg.type_name != "installed"
 
@@ -1244,6 +1246,7 @@ class depgraph(object):
 			# from dep_check, map it back to the original, in
 			# order to avoid distortion in places like display
 			# or conflict resolution code.
+			is_virt = hasattr(atom, '_orig_atom')
 			atom = getattr(atom, '_orig_atom', atom)
 
 			if ignore_blockers and atom.blocker:
@@ -1264,9 +1267,44 @@ class depgraph(object):
 						# none visible, so use highest
 						mypriority.satisfied = inst_pkgs[0]
 
-			if not self._add_dep(Dependency(atom=atom,
+			dep = Dependency(atom=atom,
 				blocker=atom.blocker, child=child, depth=depth, parent=pkg,
-				priority=mypriority, root=dep_root),
+				priority=mypriority, root=dep_root)
+
+			# In some cases, dep_check will return deps that shouldn't
+			# be proccessed any further, so they are identified and
+			# discarded here. Try to discard as few as possible since
+			# discarded dependencies reduce the amount of information
+			# available for optimization of merge order.
+			ignored = False
+			if not atom.blocker and \
+				not is_virt and \
+				not recurse_satisfied and \
+				mypriority.satisfied and \
+				mypriority.satisfied.visible and \
+				dep.child is not None and \
+				not dep.child.installed:
+				myarg = None
+				if dep.root == self._frozen_config.target_root:
+					try:
+							myarg = next(self._iter_atoms_for_pkg(dep.child))
+					except StopIteration:
+							pass
+					except InvalidDependString:
+						if not dep.child.installed:
+							# This shouldn't happen since the package
+							# should have been masked.
+							raise
+
+				if myarg is None:
+					# Existing child selection may not be valid unless
+					# it's added to the graph immediately, since "complete"
+					# mode may select a different child later.
+					ignored = True
+					dep.child = None
+					self._dynamic_config._ignored_deps.append(dep)
+
+			if not ignored and not self._add_dep(dep,
 				allow_unsatisfied=allow_unsatisfied):
 				return 0
 

diff --git a/pym/portage/tests/resolver/test_depth.py b/pym/portage/tests/resolver/test_depth.py
new file mode 100644
index 0000000..5a30941
--- /dev/null
+++ b/pym/portage/tests/resolver/test_depth.py
@@ -0,0 +1,53 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+	ResolverPlaygroundTestCase)
+
+class ResolverDepthTestCase(TestCase):
+
+	def testResolverDepth(self):
+
+		ebuilds = {
+			"dev-libs/A-1": {"RDEPEND" : "dev-libs/B"},
+			"dev-libs/A-2": {"RDEPEND" : "dev-libs/B"},
+			"dev-libs/B-1": {"RDEPEND" : "dev-libs/C"},
+			"dev-libs/B-2": {"RDEPEND" : "dev-libs/C"},
+			"dev-libs/C-1": {},
+			"dev-libs/C-2": {},
+			}
+
+		installed = {
+			"dev-libs/A-1": {"RDEPEND" : "dev-libs/B"},
+			"dev-libs/B-1": {"RDEPEND" : "dev-libs/C"},
+			"dev-libs/C-1": {},
+			}
+
+		test_cases = (
+			ResolverPlaygroundTestCase(
+				["dev-libs/A"],
+				options = {"--update": True, "--deep": 0},
+				success = True,
+				mergelist = ["dev-libs/A-2"]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/A"],
+				options = {"--update": True, "--deep": 1},
+				success = True,
+				mergelist = ["dev-libs/B-2", "dev-libs/A-2"]),
+
+			ResolverPlaygroundTestCase(
+				["dev-libs/A"],
+				options = {"--update": True, "--deep": 3},
+				success = True,
+				mergelist = ["dev-libs/C-2", "dev-libs/B-2", "dev-libs/A-2"]),
+			)
+
+		playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+		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] 56+ messages in thread

end of thread, other threads:[~2018-05-04 17:12 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-05  0:56 [gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/_emerge/ Zac Medico
  -- strict thread matches above, loose matches on Subject: below --
2018-05-04 17:12 Zac Medico
2018-04-12  2:45 Zac Medico
2017-09-29 17:24 Zac Medico
2017-06-02  5:41 Zac Medico
2017-04-01  5:48 Zac Medico
2017-03-22  8:59 Zac Medico
2017-03-16  4:51 Zac Medico
2017-03-09 19:36 Zac Medico
2016-08-07 17:55 Zac Medico
2015-11-24 16:45 Zac Medico
2014-11-16  9:04 Zac Medico
2014-10-27  9:26 Zac Medico
2014-09-19  9:28 Zac Medico
2014-09-19  9:17 Zac Medico
2014-09-17 16:35 Zac Medico
2014-09-16 21:04 Brian Dolbec
2014-09-11 21:37 Zac Medico
2014-04-26 19:44 Sebastian Luther
2014-02-16 17:25 Sebastian Luther
2014-02-15 12:40 Sebastian Luther
2014-02-05 19:42 Sebastian Luther
2014-01-07 22:22 Arfrever Frehtes Taifersar Arahesis
2013-12-05 15:38 Brian Dolbec
2013-12-01 10:19 Brian Dolbec
2013-11-27  7:44 Mike Frysinger
2013-08-02  8:26 Zac Medico
2013-07-07 19:16 Zac Medico
2013-07-06 21:45 Zac Medico
2013-03-19 21:06 Zac Medico
2013-02-14  4:45 Zac Medico
2013-02-12  2:50 Zac Medico
2013-02-11 22:51 Zac Medico
2013-02-11  1:58 Zac Medico
2012-12-01 23:23 Zac Medico
2012-10-26  6:06 Zac Medico
2012-10-26  4:57 Zac Medico
2012-07-05  3:16 Zac Medico
2012-06-15 23:04 Zac Medico
2012-02-26 10:00 Zac Medico
2011-11-18  1:26 Zac Medico
2011-09-30  8:30 Zac Medico
2011-09-19  3:05 Zac Medico
2011-09-18 20:08 Zac Medico
2011-09-18 19:42 Zac Medico
2011-09-15  5:10 Zac Medico
2011-09-11 20:43 Zac Medico
2011-06-12 22:13 Zac Medico
2011-05-24 23:59 Zac Medico
2011-05-23  5:40 Zac Medico
2011-05-22 23:49 Zac Medico
2011-05-21  3:49 Zac Medico
2011-05-03 22:59 Zac Medico
2011-04-27 20:40 Zac Medico
2011-02-13 13:55 Zac Medico
2011-02-13 10:23 Zac Medico

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