commit: 0a0b89f1a3fc6c549f68c76bd3c031a8a1b5d902 Author: Jethro Donaldson <devel <AT> jro <DOT> nz> AuthorDate: Thu Dec 4 09:49:03 2025 +0000 Commit: Sam James <sam <AT> gentoo <DOT> org> CommitDate: Mon Feb 16 06:54:16 2026 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=0a0b89f1
config: add usepkg-exclude and usepkg-include to repos.conf Allow configuration in repos.conf of specific packages which are to be satisfied (or not) using binary packages. These attributes appear under the repository section and are specific to that repository, with behaviour otherwise identical to the command line arguments of the same name. Where atoms specified with usepkg-exclude or usepkg-include in repos.conf match those for the opposing command line options then emit a warning and override the repos.conf atoms. Signed-off-by: Jethro Donaldson <devel <AT> jro.nz> Part-of: https://github.com/gentoo/portage/pull/1527 Signed-off-by: Sam James <sam <AT> gentoo.org> lib/_emerge/actions.py | 42 ++ lib/_emerge/depgraph.py | 12 +- lib/_emerge/main.py | 30 +- lib/portage/repository/config.py | 70 +++ lib/portage/tests/resolver/ResolverPlayground.py | 21 +- .../tests/resolver/test_binpackage_selection.py | 541 +++++++++++++++++++++ man/emerge.1 | 3 +- man/portage.5 | 14 + 8 files changed, 690 insertions(+), 43 deletions(-) diff --git a/lib/_emerge/actions.py b/lib/_emerge/actions.py index 472feb135f..1838582ff6 100644 --- a/lib/_emerge/actions.py +++ b/lib/_emerge/actions.py @@ -2851,6 +2851,48 @@ def binpkg_selection_config(opts, settings): "\n %s\n" % ("\n ".join(usepkg_include.getAtoms())) ) usepkg_include.clear() + for repo in settings.repositories: + if not repo.usepkg_exclude.isEmpty(): + writemsg( + "\n!!! The following usepkg-exclude atoms for [%s] are " + "ignored due to use of --nobindeps:\n" + "\n %s\n" + % (repo.name, "\n ".join(repo.usepkg_exclude.getAtoms())) + ) + repo.usepkg_exclude.clear() + if not repo.usepkg_include.isEmpty(): + writemsg( + "\n!!! The following usepkg-include atoms for [%s] are " + "ignored due to use of --nobindeps:\n" + "\n %s\n" + % (repo.name, "\n ".join(repo.usepkg_include.getAtoms())) + ) + repo.usepkg_include.clear() + + # --usepkg-exclude and --usepkg-include override repos.conf + for repo in settings.repositories: + conflicted_exclude = repo.usepkg_exclude.getAtoms().intersection( + usepkg_include.getAtoms() + ) + if conflicted_exclude: + writemsg( + "\n!!! The following usepkg-exclude atoms for [%s] have " + "been overridden by the --usepkg-include option:\n" + "\n %s\n" % (repo.name, "\n ".join(conflicted_exclude)) + ) + for a in conflicted_exclude: + repo.usepkg_exclude.remove(a) + conflicted_include = repo.usepkg_include.getAtoms().intersection( + usepkg_exclude.getAtoms() + ) + if conflicted_include: + writemsg( + "\n!!! The following usepkg-include atoms for [%s] have " + "been overridden by the --usepkg-exclude option:\n" + "\n %s\n" % (repo.name, "\n ".join(conflicted_include)) + ) + for a in conflicted_include: + repo.usepkg_include.remove(a) # --getbinpkg-include and --getbinpkg-exclude may not overlap conflicted_atoms = getbinpkg_exclude.getAtoms().intersection( diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py index 17c5e54900..7ac07ad5e4 100644 --- a/lib/_emerge/depgraph.py +++ b/lib/_emerge/depgraph.py @@ -197,9 +197,9 @@ class _frozen_depgraph_config: atoms = " ".join(myopts.get("--reinstall-atoms", [])).split() self.reinstall_atoms = WildcardPackageSet(atoms) atoms = " ".join(myopts.get("--usepkg-exclude", [])).split() - self.usepkg_exclude = WildcardPackageSet(atoms) + self.usepkg_exclude = WildcardPackageSet(atoms, allow_repo=True) atoms = " ".join(myopts.get("--usepkg-include", [])).split() - self.usepkg_include = WildcardPackageSet(atoms) + self.usepkg_include = WildcardPackageSet(atoms, allow_repo=True) atoms = " ".join(myopts.get("--useoldpkg-atoms", [])).split() self.useoldpkg_atoms = WildcardPackageSet(atoms) atoms = " ".join(myopts.get("--rebuild-exclude", [])).split() @@ -207,6 +207,14 @@ class _frozen_depgraph_config: atoms = " ".join(myopts.get("--rebuild-ignore", [])).split() self.rebuild_ignore = WildcardPackageSet(atoms) + for repo in settings.repositories: + self.usepkg_exclude.update( + a + _repo_separator + repo.name for a in repo.usepkg_exclude.getAtoms() + ) + self.usepkg_include.update( + a + _repo_separator + repo.name for a in repo.usepkg_include.getAtoms() + ) + self.rebuild_if_new_rev = "--rebuild-if-new-rev" in myopts self.rebuild_if_new_ver = "--rebuild-if-new-ver" in myopts self.rebuild_if_unbuilt = "--rebuild-if-unbuilt" in myopts diff --git a/lib/_emerge/main.py b/lib/_emerge/main.py index 5eef25193e..f176e40e44 100644 --- a/lib/_emerge/main.py +++ b/lib/_emerge/main.py @@ -11,6 +11,7 @@ import sys import portage from portage import os +from portage.repository.config import _find_bad_atoms from portage.sync import _SUBMODULE_PATH_MAP from typing import Optional @@ -281,35 +282,6 @@ def insert_optional_args(args): return new_args -def _find_bad_atoms(atoms, less_strict=False): - """ - Declares all atoms as invalid that have an operator, - a use dependency, a blocker or a repo spec. - It accepts atoms with wildcards. - In less_strict mode it accepts operators and repo specs. - """ - from _emerge.is_valid_package_atom import insert_category_into_atom - from portage.dep import Atom - - bad_atoms = [] - for x in " ".join(atoms).split(): - atom = x - if "/" not in x.split(":")[0]: - x_cat = insert_category_into_atom(x, "dummy-category") - if x_cat is not None: - atom = x_cat - - bad_atom = False - try: - atom = Atom(atom, allow_wildcard=True, allow_repo=less_strict) - except portage.exception.InvalidAtom: - bad_atom = True - - if bad_atom or (atom.operator and not less_strict) or atom.blocker or atom.use: - bad_atoms.append(x) - return bad_atoms - - def parse_opts(tmpcmdline, silent=False): myaction = None myopts = {} diff --git a/lib/portage/repository/config.py b/lib/portage/repository/config.py index 16b9ae701f..a98fc17f25 100644 --- a/lib/portage/repository/config.py +++ b/lib/portage/repository/config.py @@ -12,7 +12,9 @@ import typing import portage from pathlib import Path from portage import eclass_cache, os +from portage._sets.base import WildcardPackageSet from portage.checksum import get_valid_checksum_keys +from portage.dep import Atom from portage.const import PORTAGE_BASE_PATH, REPO_NAME_LOC, USER_CONFIG_PATH from portage.eapi import ( eapi_allows_directories_on_profile_level_and_repository_level, @@ -89,6 +91,34 @@ def _gen_valid_repo(name): return name +def _find_bad_atoms(atoms, less_strict=False): + """ + Declares all atoms as invalid that have an operator, + a use dependency, a blocker or a repo spec. + It accepts atoms with wildcards. + In less_strict mode it accepts operators and repo specs. + """ + from _emerge.is_valid_package_atom import insert_category_into_atom + + bad_atoms = [] + for x in " ".join(atoms or []).split(): + atom = x + if "/" not in x.split(":")[0]: + x_cat = insert_category_into_atom(x, "dummy-category") + if x_cat is not None: + atom = x_cat + + bad_atom = False + try: + atom = Atom(atom, allow_wildcard=True, allow_repo=less_strict) + except portage.exception.InvalidAtom: + bad_atom = True + + if bad_atom or (atom.operator and not less_strict) or atom.blocker or atom.use: + bad_atoms.append(x) + return bad_atoms + + def _find_invalid_path_char(path, pos=0, endpos=None): """ Returns the position of the first invalid character found in basename, @@ -163,6 +193,8 @@ class RepoConfig: "sync_user", "thin_manifest", "update_changelog", + "usepkg_exclude", + "usepkg_include", "user_location", "volatile", "_eapis_banned", @@ -218,6 +250,40 @@ class RepoConfig: # The main-repo key makes only sense for the 'DEFAULT' section. self.main_repo = repo_opts.get("main-repo") + # usepkg-exclude and usepkg-include validation + for opt in ("usepkg-exclude", "usepkg-include"): + attr = opt.replace("-", "_") + if name == "DEFAULT": + setattr(self, attr, None) + continue + usepkg_atoms = repo_opts.get(opt, "").split() + bad_atoms = _find_bad_atoms(usepkg_atoms) + if bad_atoms: + writemsg( + "\n!!! The following atoms are invalid in %s attribute for " + "repo [%s] (only package names and slot atoms allowed):\n" + "\n %s\n" % (opt, name, "\n ".join(bad_atoms)) + ) + for a in bad_atoms: + usepkg_atoms.remove(a) + usepkg_set = WildcardPackageSet(usepkg_atoms) + setattr(self, attr, usepkg_set) + conflicted_atoms = ( + self.usepkg_exclude + and self.usepkg_exclude.getAtoms().intersection( + self.usepkg_include.getAtoms() + ) + ) + if conflicted_atoms: + writemsg( + "\n!!! The following atoms appear in both the usepkg-exclude " + "usepkg-include lists for repo [%s]:\n" + "\n %s\n" % (name, "\n ".join(conflicted_atoms)) + ) + for a in conflicted_atoms: + self.usepkg_exclude.remove(a) + self.usepkg_include.remove(a) + priority = repo_opts.get("priority") if priority is not None: try: @@ -773,6 +839,8 @@ class RepoConfigLoader: "sync_umask", "sync_uri", "sync_user", + "usepkg_exclude", + "usepkg_include", "volatile", ): v = getattr(repos_conf_opts, k, None) @@ -1338,6 +1406,8 @@ class RepoConfigLoader: "aliases", "eclass_overrides", "force", + "usepkg_exclude", + "usepkg_include", ) repo_config_tuple_keys = ("masters",) keys = bool_keys + str_or_int_keys + str_tuple_keys + repo_config_tuple_keys diff --git a/lib/portage/tests/resolver/ResolverPlayground.py b/lib/portage/tests/resolver/ResolverPlayground.py index a66ed54944..d325690618 100644 --- a/lib/portage/tests/resolver/ResolverPlayground.py +++ b/lib/portage/tests/resolver/ResolverPlayground.py @@ -94,6 +94,7 @@ class ResolverPlayground: "package.use.stable", "package.use.stable.force", "package.use.stable.mask", + "repos.conf", "soname.provided", "use.force", "use.mask", @@ -678,6 +679,11 @@ class ResolverPlayground: configs = user_config.copy() configs["make.conf"] = make_conf_lines + repos_conf_lines = list(user_config.get("repos.conf", ())) + configs["repos.conf"] = _combine_repo_config( + self._repositories, repos_conf_lines + ) + if self._binrepos: binrepos_conf_lines = list(user_config.get("binrepos.conf", ())) configs["binrepos.conf"] = _combine_repo_config( @@ -750,17 +756,10 @@ class ResolverPlayground: if self.target_root != os.sep: create_trees_kwargs["target_root"] = self.target_root - env = { - "PATH": f"{self.eprefix}/usr/sbin:{self.eprefix}/usr/bin:{os.environ['PATH']}", - "PORTAGE_REPOSITORIES": "\n".join( - "[%s]\n%s" - % ( - repo_name, - "\n".join(f"{k} = {v}" for k, v in repo_config.items()), - ) - for repo_name, repo_config in self._repositories.items() - ), - } + path = f"{self.eprefix}/usr/sbin:{self.eprefix}/usr/bin:{os.environ['PATH']}" + env = {"PATH": path} + with open(os.path.join(self.eprefix, USER_CONFIG_PATH, "repos.conf")) as f: + env["PORTAGE_REPOSITORIES"] = f.read() if self.debug: env["PORTAGE_DEBUG"] = "1" diff --git a/lib/portage/tests/resolver/test_binpackage_selection.py b/lib/portage/tests/resolver/test_binpackage_selection.py index ac2f10ec63..ce1f57d9c7 100644 --- a/lib/portage/tests/resolver/test_binpackage_selection.py +++ b/lib/portage/tests/resolver/test_binpackage_selection.py @@ -8,6 +8,11 @@ from portage.tests.resolver.ResolverPlayground import ( ) +# attach build-ids to existing package collection +def with_build_id(pkgs, build): + return [(cpv, meta | {"BUILD_ID": build}) for cpv, meta in pkgs.items()] + + # base class for unit tests of binary package selection options class BinPkgSelectionTestCase(TestCase): pkgs_no_deps = { @@ -28,6 +33,12 @@ class BinPkgSelectionTestCase(TestCase): "app-misc/baz-1.1": {}, } + pkgs_other_repo = { + "app-misc/foo-1.0::other_repo": {}, + "app-misc/bar-1.0::other_repo": {}, + "app-misc/baz-1.0::other_repo": {}, + } + pkgs_with_deps = { "app-misc/foo-1.0": {"RDEPEND": "app-misc/bar"}, "app-misc/bar-1.0": {"RDEPEND": "app-misc/baz"}, @@ -57,6 +68,15 @@ class BinPkgSelectionTestCase(TestCase): finally: playground.cleanup() + # runs multiple test cases in multiple playgrounds with different config + def runBinPkgSelectionTestUserConfig(self, config, test_cases, **kwargs): + for n, test_case in enumerate(test_cases.items()): + lines, tests = test_case + kwargs.setdefault("user_config", {})[config] = lines + + with self.subTest(f"Playground {n+1}/{len(test_cases)}"): + self.runBinPkgSelectionTest(tests, **kwargs) + # test --getbinpkg-exclude option class GetBinPkgExcludeTestCase(BinPkgSelectionTestCase): @@ -954,6 +974,278 @@ class UsePkgExcludeTestCase(BinPkgSelectionTestCase): world=world, ) + def testUsePkgExcludeReposConf(self): + binpkgs = self.pkgs_no_deps + ebuilds = self.pkgs_no_deps + + test_cases = { + ( + "[test_repo]", + "usepkg-exclude = foo", + ): ( + # reposconf.conf attributes to have no effect without --usepkg + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + mergelist=[ + "app-misc/foo-1.0", + "app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + # request all packages with usepkg-exclude in repos.conf + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True}, + mergelist=[ + "app-misc/foo-1.0", + "[binary]app-misc/bar-1.0", + "[binary]app-misc/baz-1.0", + ], + ), + # suppliment repos.conf with --usepkg-exclude on command line + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True, "--usepkg-exclude": ["bar"]}, + mergelist=[ + "app-misc/foo-1.0", + "app-misc/bar-1.0", + "[binary]app-misc/baz-1.0", + ], + ), + # override repos.conf with --usepkg-include on command line + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True, "--usepkg-include": ["foo"]}, + mergelist=[ + "[binary]app-misc/foo-1.0", + "app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + ), + ( + "[test_repo]", + "usepkg-exclude = foo", + "usepkg-include = foo", + ): ( + # conflicted repos.conf attributes to have no effect + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True}, + mergelist=[ + "[binary]app-misc/foo-1.0", + "[binary]app-misc/bar-1.0", + "[binary]app-misc/baz-1.0", + ], + ), + ), + ( + "[test_repo]", + "usepkg-exclude = foo bar", + "usepkg-include = foo", + ): ( + # conflicted repos.conf attributes to not interfere with + # non-overlapping usepkg-exclude + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True}, + mergelist=[ + "[binary]app-misc/foo-1.0", + "app-misc/bar-1.0", + "[binary]app-misc/baz-1.0", + ], + ), + # remaining atoms in repos.conf sourced lists after conflicting + # attributes have been filtered still to be overridable using + # --usepkg-include on command line + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True, "--usepkg-include": ["bar"]}, + mergelist=[ + "app-misc/foo-1.0", + "[binary]app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + ), + } + + self.runBinPkgSelectionTestUserConfig( + "repos.conf", + test_cases, + binpkgs=binpkgs, + ebuilds=ebuilds, + ) + + def testUsePkgExcludeReposConfDeps(self): + binpkgs = self.pkgs_with_deps + ebuilds = self.pkgs_with_deps + + user_config = { + "repos.conf": ( + "[test_repo]", + "usepkg-exclude = foo", + ) + } + + test_cases = ( + # usepkg-exclude in repos.conf to have no effect on --nobindeps + ResolverPlaygroundTestCase( + ["app-misc/foo"], + success=True, + options={"--usepkg": True, "--nobindeps": True}, + mergelist=[ + "app-misc/baz-1.0", + "app-misc/bar-1.0", + "[binary]app-misc/foo-1.0", + ], + ), + ) + + self.runBinPkgSelectionTest( + test_cases, + binpkgs=binpkgs, + ebuilds=ebuilds, + user_config=user_config, + ) + + def testUsePkgExcludeMultiRepo(self): + # see commentary in testGetBinPkgExcludeMultiBinrepo() + pkgs_no_deps = with_build_id(self.pkgs_no_deps, "1") + pkgs_other_repo = with_build_id(self.pkgs_other_repo, "2") + + ebuilds = self.pkgs_no_deps | self.pkgs_other_repo + binpkgs = pkgs_no_deps + pkgs_other_repo + + user_config = { + "repos.conf": ( + "[test_repo]", + "usepkg-exclude = foo", + "[other_repo]", + "usepkg-exclude = bar", + ) + } + + # note that repository priority order is not well defined *within* pkgdir + # and so test cases which assume a plan c/p atom will resolve to a binary + # for any given repo implicitly can spuriously fail, regardless of priority + # set in repos.conf. + # + # TL;DR = all atoms in these tests cases *must* be ::repo qualified! + test_cases = ( + # request test_repo for which only app-misc/foo is excluded in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::test_repo", + "app-misc/bar::test_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "app-misc/foo-1.0", + "[binary]app-misc/bar-1.0-1", + "[binary]app-misc/baz-1.0-1", + ], + ), + # request other_repo for which only app-misc/bar is excluded in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::other_repo", + "app-misc/bar::other_repo", + "app-misc/baz::other_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "[binary]app-misc/foo-1.0-2::other_repo", + "app-misc/bar-1.0::other_repo", + "[binary]app-misc/baz-1.0-2::other_repo", + ], + ), + # use repo qualifier to request packages from repos for which both + # app-misc/foo and app-misc/bar are excluded in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::test_repo", + "app-misc/bar::other_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "app-misc/foo-1.0", + "app-misc/bar-1.0::other_repo", + "[binary]app-misc/baz-1.0-1", + ], + ), + # use repo qualifier to request packages from repos for which neither + # app-misc/foo nor app-misc/bar are excluded in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::other_repo", + "app-misc/bar::test_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "[binary]app-misc/foo-1.0-2::other_repo", + "[binary]app-misc/bar-1.0-1", + "[binary]app-misc/baz-1.0-1", + ], + ), + # use repo qualifier to arrange for neither app-misc/foo nor app-misc/bar + # to be binary, but override repos.conf for foo using --usepkg-include + # which implicitly excludes app-misc/baz as the command line option + # applies to all repositories + ResolverPlaygroundTestCase( + [ + "app-misc/foo::test_repo", + "app-misc/bar::other_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True, "--usepkg-include": ["foo"]}, + mergelist=[ + "[binary]app-misc/foo-1.0-1", + "app-misc/bar-1.0::other_repo", + "app-misc/baz-1.0", + ], + ), + ) + + self.runBinPkgSelectionTest( + test_cases, + binpkgs=binpkgs, + ebuilds=ebuilds, + user_config=user_config, + ) + # test --usepkg-include option class UsePkgIncludeTestCase(BinPkgSelectionTestCase): @@ -1252,3 +1544,252 @@ class UsePkgIncludeTestCase(BinPkgSelectionTestCase): installed=installed, world=world, ) + + def testUsePkgIncludeReposConf(self): + binpkgs = self.pkgs_no_deps + ebuilds = self.pkgs_no_deps + + test_cases = { + ( + "[test_repo]", + "usepkg-include = foo", + ): ( + # repos.conf attribute to have no effect without --usepkg + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + mergelist=[ + "app-misc/foo-1.0", + "app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + # request all packages with usepkg-include in repos.conf + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True}, + mergelist=[ + "[binary]app-misc/foo-1.0", + "app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + # suppliment repos.conf with --usepkg-include on command line + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True, "--usepkg-include": ["bar"]}, + mergelist=[ + "[binary]app-misc/foo-1.0", + "[binary]app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + # override repos.conf with --usepkg-exclude on command line + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True, "--usepkg-exclude": ["foo"]}, + mergelist=[ + "app-misc/foo-1.0", + "[binary]app-misc/bar-1.0", + "[binary]app-misc/baz-1.0", + ], + ), + ), + ( + "[test_repo]", + "usepkg-exclude = foo", + "usepkg-include = foo bar", + ): ( + # conflicted repos.conf attributes to not interfere with + # non-overlapping usepkg-include + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True}, + mergelist=[ + "app-misc/foo-1.0", + "[binary]app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + # remaining atoms in repos.conf sourced lists after conflicting + # attributes have been filtered still to be overridable using + # --usepkg-exclude on command line + ResolverPlaygroundTestCase( + self.pkg_atoms, + success=True, + ignore_mergelist_order=True, + options={"--usepkg": True, "--usepkg-exclude": ["bar"]}, + mergelist=[ + "[binary]app-misc/foo-1.0", + "app-misc/bar-1.0", + "[binary]app-misc/baz-1.0", + ], + ), + ), + } + + self.runBinPkgSelectionTestUserConfig( + "repos.conf", + test_cases, + binpkgs=binpkgs, + ebuilds=ebuilds, + ) + + def testUsePkgIncludeReposConfDeps(self): + binpkgs = self.pkgs_with_deps + ebuilds = self.pkgs_with_deps + + user_config = { + "repos.conf": ( + "[test_repo]", + "usepkg-include = bar", + ) + } + + test_cases = ( + # usepkg-include in repos.conf to have no effect on --nobindeps + ResolverPlaygroundTestCase( + ["app-misc/foo"], + success=True, + options={"--usepkg": True, "--nobindeps": True}, + mergelist=[ + "app-misc/baz-1.0", + "app-misc/bar-1.0", + "[binary]app-misc/foo-1.0", + ], + ), + ) + + self.runBinPkgSelectionTest( + test_cases, + binpkgs=binpkgs, + ebuilds=ebuilds, + user_config=user_config, + ) + + def testUsePkgIncludeMultiRepo(self): + # see commentary in testGetBinPkgExcludeMultiBinrepo() + pkgs_no_deps = with_build_id(self.pkgs_no_deps, "1") + pkgs_other_repo = with_build_id(self.pkgs_other_repo, "2") + + ebuilds = self.pkgs_no_deps | self.pkgs_other_repo + binpkgs = pkgs_no_deps + pkgs_other_repo + + user_config = { + "repos.conf": ( + "[test_repo]", + "usepkg-include = foo", + "[other_repo]", + "usepkg-include = bar", + ) + } + + # all atoms in these tests cases *must* be ::repo qualified! see comments + # in testUsePkgExcludeMultiRepo() + test_cases = ( + # request test_repo for which only app-misc/foo is included in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::test_repo", + "app-misc/bar::test_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "[binary]app-misc/foo-1.0-1", + "app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + # request other_repo for which only app-misc/bar is included in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::other_repo", + "app-misc/bar::other_repo", + "app-misc/baz::other_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "app-misc/foo-1.0::other_repo", + "[binary]app-misc/bar-1.0-2::other_repo", + "app-misc/baz-1.0::other_repo", + ], + ), + # use repo qualifier to request packages from repos for which both + # app-misc/foo and app-misc/bar are included in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::test_repo", + "app-misc/bar::other_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "[binary]app-misc/foo-1.0-1", + "[binary]app-misc/bar-1.0-2::other_repo", + "app-misc/baz-1.0", + ], + ), + # use repo qualifier to request packages from repos for which neither + # app-misc/foo nor app-misc/bar are included in repos.conf + ResolverPlaygroundTestCase( + [ + "app-misc/foo::other_repo", + "app-misc/bar::test_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True}, + mergelist=[ + "app-misc/foo-1.0::other_repo", + "app-misc/bar-1.0", + "app-misc/baz-1.0", + ], + ), + # use repo qualifier to arrange for both app-misc/foo and app-misc/bar + # to be binary, but override repos.conf for foo using --usepkg-exclude + # which has no effect on app-misc/baz + ResolverPlaygroundTestCase( + [ + "app-misc/foo::test_repo", + "app-misc/bar::other_repo", + "app-misc/baz::test_repo", + ], + success=True, + ignore_mergelist_order=True, + check_repo_names=True, + options={"--usepkg": True, "--usepkg-exclude": ["foo"]}, + mergelist=[ + "app-misc/foo-1.0", + "[binary]app-misc/bar-1.0-2::other_repo", + "app-misc/baz-1.0", + ], + ), + ) + + self.runBinPkgSelectionTest( + test_cases, + binpkgs=binpkgs, + ebuilds=ebuilds, + user_config=user_config, + ) diff --git a/man/emerge.1 b/man/emerge.1 index a7b5fa0cf1..ff242eacb6 100644 --- a/man/emerge.1 +++ b/man/emerge.1 @@ -761,7 +761,8 @@ specific packages, see the \fB\-\-exclude\fR option. Prefer ebuilds for any dependencies and select binary packages only for the atoms or sets requested for install, i.e. those named on the command line. Has no effect unless \fB-k\fR is also used or implied. Both \fB--usepkg-exclude\fR -and \fB--usepkg-include\fR are ignored when this option is used. +and \fB--usepkg-include\fR are ignored when this option is used, as are the +usepkg-exclude and usepkg-include attributes in \fBrepos.conf\fR. .TP .BR \-\-noconfmem Causes portage to disregard merge records indicating that a config file diff --git a/man/portage.5 b/man/portage.5 index 6c1ec5e039..41c68ab961 100644 --- a/man/portage.5 +++ b/man/portage.5 @@ -1320,6 +1320,20 @@ Require the detached tarball signature to contain a good OpenPGP signature. This uses the OpenPGP key(ring) specified by the sync\-openpgp\-key\-path setting. Defaults to no, false. .TP +.B usepkg\-exclude +A space separated list of package names or slot atoms. Emerge will ignore +matching binary packages except where overridden by the \-\-usepkg\-include +command line option (see \fBemerge\fR(1)). + +This is an experimental option subject to change. +.TP +.B usepkg\-include +A space separated list of package names or slot names. Emerge will ignore +non-matching binary packages except where overridden by the \-\-usepkg\-exclude +command line option (see \fBemerge\fR(1)). + +This is an experimental option subject to change. +.TP .B volatile = yes|no|true|false Specifies whether a repository is volatile. Volatile repositories are assumed to contain changes made outside of Portage. This prohibits
