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