commit: 12f6056da88041f82a9c9dfc23ee0eab39077782 Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Sun Feb 11 04:12:45 2024 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Sun Feb 11 04:36:22 2024 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=12f6056d
_overlap_dnf: deduplicate any-of blocks Duplicate any-of blocks are eliminated since DNF expansion of duplicates is nonsensical. Bug: https://bugs.gentoo.org/891137 Signed-off-by: Zac Medico <zmedico <AT> gentoo.org> lib/portage/dep/dep_check.py | 17 ++++++++++++++--- lib/portage/tests/dep/test_overlap_dnf.py | 31 +++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/portage/dep/dep_check.py b/lib/portage/dep/dep_check.py index 5ca0995a87..c361ee59e2 100644 --- a/lib/portage/dep/dep_check.py +++ b/lib/portage/dep/dep_check.py @@ -1,4 +1,4 @@ -# Copyright 2010-2020 Gentoo Authors +# Copyright 2010-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 __all__ = ["dep_check", "dep_eval", "dep_wordreduce", "dep_zapdeps"] @@ -963,7 +963,8 @@ def _overlap_dnf(dep_struct): order to minimize the number of packages chosen to satisfy cases like "|| ( foo bar ) || ( bar baz )" as in bug #632026. Non-overlapping groups are excluded from the conversion, since DNF leads to exponential - explosion of the formula. + explosion of the formula. Duplicate || groups are eliminated since + DNF expansion of duplicates is nonsensical (bug #891137). When dep_struct does not contain any overlapping groups, no DNF conversion will be performed, and dep_struct will be returned as-is. @@ -1021,7 +1022,17 @@ def _overlap_dnf(dep_struct): if len(disjunctions) > 1: overlap = True # convert overlapping disjunctions to DNF - result.extend(_dnf_convert(sorted(disjunctions.values(), key=order_key))) + dedup_set = set() + unique_disjunctions = [] + for x in sorted(disjunctions.values(), key=order_key): + dep_repr = portage.dep.paren_enclose(x, opconvert=True) + if dep_repr not in dedup_set: + dedup_set.add(dep_repr) + unique_disjunctions.append(x) + if len(unique_disjunctions) > 1: + result.extend(_dnf_convert(unique_disjunctions)) + else: + result.extend(unique_disjunctions) else: # pass through non-overlapping disjunctions result.append(disjunctions.popitem()[1]) diff --git a/lib/portage/tests/dep/test_overlap_dnf.py b/lib/portage/tests/dep/test_overlap_dnf.py index 77352021a9..7fd1cfe7dd 100644 --- a/lib/portage/tests/dep/test_overlap_dnf.py +++ b/lib/portage/tests/dep/test_overlap_dnf.py @@ -1,4 +1,4 @@ -# Copyright 2017-2023 Gentoo Authors +# Copyright 2017-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 from portage.tests import TestCase @@ -51,22 +51,41 @@ class OverlapDNFTestCase(TestCase): class DuplicateOverlapDNFTestCase(TestCase): def testDuplicateOverlapDNF(self): """ - Demonstrate unnecessary DNF expansion for duplicate - any-of blocks as in bug 891137. + Demonstrate deduplication of any-of blocks, preventing unnecessary + DNF expansion for duplicate any-of blocks as in bug 891137. """ test_cases = ( + ("|| ( cat/A cat/B ) || ( cat/A cat/B )", [["||", "cat/A", "cat/B"]]), ( - "|| ( cat/A cat/B ) || ( cat/A cat/B )", + "|| ( cat/A cat/B ) cat/E || ( cat/C cat/D ) || ( cat/A cat/B )", + ["cat/E", ["||", "cat/A", "cat/B"], ["||", "cat/C", "cat/D"]], + ), + ( + "|| ( cat/A cat/B ) cat/D || ( cat/B cat/C ) || ( cat/A cat/B )", [ + "cat/D", [ "||", - ["cat/A", "cat/A"], ["cat/A", "cat/B"], - ["cat/B", "cat/A"], + ["cat/A", "cat/C"], ["cat/B", "cat/B"], + ["cat/B", "cat/C"], ], ], ), + ( + "|| ( cat/A cat/B ) || ( cat/C cat/D ) || ( ( cat/B cat/E ) cat/F ) || ( cat/A cat/B )", + [ + [ + "||", + ["cat/A", "cat/B", "cat/E"], + ["cat/A", "cat/F"], + ["cat/B", "cat/B", "cat/E"], + ["cat/B", "cat/F"], + ], + ["||", "cat/C", "cat/D"], + ], + ), ) for dep_str, result in test_cases: