|
@@ -2,6 +2,7 @@
|
|
|
#
|
|
|
# Copyright (C) 2012-2017 Intel Corporation
|
|
|
# Copyright (C) 2011 Mentor Graphics Corporation
|
|
|
+# Copyright (C) 2006-2012 Richard Purdie
|
|
|
#
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
@@ -218,6 +219,7 @@ class Tinfoil:
|
|
|
self.ui_module = None
|
|
|
self.server_connection = None
|
|
|
self.recipes_parsed = False
|
|
|
+ self.quiet = 0
|
|
|
if setup_logging:
|
|
|
# This is the *client-side* logger, nothing to do with
|
|
|
# logging messages from the server
|
|
@@ -230,6 +232,8 @@ class Tinfoil:
|
|
|
self.shutdown()
|
|
|
|
|
|
def prepare(self, config_only=False, config_params=None, quiet=0, extra_features=None):
|
|
|
+ self.quiet = quiet
|
|
|
+
|
|
|
if self.tracking:
|
|
|
extrafeatures = [bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING]
|
|
|
else:
|
|
@@ -434,6 +438,156 @@ class Tinfoil:
|
|
|
"""
|
|
|
return self.run_command('buildFile', buildfile, task, internal)
|
|
|
|
|
|
+ def build_targets(self, targets, task=None, handle_events=True, extra_events=None, event_callback=None):
|
|
|
+ """
|
|
|
+ Builds the specified targets. This is equivalent to a normal invocation
|
|
|
+ of bitbake. Has built-in event handling which is enabled by default and
|
|
|
+ can be extended if needed.
|
|
|
+ Parameters:
|
|
|
+ targets:
|
|
|
+ One or more targets to build. Can be a list or a
|
|
|
+ space-separated string.
|
|
|
+ task:
|
|
|
+ The task to run; if None then the value of BB_DEFAULT_TASK
|
|
|
+ will be used. Default None.
|
|
|
+ handle_events:
|
|
|
+ True to handle events in a similar way to normal bitbake
|
|
|
+ invocation with knotty; False to return immediately (on the
|
|
|
+ assumption that the caller will handle the events instead).
|
|
|
+ Default True.
|
|
|
+ extra_events:
|
|
|
+ An optional list of events to add to the event mask (if
|
|
|
+ handle_events=True). If you add events here you also need
|
|
|
+ to specify a callback function in event_callback that will
|
|
|
+ handle the additional events. Default None.
|
|
|
+ event_callback:
|
|
|
+ An optional function taking a single parameter which
|
|
|
+ will be called first upon receiving any event (if
|
|
|
+ handle_events=True) so that the caller can override or
|
|
|
+ extend the event handling. Default None.
|
|
|
+ """
|
|
|
+ if isinstance(targets, str):
|
|
|
+ targets = targets.split()
|
|
|
+ if not task:
|
|
|
+ task = self.config_data.getVar('BB_DEFAULT_TASK')
|
|
|
+
|
|
|
+ if handle_events:
|
|
|
+ # A reasonable set of default events matching up with those we handle below
|
|
|
+ eventmask = [
|
|
|
+ 'bb.event.BuildStarted',
|
|
|
+ 'bb.event.BuildCompleted',
|
|
|
+ 'logging.LogRecord',
|
|
|
+ 'bb.event.NoProvider',
|
|
|
+ 'bb.command.CommandCompleted',
|
|
|
+ 'bb.command.CommandFailed',
|
|
|
+ 'bb.build.TaskStarted',
|
|
|
+ 'bb.build.TaskFailed',
|
|
|
+ 'bb.build.TaskSucceeded',
|
|
|
+ 'bb.build.TaskFailedSilent',
|
|
|
+ 'bb.build.TaskProgress',
|
|
|
+ 'bb.runqueue.runQueueTaskStarted',
|
|
|
+ 'bb.runqueue.sceneQueueTaskStarted',
|
|
|
+ 'bb.event.ProcessStarted',
|
|
|
+ 'bb.event.ProcessProgress',
|
|
|
+ 'bb.event.ProcessFinished',
|
|
|
+ ]
|
|
|
+ if extra_events:
|
|
|
+ eventmask.extend(extra_events)
|
|
|
+ ret = self.set_event_mask(eventmask)
|
|
|
+
|
|
|
+ ret = self.run_command('buildTargets', targets, task)
|
|
|
+ if handle_events:
|
|
|
+ result = False
|
|
|
+ # Borrowed from knotty, instead somewhat hackily we use the helper
|
|
|
+ # as the object to store "shutdown" on
|
|
|
+ helper = bb.ui.uihelper.BBUIHelper()
|
|
|
+ # We set up logging optionally in the constructor so now we need to
|
|
|
+ # grab the handlers to pass to TerminalFilter
|
|
|
+ console = None
|
|
|
+ errconsole = None
|
|
|
+ for handler in self.logger.handlers:
|
|
|
+ if isinstance(handler, logging.StreamHandler):
|
|
|
+ if handler.stream == sys.stdout:
|
|
|
+ console = handler
|
|
|
+ elif handler.stream == sys.stderr:
|
|
|
+ errconsole = handler
|
|
|
+ format_str = "%(levelname)s: %(message)s"
|
|
|
+ format = bb.msg.BBLogFormatter(format_str)
|
|
|
+ helper.shutdown = 0
|
|
|
+ parseprogress = None
|
|
|
+ termfilter = bb.ui.knotty.TerminalFilter(helper, helper, console, errconsole, format, quiet=self.quiet)
|
|
|
+ try:
|
|
|
+ while True:
|
|
|
+ try:
|
|
|
+ event = self.wait_event(0.25)
|
|
|
+ if event:
|
|
|
+ if event_callback and event_callback(event):
|
|
|
+ continue
|
|
|
+ if helper.eventHandler(event):
|
|
|
+ continue
|
|
|
+ if isinstance(event, bb.event.ProcessStarted):
|
|
|
+ if self.quiet > 1:
|
|
|
+ continue
|
|
|
+ parseprogress = bb.ui.knotty.new_progress(event.processname, event.total)
|
|
|
+ parseprogress.start(False)
|
|
|
+ continue
|
|
|
+ if isinstance(event, bb.event.ProcessProgress):
|
|
|
+ if self.quiet > 1:
|
|
|
+ continue
|
|
|
+ if parseprogress:
|
|
|
+ parseprogress.update(event.progress)
|
|
|
+ else:
|
|
|
+ bb.warn("Got ProcessProgress event for someting that never started?")
|
|
|
+ continue
|
|
|
+ if isinstance(event, bb.event.ProcessFinished):
|
|
|
+ if self.quiet > 1:
|
|
|
+ continue
|
|
|
+ if parseprogress:
|
|
|
+ parseprogress.finish()
|
|
|
+ parseprogress = None
|
|
|
+ continue
|
|
|
+ if isinstance(event, bb.command.CommandCompleted):
|
|
|
+ result = True
|
|
|
+ break
|
|
|
+ if isinstance(event, bb.command.CommandFailed):
|
|
|
+ self.logger.error(str(event))
|
|
|
+ result = False
|
|
|
+ break
|
|
|
+ if isinstance(event, logging.LogRecord):
|
|
|
+ if event.taskpid == 0 or event.levelno > logging.INFO:
|
|
|
+ self.logger.handle(event)
|
|
|
+ continue
|
|
|
+ if isinstance(event, bb.event.NoProvider):
|
|
|
+ self.logger.error(str(event))
|
|
|
+ result = False
|
|
|
+ break
|
|
|
+
|
|
|
+ elif helper.shutdown > 1:
|
|
|
+ break
|
|
|
+ termfilter.updateFooter()
|
|
|
+ except KeyboardInterrupt:
|
|
|
+ termfilter.clearFooter()
|
|
|
+ if helper.shutdown == 1:
|
|
|
+ print("\nSecond Keyboard Interrupt, stopping...\n")
|
|
|
+ ret = self.run_command("stateForceShutdown")
|
|
|
+ if ret and ret[2]:
|
|
|
+ self.logger.error("Unable to cleanly stop: %s" % ret[2])
|
|
|
+ elif helper.shutdown == 0:
|
|
|
+ print("\nKeyboard Interrupt, closing down...\n")
|
|
|
+ interrupted = True
|
|
|
+ ret = self.run_command("stateShutdown")
|
|
|
+ if ret and ret[2]:
|
|
|
+ self.logger.error("Unable to cleanly shutdown: %s" % ret[2])
|
|
|
+ helper.shutdown = helper.shutdown + 1
|
|
|
+ termfilter.clearFooter()
|
|
|
+ finally:
|
|
|
+ termfilter.finish()
|
|
|
+ if helper.failed_tasks:
|
|
|
+ result = False
|
|
|
+ return result
|
|
|
+ else:
|
|
|
+ return ret
|
|
|
+
|
|
|
def shutdown(self):
|
|
|
if self.server_connection:
|
|
|
self.run_command('clientComplete')
|