From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 4D273138334 for ; Mon, 23 Dec 2019 22:47:53 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 85692E09F1; Mon, 23 Dec 2019 22:47:51 +0000 (UTC) Received: from smtp.gentoo.org (mail.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 5CBADE09F1 for ; Mon, 23 Dec 2019 22:47:51 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 2733D34DB02 for ; Mon, 23 Dec 2019 22:47:50 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id CA4B07CAF3 for ; Mon, 23 Dec 2019 22:47:48 +0000 (UTC) From: "Zac Medico" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Zac Medico" Message-ID: <1577139795.85f0dd173ab75bcc39c3616b5a3a967bdc88cf73.zmedico@gentoo> Subject: [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/portage/dep/, lib/_emerge/, ... X-VCS-Repository: proj/portage X-VCS-Files: lib/_emerge/depgraph.py lib/portage/dep/__init__.py lib/portage/tests/dep/test_use_reduce.py lib/portage/tests/resolver/test_with_test_deps.py X-VCS-Directories: lib/portage/tests/resolver/ lib/portage/tests/dep/ lib/portage/dep/ lib/_emerge/ X-VCS-Committer: zmedico X-VCS-Committer-Name: Zac Medico X-VCS-Revision: 85f0dd173ab75bcc39c3616b5a3a967bdc88cf73 X-VCS-Branch: master Date: Mon, 23 Dec 2019 22:47:48 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 74f0905f-5902-4516-ab39-658cba35438f X-Archives-Hash: 419fcf7e5d47ea562ffc502b8937ff3d commit: 85f0dd173ab75bcc39c3616b5a3a967bdc88cf73 Author: Zac Medico gentoo org> AuthorDate: Fri Dec 20 06:58:58 2019 +0000 Commit: Zac Medico gentoo org> CommitDate: Mon Dec 23 22:23:15 2019 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=85f0dd17 emerge --with-test-deps: allow circular deps When USE=test is not enabled, allow circular test dependencies by treating them like PDEPEND. When USE=test is enabled, circular dependencies are still not allowed, as shown in unit tests. Suggested-by: Michał Górny gentoo.org> Bug: https://bugs.gentoo.org/703348 Signed-off-by: Zac Medico gentoo.org> lib/_emerge/depgraph.py | 19 ++++-- lib/portage/dep/__init__.py | 44 +++++++++++++- lib/portage/tests/dep/test_use_reduce.py | 72 ++++++++++++++++++++++- lib/portage/tests/resolver/test_with_test_deps.py | 39 +++++++++++- 4 files changed, 166 insertions(+), 8 deletions(-) diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py index 1a5448c8f..83631fe70 100644 --- a/lib/_emerge/depgraph.py +++ b/lib/_emerge/depgraph.py @@ -3325,10 +3325,6 @@ class depgraph(object): pkg.iuse.is_valid_flag("test") and \ self._is_argument(pkg) - if with_test_deps: - use_enabled = set(use_enabled) - use_enabled.add("test") - if not pkg.built and \ "--buildpkgonly" in self._frozen_config.myopts and \ "deep" not in self._dynamic_config.myparams: @@ -3430,6 +3426,21 @@ class depgraph(object): noiselevel=-1, level=logging.DEBUG) try: + if (with_test_deps and 'test' not in use_enabled and + pkg.iuse.is_valid_flag('test')): + test_deps = portage.dep.use_reduce(dep_string, + uselist=use_enabled | {'test'}, + is_valid_flag=pkg.iuse.is_valid_flag, + opconvert=True, token_class=Atom, + eapi=pkg.eapi, + subset={'test'}) + + if test_deps and not self._add_pkg_dep_string( + pkg, dep_root, self._priority(runtime_post=True), + test_deps, + allow_unsatisfied): + return 0 + dep_string = portage.dep.use_reduce(dep_string, uselist=use_enabled, is_valid_flag=pkg.iuse.is_valid_flag, diff --git a/lib/portage/dep/__init__.py b/lib/portage/dep/__init__.py index f08f6ba4c..72988357a 100644 --- a/lib/portage/dep/__init__.py +++ b/lib/portage/dep/__init__.py @@ -405,7 +405,8 @@ def paren_enclose(mylist, unevaluated_atom=False, opconvert=False): return " ".join(mystrparts) def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), is_src_uri=False, \ - eapi=None, opconvert=False, flat=False, is_valid_flag=None, token_class=None, matchnone=False): + eapi=None, opconvert=False, flat=False, is_valid_flag=None, token_class=None, matchnone=False, + subset=None): """ Takes a dep string and reduces the use? conditionals out, leaving an array with subarrays. All redundant brackets are removed. @@ -434,6 +435,8 @@ def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), i @type token_class: Class @param matchnone: Treat all conditionals as inactive. Used by digestgen(). @type matchnone: Bool + @param subset: Select a subset of dependencies conditional on the given flags + @type subset: Sequence @rtype: List @return: The use reduced depend array """ @@ -491,6 +494,45 @@ def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), i return (flag in uselist and not is_negated) or \ (flag not in uselist and is_negated) + if subset: + def select_subset(dep_struct, disjunction, selected): + result = [] + stack = list(dep_struct) + stack.reverse() + while stack: + token = stack.pop() + try: + conditional = token.endswith('?') + except AttributeError: + if disjunction: + children = select_subset(token, False, selected) + if children: + result.append(children) + else: + result.extend(select_subset(token, False, selected)) + else: + if conditional: + children = stack.pop() + if is_active(token): + if disjunction: + children = select_subset(children, False, selected or token[:-1] in subset) + if children: + result.append(children) + else: + result.extend(select_subset(children, False, selected or token[:-1] in subset)) + elif token == '||': + children = select_subset(stack.pop(), True, selected) + if children: + if disjunction: + result.extend(children) + else: + result.append(token) + result.append(children) + elif selected: + result.append(token) + return result + depstr = paren_enclose(select_subset(paren_reduce(depstr, _deprecation_warn=False), False, False)) + def missing_white_space_check(token, pos): """ Used to generate good error messages for invalid tokens. diff --git a/lib/portage/tests/dep/test_use_reduce.py b/lib/portage/tests/dep/test_use_reduce.py index 4f65567cf..d9ee5a309 100644 --- a/lib/portage/tests/dep/test_use_reduce.py +++ b/lib/portage/tests/dep/test_use_reduce.py @@ -9,7 +9,7 @@ class UseReduceTestCase(object): def __init__(self, deparray, uselist=[], masklist=[], matchall=0, excludeall=[], is_src_uri=False, eapi='0', opconvert=False, flat=False, expected_result=None, - is_valid_flag=None, token_class=None): + is_valid_flag=None, token_class=None, subset=None): self.deparray = deparray self.uselist = uselist self.masklist = masklist @@ -21,13 +21,15 @@ class UseReduceTestCase(object): self.flat = flat self.is_valid_flag = is_valid_flag self.token_class = token_class + self.subset = subset self.expected_result = expected_result def run(self): try: return use_reduce(self.deparray, self.uselist, self.masklist, self.matchall, self.excludeall, self.is_src_uri, self.eapi, - self.opconvert, self.flat, self.is_valid_flag, self.token_class) + self.opconvert, self.flat, self.is_valid_flag, self.token_class, + subset=self.subset) except InvalidDependString as e: raise InvalidDependString("%s: %s" % (e, self.deparray)) @@ -50,6 +52,72 @@ class UseReduce(TestCase): uselist=["a", "b", "c", "d"], expected_result=["A", "B"] ), + UseReduceTestCase( + "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )", + uselist=["a", "b", "c", "d"], + subset=["b"], + expected_result=["B"] + ), + UseReduceTestCase( + "bar? ( || ( foo bar? ( baz ) ) )", + uselist=["bar"], + subset=["bar"], + expected_result=['||', ['foo', 'baz']] + ), + UseReduceTestCase( + "bar? ( foo bar? ( baz ) foo )", + uselist=["bar"], + subset=["bar"], + expected_result=['foo', 'baz', 'foo'] + ), + UseReduceTestCase( + "|| ( ( a b ) ( c d ) )", + uselist=[], + subset=["bar"], + expected_result=[] + ), + UseReduceTestCase( + "|| ( ( a b ) ( bar? ( c d ) e f ) )", + uselist=["bar"], + subset=["bar"], + expected_result=['c', 'd'] + ), + UseReduceTestCase( + "( a b ) ( c d bar? ( e f baz? ( g h ) ) )", + uselist=["bar"], + subset=["bar"], + expected_result=['e', 'f'] + ), + UseReduceTestCase( + "( a b ) ( c d bar? ( e f baz? ( g h ) ) )", + uselist=["bar", "baz"], + subset=["bar"], + expected_result=['e', 'f', 'g', 'h'] + ), + UseReduceTestCase( + "( bar? ( a b ) ( bar? ( c d ) ) ) ( e f )", + uselist=["bar"], + subset=["bar"], + expected_result=['a', 'b', 'c', 'd'] + ), + UseReduceTestCase( + "|| ( foo bar? ( baz ) )", + uselist=["bar"], + subset=["bar"], + expected_result=["baz"] + ), + UseReduceTestCase( + "|| ( || ( bar? ( a || ( b c || ( d e ) ) ) ) )", + uselist=["bar"], + subset=["bar"], + expected_result=['a', '||', ['b', 'c', 'd', 'e']] + ), + UseReduceTestCase( + "|| ( || ( bar? ( a || ( ( b c ) ( d e ) ) ) ) )", + uselist=["bar"], + subset=["bar"], + expected_result=['a', '||', [['b', 'c'], ['d', 'e']]] + ), UseReduceTestCase( "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )", uselist=["a", "b", "c"], diff --git a/lib/portage/tests/resolver/test_with_test_deps.py b/lib/portage/tests/resolver/test_with_test_deps.py index 5bfc6a8a2..d88e3cb6e 100644 --- a/lib/portage/tests/resolver/test_with_test_deps.py +++ b/lib/portage/tests/resolver/test_with_test_deps.py @@ -21,7 +21,27 @@ class WithTestDepsTestCase(TestCase): }, "app-misc/C-0": { "EAPI": "5", - } + }, + "app-misc/D-0": { + "EAPI": "5", + "IUSE": "test", + "DEPEND": "test? ( app-misc/E )" + }, + "app-misc/E-0": { + "EAPI": "5", + "IUSE": "test", + "DEPEND": "test? ( app-misc/D )" + }, + "app-misc/F-0": { + "EAPI": "5", + "IUSE": "+test", + "DEPEND": "test? ( app-misc/G )" + }, + "app-misc/G-0": { + "EAPI": "5", + "IUSE": "+test", + "DEPEND": "test? ( app-misc/F )" + }, } test_cases = ( @@ -32,6 +52,23 @@ class WithTestDepsTestCase(TestCase): success = True, options = { "--onlydeps": True, "--with-test-deps": True }, mergelist = ["app-misc/B-0"]), + + # Test that --with-test-deps allows circular dependencies. + ResolverPlaygroundTestCase( + ['app-misc/D'], + success = True, + options = {'--with-test-deps': True}, + mergelist = [('app-misc/D-0', 'app-misc/E-0')], + ambiguous_merge_order=True), + + # Test that --with-test-deps does not allow circular dependencies + # when USE=test is explicitly enabled. + ResolverPlaygroundTestCase( + ['app-misc/F'], + success = False, + options = {'--with-test-deps': True}, + circular_dependency_solutions = {'app-misc/G-0': {frozenset({('test', False)})}, 'app-misc/F-0': {frozenset({('test', False)})}}, + ) ) playground = ResolverPlayground(ebuilds=ebuilds, debug=False)