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