Enable BytesWarnings.
[portage.git] / pym / portage / tests / emerge / test_simple.py
index f6f5ab06ef06b2d67dcea86c79fc4711604f92e6..2016ae69fae945c47ec19be1178b18d7338f81e2 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2011 Gentoo Foundation
+# Copyright 2011-2014 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import subprocess
@@ -7,7 +7,8 @@ import sys
 import portage
 from portage import os
 from portage import _unicode_decode
-from portage.const import PORTAGE_BIN_PATH, PORTAGE_PYM_PATH
+from portage.const import (BASH_BINARY, PORTAGE_BASE_PATH,
+       PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, USER_CONFIG_PATH)
 from portage.process import find_binary
 from portage.tests import TestCase
 from portage.tests.resolver.ResolverPlayground import ResolverPlayground
@@ -15,27 +16,104 @@ from portage.util import ensure_dirs
 
 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 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
+}
+
+pkg_config() {
+       einfo "called pkg_config for $CATEGORY/$PF"
+}
+
+pkg_info() {
+       einfo "called pkg_info for $CATEGORY/$PF"
+}
+
+pkg_preinst() {
+       einfo "called pkg_preinst for $CATEGORY/$PF"
+
+       # 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 --host-root $CATEGORY/$PN:$SLOT ; then
+                       einfo "has_version --host-root detects an installed instance of $CATEGORY/$PN:$SLOT"
+                       einfo "best_version --host-root reports that the installed instance is $(best_version $CATEGORY/$PN:$SLOT)"
+               else
+                       einfo "has_version --host-root does not detect an installed instance of $CATEGORY/$PN:$SLOT"
+               fi
+       fi
+}
+
+"""
+
                ebuilds = {
                        "dev-libs/A-1": {
-                               "EAPI" : "4",
+                               "EAPI" : "5",
                                "IUSE" : "+flag",
                                "KEYWORDS": "x86",
                                "LICENSE": "GPL-2",
+                               "MISC_CONTENT": install_something,
                                "RDEPEND": "flag? ( dev-libs/B[flag] )",
                        },
                        "dev-libs/B-1": {
-                               "EAPI" : "4",
+                               "EAPI" : "5",
                                "IUSE" : "+flag",
                                "KEYWORDS": "x86",
                                "LICENSE": "GPL-2",
+                               "MISC_CONTENT": install_something,
+                       },
+                       "virtual/foo-0": {
+                               "EAPI" : "5",
+                               "KEYWORDS": "x86",
+                               "LICENSE": "GPL-2",
                        },
                }
 
                installed = {
                        "dev-libs/A-1": {
-                               "EAPI" : "4",
+                               "EAPI" : "5",
                                "IUSE" : "+flag",
                                "KEYWORDS": "x86",
                                "LICENSE": "GPL-2",
@@ -43,39 +121,189 @@ class SimpleEmergeTestCase(TestCase):
                                "USE": "flag",
                        },
                        "dev-libs/B-1": {
-                               "EAPI" : "4",
+                               "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": "",
+                       },
                }
 
-               test_args = (
-                       ("--version",),
-                       ("--info",),
-                       ("--info", "--verbose"),
-                       ("--pretend", "dev-libs/A"),
-                       ("--pretend", "--tree", "--complete-graph", "dev-libs/A"),
-                       ("-p", "dev-libs/B"),
-                       ("--oneshot", "dev-libs/A",),
-                       ("--noreplace", "dev-libs/A",),
-                       ("--pretend", "--depclean", "--verbose", "dev-libs/B"),
-                       ("--pretend", "--depclean",),
-                       ("--depclean",),
-                       ("--unmerge", "--quiet", "dev-libs/A"),
-                       ("-C", "--quiet", "dev-libs/B"),
+               metadata_xml_files = (
+                       (
+                               "dev-libs/A",
+                               {
+                                       "herd" : "base-system",
+                                       "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>",
+                               },
+                       ),
+                       (
+                               "dev-libs/B",
+                               {
+                                       "herd" : "no-herd",
+                                       "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>",
+                               },
+                       ),
                )
 
-               playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+               playground = ResolverPlayground(
+                       ebuilds=ebuilds, installed=installed, debug=debug)
                settings = playground.settings
                eprefix = settings["EPREFIX"]
-               distdir = os.path.join(eprefix, "distdir")
+               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, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "dispatch-conf"))
+               ebuild_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "ebuild"))
+               egencache_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "egencache"),
+                       "--repo", "test_repo",
+                       "--repositories-configuration", settings.repositories.config_string())
+               emerge_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "emerge"))
+               emaint_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "emaint"))
+               env_update_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "env-update"))
+               etc_update_cmd = (BASH_BINARY,
+                       os.path.join(PORTAGE_BIN_PATH, "etc-update"))
+               fixpackages_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "fixpackages"))
+               portageq_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "portageq"))
+               quickpkg_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "quickpkg"))
+               regenworld_cmd = (portage_python, "-bb", "-Wd",
+                       os.path.join(PORTAGE_BIN_PATH, "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")
+
+               test_commands = (
+                       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"),
+                       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 + ("-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 + ("dev-libs/A",),
+                       emerge_cmd + ("--usepkgonly", "dev-libs/A"),
+                       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"),
+
+                       # Test cross-prefix usage, including chpathtool for binpkgs.
+                       ({"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"),
+               )
+
+               distdir = playground.distdir
+               pkgdir = playground.pkgdir
                fake_bin = os.path.join(eprefix, "bin")
                portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage")
-               portdir = settings["PORTDIR"]
                profile_path = settings.profile_path
-               var_cache_edb = os.path.join(eprefix, "var", "cache", "edb")
+               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():
@@ -100,20 +328,36 @@ class SimpleEmergeTestCase(TestCase):
                        pythonpath = PORTAGE_PYM_PATH + pythonpath
 
                env = {
-                       "__PORTAGE_TEST_EPREFIX" : eprefix,
+                       "PORTAGE_OVERRIDE_EPREFIX" : eprefix,
+                       "CLEAN_DELAY" : "0",
                        "DISTDIR" : distdir,
+                       "EMERGE_WARNING_DELAY" : "0",
                        "INFODIR" : "",
                        "INFOPATH" : "",
                        "PATH" : path,
-                       "PORTAGE_GRPNAME" : os.environ["PORTAGE_GRPNAME"],
+                       "PKGDIR" : pkgdir,
+                       "PORTAGE_INST_GID" : str(portage.data.portage_gid),
+                       "PORTAGE_INST_UID" : str(portage.data.portage_uid),
+                       "PORTAGE_PYTHON" : portage_python,
+                       "PORTAGE_REPOSITORIES" : settings.repositories.config_string(),
                        "PORTAGE_TMPDIR" : portage_tmpdir,
-                       "PORTAGE_USERNAME" : os.environ["PORTAGE_USERNAME"],
-                       "PORTDIR" : portdir,
                        "PYTHONPATH" : pythonpath,
+                       "__PORTAGE_TEST_PATH_OVERRIDE" : fake_bin,
                }
 
-               dirs = [distdir, fake_bin, portage_tmpdir, var_cache_edb]
-               true_symlinks = ["chown", "chgrp"]
+               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, 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")
@@ -122,21 +366,53 @@ class SimpleEmergeTestCase(TestCase):
                                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(PORTAGE_BASE_PATH, "cnf", 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 args in test_args:
-                               proc = subprocess.Popen([portage._python_interpreter, "-Wd",
-                                       os.path.join(PORTAGE_BIN_PATH, "emerge")] + list(args),
-                                       env=env, stdout=subprocess.PIPE)
-                               output = proc.stdout.readlines()
-                               proc.wait()
-                               proc.stdout.close()
-                               if proc.returncode != os.EX_OK:
-                                       for line in output:
-                                               sys.stderr.write(_unicode_decode(line))
+                       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 isinstance(args[0], dict):
+                                       local_env = env.copy()
+                                       local_env.update(args[0])
+                                       args = args[1:]
+                               else:
+                                       local_env = env
+
+                               proc = subprocess.Popen(args,
+                                       env=local_env, stdout=stdout)
+
+                               if debug:
+                                       proc.wait()
+                               else:
+                                       output = proc.stdout.readlines()
+                                       proc.wait()
+                                       proc.stdout.close()
+                                       if proc.returncode != os.EX_OK:
+                                               for line in output:
+                                                       sys.stderr.write(_unicode_decode(line))
 
                                self.assertEqual(os.EX_OK, proc.returncode,
                                        "emerge failed with args %s" % (args,))