Fix headers that contain $Header instead of $Id.
[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.append("test")
190                 tmpsettings.features.sort()
191                 tmpsettings["FEATURES"] = " ".join(tmpsettings.features)
192                 tmpsettings.backup_changes("FEATURES")
193
194 if opts.skip_manifest:
195         tmpsettings["EBUILD_SKIP_MANIFEST"] = "1"
196         tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST")
197         portage._doebuild_manifest_exempt_depend += 1
198
199 build_dir_phases = set(["setup", "unpack", "configure", "compile",
200         "test", "install", "package", "rpm"])
201
202 def stale_env_warning():
203         if "clean" not in pargs and \
204                 "noauto" not in tmpsettings.features and \
205                 tmpsettings.get("PORTAGE_QUIET") != "1" and \
206                 build_dir_phases.intersection(pargs):
207                 portage.doebuild_environment(ebuild, "setup", portage.root,
208                         tmpsettings, debug, 1, portage.portdb)
209                 env_filename = os.path.join(tmpsettings["T"], "environment")
210                 if os.path.exists(env_filename):
211                         msg = ("Existing ${T}/environment for '%s' will be sourced. " + \
212                                 "Run 'clean' to start with a fresh environment.") % \
213                                 (tmpsettings["PF"], )
214                         from textwrap import wrap
215                         msg = wrap(msg, 70)
216                         for x in msg:
217                                 portage.writemsg(">>> %s\n" % x)
218
219 from portage.exception import PermissionDenied, \
220         PortagePackageException, UnsupportedAPIException
221 checked_for_stale_env = False
222
223 for arg in pargs:
224         try:
225                 if not checked_for_stale_env and arg not in ("digest","manifest"):
226                         # This has to go after manifest generation since otherwise
227                         # aux_get() might fail due to invalid ebuild digests.
228                         stale_env_warning()
229                         checked_for_stale_env = True
230
231                 if arg in ("digest", "manifest") and force:
232                         discard_digests(ebuild, tmpsettings, portage.portdb)
233                 a = portage.doebuild(ebuild, arg, portage.root, tmpsettings,
234                         debug=debug, tree=mytree)
235         except KeyboardInterrupt:
236                 print "Interrupted."
237                 a = 1
238         except KeyError:
239                 # aux_get error
240                 a = 1
241         except UnsupportedAPIException, e:
242                 from textwrap import wrap
243                 msg = wrap(str(e), 70)
244                 del e
245                 for x in msg:
246                         portage.writemsg("!!! %s\n" % x, noiselevel=-1)
247                 a = 1
248         except PortagePackageException, e:
249                 portage.writemsg("!!! %s\n" % (e,), noiselevel=-1)
250                 a = 1
251         except PermissionDenied, e:
252                 portage.writemsg("!!! Permission Denied: %s\n" % (e,), noiselevel=-1)
253                 a = 1
254         if a == None:
255                 print "Could not run the required binary?"
256                 a = 127
257         if a:
258                 sys.exit(a)