Enable BytesWarnings.
[portage.git] / bin / ebuild
1 #!/usr/bin/python -bbO
2 # Copyright 1999-2014 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 from __future__ import print_function
6
7 import platform
8 import signal
9 import sys
10 # This block ensures that ^C interrupts are handled quietly.
11 try:
12
13         def exithandler(signum, _frame):
14                 signal.signal(signal.SIGINT, signal.SIG_IGN)
15                 signal.signal(signal.SIGTERM, signal.SIG_IGN)
16                 sys.exit(128 + signum)
17
18         signal.signal(signal.SIGINT, exithandler)
19         signal.signal(signal.SIGTERM, exithandler)
20         # Prevent "[Errno 32] Broken pipe" exceptions when
21         # writing to a pipe.
22         signal.signal(signal.SIGPIPE, signal.SIG_DFL)
23
24 except KeyboardInterrupt:
25         sys.exit(128 + signal.SIGINT)
26
27 def debug_signal(_signum, _frame):
28         import pdb
29         pdb.set_trace()
30
31 if platform.python_implementation() == 'Jython':
32         debug_signum = signal.SIGUSR2 # bug #424259
33 else:
34         debug_signum = signal.SIGUSR1
35
36 signal.signal(debug_signum, debug_signal)
37
38 import io
39 import os
40 from os import path as osp
41 pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")
42 sys.path.insert(0, pym_path)
43 import portage
44 portage._internal_caller = True
45 from portage import os
46 from portage import _encodings
47 from portage import _shell_quote
48 from portage import _unicode_decode
49 from portage import _unicode_encode
50 from portage.const import VDB_PATH
51 from portage.util._argparse import ArgumentParser
52 from _emerge.Package import Package
53 from _emerge.RootConfig import RootConfig
54
55 description = "See the ebuild(1) man page for more info"
56 usage = "Usage: ebuild <ebuild file> <command> [command] ..."
57 parser = ArgumentParser(description=description, usage=usage)
58
59 force_help = "When used together with the digest or manifest " + \
60         "command, this option forces regeneration of digests for all " + \
61         "distfiles associated with the current ebuild. Any distfiles " + \
62         "that do not already exist in ${DISTDIR} will be automatically fetched."
63
64 parser.add_argument("--force", help=force_help, action="store_true")
65 parser.add_argument("--color", help="enable or disable color output",
66         choices=("y", "n"))
67 parser.add_argument("--debug", help="show debug output",
68         action="store_true")
69 parser.add_argument("--version", help="show version and exit",
70         action="store_true")
71 parser.add_argument("--ignore-default-opts",
72         action="store_true",
73         help="do not use the EBUILD_DEFAULT_OPTS environment variable")
74 parser.add_argument("--skip-manifest", help="skip all manifest checks",
75         action="store_true")
76
77 opts, pargs = parser.parse_known_args(args=sys.argv[1:])
78
79 def err(txt):
80         portage.writemsg('ebuild: %s\n' % (txt,), noiselevel=-1)
81         sys.exit(1)
82
83 if opts.version:
84         print("Portage", portage.VERSION)
85         sys.exit(os.EX_OK)
86
87 if len(pargs) < 2:
88         parser.error("missing required args")
89
90 if not opts.ignore_default_opts:
91         default_opts = portage.util.shlex_split(
92                 portage.settings.get("EBUILD_DEFAULT_OPTS", ""))
93         opts, pargs = parser.parse_known_args(default_opts + sys.argv[1:])
94
95 debug = opts.debug
96 force = opts.force
97
98 import portage.util, portage.const
99
100 # do this _after_ 'import portage' to prevent unnecessary tracing
101 if debug and "python-trace" in portage.features:
102         import portage.debug
103         portage.debug.set_trace(True)
104
105 if not opts.color == 'y' and \
106         (opts.color == 'n' or \
107         portage.settings.get('NOCOLOR') in ('yes', 'true') or \
108         portage.settings.get('TERM') == 'dumb' or \
109         not sys.stdout.isatty()):
110         portage.output.nocolor()
111         portage.settings.unlock()
112         portage.settings['NOCOLOR'] = 'true'
113         portage.settings.lock()
114
115 ebuild = pargs.pop(0)
116
117 pf = None
118 if ebuild.endswith(".ebuild"):
119         pf = os.path.basename(ebuild)[:-7]
120
121 if pf is None:
122         err("%s: does not end with '.ebuild'" % (ebuild,))
123
124 if not os.path.isabs(ebuild):
125         mycwd = os.getcwd()
126         # Try to get the non-canonical path from the PWD evironment variable, since
127         # the canonical path returned from os.getcwd() may may be unusable in
128         # cases where the directory stucture is built from symlinks.
129         pwd = os.environ.get('PWD', '')
130         if sys.hexversion < 0x3000000:
131                 pwd = _unicode_decode(pwd, encoding=_encodings['content'],
132                         errors='strict')
133         if pwd and pwd != mycwd and \
134                 os.path.realpath(pwd) == mycwd:
135                 mycwd = portage.normalize_path(pwd)
136         ebuild = os.path.join(mycwd, ebuild)
137 ebuild = portage.normalize_path(ebuild)
138 # portdbapi uses the canonical path for the base of the portage tree, but
139 # subdirectories of the base can be built from symlinks (like crossdev does).
140 ebuild_portdir = os.path.realpath(
141         os.path.dirname(os.path.dirname(os.path.dirname(ebuild))))
142 ebuild = os.path.join(ebuild_portdir, *ebuild.split(os.path.sep)[-3:])
143 vdb_path = os.path.realpath(os.path.join(portage.settings['EROOT'], VDB_PATH))
144
145 # Make sure that portdb.findname() returns the correct ebuild.
146 if ebuild_portdir != vdb_path and \
147         ebuild_portdir not in portage.portdb.porttrees:
148         portdir_overlay = portage.settings.get("PORTDIR_OVERLAY", "")
149         if sys.hexversion >= 0x3000000:
150                 os.environ["PORTDIR_OVERLAY"] = \
151                         portdir_overlay + \
152                         " " + _shell_quote(ebuild_portdir)
153         else:
154                 os.environ["PORTDIR_OVERLAY"] = \
155                         _unicode_encode(portdir_overlay,
156                         encoding=_encodings['content'], errors='strict') + \
157                         " " + _unicode_encode(_shell_quote(ebuild_portdir),
158                         encoding=_encodings['content'], errors='strict')
159
160         print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir)
161         portage._reset_legacy_globals()
162
163 myrepo = None
164 if ebuild_portdir != vdb_path:
165         myrepo = portage.portdb.getRepositoryName(ebuild_portdir)
166
167 if not os.path.exists(ebuild):
168         err('%s: does not exist' % (ebuild,))
169
170 ebuild_split = ebuild.split("/")
171 cpv = "%s/%s" % (ebuild_split[-3], pf)
172
173 with io.open(_unicode_encode(ebuild, encoding=_encodings['fs'], errors='strict'),
174         mode='r', encoding=_encodings['repo.content'], errors='replace') as f:
175         eapi = portage._parse_eapi_ebuild_head(f)[0]
176 if eapi is None:
177         eapi = "0"
178 if not portage.catpkgsplit(cpv, eapi=eapi):
179         err('%s: %s: does not follow correct package syntax' % (ebuild, cpv))
180
181 if ebuild.startswith(vdb_path):
182         mytree = "vartree"
183         pkg_type = "installed"
184
185         portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv, myrepo=myrepo)
186
187         if os.path.realpath(portage_ebuild) != ebuild:
188                 err('Portage seems to think that %s is at %s' % (cpv, portage_ebuild))
189
190 else:
191         mytree = "porttree"
192         pkg_type = "ebuild"
193
194         portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo)
195
196         if not portage_ebuild or portage_ebuild != ebuild:
197                 err('%s: does not seem to have a valid PORTDIR structure' % (ebuild,))
198
199 if len(pargs) > 1 and "config" in pargs:
200         err('"config" must not be called with any other phase')
201
202 def discard_digests(myebuild, mysettings, mydbapi):
203         """Discard all distfiles digests for the given ebuild.  This is useful when
204         upstream has changed the identity of the distfiles and the user would
205         otherwise have to manually remove the Manifest and files/digest-* files in
206         order to ensure correct results."""
207         try:
208                 portage._doebuild_manifest_exempt_depend += 1
209                 pkgdir = os.path.dirname(myebuild)
210                 fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi)
211                 mf = mysettings.repositories.get_repo_for_location(
212                         os.path.dirname(os.path.dirname(pkgdir)))
213                 mf = mf.load_manifest(pkgdir, mysettings["DISTDIR"],
214                         fetchlist_dict=fetchlist_dict)
215                 mf.create(requiredDistfiles=None,
216                         assumeDistHashesSometimes=True, assumeDistHashesAlways=True)
217                 distfiles = fetchlist_dict[cpv]
218                 for myfile in distfiles:
219                         try:
220                                 del mf.fhashdict["DIST"][myfile]
221                         except KeyError:
222                                 pass
223                 mf.write()
224         finally:
225                 portage._doebuild_manifest_exempt_depend -= 1
226
227 portage.settings.validate() # generate warning messages if necessary
228
229 build_dir_phases = set(["setup", "unpack", "prepare", "configure", "compile",
230         "test", "install", "package", "rpm", "merge", "qmerge"])
231
232 # If the current metadata is invalid then force the ebuild to be
233 # sourced again even if $T/environment already exists.
234 ebuild_changed = False
235 if mytree == "porttree" and build_dir_phases.intersection(pargs):
236         ebuild_changed = \
237                 portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir)[0] is None
238
239 tmpsettings = portage.config(clone=portage.settings)
240 tmpsettings["PORTAGE_VERBOSE"] = "1"
241 tmpsettings.backup_changes("PORTAGE_VERBOSE")
242
243 if opts.skip_manifest:
244         tmpsettings["EBUILD_SKIP_MANIFEST"] = "1"
245         tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST")
246
247 if opts.skip_manifest or \
248         "digest" in tmpsettings.features or \
249         "digest" in pargs or \
250         "manifest" in pargs:
251         portage._doebuild_manifest_exempt_depend += 1
252
253 if "test" in pargs:
254         # This variable is a signal to config.regenerate() to
255         # indicate that the test phase should be enabled regardless
256         # of problems such as masked "test" USE flag.
257         tmpsettings["EBUILD_FORCE_TEST"] = "1"
258         tmpsettings.backup_changes("EBUILD_FORCE_TEST")
259         tmpsettings.features.add("test")
260
261 tmpsettings.features.discard("fail-clean")
262
263 if "merge" in pargs and "noauto" in tmpsettings.features:
264         print("Disabling noauto in features... merge disables it. (qmerge doesn't)")
265         tmpsettings.features.discard("noauto")
266
267 try:
268         metadata = dict(zip(Package.metadata_keys,
269                 portage.db[portage.settings['EROOT']][mytree].dbapi.aux_get(
270                 cpv, Package.metadata_keys, myrepo=myrepo)))
271 except KeyError:
272         # aux_get failure, message should have been shown on stderr.
273         sys.exit(1)
274
275 root_config = RootConfig(portage.settings,
276         portage.db[portage.settings['EROOT']], None)
277
278 pkg = Package(built=(pkg_type != "ebuild"), cpv=cpv,
279         installed=(pkg_type=="installed"),
280         metadata=metadata, root_config=root_config,
281         type_name=pkg_type)
282
283 # Apply package.env and repo-level settings. This allows per-package
284 # FEATURES and other variables (possibly PORTAGE_TMPDIR) to be
285 # available as soon as possible. Also, note that the only way to ensure
286 # that setcpv gets metadata from the correct repository is to pass in
287 # a Package instance, as we do here (previously we had to modify
288 # portdb.porttrees in order to accomplish this).
289 tmpsettings.setcpv(pkg)
290
291 def stale_env_warning():
292         if "clean" not in pargs and \
293                 "noauto" not in tmpsettings.features and \
294                 build_dir_phases.intersection(pargs):
295                 portage.doebuild_environment(ebuild, "setup", portage.root,
296                         tmpsettings, debug, 1, portage.portdb)
297                 env_filename = os.path.join(tmpsettings["T"], "environment")
298                 if os.path.exists(env_filename):
299                         msg = ("Existing ${T}/environment for '%s' will be sourced. " + \
300                                 "Run 'clean' to start with a fresh environment.") % \
301                                 (tmpsettings["PF"], )
302                         from textwrap import wrap
303                         msg = wrap(msg, 70)
304                         for x in msg:
305                                 portage.writemsg(">>> %s\n" % x)
306
307                         if ebuild_changed:
308                                 open(os.path.join(tmpsettings['PORTAGE_BUILDDIR'],
309                                         '.ebuild_changed'), 'w').close()
310
311 from portage.exception import PermissionDenied, \
312         PortagePackageException, UnsupportedAPIException
313
314 if 'digest' in tmpsettings.features:
315         if pargs and pargs[0] not in ("digest", "manifest"):
316                 pargs = ['digest'] + pargs
317         # We only need to build digests on the first pass.
318         tmpsettings.features.discard('digest')
319
320 checked_for_stale_env = False
321
322 for arg in pargs:
323         try:
324                 if not checked_for_stale_env and arg not in ("digest","manifest"):
325                         # This has to go after manifest generation since otherwise
326                         # aux_get() might fail due to invalid ebuild digests.
327                         stale_env_warning()
328                         checked_for_stale_env = True
329
330                 if arg in ("digest", "manifest") and force:
331                         discard_digests(ebuild, tmpsettings, portage.portdb)
332                 a = portage.doebuild(ebuild, arg, settings=tmpsettings,
333                         debug=debug, tree=mytree,
334                         vartree=portage.db[portage.root]['vartree'])
335         except KeyboardInterrupt:
336                 print("Interrupted.")
337                 a = 1
338         except KeyError:
339                 # aux_get error
340                 a = 1
341         except UnsupportedAPIException as e:
342                 from textwrap import wrap
343                 msg = wrap(str(e), 70)
344                 del e
345                 for x in msg:
346                         portage.writemsg("!!! %s\n" % x, noiselevel=-1)
347                 a = 1
348         except PortagePackageException as e:
349                 portage.writemsg("!!! %s\n" % (e,), noiselevel=-1)
350                 a = 1
351         except PermissionDenied as e:
352                 portage.writemsg("!!! Permission Denied: %s\n" % (e,), noiselevel=-1)
353                 a = 1
354         if a == None:
355                 print("Could not run the required binary?")
356                 a = 127
357         if a:
358                 sys.exit(a)