2013-09-26 11:50:50 +00:00
|
|
|
#
|
|
|
|
# BitBake ToasterUI Implementation
|
|
|
|
# based on (No)TTY UI Implementation by Richard Purdie
|
|
|
|
#
|
|
|
|
# Handling output to TTYs or files (no TTY)
|
|
|
|
#
|
|
|
|
# Copyright (C) 2006-2012 Richard Purdie
|
|
|
|
# Copyright (C) 2013 Intel Corporation
|
|
|
|
#
|
|
|
|
# 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
|
|
|
|
# published by the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along
|
|
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
|
|
|
from __future__ import division
|
2015-10-29 11:59:44 +00:00
|
|
|
import time
|
2015-08-18 16:28:57 +00:00
|
|
|
import sys
|
2013-09-26 11:50:50 +00:00
|
|
|
try:
|
|
|
|
import bb
|
|
|
|
except RuntimeError as exc:
|
|
|
|
sys.exit(str(exc))
|
|
|
|
|
|
|
|
from bb.ui import uihelper
|
|
|
|
from bb.ui.buildinfohelper import BuildInfoHelper
|
|
|
|
|
|
|
|
import bb.msg
|
|
|
|
import logging
|
|
|
|
import os
|
2015-08-18 16:28:58 +00:00
|
|
|
|
|
|
|
# pylint: disable=invalid-name
|
|
|
|
# module properties for UI modules are read by bitbake and the contract should not be broken
|
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2016-05-13 13:02:56 +00:00
|
|
|
featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES, bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING, bb.cooker.CookerFeatures.SEND_SANITYEVENTS]
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2015-06-17 11:27:48 +00:00
|
|
|
logger = logging.getLogger("ToasterLogger")
|
2013-09-26 11:50:50 +00:00
|
|
|
interactive = sys.stdout.isatty()
|
|
|
|
|
|
|
|
def _log_settings_from_server(server):
|
|
|
|
# Get values of variables which control our output
|
|
|
|
includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
|
|
|
|
if error:
|
2015-08-18 16:28:58 +00:00
|
|
|
logger.error("Unable to get the value of BBINCLUDELOGS variable: %s", error)
|
2013-09-26 11:50:50 +00:00
|
|
|
raise BaseException(error)
|
|
|
|
loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
|
|
|
|
if error:
|
2015-08-18 16:28:58 +00:00
|
|
|
logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s", error)
|
2013-09-26 11:50:50 +00:00
|
|
|
raise BaseException(error)
|
2015-10-29 11:59:44 +00:00
|
|
|
consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"])
|
2015-02-16 17:47:07 +00:00
|
|
|
if error:
|
2015-08-18 16:28:58 +00:00
|
|
|
logger.error("Unable to get the value of BB_CONSOLELOG variable: %s", error)
|
2015-02-16 17:47:07 +00:00
|
|
|
raise BaseException(error)
|
2015-10-29 11:59:44 +00:00
|
|
|
return consolelogfile
|
|
|
|
|
|
|
|
# create a log file for a single build and direct the logger at it;
|
|
|
|
# log file name is timestamped to the millisecond (depending
|
|
|
|
# on system clock accuracy) to ensure it doesn't overlap with
|
|
|
|
# other log file names
|
|
|
|
#
|
|
|
|
# returns (log file, path to log file) for a build
|
|
|
|
def _open_build_log(log_dir):
|
|
|
|
format_str = "%(levelname)s: %(message)s"
|
|
|
|
|
|
|
|
now = time.time()
|
|
|
|
now_ms = int((now - int(now)) * 1000)
|
|
|
|
time_str = time.strftime('build_%Y%m%d_%H%M%S', time.localtime(now))
|
|
|
|
log_file_name = time_str + ('.%d.log' % now_ms)
|
|
|
|
build_log_file_path = os.path.join(log_dir, log_file_name)
|
|
|
|
|
|
|
|
build_log = logging.FileHandler(build_log_file_path)
|
|
|
|
|
|
|
|
logformat = bb.msg.BBLogFormatter(format_str)
|
|
|
|
build_log.setFormatter(logformat)
|
2015-02-16 17:47:07 +00:00
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
bb.msg.addDefaultlogFilter(build_log)
|
|
|
|
logger.addHandler(build_log)
|
|
|
|
|
|
|
|
return (build_log, build_log_file_path)
|
|
|
|
|
|
|
|
# stop logging to the build log if it exists
|
|
|
|
def _close_build_log(build_log):
|
|
|
|
if build_log:
|
|
|
|
build_log.flush()
|
|
|
|
build_log.close()
|
|
|
|
logger.removeHandler(build_log)
|
|
|
|
|
2016-03-03 06:47:38 +00:00
|
|
|
_evt_list = [
|
|
|
|
"bb.build.TaskBase",
|
|
|
|
"bb.build.TaskFailed",
|
|
|
|
"bb.build.TaskFailedSilent",
|
|
|
|
"bb.build.TaskStarted",
|
|
|
|
"bb.build.TaskSucceeded",
|
|
|
|
"bb.command.CommandCompleted",
|
|
|
|
"bb.command.CommandExit",
|
|
|
|
"bb.command.CommandFailed",
|
|
|
|
"bb.cooker.CookerExit",
|
2016-07-11 13:47:06 +00:00
|
|
|
"bb.event.BuildInit",
|
2016-03-03 06:47:39 +00:00
|
|
|
"bb.event.BuildCompleted",
|
|
|
|
"bb.event.BuildStarted",
|
2016-03-03 06:47:38 +00:00
|
|
|
"bb.event.CacheLoadCompleted",
|
|
|
|
"bb.event.CacheLoadProgress",
|
|
|
|
"bb.event.CacheLoadStarted",
|
2016-03-03 06:47:39 +00:00
|
|
|
"bb.event.ConfigParsed",
|
|
|
|
"bb.event.DepTreeGenerated",
|
2016-03-03 06:47:38 +00:00
|
|
|
"bb.event.LogExecTTY",
|
|
|
|
"bb.event.MetadataEvent",
|
|
|
|
"bb.event.MultipleProviders",
|
|
|
|
"bb.event.NoProvider",
|
|
|
|
"bb.event.ParseCompleted",
|
|
|
|
"bb.event.ParseProgress",
|
2016-07-11 13:47:06 +00:00
|
|
|
"bb.event.ParseStarted",
|
2016-03-03 06:47:39 +00:00
|
|
|
"bb.event.RecipeParsed",
|
|
|
|
"bb.event.SanityCheck",
|
|
|
|
"bb.event.SanityCheckPassed",
|
|
|
|
"bb.event.TreeDataPreparationCompleted",
|
|
|
|
"bb.event.TreeDataPreparationStarted",
|
|
|
|
"bb.runqueue.runQueueTaskCompleted",
|
2016-03-03 06:47:38 +00:00
|
|
|
"bb.runqueue.runQueueTaskFailed",
|
2016-03-03 06:47:39 +00:00
|
|
|
"bb.runqueue.runQueueTaskSkipped",
|
2016-03-03 06:47:38 +00:00
|
|
|
"bb.runqueue.runQueueTaskStarted",
|
2016-03-03 06:47:39 +00:00
|
|
|
"bb.runqueue.sceneQueueTaskCompleted",
|
2016-03-03 06:47:38 +00:00
|
|
|
"bb.runqueue.sceneQueueTaskFailed",
|
|
|
|
"bb.runqueue.sceneQueueTaskStarted",
|
|
|
|
"logging.LogRecord"]
|
2015-11-17 16:47:56 +00:00
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
def main(server, eventHandler, params):
|
|
|
|
# set to a logging.FileHandler instance when a build starts;
|
|
|
|
# see _open_build_log()
|
|
|
|
build_log = None
|
|
|
|
|
|
|
|
# set to the log path when a build starts
|
|
|
|
build_log_file_path = None
|
2013-09-26 11:50:50 +00:00
|
|
|
|
|
|
|
helper = uihelper.BBUIHelper()
|
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
# TODO don't use log output to determine when bitbake has started
|
|
|
|
#
|
|
|
|
# WARNING: this log handler cannot be removed, as localhostbecontroller
|
|
|
|
# relies on output in the toaster_ui.log file to determine whether
|
|
|
|
# the bitbake server has started, which only happens if
|
|
|
|
# this logger is setup here (see the TODO in the loop below)
|
2013-09-26 11:50:50 +00:00
|
|
|
console = logging.StreamHandler(sys.stdout)
|
|
|
|
format_str = "%(levelname)s: %(message)s"
|
2015-08-18 16:28:58 +00:00
|
|
|
formatter = bb.msg.BBLogFormatter(format_str)
|
2013-09-26 11:50:50 +00:00
|
|
|
bb.msg.addDefaultlogFilter(console)
|
2015-08-18 16:28:58 +00:00
|
|
|
console.setFormatter(formatter)
|
2013-09-26 11:50:50 +00:00
|
|
|
logger.addHandler(console)
|
2015-07-28 14:24:41 +00:00
|
|
|
logger.setLevel(logging.INFO)
|
2015-11-17 16:47:56 +00:00
|
|
|
llevel, debug_domains = bb.msg.constructLogOptions()
|
2016-03-03 06:47:41 +00:00
|
|
|
result, error = server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list])
|
|
|
|
if not result or error:
|
|
|
|
logger.error("can't set event mask: %s", error)
|
|
|
|
return 1
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2014-01-20 09:39:34 +00:00
|
|
|
# verify and warn
|
|
|
|
build_history_enabled = True
|
2015-08-18 16:28:58 +00:00
|
|
|
inheritlist, _ = server.runCommand(["getVariable", "INHERIT"])
|
2014-01-20 09:39:34 +00:00
|
|
|
|
|
|
|
if not "buildhistory" in inheritlist.split(" "):
|
2016-05-09 13:01:12 +00:00
|
|
|
logger.warning("buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details.")
|
2014-01-20 09:39:34 +00:00
|
|
|
build_history_enabled = False
|
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
if not params.observe_only:
|
2016-03-03 06:47:42 +00:00
|
|
|
params.updateFromServer(server)
|
|
|
|
params.updateToServer(server, os.environ.copy())
|
|
|
|
cmdline = params.parseActions()
|
|
|
|
if not cmdline:
|
|
|
|
print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
|
|
|
|
return 1
|
|
|
|
if 'msg' in cmdline and cmdline['msg']:
|
|
|
|
logger.error(cmdline['msg'])
|
|
|
|
return 1
|
|
|
|
|
|
|
|
ret, error = server.runCommand(cmdline['action'])
|
|
|
|
if error:
|
|
|
|
logger.error("Command '%s' failed: %s" % (cmdline, error))
|
|
|
|
return 1
|
|
|
|
elif ret != True:
|
|
|
|
logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
|
|
|
|
return 1
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
# set to 1 when toasterui needs to shut down
|
2013-09-26 11:50:50 +00:00
|
|
|
main.shutdown = 0
|
2015-10-29 11:59:44 +00:00
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
interrupted = False
|
|
|
|
return_value = 0
|
|
|
|
errors = 0
|
|
|
|
warnings = 0
|
|
|
|
taskfailures = []
|
2014-06-25 14:40:29 +00:00
|
|
|
first = True
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2016-04-06 16:46:14 +00:00
|
|
|
buildinfohelper = BuildInfoHelper(server, build_history_enabled,
|
|
|
|
os.getenv('TOASTER_BRBE'))
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
# write our own log files into bitbake's log directory;
|
|
|
|
# we're only interested in the path to the parent directory of
|
|
|
|
# this file, as we're writing our own logs into the same directory
|
|
|
|
consolelogfile = _log_settings_from_server(server)
|
|
|
|
log_dir = os.path.dirname(consolelogfile)
|
|
|
|
bb.utils.mkdirhier(log_dir)
|
2015-02-16 17:47:07 +00:00
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
event = eventHandler.waitEvent(0.25)
|
2014-06-25 14:40:29 +00:00
|
|
|
if first:
|
|
|
|
first = False
|
2015-10-29 11:59:44 +00:00
|
|
|
|
|
|
|
# TODO don't use log output to determine when bitbake has started
|
|
|
|
#
|
|
|
|
# this is the line localhostbecontroller needs to
|
|
|
|
# see in toaster_ui.log which it uses to decide whether
|
|
|
|
# the bitbake server has started...
|
2014-06-25 14:40:29 +00:00
|
|
|
logger.info("ToasterUI waiting for events")
|
2013-09-26 11:50:50 +00:00
|
|
|
|
|
|
|
if event is None:
|
|
|
|
if main.shutdown > 0:
|
2015-10-29 11:59:44 +00:00
|
|
|
# if shutting down, close any open build log first
|
|
|
|
_close_build_log(build_log)
|
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
break
|
|
|
|
continue
|
|
|
|
|
|
|
|
helper.eventHandler(event)
|
|
|
|
|
2015-08-18 16:28:58 +00:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
# the code will look into the protected variables of the event; no easy way around this
|
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
if isinstance(event, bb.event.ParseStarted):
|
|
|
|
if not (build_log and build_log_file_path):
|
|
|
|
build_log, build_log_file_path = _open_build_log(log_dir)
|
2016-07-11 13:47:06 +00:00
|
|
|
|
2016-08-04 15:32:33 +00:00
|
|
|
buildinfohelper.store_started_build()
|
|
|
|
buildinfohelper.save_build_log_file_path(build_log_file_path)
|
2016-07-11 13:47:06 +00:00
|
|
|
buildinfohelper.set_recipes_to_parse(event.total)
|
2015-10-29 11:59:44 +00:00
|
|
|
continue
|
|
|
|
|
2016-07-11 13:47:06 +00:00
|
|
|
# create a build object in buildinfohelper from either BuildInit
|
|
|
|
# (if available) or BuildStarted (for jethro and previous versions)
|
|
|
|
if isinstance(event, (bb.event.BuildStarted, bb.event.BuildInit)):
|
2016-08-04 15:32:33 +00:00
|
|
|
if not (build_log and build_log_file_path):
|
|
|
|
build_log, build_log_file_path = _open_build_log(log_dir)
|
|
|
|
|
|
|
|
buildinfohelper.save_build_targets(event)
|
|
|
|
buildinfohelper.save_build_log_file_path(build_log_file_path)
|
2015-10-29 11:59:44 +00:00
|
|
|
|
2016-07-11 13:47:06 +00:00
|
|
|
# get additional data from BuildStarted
|
|
|
|
if isinstance(event, bb.event.BuildStarted):
|
|
|
|
buildinfohelper.save_build_layers_and_variables()
|
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, bb.event.ParseProgress):
|
|
|
|
buildinfohelper.set_recipes_parsed(event.current)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, bb.event.ParseCompleted):
|
|
|
|
buildinfohelper.set_recipes_parsed(event.total)
|
2016-03-03 06:47:44 +00:00
|
|
|
continue
|
2013-09-26 11:50:50 +00:00
|
|
|
|
|
|
|
if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)):
|
|
|
|
buildinfohelper.update_and_store_task(event)
|
2015-10-05 09:43:18 +00:00
|
|
|
logger.info("Logfile for task %s", event.logfile)
|
2013-09-26 11:50:50 +00:00
|
|
|
continue
|
|
|
|
|
2015-02-16 17:47:07 +00:00
|
|
|
if isinstance(event, bb.build.TaskBase):
|
|
|
|
logger.info(event._message)
|
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
if isinstance(event, bb.event.LogExecTTY):
|
2015-10-05 09:43:18 +00:00
|
|
|
logger.info(event.msg)
|
2013-09-26 11:50:50 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, logging.LogRecord):
|
2015-06-17 16:30:34 +00:00
|
|
|
if event.levelno == -1:
|
2015-08-18 16:28:58 +00:00
|
|
|
event.levelno = formatter.ERROR
|
2015-06-17 16:30:34 +00:00
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
buildinfohelper.store_log_event(event)
|
2015-10-15 12:45:13 +00:00
|
|
|
|
2015-08-18 16:28:58 +00:00
|
|
|
if event.levelno >= formatter.ERROR:
|
2013-09-26 11:50:50 +00:00
|
|
|
errors = errors + 1
|
2015-08-18 16:28:58 +00:00
|
|
|
elif event.levelno == formatter.WARNING:
|
2013-09-26 11:50:50 +00:00
|
|
|
warnings = warnings + 1
|
2015-10-15 12:45:13 +00:00
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
# For "normal" logging conditions, don't show note logs from tasks
|
|
|
|
# but do show them if the user has changed the default log level to
|
|
|
|
# include verbose/debug messages
|
2015-08-18 16:28:58 +00:00
|
|
|
if event.taskpid != 0 and event.levelno <= formatter.NOTE:
|
2013-09-26 11:50:50 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
logger.handle(event)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, bb.build.TaskFailed):
|
|
|
|
buildinfohelper.update_and_store_task(event)
|
|
|
|
logfile = event.logfile
|
|
|
|
if logfile and os.path.exists(logfile):
|
|
|
|
bb.error("Logfile of failure stored in: %s" % logfile)
|
2013-11-01 15:58:28 +00:00
|
|
|
continue
|
2013-09-26 11:50:50 +00:00
|
|
|
|
|
|
|
# these events are unprocessed now, but may be used in the future to log
|
|
|
|
# timing and error informations from the parsing phase in Toaster
|
2014-04-02 10:56:52 +00:00
|
|
|
if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)):
|
|
|
|
continue
|
2013-09-26 11:50:50 +00:00
|
|
|
if isinstance(event, bb.event.CacheLoadStarted):
|
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.CacheLoadProgress):
|
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.CacheLoadCompleted):
|
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.MultipleProviders):
|
2015-02-16 17:47:07 +00:00
|
|
|
logger.info("multiple providers are available for %s%s (%s)", event._is_runtime and "runtime " or "",
|
|
|
|
event._item,
|
|
|
|
", ".join(event._candidates))
|
|
|
|
logger.info("consider defining a PREFERRED_PROVIDER entry to match %s", event._item)
|
2013-09-26 11:50:50 +00:00
|
|
|
continue
|
2015-02-16 17:47:07 +00:00
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
if isinstance(event, bb.event.NoProvider):
|
|
|
|
errors = errors + 1
|
|
|
|
if event._runtime:
|
|
|
|
r = "R"
|
|
|
|
else:
|
|
|
|
r = ""
|
|
|
|
|
|
|
|
if event._dependees:
|
|
|
|
text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r)
|
|
|
|
else:
|
|
|
|
text = "Nothing %sPROVIDES '%s'" % (r, event._item)
|
|
|
|
|
|
|
|
logger.error(text)
|
|
|
|
if event._reasons:
|
|
|
|
for reason in event._reasons:
|
|
|
|
logger.error("%s", reason)
|
|
|
|
text += reason
|
|
|
|
buildinfohelper.store_log_error(text)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, bb.event.ConfigParsed):
|
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.RecipeParsed):
|
|
|
|
continue
|
|
|
|
|
|
|
|
# end of saved events
|
|
|
|
|
|
|
|
if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)):
|
|
|
|
buildinfohelper.store_started_task(event)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, bb.runqueue.runQueueTaskCompleted):
|
|
|
|
buildinfohelper.update_and_store_task(event)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, bb.runqueue.runQueueTaskFailed):
|
|
|
|
buildinfohelper.update_and_store_task(event)
|
|
|
|
taskfailures.append(event.taskstring)
|
2016-08-18 15:06:29 +00:00
|
|
|
logger.error("Task (%s) failed with exit code '%s'",
|
|
|
|
event.taskstring, event.exitcode)
|
2013-09-26 11:50:50 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)):
|
|
|
|
buildinfohelper.update_and_store_task(event)
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)):
|
|
|
|
continue
|
|
|
|
|
2015-06-17 11:27:48 +00:00
|
|
|
if isinstance(event, (bb.event.BuildCompleted, bb.command.CommandFailed)):
|
|
|
|
|
2015-08-18 16:28:58 +00:00
|
|
|
errorcode = 0
|
|
|
|
if isinstance(event, bb.command.CommandFailed):
|
2015-06-17 11:27:48 +00:00
|
|
|
errors += 1
|
|
|
|
errorcode = 1
|
|
|
|
logger.error("Command execution failed: %s", event.error)
|
2016-07-12 22:54:44 +00:00
|
|
|
elif isinstance(event, bb.event.BuildCompleted):
|
bitbake: toaster: improve scan for SDK artifacts
SDK artifacts were previously picked up by toaster.bbclass and
notified to buildinfohelper (via toasterui). The artifacts
were then added to the Build object, so that it wasn't clear
which artifact went with which target; we were also unable
to attach SDK artifacts to a Build if they had already been
attached to a previous build.
Now, toaster.bbclass just notifies the TOOLCHAIN_OUTPUTNAME when
a populate_sdk* target completes. The scan is moved to buildinfohelper,
where we search the SDK deploy directory for files matching
TOOLCHAIN_OUTPUTNAME and attach them to targets (not builds).
If an SDK file is not produced by a target, we now look for a
similar, previously-run target which did produce artifacts.
If there is one, we clone the SDK artifacts from that target
onto the current one.
This all means that we can show SDK artifacts by target, and should
always get artifacts associated with a target, regardless of whether
it really build them.
This requires an additional model, TargetSDKFile, which tracks
the size and path of SDK artifact files with respect to Target
objects.
[YOCTO #8556]
(Bitbake rev: 5e650c611605507e1e0d1588cd5eb6535c2d34fc)
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: bavery <brian.avery@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2016-07-12 22:54:48 +00:00
|
|
|
buildinfohelper.scan_image_artifacts()
|
|
|
|
buildinfohelper.clone_required_sdk_artifacts()
|
2015-06-17 11:27:48 +00:00
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
# turn off logging to the current build log
|
|
|
|
_close_build_log(build_log)
|
|
|
|
|
|
|
|
# reset ready for next BuildStarted
|
|
|
|
build_log = None
|
|
|
|
|
2015-05-01 15:42:39 +00:00
|
|
|
# update the build info helper on BuildCompleted, not on CommandXXX
|
2013-09-26 11:50:50 +00:00
|
|
|
buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
|
2016-04-06 16:46:17 +00:00
|
|
|
|
|
|
|
brbe = buildinfohelper.brbe
|
2014-10-13 16:10:39 +00:00
|
|
|
buildinfohelper.close(errorcode)
|
2014-06-03 15:26:16 +00:00
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
# we start a new build info
|
2016-04-06 16:46:28 +00:00
|
|
|
if params.observe_only:
|
|
|
|
logger.debug("ToasterUI prepared for new build")
|
|
|
|
errors = 0
|
|
|
|
warnings = 0
|
|
|
|
taskfailures = []
|
|
|
|
buildinfohelper = BuildInfoHelper(server, build_history_enabled)
|
|
|
|
else:
|
|
|
|
main.shutdown = 1
|
2014-06-03 15:26:16 +00:00
|
|
|
|
2016-04-06 16:46:17 +00:00
|
|
|
logger.info("ToasterUI build done, brbe: %s", brbe)
|
2013-09-26 11:50:50 +00:00
|
|
|
continue
|
|
|
|
|
2015-05-01 15:42:39 +00:00
|
|
|
if isinstance(event, (bb.command.CommandCompleted,
|
|
|
|
bb.command.CommandFailed,
|
|
|
|
bb.command.CommandExit)):
|
2016-03-03 06:47:43 +00:00
|
|
|
if params.observe_only:
|
|
|
|
errorcode = 0
|
|
|
|
else:
|
|
|
|
main.shutdown = 1
|
2015-05-01 15:42:39 +00:00
|
|
|
|
|
|
|
continue
|
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
if isinstance(event, bb.event.MetadataEvent):
|
|
|
|
if event.type == "SinglePackageInfo":
|
|
|
|
buildinfohelper.store_build_package_information(event)
|
2014-03-12 18:47:40 +00:00
|
|
|
elif event.type == "LayerInfo":
|
2013-11-27 13:56:19 +00:00
|
|
|
buildinfohelper.store_layer_info(event)
|
2014-03-12 18:47:40 +00:00
|
|
|
elif event.type == "BuildStatsList":
|
2013-11-27 16:38:29 +00:00
|
|
|
buildinfohelper.store_tasks_stats(event)
|
2014-03-12 18:47:40 +00:00
|
|
|
elif event.type == "ImagePkgList":
|
2013-11-26 18:12:43 +00:00
|
|
|
buildinfohelper.store_target_package_data(event)
|
2014-02-17 17:33:27 +00:00
|
|
|
elif event.type == "MissedSstate":
|
|
|
|
buildinfohelper.store_missed_state_tasks(event)
|
bitbake: toaster: improve scan for SDK artifacts
SDK artifacts were previously picked up by toaster.bbclass and
notified to buildinfohelper (via toasterui). The artifacts
were then added to the Build object, so that it wasn't clear
which artifact went with which target; we were also unable
to attach SDK artifacts to a Build if they had already been
attached to a previous build.
Now, toaster.bbclass just notifies the TOOLCHAIN_OUTPUTNAME when
a populate_sdk* target completes. The scan is moved to buildinfohelper,
where we search the SDK deploy directory for files matching
TOOLCHAIN_OUTPUTNAME and attach them to targets (not builds).
If an SDK file is not produced by a target, we now look for a
similar, previously-run target which did produce artifacts.
If there is one, we clone the SDK artifacts from that target
onto the current one.
This all means that we can show SDK artifacts by target, and should
always get artifacts associated with a target, regardless of whether
it really build them.
This requires an additional model, TargetSDKFile, which tracks
the size and path of SDK artifact files with respect to Target
objects.
[YOCTO #8556]
(Bitbake rev: 5e650c611605507e1e0d1588cd5eb6535c2d34fc)
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: bavery <brian.avery@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2016-07-12 22:54:48 +00:00
|
|
|
elif event.type == "SDKArtifactInfo":
|
|
|
|
buildinfohelper.scan_sdk_artifacts(event)
|
2015-12-09 14:25:49 +00:00
|
|
|
elif event.type == "SetBRBE":
|
|
|
|
buildinfohelper.brbe = buildinfohelper._get_data_from_event(event)
|
2016-01-18 13:45:09 +00:00
|
|
|
elif event.type == "OSErrorException":
|
|
|
|
logger.error(event)
|
2014-12-05 15:14:20 +00:00
|
|
|
else:
|
2015-08-18 16:28:58 +00:00
|
|
|
logger.error("Unprocessed MetadataEvent %s ", str(event))
|
2013-09-26 11:50:50 +00:00
|
|
|
continue
|
|
|
|
|
2014-01-09 15:11:59 +00:00
|
|
|
if isinstance(event, bb.cooker.CookerExit):
|
2015-10-29 11:59:44 +00:00
|
|
|
# shutdown when bitbake server shuts down
|
|
|
|
main.shutdown = 1
|
|
|
|
continue
|
2014-01-09 15:11:59 +00:00
|
|
|
|
2013-09-26 11:50:50 +00:00
|
|
|
if isinstance(event, bb.event.DepTreeGenerated):
|
|
|
|
buildinfohelper.store_dependency_information(event)
|
|
|
|
continue
|
|
|
|
|
2016-05-09 13:01:12 +00:00
|
|
|
logger.warning("Unknown event: %s", event)
|
2015-05-01 15:20:33 +00:00
|
|
|
return_value += 1
|
2013-09-26 11:50:50 +00:00
|
|
|
|
|
|
|
except EnvironmentError as ioerror:
|
2016-09-27 15:16:54 +00:00
|
|
|
logger.warning("EnvironmentError: %s" % ioerror)
|
|
|
|
# ignore interrupted io system calls
|
|
|
|
if ioerror.args[0] == 4: # errno 4 is EINTR
|
|
|
|
logger.warning("Skipped EINTR: %s" % ioerror)
|
|
|
|
else:
|
|
|
|
raise
|
2013-09-26 11:50:50 +00:00
|
|
|
except KeyboardInterrupt:
|
2016-05-12 14:10:37 +00:00
|
|
|
if params.observe_only:
|
|
|
|
print("\nKeyboard Interrupt, exiting observer...")
|
|
|
|
main.shutdown = 2
|
|
|
|
if not params.observe_only and main.shutdown == 1:
|
|
|
|
print("\nSecond Keyboard Interrupt, stopping...\n")
|
|
|
|
_, error = server.runCommand(["stateForceShutdown"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to cleanly stop: %s" % error)
|
|
|
|
if not params.observe_only and main.shutdown == 0:
|
|
|
|
print("\nKeyboard Interrupt, closing down...\n")
|
|
|
|
interrupted = True
|
|
|
|
_, error = server.runCommand(["stateShutdown"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to cleanly shutdown: %s" % error)
|
|
|
|
buildinfohelper.cancel_cli_build()
|
|
|
|
main.shutdown = main.shutdown + 1
|
2013-09-26 11:50:50 +00:00
|
|
|
except Exception as e:
|
2014-11-04 16:47:36 +00:00
|
|
|
# print errors to log
|
2013-09-26 11:50:50 +00:00
|
|
|
import traceback
|
2015-03-12 12:44:05 +00:00
|
|
|
from pprint import pformat
|
2014-11-04 16:47:36 +00:00
|
|
|
exception_data = traceback.format_exc()
|
2015-08-18 16:28:58 +00:00
|
|
|
logger.error("%s\n%s" , e, exception_data)
|
2014-11-04 16:47:36 +00:00
|
|
|
|
|
|
|
# save them to database, if possible; if it fails, we already logged to console.
|
|
|
|
try:
|
2014-11-25 10:12:46 +00:00
|
|
|
buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data))
|
|
|
|
except Exception as ce:
|
2015-08-18 16:28:58 +00:00
|
|
|
logger.error("CRITICAL - Failed to to save toaster exception to the database: %s", str(ce))
|
2014-11-04 16:47:36 +00:00
|
|
|
|
2015-05-01 15:20:33 +00:00
|
|
|
# make sure we return with an error
|
|
|
|
return_value += 1
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2015-10-29 11:59:44 +00:00
|
|
|
if interrupted and return_value == 0:
|
|
|
|
return_value += 1
|
2013-09-26 11:50:50 +00:00
|
|
|
|
2016-05-09 13:01:12 +00:00
|
|
|
logger.warning("Return value is %d", return_value)
|
2013-09-26 11:50:50 +00:00
|
|
|
return return_value
|