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