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