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