23b0e0a4538f21f64f753e41a23339b11244fe41
[portage.git] / pym / portage / tests / repoman / 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 import time
7
8 import portage
9 from portage import os
10 from portage import shutil
11 from portage import _unicode_decode
12 from portage.const import PORTAGE_BASE_PATH, PORTAGE_BIN_PATH, PORTAGE_PYM_PATH
13 from portage.process import find_binary
14 from portage.tests import TestCase
15 from portage.tests.resolver.ResolverPlayground import ResolverPlayground
16 from portage.util import ensure_dirs
17 from repoman.utilities import _update_copyright_year
18
19 class SimpleRepomanTestCase(TestCase):
20
21         def testCopyrightUpdate(self):
22                 test_cases = (
23                         (
24                                 '2011',
25                                 '# Copyright 1999-2008 Gentoo Foundation; Distributed under the GPL v2',
26                                 '# Copyright 1999-2011 Gentoo Foundation; Distributed under the GPL v2',
27                         ),
28                         (
29                                 '2011',
30                                 '# Copyright 1999 Gentoo Foundation; Distributed under the GPL v2',
31                                 '# Copyright 1999-2011 Gentoo Foundation; Distributed under the GPL v2',
32                         ),
33                         (
34                                 '1999',
35                                 '# Copyright 1999 Gentoo Foundation; Distributed under the GPL v2',
36                                 '# Copyright 1999 Gentoo Foundation; Distributed under the GPL v2',
37                         ),
38                 )
39
40                 for year, before, after in test_cases:
41                         self.assertEqual(_update_copyright_year(year, before), after)
42
43         def _must_skip(self):
44                 xmllint = find_binary("xmllint")
45                 if not xmllint:
46                         return "xmllint not found"
47
48                 try:
49                         __import__("xml.etree.ElementTree")
50                         __import__("xml.parsers.expat").parsers.expat.ExpatError
51                 except (AttributeError, ImportError):
52                         return "python is missing xml support"
53
54         def testSimple(self):
55                 debug = False
56
57                 skip_reason = self._must_skip()
58                 if skip_reason:
59                         self.portage_skip = skip_reason
60                         self.assertFalse(True, skip_reason)
61                         return
62
63                 copyright_header = """# Copyright 1999-%s Gentoo Foundation
64 # Distributed under the terms of the GNU General Public License v2
65 # $Header: $
66 """ % time.gmtime().tm_year
67
68                 repo_configs = {
69                         "test_repo": {
70                                 "layout.conf":
71                                         (
72                                                 "update-changelog = true",
73                                         ),
74                         }
75                 }
76
77                 profiles = (
78                         ("x86", "default/linux/x86/test_profile", "stable"),
79                         ("x86", "default/linux/x86/test_dev", "dev"),
80                         ("x86", "default/linux/x86/test_exp", "exp"),
81                 )
82
83                 profile = {
84                         "eapi": ("5",),
85                         "package.use.stable.mask": ("dev-libs/A flag",)
86                 }
87
88                 ebuilds = {
89                         "dev-libs/A-0": {
90                                 "COPYRIGHT_HEADER" : copyright_header,
91                                 "DESCRIPTION" : "Desc goes here",
92                                 "EAPI" : "5",
93                                 "HOMEPAGE" : "http://example.com",
94                                 "IUSE" : "flag",
95                                 "KEYWORDS": "x86",
96                                 "LICENSE": "GPL-2",
97                                 "RDEPEND": "flag? ( dev-libs/B[flag] )",
98                         },
99                         "dev-libs/A-1": {
100                                 "COPYRIGHT_HEADER" : copyright_header,
101                                 "DESCRIPTION" : "Desc goes here",
102                                 "EAPI" : "4",
103                                 "HOMEPAGE" : "http://example.com",
104                                 "IUSE" : "flag",
105                                 "KEYWORDS": "~x86",
106                                 "LICENSE": "GPL-2",
107                                 "RDEPEND": "flag? ( dev-libs/B[flag] )",
108                         },
109                         "dev-libs/B-1": {
110                                 "COPYRIGHT_HEADER" : copyright_header,
111                                 "DESCRIPTION" : "Desc goes here",
112                                 "EAPI" : "4",
113                                 "HOMEPAGE" : "http://example.com",
114                                 "IUSE" : "flag",
115                                 "KEYWORDS": "~x86",
116                                 "LICENSE": "GPL-2",
117                         },
118                         "dev-libs/C-0": {
119                                 "COPYRIGHT_HEADER" : copyright_header,
120                                 "DESCRIPTION" : "Desc goes here",
121                                 "EAPI" : "4",
122                                 "HOMEPAGE" : "http://example.com",
123                                 "IUSE" : "flag",
124                                 # must be unstable, since dev-libs/A[flag] is stable masked
125                                 "KEYWORDS": "~x86",
126                                 "LICENSE": "GPL-2",
127                                 "RDEPEND": "flag? ( dev-libs/A[flag] )",
128                         },
129                 }
130                 licenses = ["GPL-2"]
131                 arch_list = ["x86"]
132                 metadata_dtd = os.path.join(PORTAGE_BASE_PATH, "cnf/metadata.dtd")
133                 metadata_xml_files = (
134                         (
135                                 "dev-libs/A",
136                                 {
137                                         "herd" : "base-system",
138                                         "flags" : "<flag name='flag' restrict='&gt;=dev-libs/A-0'>Description of how USE='flag' affects this package</flag>",
139                                 },
140                         ),
141                         (
142                                 "dev-libs/B",
143                                 {
144                                         "herd" : "no-herd",
145                                         "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>",
146                                 },
147                         ),
148                         (
149                                 "dev-libs/C",
150                                 {
151                                         "herd" : "no-herd",
152                                         "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>",
153                                 },
154                         ),
155                 )
156
157                 use_desc = (
158                         ("flag", "Description of how USE='flag' affects packages"),
159                 )
160
161                 playground = ResolverPlayground(ebuilds=ebuilds,
162                         profile=profile, repo_configs=repo_configs, debug=debug)
163                 settings = playground.settings
164                 eprefix = settings["EPREFIX"]
165                 eroot = settings["EROOT"]
166                 portdb = playground.trees[playground.eroot]["porttree"].dbapi
167                 homedir = os.path.join(eroot, "home")
168                 distdir = os.path.join(eprefix, "distdir")
169                 test_repo_location = settings.repositories["test_repo"].location
170                 profiles_dir = os.path.join(test_repo_location, "profiles")
171                 license_dir = os.path.join(test_repo_location, "licenses")
172
173                 repoman_cmd = (portage._python_interpreter, "-Wd",
174                         os.path.join(PORTAGE_BIN_PATH, "repoman"))
175
176                 git_binary = find_binary("git")
177                 git_cmd = (git_binary,)
178
179                 cp_binary = find_binary("cp")
180                 self.assertEqual(cp_binary is None, False,
181                         "cp command not found")
182                 cp_cmd = (cp_binary,)
183
184                 test_ebuild = portdb.findname("dev-libs/A-1")
185                 self.assertFalse(test_ebuild is None)
186
187                 committer_name = "Gentoo Dev"
188                 committer_email = "gentoo-dev@gentoo.org"
189                 
190                 git_test = (
191                         ("", repoman_cmd + ("manifest",)),
192                         ("", git_cmd + ("config", "--global", "user.name", committer_name,)),
193                         ("", git_cmd + ("config", "--global", "user.email", committer_email,)),
194                         ("", git_cmd + ("init-db",)),
195                         ("", git_cmd + ("add", ".")),
196                         ("", git_cmd + ("commit", "-a", "-m", "add whole repo")),
197                         ("", repoman_cmd + ("full", "-d")),
198                         ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "2.ebuild")),
199                         ("", git_cmd + ("add", test_ebuild[:-8] + "2.ebuild")),
200                         ("", repoman_cmd + ("commit", "-m", "bump to version 2")),
201                         ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "3.ebuild")),
202                         ("", git_cmd + ("add", test_ebuild[:-8] + "3.ebuild")),
203                         ("dev-libs", repoman_cmd + ("commit", "-m", "bump to version 3")),
204                         ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "4.ebuild")),
205                         ("", git_cmd + ("add", test_ebuild[:-8] + "4.ebuild")),
206                         ("dev-libs/A", repoman_cmd + ("commit", "-m", "bump to version 4")),
207                 )
208
209                 pythonpath =  os.environ.get("PYTHONPATH")
210                 if pythonpath is not None and not pythonpath.strip():
211                         pythonpath = None
212                 if pythonpath is not None and \
213                         pythonpath.split(":")[0] == PORTAGE_PYM_PATH:
214                         pass
215                 else:
216                         if pythonpath is None:
217                                 pythonpath = ""
218                         else:
219                                 pythonpath = ":" + pythonpath
220                         pythonpath = PORTAGE_PYM_PATH + pythonpath
221
222                 env = {
223                         "PORTAGE_OVERRIDE_EPREFIX" : eprefix,
224                         "DISTDIR" : distdir,
225                         "GENTOO_COMMITTER_NAME" : committer_name,
226                         "GENTOO_COMMITTER_EMAIL" : committer_email,
227                         "HOME" : homedir,
228                         "PATH" : os.environ["PATH"],
229                         "PORTAGE_GRPNAME" : os.environ["PORTAGE_GRPNAME"],
230                         "PORTAGE_USERNAME" : os.environ["PORTAGE_USERNAME"],
231                         "PORTAGE_REPOSITORIES" : settings.repositories.config_string(),
232                         "PYTHONPATH" : pythonpath,
233                 }
234
235                 if os.environ.get("SANDBOX_ON") == "1":
236                         # avoid problems from nested sandbox instances
237                         env["FEATURES"] = "-sandbox -usersandbox"
238
239                 dirs = [homedir, license_dir, profiles_dir, distdir]
240                 try:
241                         for d in dirs:
242                                 ensure_dirs(d)
243                         with open(os.path.join(test_repo_location, "skel.ChangeLog"), 'w') as f:
244                                 f.write(copyright_header)
245                         with open(os.path.join(profiles_dir, "profiles.desc"), 'w') as f:
246                                 for x in profiles:
247                                         f.write("%s %s %s\n" % x)
248
249                         # ResolverPlayground only created the first profile,
250                         # so create the remaining ones.
251                         for x in profiles[1:]:
252                                 sub_profile_dir = os.path.join(profiles_dir, x[1])
253                                 ensure_dirs(sub_profile_dir)
254                                 for config_file, lines in profile.items():
255                                         file_name = os.path.join(sub_profile_dir, config_file)
256                                         with open(file_name, "w") as f:
257                                                 for line in lines:
258                                                         f.write("%s\n" % line)
259
260                         for x in licenses:
261                                 open(os.path.join(license_dir, x), 'wb').close()
262                         with open(os.path.join(profiles_dir, "arch.list"), 'w') as f:
263                                 for x in arch_list:
264                                         f.write("%s\n" % x)
265                         with open(os.path.join(profiles_dir, "use.desc"), 'w') as f:
266                                 for k, v in use_desc:
267                                         f.write("%s - %s\n" % (k, v))
268                         for cp, xml_data in metadata_xml_files:
269                                 with open(os.path.join(test_repo_location, cp, "metadata.xml"), 'w') as f:
270                                         f.write(playground.metadata_xml_template % xml_data)
271                         # Use a symlink to test_repo, in order to trigger bugs
272                         # involving canonical vs. non-canonical paths.
273                         test_repo_symlink = os.path.join(eroot, "test_repo_symlink")
274                         os.symlink(test_repo_location, test_repo_symlink)
275                         # repoman checks metadata.dtd for recent CTIME, so copy the file in
276                         # order to ensure that the CTIME is current
277                         shutil.copyfile(metadata_dtd, os.path.join(distdir, "metadata.dtd"))
278
279                         if debug:
280                                 # The subprocess inherits both stdout and stderr, for
281                                 # debugging purposes.
282                                 stdout = None
283                         else:
284                                 # The subprocess inherits stderr so that any warnings
285                                 # triggered by python -Wd will be visible.
286                                 stdout = subprocess.PIPE
287
288                         for cwd in ("", "dev-libs", "dev-libs/A", "dev-libs/B"):
289                                 abs_cwd = os.path.join(test_repo_symlink, cwd)
290                                 proc = subprocess.Popen([portage._python_interpreter, "-Wd",
291                                         os.path.join(PORTAGE_BIN_PATH, "repoman"), "full"],
292                                         cwd=abs_cwd, env=env, stdout=stdout)
293
294                                 if debug:
295                                         proc.wait()
296                                 else:
297                                         output = proc.stdout.readlines()
298                                         proc.wait()
299                                         proc.stdout.close()
300                                         if proc.returncode != os.EX_OK:
301                                                 for line in output:
302                                                         sys.stderr.write(_unicode_decode(line))
303
304                                 self.assertEqual(os.EX_OK, proc.returncode,
305                                         "repoman failed in %s" % (cwd,))
306
307                         if git_binary is not None:
308                                 for cwd, cmd in git_test:
309                                         abs_cwd = os.path.join(test_repo_symlink, cwd)
310                                         proc = subprocess.Popen(cmd,
311                                                 cwd=abs_cwd, env=env, stdout=stdout)
312
313                                         if debug:
314                                                 proc.wait()
315                                         else:
316                                                 output = proc.stdout.readlines()
317                                                 proc.wait()
318                                                 proc.stdout.close()
319                                                 if proc.returncode != os.EX_OK:
320                                                         for line in output:
321                                                                 sys.stderr.write(_unicode_decode(line))
322
323                                         self.assertEqual(os.EX_OK, proc.returncode,
324                                                 "%s failed in %s" % (cmd, cwd,))
325                 finally:
326                         playground.cleanup()