From 5c02700c9891922ba9af48165273b91bf52e314a Mon Sep 17 00:00:00 2001 From: Arfrever Frehtes Taifersar Arahesis Date: Thu, 15 Nov 2012 08:19:21 +0100 Subject: [PATCH] EAPI="4-python" and EAPI="5-progress": Add support for use.aliases and package.use.aliases. --- doc/package/ebuild/eapi/4-python.docbook | 36 +++++ doc/package/ebuild/eapi/5-progress.docbook | 36 +++++ pym/_emerge/Package.py | 61 ++++++-- pym/_emerge/depgraph.py | 13 +- pym/_emerge/resolver/slot_collision.py | 5 +- pym/portage/eapi.py | 3 + .../package/ebuild/_config/UseManager.py | 119 +++++++++++++++- .../tests/resolver/ResolverPlayground.py | 8 +- .../tests/resolver/test_use_aliases.py | 131 ++++++++++++++++++ 9 files changed, 383 insertions(+), 29 deletions(-) create mode 100644 pym/portage/tests/resolver/test_use_aliases.py diff --git a/doc/package/ebuild/eapi/4-python.docbook b/doc/package/ebuild/eapi/4-python.docbook index c49033023..9e8a9daa1 100644 --- a/doc/package/ebuild/eapi/4-python.docbook +++ b/doc/package/ebuild/eapi/4-python.docbook @@ -122,4 +122,40 @@ +
+ USE Flag Aliases + + USE flag aliases are supported to allow to satisfy dependencies of packages from other repositories, which require differently named USE flags. USE flag aliases are defined in ${repository_path}/profiles/use.aliases and ${repository_path}/profiles/package.use.aliases files. + + use.aliases Example + + + + real_flag1 alias1 alias2 + + + real_flag2 alias3 alias4 + + + +
+ package.use.aliases Example + + + + category/package1 real_flag1 alias1 alias2 + + + category/package1 real_flag2 alias3 alias4 + + + =category/package2-1* real_flag3 alias5 alias6 + + + =category/package2-2* real_flag4 alias5 alias6 + + + +
+
diff --git a/doc/package/ebuild/eapi/5-progress.docbook b/doc/package/ebuild/eapi/5-progress.docbook index 2acda9597..bc7c30066 100644 --- a/doc/package/ebuild/eapi/5-progress.docbook +++ b/doc/package/ebuild/eapi/5-progress.docbook @@ -161,4 +161,40 @@ +
+ USE Flag Aliases + + USE flag aliases are supported to allow to satisfy dependencies of packages from other repositories, which require differently named USE flags. USE flag aliases are defined in ${repository_path}/profiles/use.aliases and ${repository_path}/profiles/package.use.aliases files. + + use.aliases Example + + + + real_flag1 alias1 alias2 + + + real_flag2 alias3 alias4 + + + +
+ package.use.aliases Example + + + + category/package1 real_flag1 alias1 alias2 + + + category/package1 real_flag2 alias3 alias4 + + + =category/package2-1* real_flag3 alias5 alias6 + + + =category/package2-2* real_flag4 alias5 alias6 + + + +
+
diff --git a/pym/_emerge/Package.py b/pym/_emerge/Package.py index b60f74486..1c1840836 100644 --- a/pym/_emerge/Package.py +++ b/pym/_emerge/Package.py @@ -10,7 +10,7 @@ from portage.const import EBUILD_PHASES from portage.dep import Atom, check_required_use, use_reduce, \ paren_enclose, _slot_separator, _repo_separator from portage.versions import _pkg_str, _unknown_repo -from portage.eapi import _get_eapi_attrs +from portage.eapi import _get_eapi_attrs, eapi_has_use_aliases from portage.exception import InvalidDependString from portage.localization import _ from _emerge.Task import Task @@ -62,9 +62,13 @@ class Package(Task): if hasattr(self.cpv, 'slot_invalid'): self._invalid_metadata('SLOT.invalid', "SLOT: invalid value: '%s'" % self.metadata["SLOT"]) + self.cpv_split = self.cpv.cpv_split + self.category, self.pf = portage.catsplit(self.cpv) self.cp = self.cpv.cp + self.version = self.cpv.version self.slot = self.cpv.slot self.sub_slot = self.cpv.sub_slot + self.slot_atom = Atom("%s%s%s" % (self.cp, _slot_separator, self.slot)) # sync metadata with validated repo (may be UNKNOWN_REPO) self.metadata['repository'] = self.cpv.repo @@ -72,17 +76,15 @@ class Package(Task): implicit_match = self.root_config.settings._iuse_effective_match else: implicit_match = self.root_config.settings._iuse_implicit_match - self.iuse = self._iuse(self.metadata["IUSE"].split(), implicit_match) + usealiases = self.root_config.settings._use_manager.getUseAliases(self) + self.iuse = self._iuse(self, self.metadata["IUSE"].split(), implicit_match, + usealiases, self.metadata["EAPI"]) if (self.iuse.enabled or self.iuse.disabled) and \ not eapi_attrs.iuse_defaults: if not self.installed: self._invalid_metadata('EAPI.incompatible', "IUSE contains defaults, but EAPI doesn't allow them") - self.slot_atom = Atom("%s%s%s" % (self.cp, _slot_separator, self.slot)) - self.category, self.pf = portage.catsplit(self.cpv) - self.cpv_split = self.cpv.cpv_split - self.version = self.cpv.version if self.inherited is None: self.inherited = frozenset() @@ -469,7 +471,11 @@ class Package(Task): self._expand_hidden = None self._force = None self._mask = None - self.enabled = frozenset(use_str.split()) + enabled_flags = use_str.split() + if eapi_has_use_aliases(pkg.metadata["EAPI"]): + for enabled_flag in enabled_flags: + enabled_flags.extend(pkg.iuse.alias_mapping.get(enabled_flag, [])) + self.enabled = frozenset(enabled_flags) if pkg.built: # Use IUSE to validate USE settings for built packages, # in case the package manager that built this package @@ -542,26 +548,42 @@ class Package(Task): class _iuse(object): - __slots__ = ("__weakref__", "all", "enabled", "disabled", - "tokens") + ("_iuse_implicit_match",) + __slots__ = ("__weakref__", "_iuse_implicit_match", "_pkg", "alias_mapping", + "all", "all_aliases", "enabled", "disabled", "tokens") - def __init__(self, tokens, iuse_implicit_match): + def __init__(self, pkg, tokens, iuse_implicit_match, aliases, eapi): + self._pkg = pkg self.tokens = tuple(tokens) self._iuse_implicit_match = iuse_implicit_match enabled = [] disabled = [] other = [] + enabled_aliases = [] + disabled_aliases = [] + other_aliases = [] + aliases_supported = eapi_has_use_aliases(eapi) + self.alias_mapping = {} for x in tokens: prefix = x[:1] if prefix == "+": enabled.append(x[1:]) + if aliases_supported: + self.alias_mapping[x[1:]] = aliases.get(x[1:], []) + enabled_aliases.extend(self.alias_mapping[x[1:]]) elif prefix == "-": disabled.append(x[1:]) + if aliases_supported: + self.alias_mapping[x[1:]] = aliases.get(x[1:], []) + disabled_aliases.extend(self.alias_mapping[x[1:]]) else: other.append(x) - self.enabled = frozenset(enabled) - self.disabled = frozenset(disabled) + if aliases_supported: + self.alias_mapping[x] = aliases.get(x, []) + other_aliases.extend(self.alias_mapping[x]) + self.enabled = frozenset(chain(enabled, enabled_aliases)) + self.disabled = frozenset(chain(disabled, disabled_aliases)) self.all = frozenset(chain(enabled, disabled, other)) + self.all_aliases = frozenset(chain(enabled_aliases, disabled_aliases, other_aliases)) def is_valid_flag(self, flags): """ @@ -572,7 +594,7 @@ class Package(Task): flags = [flags] for flag in flags: - if not flag in self.all and \ + if not flag in self.all and not flag in self.all_aliases and \ not self._iuse_implicit_match(flag): return False return True @@ -585,11 +607,22 @@ class Package(Task): flags = [flags] missing_iuse = [] for flag in flags: - if not flag in self.all and \ + if not flag in self.all and not flag in self.all_aliases and \ not self._iuse_implicit_match(flag): missing_iuse.append(flag) return missing_iuse + def get_real_flag(self, flag): + if flag in self.all: + return flag + elif flag in self.all_aliases: + for k, v in self.alias_mapping.items(): + if flag in v: + return k + else: + raise ValueError("'%s' flag is not in IUSE and is not an alias of any flag in IUSE of '%s::%s'" % + (flag, self._pkg.cpv, self._pkg.repo)) + def __len__(self): return 4 diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 952d0618d..dace4fc74 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -4150,17 +4150,18 @@ class depgraph(object): new_changes = {} for flag, state in target_use.items(): + real_flag = pkg.iuse.get_real_flag(flag) if state: - if flag not in old_use: - if new_changes.get(flag) == False: + if real_flag not in old_use: + if new_changes.get(real_flag) == False: return old_use - new_changes[flag] = True + new_changes[real_flag] = True new_use.add(flag) else: - if flag in old_use: - if new_changes.get(flag) == True: + if real_flag in old_use: + if new_changes.get(real_flag) == True: return old_use - new_changes[flag] = False + new_changes[real_flag] = False new_use.update(old_use.difference(target_use)) def want_restart_for_use_change(pkg, new_use): diff --git a/pym/_emerge/resolver/slot_collision.py b/pym/_emerge/resolver/slot_collision.py index bc95e916e..c2b04d58c 100644 --- a/pym/_emerge/resolver/slot_collision.py +++ b/pym/_emerge/resolver/slot_collision.py @@ -225,10 +225,11 @@ class slot_conflict_handler(object): new_change = {} for pkg in solution: for flag, state in solution[pkg].items(): + real_flag = pkg.iuse.get_real_flag(flag) if state == "enabled" and flag not in _pkg_use_enabled(pkg): - new_change.setdefault(pkg, {})[flag] = True + new_change.setdefault(pkg, {})[real_flag] = True elif state == "disabled" and flag in _pkg_use_enabled(pkg): - new_change.setdefault(pkg, {})[flag] = False + new_change.setdefault(pkg, {})[real_flag] = False return new_change def _prepare_conflict_msg_and_check_for_specificity(self): diff --git a/pym/portage/eapi.py b/pym/portage/eapi.py index 4936e6cd7..bc1240c90 100644 --- a/pym/portage/eapi.py +++ b/pym/portage/eapi.py @@ -83,6 +83,9 @@ def eapi_supports_stable_use_forcing_and_masking(eapi): def eapi_allows_directories_on_profile_level_and_repository_level(eapi): return eapi in ("4-python", "5-progress") +def eapi_has_use_aliases(eapi): + return eapi in ("4-python", "5-progress") + def eapi_has_hdepend(eapi): return eapi in ("5-hdepend",) diff --git a/pym/portage/package/ebuild/_config/UseManager.py b/pym/portage/package/ebuild/_config/UseManager.py index cd67ced93..93ec6209c 100644 --- a/pym/portage/package/ebuild/_config/UseManager.py +++ b/pym/portage/package/ebuild/_config/UseManager.py @@ -7,10 +7,11 @@ __all__ = ( from _emerge.Package import Package from portage import os -from portage.dep import dep_getrepo, dep_getslot, ExtendedAtomDict, remove_slot, _get_useflag_re -from portage.eapi import eapi_supports_stable_use_forcing_and_masking +from portage.dep import Atom, dep_getrepo, dep_getslot, ExtendedAtomDict, remove_slot, _get_useflag_re, _repo_separator +from portage.eapi import eapi_has_use_aliases, eapi_supports_stable_use_forcing_and_masking +from portage.exception import InvalidAtom from portage.localization import _ -from portage.util import grabfile, grabdict_package, read_corresponding_eapi_file, stack_lists, writemsg +from portage.util import grabfile, grabdict, grabdict_package, read_corresponding_eapi_file, stack_lists, writemsg from portage.versions import _pkg_str from portage.package.ebuild._config.helper import ordered_by_atom_specificity @@ -26,10 +27,12 @@ class UseManager(object): # use.stable.mask _repo_usestablemask_dict # use.force _repo_useforce_dict # use.stable.force _repo_usestableforce_dict + # use.aliases _repo_usealiases_dict # package.use.mask _repo_pusemask_dict # package.use.stable.mask _repo_pusestablemask_dict # package.use.force _repo_puseforce_dict # package.use.stable.force _repo_pusestableforce_dict + # package.use.aliases _repo_pusealiases_dict #-------------------------------- # profiles #-------------------------------- @@ -96,6 +99,9 @@ class UseManager(object): self._pusedict = self._parse_user_files_to_extatomdict("package.use", abs_user_config, user_config) + self._repo_usealiases_dict = self._parse_repository_usealiases(repositories) + self._repo_pusealiases_dict = self._parse_repository_packageusealiases(repositories) + self.repositories = repositories def _parse_file_to_tuple(self, file_name, recursive=True, eapi_filter=None): @@ -200,6 +206,69 @@ class UseManager(object): user_config=profile.user_config) for profile in locations) + def _parse_repository_usealiases(self, repositories): + ret = {} + for repo in repositories.repos_with_profiles(): + file_name = os.path.join(repo.location, "profiles", "use.aliases") + eapi = read_corresponding_eapi_file(file_name) + useflag_re = _get_useflag_re(eapi) + raw_file_dict = grabdict(file_name, recursive=True) + file_dict = {} + for real_flag, aliases in raw_file_dict.items(): + if useflag_re.match(real_flag) is None: + writemsg(_("--- Invalid real USE flag in '%s': '%s'\n") % (file_name, real_flag), noiselevel=-1) + else: + for alias in aliases: + if useflag_re.match(alias) is None: + writemsg(_("--- Invalid USE flag alias for '%s' real USE flag in '%s': '%s'\n") % + (real_flag, file_name, alias), noiselevel=-1) + else: + if any(alias in v for k, v in file_dict.items() if k != real_flag): + writemsg(_("--- Duplicated USE flag alias in '%s': '%s'\n") % + (file_name, alias), noiselevel=-1) + else: + file_dict.setdefault(real_flag, []).append(alias) + ret[repo.name] = file_dict + return ret + + def _parse_repository_packageusealiases(self, repositories): + ret = {} + for repo in repositories.repos_with_profiles(): + file_name = os.path.join(repo.location, "profiles", "package.use.aliases") + eapi = read_corresponding_eapi_file(file_name) + useflag_re = _get_useflag_re(eapi) + lines = grabfile(file_name, recursive=True) + file_dict = {} + for line in lines: + elements = line.split() + atom = elements[0] + try: + atom = Atom(atom, eapi=eapi) + except InvalidAtom: + writemsg(_("--- Invalid atom in '%s': '%s'\n") % (file_name, atom)) + continue + if len(elements) == 1: + writemsg(_("--- Missing real USE flag for '%s' in '%s'\n") % (atom, file_name), noiselevel=-1) + continue + real_flag = elements[1] + if useflag_re.match(real_flag) is None: + writemsg(_("--- Invalid real USE flag for '%s' in '%s': '%s'\n") % (atom, file_name, real_flag), noiselevel=-1) + else: + for alias in elements[2:]: + if useflag_re.match(alias) is None: + writemsg(_("--- Invalid USE flag alias for '%s' real USE flag for '%s' in '%s': '%s'\n") % + (real_flag, atom, file_name, alias), noiselevel=-1) + else: + # Duplicated USE flag aliases in entries for different atoms + # matching the same package version are detected in getUseAliases(). + if any(alias in v for k, v in file_dict.get(atom.cp, {}).get(atom, {}).items() if k != real_flag): + writemsg(_("--- Duplicated USE flag alias for '%s' in '%s': '%s'\n") % + (atom, file_name, alias), noiselevel=-1) + else: + file_dict.setdefault(atom.cp, {}).setdefault(atom, {}).setdefault(real_flag, []).append(alias) + ret[repo.name] = file_dict + return ret + def getUseMask(self, pkg=None): if pkg is None: return frozenset(stack_lists( @@ -327,6 +396,50 @@ class UseManager(object): return frozenset(stack_lists(useforce, incremental=True)) + def getUseAliases(self, pkg): + if not eapi_has_use_aliases(pkg.metadata["EAPI"]): + return {} + + cp = getattr(pkg, "cp", None) + if cp is None: + slot = dep_getslot(pkg) + repo = dep_getrepo(pkg) + pkg = _pkg_str(remove_slot(pkg), slot=slot, repo=repo) + cp = pkg.cp + + usealiases = {} + + if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: + repos = [] + try: + repos.extend(repo.name for repo in + self.repositories[pkg.repo].masters) + except KeyError: + pass + repos.append(pkg.repo) + for repo in repos: + usealiases_dict = self._repo_usealiases_dict.get(repo, {}) + for real_flag, aliases in usealiases_dict.items(): + for alias in aliases: + if any(alias in v for k, v in usealiases.items() if k != real_flag): + writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") % + (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1) + else: + usealiases.setdefault(real_flag, []).append(alias) + cp_usealiases_dict = self._repo_pusealiases_dict.get(repo, {}).get(cp) + if cp_usealiases_dict: + usealiases_dict_list = ordered_by_atom_specificity(cp_usealiases_dict, pkg) + for usealiases_dict in usealiases_dict_list: + for real_flag, aliases in usealiases_dict.items(): + for alias in aliases: + if any(alias in v for k, v in usealiases.items() if k != real_flag): + writemsg(_("--- Duplicated USE flag alias for '%s%s%s': '%s'\n") % + (pkg.cpv, _repo_separator, pkg.repo, alias), noiselevel=-1) + else: + usealiases.setdefault(real_flag, []).append(alias) + + return usealiases + def getPUSE(self, pkg): cp = getattr(pkg, "cp", None) if cp is None: diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py index 62aafb56e..9b30edbee 100644 --- a/pym/portage/tests/resolver/ResolverPlayground.py +++ b/pym/portage/tests/resolver/ResolverPlayground.py @@ -34,10 +34,10 @@ class ResolverPlayground(object): its work. """ - config_files = frozenset(("eapi", "make.conf", "package.accept_keywords", "package.use", - "package.use.stable.mask", "package.mask", "package.keywords", - "package.unmask", "package.properties", "package.license", "use.mask", "use.force", - "layout.conf",)) + config_files = frozenset(("eapi", "layout.conf", "make.conf", "package.accept_keywords", + "package.keywords", "package.license", "package.mask", "package.properties", + "package.unmask", "package.use", "package.use.aliases", "package.use.stable.mask", + "use.aliases", "use.force", "use.mask", "layout.conf")) metadata_xml_template = """ diff --git a/pym/portage/tests/resolver/test_use_aliases.py b/pym/portage/tests/resolver/test_use_aliases.py new file mode 100644 index 000000000..7c2debbb1 --- /dev/null +++ b/pym/portage/tests/resolver/test_use_aliases.py @@ -0,0 +1,131 @@ +# 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 UseAliasesTestCase(TestCase): + def testUseAliases(self): + ebuilds = { + "dev-libs/A-1": {"DEPEND": "dev-libs/K[x]", "RDEPEND": "dev-libs/K[x]", "EAPI": "5"}, + "dev-libs/B-1": {"DEPEND": "dev-libs/L[x]", "RDEPEND": "dev-libs/L[x]", "EAPI": "5"}, + "dev-libs/C-1": {"DEPEND": "dev-libs/M[xx]", "RDEPEND": "dev-libs/M[xx]", "EAPI": "5"}, + "dev-libs/D-1": {"DEPEND": "dev-libs/N[-x]", "RDEPEND": "dev-libs/N[-x]", "EAPI": "5"}, + "dev-libs/E-1": {"DEPEND": "dev-libs/O[-xx]", "RDEPEND": "dev-libs/O[-xx]", "EAPI": "5"}, + "dev-libs/F-1": {"DEPEND": "dev-libs/P[-xx]", "RDEPEND": "dev-libs/P[-xx]", "EAPI": "5"}, + "dev-libs/G-1": {"DEPEND": "dev-libs/Q[x-y]", "RDEPEND": "dev-libs/Q[x-y]", "EAPI": "5"}, + "dev-libs/H-1": {"DEPEND": "=dev-libs/R-1*[yy]", "RDEPEND": "=dev-libs/R-1*[yy]", "EAPI": "5"}, + "dev-libs/H-2": {"DEPEND": "=dev-libs/R-2*[yy]", "RDEPEND": "=dev-libs/R-2*[yy]", "EAPI": "5"}, + "dev-libs/I-1": {"DEPEND": "dev-libs/S[y-z]", "RDEPEND": "dev-libs/S[y-z]", "EAPI": "5"}, + "dev-libs/I-2": {"DEPEND": "dev-libs/S[y_z]", "RDEPEND": "dev-libs/S[y_z]", "EAPI": "5"}, + "dev-libs/J-1": {"DEPEND": "dev-libs/T[x]", "RDEPEND": "dev-libs/T[x]", "EAPI": "5"}, + "dev-libs/K-1": {"IUSE": "+x", "EAPI": "5"}, + "dev-libs/K-2::repo1": {"IUSE": "+X", "EAPI": "5-progress"}, + "dev-libs/L-1": {"IUSE": "+x", "EAPI": "5"}, + "dev-libs/M-1::repo1": {"IUSE": "X", "EAPI": "5-progress"}, + "dev-libs/N-1": {"IUSE": "x", "EAPI": "5"}, + "dev-libs/N-2::repo1": {"IUSE": "X", "EAPI": "5-progress"}, + "dev-libs/O-1": {"IUSE": "x", "EAPI": "5"}, + "dev-libs/P-1::repo1": {"IUSE": "+X", "EAPI": "5-progress"}, + "dev-libs/Q-1::repo2": {"IUSE": "X.Y", "EAPI": "5-progress"}, + "dev-libs/R-1::repo1": {"IUSE": "Y", "EAPI": "5-progress"}, + "dev-libs/R-2::repo1": {"IUSE": "y", "EAPI": "5-progress"}, + "dev-libs/S-1::repo2": {"IUSE": "Y.Z", "EAPI": "5-progress"}, + "dev-libs/S-2::repo2": {"IUSE": "Y.Z", "EAPI": "5-progress"}, + "dev-libs/T-1::repo1": {"IUSE": "+X", "EAPI": "5"}, + } + + installed = { + "dev-libs/L-2::repo1": {"IUSE": "+X", "USE": "X", "EAPI": "5-progress"}, + "dev-libs/O-2::repo1": {"IUSE": "X", "USE": "", "EAPI": "5-progress"}, + } + + repo_configs = { + "repo1": { + "use.aliases": ("X x xx",), + "package.use.aliases": ( + "=dev-libs/R-1* Y yy", + "=dev-libs/R-2* y yy", + ) + }, + "repo2": { + "eapi": ("5-progress",), + "use.aliases": ("X.Y x-y",), + "package.use.aliases": ( + "=dev-libs/S-1* Y.Z y-z", + "=dev-libs/S-2* Y.Z y_z", + ), + }, + } + + test_cases = ( + ResolverPlaygroundTestCase( + ["dev-libs/A"], + success = True, + mergelist = ["dev-libs/K-2", "dev-libs/A-1"]), + ResolverPlaygroundTestCase( + ["dev-libs/B"], + success = True, + mergelist = ["dev-libs/B-1"]), + ResolverPlaygroundTestCase( + ["dev-libs/C"], + options = {"--autounmask": True}, + success = False, + mergelist = ["dev-libs/M-1", "dev-libs/C-1"], + use_changes = {"dev-libs/M-1": {"X": True}}), + ResolverPlaygroundTestCase( + ["dev-libs/D"], + success = True, + mergelist = ["dev-libs/N-2", "dev-libs/D-1"]), + ResolverPlaygroundTestCase( + ["dev-libs/E"], + success = True, + mergelist = ["dev-libs/E-1"]), + ResolverPlaygroundTestCase( + ["dev-libs/F"], + options = {"--autounmask": True}, + success = False, + mergelist = ["dev-libs/P-1", "dev-libs/F-1"], + use_changes = {"dev-libs/P-1": {"X": False}}), + ResolverPlaygroundTestCase( + ["dev-libs/G"], + options = {"--autounmask": True}, + success = False, + mergelist = ["dev-libs/Q-1", "dev-libs/G-1"], + use_changes = {"dev-libs/Q-1": {"X.Y": True}}), + ResolverPlaygroundTestCase( + ["=dev-libs/H-1*"], + options = {"--autounmask": True}, + success = False, + mergelist = ["dev-libs/R-1", "dev-libs/H-1"], + use_changes = {"dev-libs/R-1": {"Y": True}}), + ResolverPlaygroundTestCase( + ["=dev-libs/H-2*"], + options = {"--autounmask": True}, + success = False, + mergelist = ["dev-libs/R-2", "dev-libs/H-2"], + use_changes = {"dev-libs/R-2": {"y": True}}), + ResolverPlaygroundTestCase( + ["=dev-libs/I-1*"], + options = {"--autounmask": True}, + success = False, + mergelist = ["dev-libs/S-1", "dev-libs/I-1"], + use_changes = {"dev-libs/S-1": {"Y.Z": True}}), + ResolverPlaygroundTestCase( + ["=dev-libs/I-2*"], + options = {"--autounmask": True}, + success = False, + mergelist = ["dev-libs/S-2", "dev-libs/I-2"], + use_changes = {"dev-libs/S-2": {"Y.Z": True}}), + ResolverPlaygroundTestCase( + ["dev-libs/J"], + success = False), + ) + + playground = ResolverPlayground(ebuilds=ebuilds, installed=installed, repo_configs=repo_configs) + 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() -- 2.26.2