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.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 9EE0F158089 for ; Mon, 30 Oct 2023 03:14:38 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 73E8C2BC048; Mon, 30 Oct 2023 03:14:34 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 2D3652BC048 for ; Mon, 30 Oct 2023 03:14:34 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 209EB335C5D for ; Mon, 30 Oct 2023 03:14:33 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id C649E1308 for ; Mon, 30 Oct 2023 03:14:29 +0000 (UTC) From: "Sam James" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Sam James" Message-ID: <1698635665.e324f300247f4181362325d46a7232f0bbaf561e.sam@gentoo> Subject: [gentoo-commits] proj/portage:master commit in: lib/portage/tests/emerge/ X-VCS-Repository: proj/portage X-VCS-Files: lib/portage/tests/emerge/conftest.py lib/portage/tests/emerge/test_baseline.py lib/portage/tests/emerge/test_simple.py X-VCS-Directories: lib/portage/tests/emerge/ X-VCS-Committer: sam X-VCS-Committer-Name: Sam James X-VCS-Revision: e324f300247f4181362325d46a7232f0bbaf561e X-VCS-Branch: master Date: Mon, 30 Oct 2023 03:14:29 +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: 8aee6a6d-456e-4f0c-ba84-d053774e96d1 X-Archives-Hash: eb128bd3827b8703b3e1056c097fc408 commit: e324f300247f4181362325d46a7232f0bbaf561e Author: David Palao gmail com> AuthorDate: Tue Oct 10 01:36:02 2023 +0000 Commit: Sam James gentoo org> CommitDate: Mon Oct 30 03:14:25 2023 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=e324f300 tests: Adapt to UTF-8 changes Adapt to UTF-8 changes in 4f5f6f571e52af6d2703db760bad4e0ad7439d5a. Signed-off-by: David Palao gmail.com> Signed-off-by: Sam James gentoo.org> lib/portage/tests/emerge/conftest.py | 22 +- lib/portage/tests/emerge/test_baseline.py | 4 +- lib/portage/tests/emerge/test_simple.py | 740 ++++++++++++++++++++++++++++++ 3 files changed, 754 insertions(+), 12 deletions(-) diff --git a/lib/portage/tests/emerge/conftest.py b/lib/portage/tests/emerge/conftest.py index aaa603f731..c534f5e9d3 100644 --- a/lib/portage/tests/emerge/conftest.py +++ b/lib/portage/tests/emerge/conftest.py @@ -267,7 +267,7 @@ class PortageCommandSequence: class Emerge(PortageCommand): name = "emerge" - command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(cnf_bindir, name)) + command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(str(cnf_bindir), name)) class Noop(PortageCommand): @@ -276,7 +276,7 @@ class Noop(PortageCommand): class EnvUpdate(PortageCommand): name = "env-update" - command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(cnf_sbindir, name)) + command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(str(cnf_sbindir), name)) class DispatchConf(PortageCommand): @@ -285,13 +285,13 @@ class DispatchConf(PortageCommand): PORTAGE_PYTHON, "-b", "-Wd", - os.path.join(cnf_sbindir, name), + os.path.join(str(cnf_sbindir), name), ) class Ebuild(PortageCommand): name = "ebuild" - command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(cnf_bindir, name)) + command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(str(cnf_bindir), name)) class Egencache(PortageCommand): @@ -300,18 +300,18 @@ class Egencache(PortageCommand): PORTAGE_PYTHON, "-b", "-Wd", - os.path.join(cnf_bindir, name), + os.path.join(str(cnf_bindir), name), ) class Emaint(PortageCommand): name = "emaint" - command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(cnf_sbindir, name)) + command = (PORTAGE_PYTHON, "-b", "-Wd", os.path.join(str(cnf_sbindir), name)) class EtcUpdate(PortageCommand): name = "etc-update" - command = (BASH_BINARY, os.path.join(cnf_sbindir, name)) + command = (BASH_BINARY, os.path.join(str(cnf_sbindir), name)) class Fixpackages(PortageCommand): @@ -320,7 +320,7 @@ class Fixpackages(PortageCommand): PORTAGE_PYTHON, "-b", "-Wd", - os.path.join(cnf_sbindir, name), + os.path.join(str(cnf_sbindir), name), ) @@ -330,7 +330,7 @@ class Portageq(PortageCommand): PORTAGE_PYTHON, "-b", "-Wd", - os.path.join(cnf_bindir, name), + os.path.join(str(cnf_bindir), name), ) @@ -340,7 +340,7 @@ class Quickpkg(PortageCommand): PORTAGE_PYTHON, "-b", "-Wd", - os.path.join(cnf_bindir, name), + os.path.join(str(cnf_bindir), name), ) @@ -350,7 +350,7 @@ class Regenworld(PortageCommand): PORTAGE_PYTHON, "-b", "-Wd", - os.path.join(cnf_sbindir, name), + os.path.join(str(cnf_sbindir), name), ) diff --git a/lib/portage/tests/emerge/test_baseline.py b/lib/portage/tests/emerge/test_baseline.py index 55722d900e..8f44528949 100644 --- a/lib/portage/tests/emerge/test_baseline.py +++ b/lib/portage/tests/emerge/test_baseline.py @@ -173,7 +173,9 @@ async def _async_test_baseline(playground, binhost, commands): pass for x in etc_symlinks: try: - os.symlink(os.path.join(cnf_etc_path, x), os.path.join(eprefix, "etc", x)) + os.symlink( + os.path.join(str(cnf_etc_path), x), os.path.join(eprefix, "etc", x) + ) except FileExistsError: pass with open(os.path.join(var_cache_edb, "counter"), "wb") as f: diff --git a/lib/portage/tests/emerge/test_simple.py b/lib/portage/tests/emerge/test_simple.py new file mode 100644 index 0000000000..1cc6457ef1 --- /dev/null +++ b/lib/portage/tests/emerge/test_simple.py @@ -0,0 +1,740 @@ +# Copyright 2011-2021, 2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +import argparse +import subprocess +import sys + +import portage +from portage import shutil, os +from portage.const import ( + BASH_BINARY, + BINREPOS_CONF_FILE, + PORTAGE_PYM_PATH, + USER_CONFIG_PATH, + SUPPORTED_GENTOO_BINPKG_FORMATS, +) +from portage.cache.mappings import Mapping +from portage.process import find_binary +from portage.tests import TestCase +from portage.tests.resolver.ResolverPlayground import ResolverPlayground +from portage.tests.util.test_socks5 import AsyncHTTPServer +from portage.util import ensure_dirs, find_updated_config_files, shlex_split +from portage.util.futures import asyncio +from portage.output import colorize + + +class BinhostContentMap(Mapping): + def __init__(self, remote_path, local_path): + self._remote_path = remote_path + self._local_path = local_path + + def __getitem__(self, request_path): + safe_path = os.path.normpath(request_path) + if not safe_path.startswith(self._remote_path + "/"): + raise KeyError(request_path) + local_path = os.path.join( + self._local_path, safe_path[len(self._remote_path) + 1 :] + ) + try: + with open(local_path, "rb") as f: + return f.read() + except OSError: + raise KeyError(request_path) + + +class SimpleEmergeTestCase(TestCase): + def _have_python_xml(self): + try: + __import__("xml.etree.ElementTree") + __import__("xml.parsers.expat").parsers.expat.ExpatError + except (AttributeError, ImportError): + return False + return True + + def testSimple(self): + debug = False + + install_something = """ +S="${WORKDIR}" + +pkg_pretend() { + einfo "called pkg_pretend for $CATEGORY/$PF" +} + +src_install() { + einfo "installing something..." + insinto /usr/lib/${P} + echo "blah blah blah" > "${T}"/regular-file + doins "${T}"/regular-file + dosym regular-file /usr/lib/${P}/symlink || die + + # Test CONFIG_PROTECT + insinto /etc + newins "${T}"/regular-file ${PN}-${SLOT%/*} + + # Test code for bug #381629, using a copyright symbol encoded with latin-1. + # We use $(printf "\\xa9") rather than $'\\xa9', since printf apparently + # works in any case, while $'\\xa9' transforms to \\xef\\xbf\\xbd under + # some conditions. TODO: Find out why it transforms to \\xef\\xbf\\xbd when + # running tests for Python 3.2 (even though it's bash that is ultimately + # responsible for performing the transformation). + local latin_1_dir=/usr/lib/${P}/latin-1-$(printf "\\xa9")-directory + insinto "${latin_1_dir}" + echo "blah blah blah" > "${T}"/latin-1-$(printf "\\xa9")-regular-file || die + doins "${T}"/latin-1-$(printf "\\xa9")-regular-file + dosym latin-1-$(printf "\\xa9")-regular-file ${latin_1_dir}/latin-1-$(printf "\\xa9")-symlink || die + + call_has_and_best_version +} + +pkg_config() { + einfo "called pkg_config for $CATEGORY/$PF" +} + +pkg_info() { + einfo "called pkg_info for $CATEGORY/$PF" +} + +pkg_preinst() { + if ! ___eapi_best_version_and_has_version_support_-b_-d_-r; then + # The BROOT variable is unset during pkg_* phases for EAPI 7, + # therefore best/has_version -b is expected to fail if we attempt + # to call it for EAPI 7 here. + call_has_and_best_version + fi +} + +call_has_and_best_version() { + local root_arg + if ___eapi_best_version_and_has_version_support_-b_-d_-r; then + root_arg="-b" + else + root_arg="--host-root" + fi + einfo "called ${EBUILD_PHASE_FUNC} for $CATEGORY/$PF" + einfo "EPREFIX=${EPREFIX}" + einfo "PORTAGE_OVERRIDE_EPREFIX=${PORTAGE_OVERRIDE_EPREFIX}" + einfo "ROOT=${ROOT}" + einfo "EROOT=${EROOT}" + einfo "SYSROOT=${SYSROOT}" + einfo "ESYSROOT=${ESYSROOT}" + einfo "BROOT=${BROOT}" + # Test that has_version and best_version work correctly with + # prefix (involves internal ROOT -> EROOT calculation in order + # to support ROOT override via the environment with EAPIs 3 + # and later which support prefix). + if has_version $CATEGORY/$PN:$SLOT ; then + einfo "has_version detects an installed instance of $CATEGORY/$PN:$SLOT" + einfo "best_version reports that the installed instance is $(best_version $CATEGORY/$PN:$SLOT)" + else + einfo "has_version does not detect an installed instance of $CATEGORY/$PN:$SLOT" + fi + if [[ ${EPREFIX} != ${PORTAGE_OVERRIDE_EPREFIX} ]] ; then + if has_version ${root_arg} $CATEGORY/$PN:$SLOT ; then + einfo "has_version ${root_arg} detects an installed instance of $CATEGORY/$PN:$SLOT" + einfo "best_version ${root_arg} reports that the installed instance is $(best_version ${root_arg} $CATEGORY/$PN:$SLOT)" + else + einfo "has_version ${root_arg} does not detect an installed instance of $CATEGORY/$PN:$SLOT" + fi + fi +} + +""" + + ebuilds = { + "dev-libs/A-1": { + "EAPI": "5", + "IUSE": "+flag", + "KEYWORDS": "x86", + "LICENSE": "GPL-2", + "MISC_CONTENT": install_something, + "RDEPEND": "flag? ( dev-libs/B[flag] )", + }, + "dev-libs/B-1": { + "EAPI": "5", + "IUSE": "+flag", + "KEYWORDS": "x86", + "LICENSE": "GPL-2", + "MISC_CONTENT": install_something, + }, + "dev-libs/C-1": { + "EAPI": "7", + "KEYWORDS": "~x86", + "RDEPEND": "dev-libs/D[flag]", + "MISC_CONTENT": install_something, + }, + "dev-libs/D-1": { + "EAPI": "7", + "KEYWORDS": "~x86", + "IUSE": "flag", + "MISC_CONTENT": install_something, + }, + "virtual/foo-0": { + "EAPI": "5", + "KEYWORDS": "x86", + "LICENSE": "GPL-2", + }, + } + + installed = { + "dev-libs/A-1": { + "EAPI": "5", + "IUSE": "+flag", + "KEYWORDS": "x86", + "LICENSE": "GPL-2", + "RDEPEND": "flag? ( dev-libs/B[flag] )", + "USE": "flag", + }, + "dev-libs/B-1": { + "EAPI": "5", + "IUSE": "+flag", + "KEYWORDS": "x86", + "LICENSE": "GPL-2", + "USE": "flag", + }, + "dev-libs/depclean-me-1": { + "EAPI": "5", + "IUSE": "", + "KEYWORDS": "x86", + "LICENSE": "GPL-2", + "USE": "", + }, + "app-misc/depclean-me-1": { + "EAPI": "5", + "IUSE": "", + "KEYWORDS": "x86", + "LICENSE": "GPL-2", + "RDEPEND": "dev-libs/depclean-me", + "USE": "", + }, + } + + metadata_xml_files = ( + ( + "dev-libs/A", + { + "flags": "Description of how USE='flag' affects this package", + }, + ), + ( + "dev-libs/B", + { + "flags": "Description of how USE='flag' affects this package", + }, + ), + ) + + for binpkg_format in SUPPORTED_GENTOO_BINPKG_FORMATS: + with self.subTest(binpkg_format=binpkg_format): + print(colorize("HILITE", binpkg_format), end=" ... ") + sys.stdout.flush() + playground = ResolverPlayground( + ebuilds=ebuilds, + installed=installed, + debug=debug, + user_config={ + "make.conf": (f'BINPKG_FORMAT="{binpkg_format}"',), + }, + ) + + loop = asyncio._wrap_loop() + loop.run_until_complete( + asyncio.ensure_future( + self._async_test_simple( + playground, metadata_xml_files, loop=loop + ), + loop=loop, + ) + ) + + async def _async_test_simple(self, playground, metadata_xml_files, loop): + debug = playground.debug + settings = playground.settings + eprefix = settings["EPREFIX"] + eroot = settings["EROOT"] + trees = playground.trees + portdb = trees[eroot]["porttree"].dbapi + test_repo_location = settings.repositories["test_repo"].location + var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") + cachedir = os.path.join(var_cache_edb, "dep") + cachedir_pregen = os.path.join(test_repo_location, "metadata", "md5-cache") + + portage_python = portage._python_interpreter + dispatch_conf_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.sbindir), "dispatch-conf"), + ) + ebuild_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.bindir), "ebuild"), + ) + egencache_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.bindir), "egencache"), + "--repo", + "test_repo", + "--repositories-configuration", + settings.repositories.config_string(), + ) + emerge_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.bindir), "emerge"), + ) + emaint_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.sbindir), "emaint"), + ) + env_update_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.sbindir), "env-update"), + ) + etc_update_cmd = (BASH_BINARY, os.path.join(str(self.sbindir), "etc-update")) + fixpackages_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.sbindir), "fixpackages"), + ) + portageq_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.bindir), "portageq"), + ) + quickpkg_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.bindir), "quickpkg"), + ) + regenworld_cmd = ( + portage_python, + "-b", + "-Wd", + os.path.join(str(self.sbindir), "regenworld"), + ) + + rm_binary = find_binary("rm") + self.assertEqual(rm_binary is None, False, "rm command not found") + rm_cmd = (rm_binary,) + + egencache_extra_args = [] + if self._have_python_xml(): + egencache_extra_args.append("--update-use-local-desc") + + test_ebuild = portdb.findname("dev-libs/A-1") + self.assertFalse(test_ebuild is None) + + cross_prefix = os.path.join(eprefix, "cross_prefix") + cross_root = os.path.join(eprefix, "cross_root") + cross_eroot = os.path.join(cross_root, eprefix.lstrip(os.sep)) + + binhost_dir = os.path.join(eprefix, "binhost") + binhost_address = "127.0.0.1" + binhost_remote_path = "/binhost" + binhost_server = AsyncHTTPServer( + binhost_address, BinhostContentMap(binhost_remote_path, binhost_dir), loop + ).__enter__() + binhost_uri = "http://{address}:{port}{path}".format( + address=binhost_address, + port=binhost_server.server_port, + path=binhost_remote_path, + ) + + binpkg_format = settings.get( + "BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0] + ) + self.assertIn(binpkg_format, ("xpak", "gpkg")) + if binpkg_format == "xpak": + foo_filename = "foo-0-1.xpak" + elif binpkg_format == "gpkg": + foo_filename = "foo-0-1.gpkg.tar" + + test_commands = () + + if hasattr(argparse.ArgumentParser, "parse_intermixed_args"): + test_commands += ( + emerge_cmd + ("--oneshot", "dev-libs/A", "-v", "dev-libs/A"), + ) + + test_commands += ( + emerge_cmd + + ( + "--usepkgonly", + "--root", + cross_root, + "--quickpkg-direct=y", + "--quickpkg-direct-root", + "/", + "dev-libs/A", + ), + emerge_cmd + + ( + "--usepkgonly", + "--quickpkg-direct=y", + "--quickpkg-direct-root", + cross_root, + "dev-libs/A", + ), + env_update_cmd, + portageq_cmd + + ( + "envvar", + "-v", + "CONFIG_PROTECT", + "EROOT", + "PORTAGE_CONFIGROOT", + "PORTAGE_TMPDIR", + "USERLAND", + ), + etc_update_cmd, + dispatch_conf_cmd, + emerge_cmd + ("--version",), + emerge_cmd + ("--info",), + emerge_cmd + ("--info", "--verbose"), + emerge_cmd + ("--list-sets",), + emerge_cmd + ("--check-news",), + rm_cmd + ("-rf", cachedir), + rm_cmd + ("-rf", cachedir_pregen), + emerge_cmd + ("--regen",), + rm_cmd + ("-rf", cachedir), + ({"FEATURES": "metadata-transfer"},) + emerge_cmd + ("--regen",), + rm_cmd + ("-rf", cachedir), + ({"FEATURES": "metadata-transfer"},) + emerge_cmd + ("--regen",), + rm_cmd + ("-rf", cachedir), + egencache_cmd + ("--update",) + tuple(egencache_extra_args), + ({"FEATURES": "metadata-transfer"},) + emerge_cmd + ("--metadata",), + rm_cmd + ("-rf", cachedir), + ({"FEATURES": "metadata-transfer"},) + emerge_cmd + ("--metadata",), + emerge_cmd + ("--metadata",), + rm_cmd + ("-rf", cachedir), + emerge_cmd + ("--oneshot", "virtual/foo"), + lambda: self.assertFalse( + os.path.exists(os.path.join(pkgdir, "virtual", "foo", foo_filename)) + ), + ({"FEATURES": "unmerge-backup"},) + + emerge_cmd + + ("--unmerge", "virtual/foo"), + lambda: self.assertTrue( + os.path.exists(os.path.join(pkgdir, "virtual", "foo", foo_filename)) + ), + emerge_cmd + ("--pretend", "dev-libs/A"), + ebuild_cmd + (test_ebuild, "manifest", "clean", "package", "merge"), + emerge_cmd + ("--pretend", "--tree", "--complete-graph", "dev-libs/A"), + emerge_cmd + ("-p", "dev-libs/B"), + emerge_cmd + ("-p", "--newrepo", "dev-libs/B"), + emerge_cmd + + ( + "-B", + "dev-libs/B", + ), + emerge_cmd + + ( + "--oneshot", + "--usepkg", + "dev-libs/B", + ), + # trigger clean prior to pkg_pretend as in bug #390711 + ebuild_cmd + (test_ebuild, "unpack"), + emerge_cmd + + ( + "--oneshot", + "dev-libs/A", + ), + emerge_cmd + + ( + "--noreplace", + "dev-libs/A", + ), + emerge_cmd + + ( + "--config", + "dev-libs/A", + ), + emerge_cmd + ("--info", "dev-libs/A", "dev-libs/B"), + emerge_cmd + ("--pretend", "--depclean", "--verbose", "dev-libs/B"), + emerge_cmd + + ( + "--pretend", + "--depclean", + ), + emerge_cmd + ("--depclean",), + quickpkg_cmd + + ( + "--include-config", + "y", + "dev-libs/A", + ), + # Test bug #523684, where a file renamed or removed by the + # admin forces replacement files to be merged with config + # protection. + lambda: self.assertEqual( + 0, + len( + list( + find_updated_config_files( + eroot, shlex_split(settings["CONFIG_PROTECT"]) + ) + ) + ), + ), + lambda: os.unlink(os.path.join(eprefix, "etc", "A-0")), + emerge_cmd + ("--usepkgonly", "dev-libs/A"), + lambda: self.assertEqual( + 1, + len( + list( + find_updated_config_files( + eroot, shlex_split(settings["CONFIG_PROTECT"]) + ) + ) + ), + ), + emaint_cmd + ("--check", "all"), + emaint_cmd + ("--fix", "all"), + fixpackages_cmd, + regenworld_cmd, + portageq_cmd + ("match", eroot, "dev-libs/A"), + portageq_cmd + ("best_visible", eroot, "dev-libs/A"), + portageq_cmd + ("best_visible", eroot, "binary", "dev-libs/A"), + portageq_cmd + ("contents", eroot, "dev-libs/A-1"), + portageq_cmd + + ("metadata", eroot, "ebuild", "dev-libs/A-1", "EAPI", "IUSE", "RDEPEND"), + portageq_cmd + + ("metadata", eroot, "binary", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"), + portageq_cmd + + ( + "metadata", + eroot, + "installed", + "dev-libs/A-1", + "EAPI", + "USE", + "RDEPEND", + ), + portageq_cmd + ("owners", eroot, eroot + "usr"), + emerge_cmd + ("-p", eroot + "usr"), + emerge_cmd + ("-p", "--unmerge", "-q", eroot + "usr"), + emerge_cmd + ("--unmerge", "--quiet", "dev-libs/A"), + emerge_cmd + ("-C", "--quiet", "dev-libs/B"), + # If EMERGE_DEFAULT_OPTS contains --autounmask=n, then --autounmask + # must be specified with --autounmask-continue. + ({"EMERGE_DEFAULT_OPTS": "--autounmask=n"},) + + emerge_cmd + + ( + "--autounmask", + "--autounmask-continue", + "dev-libs/C", + ), + # Verify that the above --autounmask-continue command caused + # USE=flag to be applied correctly to dev-libs/D. + portageq_cmd + ("match", eroot, "dev-libs/D[flag]"), + # Test cross-prefix usage, including chpathtool for binpkgs. + # EAPI 7 + ({"EPREFIX": cross_prefix},) + emerge_cmd + ("dev-libs/C",), + ({"EPREFIX": cross_prefix},) + + portageq_cmd + + ("has_version", cross_prefix, "dev-libs/C"), + ({"EPREFIX": cross_prefix},) + + portageq_cmd + + ("has_version", cross_prefix, "dev-libs/D"), + ({"ROOT": cross_root},) + emerge_cmd + ("dev-libs/D",), + portageq_cmd + ("has_version", cross_eroot, "dev-libs/D"), + # EAPI 5 + ({"EPREFIX": cross_prefix},) + emerge_cmd + ("--usepkgonly", "dev-libs/A"), + ({"EPREFIX": cross_prefix},) + + portageq_cmd + + ("has_version", cross_prefix, "dev-libs/A"), + ({"EPREFIX": cross_prefix},) + + portageq_cmd + + ("has_version", cross_prefix, "dev-libs/B"), + ({"EPREFIX": cross_prefix},) + emerge_cmd + ("-C", "--quiet", "dev-libs/B"), + ({"EPREFIX": cross_prefix},) + emerge_cmd + ("-C", "--quiet", "dev-libs/A"), + ({"EPREFIX": cross_prefix},) + emerge_cmd + ("dev-libs/A",), + ({"EPREFIX": cross_prefix},) + + portageq_cmd + + ("has_version", cross_prefix, "dev-libs/A"), + ({"EPREFIX": cross_prefix},) + + portageq_cmd + + ("has_version", cross_prefix, "dev-libs/B"), + # Test ROOT support + ({"ROOT": cross_root},) + emerge_cmd + ("dev-libs/B",), + portageq_cmd + ("has_version", cross_eroot, "dev-libs/B"), + ) + + # Test binhost support if FETCHCOMMAND is available. + binrepos_conf_file = os.path.join(os.sep, eprefix, BINREPOS_CONF_FILE) + with open(binrepos_conf_file, "w") as f: + f.write("[test-binhost]\n") + f.write(f"sync-uri = {binhost_uri}\n") + fetchcommand = portage.util.shlex_split(playground.settings["FETCHCOMMAND"]) + fetch_bin = portage.process.find_binary(fetchcommand[0]) + if fetch_bin is not None: + test_commands = test_commands + ( + lambda: os.rename(pkgdir, binhost_dir), + emerge_cmd + ("-e", "--getbinpkgonly", "dev-libs/A"), + lambda: shutil.rmtree(pkgdir), + lambda: os.rename(binhost_dir, pkgdir), + # Remove binrepos.conf and test PORTAGE_BINHOST. + lambda: os.unlink(binrepos_conf_file), + lambda: os.rename(pkgdir, binhost_dir), + ({"PORTAGE_BINHOST": binhost_uri},) + + emerge_cmd + + ("-fe", "--getbinpkgonly", "dev-libs/A"), + lambda: shutil.rmtree(pkgdir), + lambda: os.rename(binhost_dir, pkgdir), + ) + + distdir = playground.distdir + pkgdir = playground.pkgdir + fake_bin = os.path.join(eprefix, "bin") + portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") + profile_path = settings.profile_path + user_config_dir = os.path.join(os.sep, eprefix, USER_CONFIG_PATH) + + path = os.environ.get("PATH") + if path is not None and not path.strip(): + path = None + if path is None: + path = "" + else: + path = ":" + path + path = fake_bin + path + + pythonpath = os.environ.get("PYTHONPATH") + if pythonpath is not None and not pythonpath.strip(): + pythonpath = None + if pythonpath is not None and pythonpath.split(":")[0] == PORTAGE_PYM_PATH: + pass + else: + if pythonpath is None: + pythonpath = "" + else: + pythonpath = ":" + pythonpath + pythonpath = PORTAGE_PYM_PATH + pythonpath + + env = { + "PORTAGE_OVERRIDE_EPREFIX": eprefix, + "CLEAN_DELAY": "0", + "DISTDIR": distdir, + "EMERGE_WARNING_DELAY": "0", + "INFODIR": "", + "INFOPATH": "", + "PATH": path, + "PKGDIR": pkgdir, + "PORTAGE_INST_GID": str(os.getgid()), # str(portage.data.portage_gid), + "PORTAGE_INST_UID": str(os.getuid()), # str(portage.data.portage_uid), + "PORTAGE_PYTHON": portage_python, + "PORTAGE_REPOSITORIES": settings.repositories.config_string(), + "PORTAGE_TMPDIR": portage_tmpdir, + "PORTAGE_LOGDIR": portage_tmpdir, + "PYTHONDONTWRITEBYTECODE": os.environ.get("PYTHONDONTWRITEBYTECODE", ""), + "PYTHONPATH": pythonpath, + "__PORTAGE_TEST_PATH_OVERRIDE": fake_bin, + } + + if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: + env["__PORTAGE_TEST_HARDLINK_LOCKS"] = os.environ[ + "__PORTAGE_TEST_HARDLINK_LOCKS" + ] + + updates_dir = os.path.join(test_repo_location, "profiles", "updates") + dirs = [ + cachedir, + cachedir_pregen, + cross_eroot, + cross_prefix, + distdir, + fake_bin, + portage_tmpdir, + updates_dir, + user_config_dir, + var_cache_edb, + ] + etc_symlinks = ("dispatch-conf.conf", "etc-update.conf") + # Override things that may be unavailable, or may have portability + # issues when running tests in exotic environments. + # prepstrip - bug #447810 (bash read builtin EINTR problem) + true_symlinks = ["find", "prepstrip", "sed", "scanelf"] + true_binary = find_binary("true") + self.assertEqual(true_binary is None, False, "true command not found") + try: + for d in dirs: + ensure_dirs(d) + for x in true_symlinks: + os.symlink(true_binary, os.path.join(fake_bin, x)) + for x in etc_symlinks: + os.symlink( + os.path.join(str(self.cnf_etc_path), x), + os.path.join(eprefix, "etc", x), + ) + with open(os.path.join(var_cache_edb, "counter"), "wb") as f: + f.write(b"100") + # non-empty system set keeps --depclean quiet + with open(os.path.join(profile_path, "packages"), "w") as f: + f.write("*dev-libs/token-system-pkg") + for cp, xml_data in metadata_xml_files: + with open( + os.path.join(test_repo_location, cp, "metadata.xml"), "w" + ) as f: + f.write(playground.metadata_xml_template % xml_data) + with open(os.path.join(updates_dir, "1Q-2010"), "w") as f: + f.write( + """ +slotmove =app-doc/pms-3 2 3 +move dev-util/git dev-vcs/git +""" + ) + + if debug: + # The subprocess inherits both stdout and stderr, for + # debugging purposes. + stdout = None + else: + # The subprocess inherits stderr so that any warnings + # triggered by python -Wd will be visible. + stdout = subprocess.PIPE + + for args in test_commands: + if hasattr(args, "__call__"): + args() + continue + + if isinstance(args[0], dict): + local_env = env.copy() + local_env.update(args[0]) + args = args[1:] + else: + local_env = env + + proc = await asyncio.create_subprocess_exec( + *args, env=local_env, stderr=None, stdout=stdout + ) + + if debug: + await proc.wait() + else: + output, _err = await proc.communicate() + await proc.wait() + if proc.returncode != os.EX_OK: + portage.writemsg(output) + + self.assertEqual( + os.EX_OK, proc.returncode, f"emerge failed with args {args}" + ) + finally: + binhost_server.__exit__(None, None, None) + playground.cleanup()