cooker: don't choke if we have nothing to parse
[bitbake.git] / bin / bitbake
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 #
5 # Copyright (C) 2003, 2004  Chris Larson
6 # Copyright (C) 2003, 2004  Phil Blundell
7 # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
8 # Copyright (C) 2005        Holger Hans Peter Freyther
9 # Copyright (C) 2005        ROAD GmbH
10 # Copyright (C) 2006        Richard Purdie
11 #
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License version 2 as
14 # published by the Free Software Foundation.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License along
22 # with this program; if not, write to the Free Software Foundation, Inc.,
23 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
25 import os
26 import sys, logging
27 sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),
28                                 'lib'))
29
30 import optparse
31 import warnings
32 import signal
33 from traceback import format_exception
34 try:
35     import bb
36 except RuntimeError, exc:
37     sys.exit(str(exc))
38 from bb import event
39 import bb.msg
40 from bb import cooker
41 from bb import ui
42 from bb import server
43 from bb.server.process import ProcessServer, ServerCommunicator
44
45 from Queue import Empty
46 from multiprocessing import Queue, Pipe
47
48 __version__ = "1.11.0"
49 logger = logging.getLogger("BitBake")
50
51
52
53 class BBConfiguration(object):
54     """
55     Manages build options and configurations for one run
56     """
57
58     def __init__(self, options):
59         for key, val in options.__dict__.items():
60             setattr(self, key, val)
61         self.pkgs_to_build = []
62
63
64 def get_ui(config):
65     if config.ui:
66         interface = config.ui
67     else:
68         interface = 'knotty'
69
70     try:
71         # Dynamically load the UI based on the ui name. Although we
72         # suggest a fixed set this allows you to have flexibility in which
73         # ones are available.
74         module = __import__("bb.ui", fromlist = [interface])
75         return getattr(module, interface).main
76     except AttributeError:
77         sys.exit("FATAL: Invalid user interface '%s' specified.\n"
78                  "Valid interfaces: depexp, goggle, ncurses, knotty [default]." % interface)
79
80
81 # Display bitbake/OE warnings via the BitBake.Warnings logger, ignoring others"""
82 warnlog = logging.getLogger("BitBake.Warnings")
83 _warnings_showwarning = warnings.showwarning
84 def _showwarning(message, category, filename, lineno, file=None, line=None):
85     if file is not None:
86         if _warnings_showwarning is not None:
87             _warnings_showwarning(message, category, filename, lineno, file, line)
88     else:
89         s = warnings.formatwarning(message, category, filename, lineno)
90         warnlog.warn(s)
91
92 warnings.showwarning = _showwarning
93 warnings.filterwarnings("ignore")
94 warnings.filterwarnings("default", module="(<string>$|(oe|bb)\.)")
95 warnings.filterwarnings("ignore", category=PendingDeprecationWarning)
96 warnings.filterwarnings("ignore", category=ImportWarning)
97 warnings.filterwarnings("ignore", category=DeprecationWarning, module="<string>$")
98 warnings.filterwarnings("ignore", message="With-statements now directly support multiple context managers")
99
100
101 def main():
102     parser = optparse.OptionParser(
103         version = "BitBake Build Tool Core version %s, %%prog version %s" % (bb.__version__, __version__),
104         usage = """%prog [options] [package ...]
105
106 Executes the specified task (default is 'build') for a given set of BitBake files.
107 It expects that BBFILES is defined, which is a space separated list of files to
108 be executed.  BBFILES does support wildcards.
109 Default BBFILES are the .bb files in the current directory.""")
110
111     parser.add_option("-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
112                action = "store", dest = "buildfile", default = None)
113
114     parser.add_option("-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
115                action = "store_false", dest = "abort", default = True)
116
117     parser.add_option("-a", "--tryaltconfigs", help = "continue with builds by trying to use alternative providers where possible.",
118                action = "store_true", dest = "tryaltconfigs", default = False)
119
120     parser.add_option("-f", "--force", help = "force run of specified cmd, regardless of stamp status",
121                action = "store_true", dest = "force", default = False)
122
123     parser.add_option("-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing). Depending on the base.bbclass a listtasks tasks is defined and will show available tasks",
124                action = "store", dest = "cmd")
125
126     parser.add_option("-r", "--read", help = "read the specified file before bitbake.conf",
127                action = "append", dest = "file", default = [])
128
129     parser.add_option("-v", "--verbose", help = "output more chit-chat to the terminal",
130                action = "store_true", dest = "verbose", default = False)
131
132     parser.add_option("-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
133                action = "count", dest="debug", default = 0)
134
135     parser.add_option("-n", "--dry-run", help = "don't execute, just go through the motions",
136                action = "store_true", dest = "dry_run", default = False)
137
138     parser.add_option("-S", "--dump-signatures", help = "don't execute, just dump out the signature construction information",
139                action = "store_true", dest = "dump_signatures", default = False)
140
141     parser.add_option("-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
142                action = "store_true", dest = "parse_only", default = False)
143
144     parser.add_option("-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
145                action = "store_true", dest = "disable_psyco", default = False)
146
147     parser.add_option("-s", "--show-versions", help = "show current and preferred versions of all packages",
148                action = "store_true", dest = "show_versions", default = False)
149
150     parser.add_option("-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
151                action = "store_true", dest = "show_environment", default = False)
152
153     parser.add_option("-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
154                 action = "store_true", dest = "dot_graph", default = False)
155
156     parser.add_option("-I", "--ignore-deps", help = """Assume these dependencies don't exist and are already provided (equivalent to ASSUME_PROVIDED). Useful to make dependency graphs more appealing""",
157                 action = "append", dest = "extra_assume_provided", default = [])
158
159     parser.add_option("-l", "--log-domains", help = """Show debug logging for the specified logging domains""",
160                 action = "append", dest = "debug_domains", default = [])
161
162     parser.add_option("-P", "--profile", help = "profile the command and print a report",
163                action = "store_true", dest = "profile", default = False)
164
165     parser.add_option("-u", "--ui", help = "userinterface to use",
166                action = "store", dest = "ui")
167
168     parser.add_option("", "--revisions-changed", help = "Set the exit code depending on whether upstream floating revisions have changed or not",
169                action = "store_true", dest = "revisions_changed", default = False)
170
171     options, args = parser.parse_args(sys.argv)
172
173     configuration = BBConfiguration(options)
174     configuration.pkgs_to_build.extend(args[1:])
175
176     ui_main = get_ui(configuration)
177
178     bb.utils.init_logger(bb.msg, configuration.verbose, configuration.debug,
179                          configuration.debug_domains)
180
181     # Ensure logging messages get sent to the UI as events
182     handler = bb.event.LogHandler()
183     logger.addHandler(handler)
184
185     # Clear away any spurious environment variables. But don't wipe the
186     # environment totally. This is necessary to ensure the correct operation
187     # of the UIs (e.g. for DISPLAY, etc.)
188     bb.utils.clean_environment()
189
190     # establish communication channels.  We use bidirectional pipes for
191     # ui <--> server command/response pairs
192     # and a queue for server -> ui event notifications
193     #
194     ui_channel, server_channel = Pipe()
195     event_queue = Queue()
196
197     server = ProcessServer(server_channel, event_queue, configuration)
198     server.start()
199
200     logger.removeHandler(handler)
201
202     def shutdown(force=False):
203         signal.signal(signal.SIGINT, signal.SIG_IGN)
204         server.stop()
205         if force:
206             server.join(0.5)
207             if server.is_alive():
208                 server.terminate()
209                 server.join()
210         else:
211             server.join()
212         while True:
213             try:
214                 event = event_queue.get(block=False)
215             except (Empty, IOError):
216                 break
217             if isinstance(event, logging.LogRecord):
218                 logger.handle(event)
219         ui_channel.close()
220         event_queue.close()
221         if force:
222             sys.exit(1)
223
224     signal.signal(signal.SIGTERM, lambda i, s: shutdown(force=True))
225     try:
226         return ui_main(ServerCommunicator(ui_channel), event_queue)
227     finally:
228         shutdown()
229
230     return 1
231
232 if __name__ == "__main__":
233     try:
234         ret = main()
235     except Exception:
236         ret = 1
237         import traceback
238         traceback.print_exc(5)
239     sys.exit(ret)
240