ad02384a823c70f6c419d983da1b9f11d6a1a8d8
[portage.git] / pym / portage / tests / emerge / test_simple.py
1 # Copyright 2011-2013 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 import subprocess
5 import sys
6
7 import portage
8 from portage import os
9 from portage import _unicode_decode
10 from portage.const import (BASH_BINARY, PORTAGE_BASE_PATH,
11         PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, USER_CONFIG_PATH)
12 from portage.process import find_binary
13 from portage.tests import TestCase
14 from portage.tests.resolver.ResolverPlayground import ResolverPlayground
15 from portage.util import ensure_dirs
16
17 class SimpleEmergeTestCase(TestCase):
18
19         def _have_python_xml(self):
20                 try:
21                         __import__("xml.etree.ElementTree")
22                         __import__("xml.parsers.expat").parsers.expat.ExpatError
23                 except (AttributeError, ImportError):
24                         return False
25                 return True
26
27         def testSimple(self):
28
29                 debug = False
30
31                 install_something = """
32 S="${WORKDIR}"
33
34 pkg_pretend() {
35         einfo "called pkg_pretend for $CATEGORY/$PF"
36 }
37
38 src_install() {
39         einfo "installing something..."
40         insinto /usr/lib/${P}
41         echo "blah blah blah" > "${T}"/regular-file
42         doins "${T}"/regular-file
43         dosym regular-file /usr/lib/${P}/symlink || die
44
45         # Test code for bug #381629, using a copyright symbol encoded with latin-1.
46         # We use $(printf "\\xa9") rather than $'\\xa9', since printf apparently
47         # works in any case, while $'\\xa9' transforms to \\xef\\xbf\\xbd under
48         # some conditions. TODO: Find out why it transforms to \\xef\\xbf\\xbd when
49         # running tests for Python 3.2 (even though it's bash that is ultimately
50         # responsible for performing the transformation).
51         local latin_1_dir=/usr/lib/${P}/latin-1-$(printf "\\xa9")-directory
52         insinto "${latin_1_dir}"
53         echo "blah blah blah" > "${T}"/latin-1-$(printf "\\xa9")-regular-file || die
54         doins "${T}"/latin-1-$(printf "\\xa9")-regular-file
55         dosym latin-1-$(printf "\\xa9")-regular-file ${latin_1_dir}/latin-1-$(printf "\\xa9")-symlink || die
56 }
57
58 pkg_config() {
59         einfo "called pkg_config for $CATEGORY/$PF"
60 }
61
62 pkg_info() {
63         einfo "called pkg_info for $CATEGORY/$PF"
64 }
65
66 pkg_preinst() {
67         einfo "called pkg_preinst for $CATEGORY/$PF"
68
69         # Test that has_version and best_version work correctly with
70         # prefix (involves internal ROOT -> EROOT calculation in order
71         # to support ROOT override via the environment with EAPIs 3
72         # and later which support prefix).
73         if has_version $CATEGORY/$PN:$SLOT ; then
74                 einfo "has_version detects an installed instance of $CATEGORY/$PN:$SLOT"
75                 einfo "best_version reports that the installed instance is $(best_version $CATEGORY/$PN:$SLOT)"
76         else
77                 einfo "has_version does not detect an installed instance of $CATEGORY/$PN:$SLOT"
78         fi
79         if [[ ${EPREFIX} != ${PORTAGE_OVERRIDE_EPREFIX} ]] ; then
80                 if has_version --host-root $CATEGORY/$PN:$SLOT ; then
81                         einfo "has_version --host-root detects an installed instance of $CATEGORY/$PN:$SLOT"
82                         einfo "best_version --host-root reports that the installed instance is $(best_version $CATEGORY/$PN:$SLOT)"
83                 else
84                         einfo "has_version --host-root does not detect an installed instance of $CATEGORY/$PN:$SLOT"
85                 fi
86         fi
87 }
88
89 """
90
91                 ebuilds = {
92                         "dev-libs/A-1": {
93                                 "EAPI" : "5",
94                                 "IUSE" : "+flag",
95                                 "KEYWORDS": "x86",
96                                 "LICENSE": "GPL-2",
97                                 "MISC_CONTENT": install_something,
98                                 "RDEPEND": "flag? ( dev-libs/B[flag] )",
99                         },
100                         "dev-libs/B-1": {
101                                 "EAPI" : "5",
102                                 "IUSE" : "+flag",
103                                 "KEYWORDS": "x86",
104                                 "LICENSE": "GPL-2",
105                                 "MISC_CONTENT": install_something,
106                         },
107                         "virtual/foo-0": {
108                                 "EAPI" : "5",
109                                 "KEYWORDS": "x86",
110                                 "LICENSE": "GPL-2",
111                         },
112                 }
113
114                 installed = {
115                         "dev-libs/A-1": {
116                                 "EAPI" : "5",
117                                 "IUSE" : "+flag",
118                                 "KEYWORDS": "x86",
119                                 "LICENSE": "GPL-2",
120                                 "RDEPEND": "flag? ( dev-libs/B[flag] )",
121                                 "USE": "flag",
122                         },
123                         "dev-libs/B-1": {
124                                 "EAPI" : "5",
125                                 "IUSE" : "+flag",
126                                 "KEYWORDS": "x86",
127                                 "LICENSE": "GPL-2",
128                                 "USE": "flag",
129                         },
130                         "dev-libs/depclean-me-1": {
131                                 "EAPI" : "5",
132                                 "IUSE" : "",
133                                 "KEYWORDS": "x86",
134                                 "LICENSE": "GPL-2",
135                                 "USE": "",
136                         },
137                         "app-misc/depclean-me-1": {
138                                 "EAPI" : "5",
139                                 "IUSE" : "",
140                                 "KEYWORDS": "x86",
141                                 "LICENSE": "GPL-2",
142                                 "RDEPEND": "dev-libs/depclean-me",
143                                 "USE": "",
144                         },
145                 }
146
147                 metadata_xml_files = (
148                         (
149                                 "dev-libs/A",
150                                 {
151                                         "herd" : "base-system",
152                                         "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>",
153                                 },
154                         ),
155                         (
156                                 "dev-libs/B",
157                                 {
158                                         "herd" : "no-herd",
159                                         "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>",
160                                 },
161                         ),
162                 )
163
164                 playground = ResolverPlayground(
165                         ebuilds=ebuilds, installed=installed, debug=debug)
166                 settings = playground.settings
167                 eprefix = settings["EPREFIX"]
168                 eroot = settings["EROOT"]
169                 trees = playground.trees
170                 portdb = trees[eroot]["porttree"].dbapi
171                 test_repo_location = settings.repositories["test_repo"].location
172                 var_cache_edb = os.path.join(eprefix, "var", "cache", "edb")
173                 cachedir = os.path.join(var_cache_edb, "dep")
174                 cachedir_pregen = os.path.join(test_repo_location, "metadata", "md5-cache")
175
176                 portage_python = portage._python_interpreter
177                 dispatch_conf_cmd = (portage_python, "-Wd",
178                         os.path.join(PORTAGE_BIN_PATH, "dispatch-conf"))
179                 ebuild_cmd = (portage_python, "-Wd",
180                         os.path.join(PORTAGE_BIN_PATH, "ebuild"))
181                 egencache_cmd = (portage_python, "-Wd",
182                         os.path.join(PORTAGE_BIN_PATH, "egencache"),
183                         "--repo", "test_repo",
184                         "--repositories-configuration", settings.repositories.config_string())
185                 emerge_cmd = (portage_python, "-Wd",
186                         os.path.join(PORTAGE_BIN_PATH, "emerge"))
187                 emaint_cmd = (portage_python, "-Wd",
188                         os.path.join(PORTAGE_BIN_PATH, "emaint"))
189                 env_update_cmd = (portage_python, "-Wd",
190                         os.path.join(PORTAGE_BIN_PATH, "env-update"))
191                 etc_update_cmd = (BASH_BINARY,
192                         os.path.join(PORTAGE_BIN_PATH, "etc-update"))
193                 fixpackages_cmd = (portage_python, "-Wd",
194                         os.path.join(PORTAGE_BIN_PATH, "fixpackages"))
195                 portageq_cmd = (portage_python, "-Wd",
196                         os.path.join(PORTAGE_BIN_PATH, "portageq"))
197                 quickpkg_cmd = (portage_python, "-Wd",
198                         os.path.join(PORTAGE_BIN_PATH, "quickpkg"))
199                 regenworld_cmd = (portage_python, "-Wd",
200                         os.path.join(PORTAGE_BIN_PATH, "regenworld"))
201
202                 rm_binary = find_binary("rm")
203                 self.assertEqual(rm_binary is None, False,
204                         "rm command not found")
205                 rm_cmd = (rm_binary,)
206
207                 egencache_extra_args = []
208                 if self._have_python_xml():
209                         egencache_extra_args.append("--update-use-local-desc")
210
211                 test_ebuild = portdb.findname("dev-libs/A-1")
212                 self.assertFalse(test_ebuild is None)
213
214                 cross_prefix = os.path.join(eprefix, "cross_prefix")
215
216                 test_commands = (
217                         env_update_cmd,
218                         portageq_cmd + ("envvar", "-v", "CONFIG_PROTECT", "EROOT",
219                                 "PORTAGE_CONFIGROOT", "PORTAGE_TMPDIR", "USERLAND"),
220                         etc_update_cmd,
221                         dispatch_conf_cmd,
222                         emerge_cmd + ("--version",),
223                         emerge_cmd + ("--info",),
224                         emerge_cmd + ("--info", "--verbose"),
225                         emerge_cmd + ("--list-sets",),
226                         emerge_cmd + ("--check-news",),
227                         rm_cmd + ("-rf", cachedir),
228                         rm_cmd + ("-rf", cachedir_pregen),
229                         emerge_cmd + ("--regen",),
230                         rm_cmd + ("-rf", cachedir),
231                         ({"FEATURES" : "metadata-transfer"},) + \
232                                 emerge_cmd + ("--regen",),
233                         rm_cmd + ("-rf", cachedir),
234                         ({"FEATURES" : "metadata-transfer"},) + \
235                                 emerge_cmd + ("--regen",),
236                         rm_cmd + ("-rf", cachedir),
237                         egencache_cmd + ("--update",) + tuple(egencache_extra_args),
238                         ({"FEATURES" : "metadata-transfer"},) + \
239                                 emerge_cmd + ("--metadata",),
240                         rm_cmd + ("-rf", cachedir),
241                         ({"FEATURES" : "metadata-transfer"},) + \
242                                 emerge_cmd + ("--metadata",),
243                         emerge_cmd + ("--metadata",),
244                         rm_cmd + ("-rf", cachedir),
245                         emerge_cmd + ("--oneshot", "virtual/foo"),
246                         emerge_cmd + ("--pretend", "dev-libs/A"),
247                         ebuild_cmd + (test_ebuild, "manifest", "clean", "package", "merge"),
248                         emerge_cmd + ("--pretend", "--tree", "--complete-graph", "dev-libs/A"),
249                         emerge_cmd + ("-p", "dev-libs/B"),
250                         emerge_cmd + ("-B", "dev-libs/B",),
251                         emerge_cmd + ("--oneshot", "--usepkg", "dev-libs/B",),
252
253                         # trigger clean prior to pkg_pretend as in bug #390711
254                         ebuild_cmd + (test_ebuild, "unpack"), 
255                         emerge_cmd + ("--oneshot", "dev-libs/A",),
256
257                         emerge_cmd + ("--noreplace", "dev-libs/A",),
258                         emerge_cmd + ("--config", "dev-libs/A",),
259                         emerge_cmd + ("--info", "dev-libs/A", "dev-libs/B"),
260                         emerge_cmd + ("--pretend", "--depclean", "--verbose", "dev-libs/B"),
261                         emerge_cmd + ("--pretend", "--depclean",),
262                         emerge_cmd + ("--depclean",),
263                         quickpkg_cmd + ("dev-libs/A",),
264                         emerge_cmd + ("--usepkgonly", "dev-libs/A"),
265                         emaint_cmd + ("--check", "all"),
266                         emaint_cmd + ("--fix", "all"),
267                         fixpackages_cmd,
268                         regenworld_cmd,
269                         portageq_cmd + ("match", eroot, "dev-libs/A"),
270                         portageq_cmd + ("best_visible", eroot, "dev-libs/A"),
271                         portageq_cmd + ("best_visible", eroot, "binary", "dev-libs/A"),
272                         portageq_cmd + ("contents", eroot, "dev-libs/A-1"),
273                         portageq_cmd + ("metadata", eroot, "ebuild", "dev-libs/A-1", "EAPI", "IUSE", "RDEPEND"),
274                         portageq_cmd + ("metadata", eroot, "binary", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"),
275                         portageq_cmd + ("metadata", eroot, "installed", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"),
276                         portageq_cmd + ("owners", eroot, eroot + "usr"),
277                         emerge_cmd + ("-p", eroot + "usr"),
278                         emerge_cmd + ("-p", "--unmerge", "-q", eroot + "usr"),
279                         emerge_cmd + ("--unmerge", "--quiet", "dev-libs/A"),
280                         emerge_cmd + ("-C", "--quiet", "dev-libs/B"),
281
282                         # Test cross-prefix usage, including chpathtool for binpkgs.
283                         ({"EPREFIX" : cross_prefix},) + \
284                                 emerge_cmd + ("--usepkgonly", "dev-libs/A"),
285                         ({"EPREFIX" : cross_prefix},) + \
286                                 portageq_cmd + ("has_version", cross_prefix, "dev-libs/A"),
287                         ({"EPREFIX" : cross_prefix},) + \
288                                 portageq_cmd + ("has_version", cross_prefix, "dev-libs/B"),
289                         ({"EPREFIX" : cross_prefix},) + \
290                                 emerge_cmd + ("-C", "--quiet", "dev-libs/B"),
291                         ({"EPREFIX" : cross_prefix},) + \
292                                 emerge_cmd + ("-C", "--quiet", "dev-libs/A"),
293                         ({"EPREFIX" : cross_prefix},) + \
294                                 emerge_cmd + ("dev-libs/A",),
295                         ({"EPREFIX" : cross_prefix},) + \
296                                 portageq_cmd + ("has_version", cross_prefix, "dev-libs/A"),
297                         ({"EPREFIX" : cross_prefix},) + \
298                                 portageq_cmd + ("has_version", cross_prefix, "dev-libs/B"),
299                 )
300
301                 distdir = playground.distdir
302                 pkgdir = playground.pkgdir
303                 fake_bin = os.path.join(eprefix, "bin")
304                 portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage")
305                 profile_path = settings.profile_path
306                 user_config_dir = os.path.join(os.sep, eprefix, USER_CONFIG_PATH)
307
308                 path =  os.environ.get("PATH")
309                 if path is not None and not path.strip():
310                         path = None
311                 if path is None:
312                         path = ""
313                 else:
314                         path = ":" + path
315                 path = fake_bin + path
316
317                 pythonpath =  os.environ.get("PYTHONPATH")
318                 if pythonpath is not None and not pythonpath.strip():
319                         pythonpath = None
320                 if pythonpath is not None and \
321                         pythonpath.split(":")[0] == PORTAGE_PYM_PATH:
322                         pass
323                 else:
324                         if pythonpath is None:
325                                 pythonpath = ""
326                         else:
327                                 pythonpath = ":" + pythonpath
328                         pythonpath = PORTAGE_PYM_PATH + pythonpath
329
330                 env = {
331                         "PORTAGE_OVERRIDE_EPREFIX" : eprefix,
332                         "CLEAN_DELAY" : "0",
333                         "DISTDIR" : distdir,
334                         "EMERGE_WARNING_DELAY" : "0",
335                         "INFODIR" : "",
336                         "INFOPATH" : "",
337                         "PATH" : path,
338                         "PKGDIR" : pkgdir,
339                         "PORTAGE_INST_GID" : str(portage.data.portage_gid),
340                         "PORTAGE_INST_UID" : str(portage.data.portage_uid),
341                         "PORTAGE_PYTHON" : portage_python,
342                         "PORTAGE_REPOSITORIES" : settings.repositories.config_string(),
343                         "PORTAGE_TMPDIR" : portage_tmpdir,
344                         "PYTHONPATH" : pythonpath,
345                         "__PORTAGE_TEST_PATH_OVERRIDE" : fake_bin,
346                 }
347
348                 if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ:
349                         env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \
350                                 os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"]
351
352                 updates_dir = os.path.join(test_repo_location, "profiles", "updates")
353                 dirs = [cachedir, cachedir_pregen, distdir, fake_bin,
354                         portage_tmpdir, updates_dir,
355                         user_config_dir, var_cache_edb]
356                 etc_symlinks = ("dispatch-conf.conf", "etc-update.conf")
357                 # Override things that may be unavailable, or may have portability
358                 # issues when running tests in exotic environments.
359                 #   prepstrip - bug #447810 (bash read builtin EINTR problem)
360                 true_symlinks = ["find", "prepstrip", "sed", "scanelf"]
361                 true_binary = find_binary("true")
362                 self.assertEqual(true_binary is None, False,
363                         "true command not found")
364                 try:
365                         for d in dirs:
366                                 ensure_dirs(d)
367                         for x in true_symlinks:
368                                 os.symlink(true_binary, os.path.join(fake_bin, x))
369                         for x in etc_symlinks:
370                                 os.symlink(os.path.join(PORTAGE_BASE_PATH, "cnf", x),
371                                         os.path.join(eprefix, "etc", x))
372                         with open(os.path.join(var_cache_edb, "counter"), 'wb') as f:
373                                 f.write(b"100")
374                         # non-empty system set keeps --depclean quiet
375                         with open(os.path.join(profile_path, "packages"), 'w') as f:
376                                 f.write("*dev-libs/token-system-pkg")
377                         for cp, xml_data in metadata_xml_files:
378                                 with open(os.path.join(test_repo_location, cp, "metadata.xml"), 'w') as f:
379                                         f.write(playground.metadata_xml_template % xml_data)
380                         with open(os.path.join(updates_dir, "1Q-2010"), 'w') as f:
381                                 f.write("""
382 slotmove =app-doc/pms-3 2 3
383 move dev-util/git dev-vcs/git
384 """)
385
386                         if debug:
387                                 # The subprocess inherits both stdout and stderr, for
388                                 # debugging purposes.
389                                 stdout = None
390                         else:
391                                 # The subprocess inherits stderr so that any warnings
392                                 # triggered by python -Wd will be visible.
393                                 stdout = subprocess.PIPE
394
395                         for args in test_commands:
396
397                                 if isinstance(args[0], dict):
398                                         local_env = env.copy()
399                                         local_env.update(args[0])
400                                         args = args[1:]
401                                 else:
402                                         local_env = env
403
404                                 proc = subprocess.Popen(args,
405                                         env=local_env, stdout=stdout)
406
407                                 if debug:
408                                         proc.wait()
409                                 else:
410                                         output = proc.stdout.readlines()
411                                         proc.wait()
412                                         proc.stdout.close()
413                                         if proc.returncode != os.EX_OK:
414                                                 for line in output:
415                                                         sys.stderr.write(_unicode_decode(line))
416
417                                 self.assertEqual(os.EX_OK, proc.returncode,
418                                         "emerge failed with args %s" % (args,))
419                 finally:
420                         playground.cleanup()