summaryrefslogtreecommitdiffstats
path: root/external/poky/bitbake/lib/bb/ui
diff options
context:
space:
mode:
Diffstat (limited to 'external/poky/bitbake/lib/bb/ui')
-rw-r--r--external/poky/bitbake/lib/bb/ui/__init__.py12
-rw-r--r--external/poky/bitbake/lib/bb/ui/buildinfohelper.py30
-rw-r--r--external/poky/bitbake/lib/bb/ui/knotty.py310
-rw-r--r--external/poky/bitbake/lib/bb/ui/ncurses.py17
-rw-r--r--external/poky/bitbake/lib/bb/ui/taskexp.py29
-rw-r--r--external/poky/bitbake/lib/bb/ui/teamcity.py396
-rw-r--r--external/poky/bitbake/lib/bb/ui/toasterui.py14
-rw-r--r--external/poky/bitbake/lib/bb/ui/uievent.py17
-rw-r--r--external/poky/bitbake/lib/bb/ui/uihelper.py55
9 files changed, 686 insertions, 194 deletions
diff --git a/external/poky/bitbake/lib/bb/ui/__init__.py b/external/poky/bitbake/lib/bb/ui/__init__.py
index a4805ed0..4b7ac36c 100644
--- a/external/poky/bitbake/lib/bb/ui/__init__.py
+++ b/external/poky/bitbake/lib/bb/ui/__init__.py
@@ -3,15 +3,5 @@
#
# Copyright (C) 2006-2007 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
-# published by the Free Software Foundation.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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.
diff --git a/external/poky/bitbake/lib/bb/ui/buildinfohelper.py b/external/poky/bitbake/lib/bb/ui/buildinfohelper.py
index 31323d28..82c62e33 100644
--- a/external/poky/bitbake/lib/bb/ui/buildinfohelper.py
+++ b/external/poky/bitbake/lib/bb/ui/buildinfohelper.py
@@ -3,18 +3,8 @@
#
# 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.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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.
import sys
import bb
@@ -656,6 +646,9 @@ class ORMWrapper(object):
Target_Installed_Package.objects.create(target = target_obj, package = packagedict[p]['object'])
packagedeps_objs = []
+ pattern_so = re.compile(r'.*\.so(\.\d*)?$')
+ pattern_lib = re.compile(r'.*\-suffix(\d*)?$')
+ pattern_ko = re.compile(r'^kernel-module-.*')
for p in packagedict:
for (px,deptype) in packagedict[p]['depends']:
if deptype == 'depends':
@@ -664,6 +657,13 @@ class ORMWrapper(object):
tdeptype = Package_Dependency.TYPE_TRECOMMENDS
try:
+ # Skip known non-package objects like libraries and kernel modules
+ if pattern_so.match(px) or pattern_lib.match(px):
+ logger.info("Toaster does not add library file dependencies to packages (%s,%s)", p, px)
+ continue
+ if pattern_ko.match(px):
+ logger.info("Toaster does not add kernel module dependencies to packages (%s,%s)", p, px)
+ continue
packagedeps_objs.append(Package_Dependency(
package = packagedict[p]['object'],
depends_on = packagedict[px]['object'],
@@ -935,7 +935,7 @@ class BuildInfoHelper(object):
# only reset the build name if the one on the server is actually
# a valid value for the build_name field
- if build_name != None:
+ if build_name is not None:
build_info['build_name'] = build_name
changed = True
@@ -1194,7 +1194,7 @@ class BuildInfoHelper(object):
evdata = BuildInfoHelper._get_data_from_event(event)
for t in self.internal_state['targets']:
- if t.is_image == True:
+ if t.is_image:
output_files = list(evdata.keys())
for output in output_files:
if t.target in output and 'rootfs' in output and not output.endswith(".manifest"):
@@ -1236,7 +1236,7 @@ class BuildInfoHelper(object):
task_information['outcome'] = Task.OUTCOME_PREBUILT
else:
task_information['task_executed'] = True
- if 'noexec' in vars(event) and event.noexec == True:
+ if 'noexec' in vars(event) and event.noexec:
task_information['task_executed'] = False
task_information['outcome'] = Task.OUTCOME_EMPTY
task_information['script_type'] = Task.CODING_NA
@@ -1776,7 +1776,7 @@ class BuildInfoHelper(object):
image_file_extensions_unique = {}
image_fstypes = self.server.runCommand(
['getVariable', 'IMAGE_FSTYPES'])[0]
- if image_fstypes != None:
+ if image_fstypes is not None:
image_types_str = image_fstypes.strip()
image_file_extensions = re.sub(r' {2,}', ' ', image_types_str)
image_file_extensions_unique = set(image_file_extensions.split(' '))
diff --git a/external/poky/bitbake/lib/bb/ui/knotty.py b/external/poky/bitbake/lib/bb/ui/knotty.py
index fa88e6cc..87e873d6 100644
--- a/external/poky/bitbake/lib/bb/ui/knotty.py
+++ b/external/poky/bitbake/lib/bb/ui/knotty.py
@@ -5,24 +5,13 @@
#
# 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
-# published by the Free Software Foundation.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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
import os
import sys
-import xmlrpc.client as xmlrpclib
import logging
import progressbar
import signal
@@ -45,15 +34,15 @@ class BBProgress(progressbar.ProgressBar):
self.msg = msg
self.extrapos = extrapos
if not widgets:
- widgets = [progressbar.Percentage(), ' ', progressbar.Bar(), ' ',
- progressbar.ETA()]
- self.extrapos = 4
+ widgets = [': ', progressbar.Percentage(), ' ', progressbar.Bar(),
+ ' ', progressbar.ETA()]
+ self.extrapos = 5
if resize_handler:
self._resize_default = resize_handler
else:
self._resize_default = signal.getsignal(signal.SIGWINCH)
- progressbar.ProgressBar.__init__(self, maxval, [self.msg + ": "] + widgets, fd=sys.stdout)
+ progressbar.ProgressBar.__init__(self, maxval, [self.msg] + widgets, fd=sys.stdout)
def _handle_resize(self, signum=None, frame=None):
progressbar.ProgressBar._handle_resize(self, signum, frame)
@@ -120,12 +109,11 @@ def pluralise(singular, plural, qty):
class InteractConsoleLogFilter(logging.Filter):
- def __init__(self, tf, format):
+ def __init__(self, tf):
self.tf = tf
- self.format = format
def filter(self, record):
- if record.levelno == self.format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("recipe ")):
+ if record.levelno == bb.msg.BBLogFormatter.NOTE and (record.msg.startswith("Running") or record.msg.startswith("recipe ")):
return False
self.tf.clearFooter()
return True
@@ -161,7 +149,7 @@ class TerminalFilter(object):
cr = (25, 80)
return cr
- def __init__(self, main, helper, console, errconsole, format, quiet):
+ def __init__(self, main, helper, handlers, quiet):
self.main = main
self.helper = helper
self.cuu = None
@@ -191,7 +179,11 @@ class TerminalFilter(object):
termios.tcsetattr(fd, termios.TCSADRAIN, new)
curses.setupterm()
if curses.tigetnum("colors") > 2:
- format.enable_color()
+ for h in handlers:
+ try:
+ h.formatter.enable_color()
+ except AttributeError:
+ pass
self.ed = curses.tigetstr("ed")
if self.ed:
self.cuu = curses.tigetstr("cuu")
@@ -207,10 +199,9 @@ class TerminalFilter(object):
self.interactive = False
bb.note("Unable to use interactive mode for this terminal, using fallback")
return
- if console:
- console.addFilter(InteractConsoleLogFilter(self, format))
- if errconsole:
- errconsole.addFilter(InteractConsoleLogFilter(self, format))
+
+ for h in handlers:
+ h.addFilter(InteractConsoleLogFilter(self))
self.main_progress = None
@@ -222,6 +213,23 @@ class TerminalFilter(object):
sys.stdout.flush()
self.footer_present = False
+ def elapsed(self, sec):
+ hrs = int(sec / 3600.0)
+ sec -= hrs * 3600
+ min = int(sec / 60.0)
+ sec -= min * 60
+ if hrs > 0:
+ return "%dh%dm%ds" % (hrs, min, sec)
+ elif min > 0:
+ return "%dm%ds" % (min, sec)
+ else:
+ return "%ds" % (sec)
+
+ def keepAlive(self, t):
+ if not self.cuu:
+ print("Bitbake still alive (%ds)" % t)
+ sys.stdout.flush()
+
def updateFooter(self):
if not self.cuu:
return
@@ -248,19 +256,19 @@ class TerminalFilter(object):
start_time = activetasks[t].get("starttime", None)
if not pbar or pbar.bouncing != (progress < 0):
if progress < 0:
- pbar = BBProgress("0: %s (pid %s) " % (activetasks[t]["title"], t), 100, widgets=[progressbar.BouncingSlider(), ''], extrapos=2, resize_handler=self.sigwinch_handle)
+ pbar = BBProgress("0: %s (pid %s)" % (activetasks[t]["title"], activetasks[t]["pid"]), 100, widgets=[' ', progressbar.BouncingSlider(), ''], extrapos=3, resize_handler=self.sigwinch_handle)
pbar.bouncing = True
else:
- pbar = BBProgress("0: %s (pid %s) " % (activetasks[t]["title"], t), 100, widgets=[progressbar.Percentage(), ' ', progressbar.Bar(), ''], extrapos=4, resize_handler=self.sigwinch_handle)
+ pbar = BBProgress("0: %s (pid %s)" % (activetasks[t]["title"], activetasks[t]["pid"]), 100, widgets=[' ', progressbar.Percentage(), ' ', progressbar.Bar(), ''], extrapos=5, resize_handler=self.sigwinch_handle)
pbar.bouncing = False
activetasks[t]["progressbar"] = pbar
tasks.append((pbar, progress, rate, start_time))
else:
start_time = activetasks[t].get("starttime", None)
if start_time:
- tasks.append("%s - %ds (pid %s)" % (activetasks[t]["title"], currenttime - start_time, t))
+ tasks.append("%s - %s (pid %s)" % (activetasks[t]["title"], self.elapsed(currenttime - start_time), activetasks[t]["pid"]))
else:
- tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
+ tasks.append("%s (pid %s)" % (activetasks[t]["title"], activetasks[t]["pid"]))
if self.main.shutdown:
content = "Waiting for %s running tasks to finish:" % len(activetasks)
@@ -293,8 +301,8 @@ class TerminalFilter(object):
if start_time:
pbar.start_time = start_time
pbar.setmessage('%s:%s' % (tasknum, pbar.msg.split(':', 1)[1]))
+ pbar.setextra(rate)
if progress > -1:
- pbar.setextra(rate)
content = pbar.update(progress)
else:
content = pbar.update(1)
@@ -356,7 +364,11 @@ def _log_settings_from_server(server, observe_only):
if error:
logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error)
raise BaseException(error)
- return includelogs, loglines, consolelogfile
+ logconfigfile, error = server.runCommand([cmd, "BB_LOGCONFIG"])
+ if error:
+ logger.error("Unable to get the value of BB_LOGCONFIG variable: %s" % error)
+ raise BaseException(error)
+ return includelogs, loglines, consolelogfile, logconfigfile
_evt_list = [ "bb.runqueue.runQueueExitWait", "bb.event.LogExecTTY", "logging.LogRecord",
"bb.build.TaskFailed", "bb.build.TaskBase", "bb.event.ParseStarted",
@@ -373,7 +385,148 @@ def main(server, eventHandler, params, tf = TerminalFilter):
if not params.observe_only:
params.updateToServer(server, os.environ.copy())
- includelogs, loglines, consolelogfile = _log_settings_from_server(server, params.observe_only)
+ includelogs, loglines, consolelogfile, logconfigfile = _log_settings_from_server(server, params.observe_only)
+
+ loglevel, _ = bb.msg.constructLogOptions()
+
+ if params.options.quiet == 0:
+ console_loglevel = loglevel
+ elif params.options.quiet > 2:
+ console_loglevel = bb.msg.BBLogFormatter.ERROR
+ else:
+ console_loglevel = bb.msg.BBLogFormatter.WARNING
+
+ logconfig = {
+ "version": 1,
+ "handlers": {
+ "BitBake.console": {
+ "class": "logging.StreamHandler",
+ "formatter": "BitBake.consoleFormatter",
+ "level": console_loglevel,
+ "stream": "ext://sys.stdout",
+ "filters": ["BitBake.stdoutFilter"],
+ ".": {
+ "is_console": True,
+ },
+ },
+ "BitBake.errconsole": {
+ "class": "logging.StreamHandler",
+ "formatter": "BitBake.consoleFormatter",
+ "level": loglevel,
+ "stream": "ext://sys.stderr",
+ "filters": ["BitBake.stderrFilter"],
+ ".": {
+ "is_console": True,
+ },
+ },
+ # This handler can be used if specific loggers should print on
+ # the console at a lower severity than the default. It will
+ # display any messages sent to it that are lower than then
+ # BitBake.console logging level (so as to prevent duplication of
+ # messages). Nothing is attached to this handler by default
+ "BitBake.verbconsole": {
+ "class": "logging.StreamHandler",
+ "formatter": "BitBake.consoleFormatter",
+ "level": 1,
+ "stream": "ext://sys.stdout",
+ "filters": ["BitBake.verbconsoleFilter"],
+ ".": {
+ "is_console": True,
+ },
+ },
+ },
+ "formatters": {
+ # This format instance will get color output enabled by the
+ # terminal
+ "BitBake.consoleFormatter" : {
+ "()": "bb.msg.BBLogFormatter",
+ "format": "%(levelname)s: %(message)s"
+ },
+ # The file log requires a separate instance so that it doesn't get
+ # color enabled
+ "BitBake.logfileFormatter": {
+ "()": "bb.msg.BBLogFormatter",
+ "format": "%(levelname)s: %(message)s"
+ }
+ },
+ "filters": {
+ "BitBake.stdoutFilter": {
+ "()": "bb.msg.LogFilterLTLevel",
+ "level": "ERROR"
+ },
+ "BitBake.stderrFilter": {
+ "()": "bb.msg.LogFilterGEQLevel",
+ "level": "ERROR"
+ },
+ "BitBake.verbconsoleFilter": {
+ "()": "bb.msg.LogFilterLTLevel",
+ "level": console_loglevel
+ },
+ },
+ "loggers": {
+ "BitBake": {
+ "level": loglevel,
+ "handlers": ["BitBake.console", "BitBake.errconsole"],
+ }
+ },
+ "disable_existing_loggers": False
+ }
+
+ # Enable the console log file if enabled
+ if consolelogfile and not params.options.show_environment and not params.options.show_versions:
+ logconfig = bb.msg.mergeLoggingConfig(logconfig, {
+ "version": 1,
+ "handlers" : {
+ "BitBake.consolelog": {
+ "class": "logging.FileHandler",
+ "formatter": "BitBake.logfileFormatter",
+ "level": loglevel,
+ "filename": consolelogfile,
+ },
+ # Just like verbconsole, anything sent here will go to the
+ # log file, unless it would go to BitBake.consolelog
+ "BitBake.verbconsolelog" : {
+ "class": "logging.FileHandler",
+ "formatter": "BitBake.logfileFormatter",
+ "level": 1,
+ "filename": consolelogfile,
+ "filters": ["BitBake.verbconsolelogFilter"],
+ },
+ },
+ "filters": {
+ "BitBake.verbconsolelogFilter": {
+ "()": "bb.msg.LogFilterLTLevel",
+ "level": loglevel,
+ },
+ },
+ "loggers": {
+ "BitBake": {
+ "handlers": ["BitBake.consolelog"],
+ },
+
+ # Other interesting things that we want to keep an eye on
+ # in the log files in case someone has an issue, but not
+ # necessarily show to the user on the console
+ "BitBake.SigGen.HashEquiv": {
+ "level": "VERBOSE",
+ "handlers": ["BitBake.verbconsolelog"],
+ },
+ "BitBake.RunQueue.HashEquiv": {
+ "level": "VERBOSE",
+ "handlers": ["BitBake.verbconsolelog"],
+ }
+ }
+ })
+
+ bb.utils.mkdirhier(os.path.dirname(consolelogfile))
+ loglink = os.path.join(os.path.dirname(consolelogfile), 'console-latest.log')
+ bb.utils.remove(loglink)
+ try:
+ os.symlink(os.path.basename(consolelogfile), loglink)
+ except OSError:
+ pass
+
+ conf = bb.msg.setLoggingConfig(logconfig, logconfigfile)
if sys.stdin.isatty() and sys.stdout.isatty():
log_exec_tty = True
@@ -382,23 +535,9 @@ def main(server, eventHandler, params, tf = TerminalFilter):
helper = uihelper.BBUIHelper()
- console = logging.StreamHandler(sys.stdout)
- errconsole = logging.StreamHandler(sys.stderr)
- format_str = "%(levelname)s: %(message)s"
- format = bb.msg.BBLogFormatter(format_str)
- if params.options.quiet == 0:
- forcelevel = None
- elif params.options.quiet > 2:
- forcelevel = bb.msg.BBLogFormatter.ERROR
- else:
- forcelevel = bb.msg.BBLogFormatter.WARNING
- bb.msg.addDefaultlogFilter(console, bb.msg.BBLogFilterStdOut, forcelevel)
- bb.msg.addDefaultlogFilter(errconsole, bb.msg.BBLogFilterStdErr)
- console.setFormatter(format)
- errconsole.setFormatter(format)
- if not bb.msg.has_console_handler(logger):
- logger.addHandler(console)
- logger.addHandler(errconsole)
+ # Look for the specially designated handlers which need to be passed to the
+ # terminal handler
+ console_handlers = [h for h in conf.config['handlers'].values() if getattr(h, 'is_console', False)]
bb.utils.set_process_name("KnottyUI")
@@ -406,24 +545,14 @@ def main(server, eventHandler, params, tf = TerminalFilter):
server.terminateServer()
return
- consolelog = None
- if consolelogfile and not params.options.show_environment and not params.options.show_versions:
- bb.utils.mkdirhier(os.path.dirname(consolelogfile))
- conlogformat = bb.msg.BBLogFormatter(format_str)
- consolelog = logging.FileHandler(consolelogfile)
- bb.msg.addDefaultlogFilter(consolelog)
- consolelog.setFormatter(conlogformat)
- logger.addHandler(consolelog)
- loglink = os.path.join(os.path.dirname(consolelogfile), 'console-latest.log')
- bb.utils.remove(loglink)
- try:
- os.symlink(os.path.basename(consolelogfile), loglink)
- except OSError:
- pass
-
llevel, debug_domains = bb.msg.constructLogOptions()
server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list])
+ # The logging_tree module is *extremely* helpful in debugging logging
+ # domains. Uncomment here to dump the logging tree when bitbake starts
+ #import logging_tree
+ #logging_tree.printout()
+
universe = False
if not params.observe_only:
params.updateFromServer(server)
@@ -441,7 +570,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
if error:
logger.error("Command '%s' failed: %s" % (cmdline, error))
return 1
- elif ret != True:
+ elif not ret:
logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
return 1
@@ -455,16 +584,23 @@ def main(server, eventHandler, params, tf = TerminalFilter):
warnings = 0
taskfailures = []
- termfilter = tf(main, helper, console, errconsole, format, params.options.quiet)
+ printinterval = 5000
+ lastprint = time.time()
+
+ termfilter = tf(main, helper, console_handlers, params.options.quiet)
atexit.register(termfilter.finish)
while True:
try:
+ if (lastprint + printinterval) <= time.time():
+ termfilter.keepAlive(printinterval)
+ printinterval += 5000
event = eventHandler.waitEvent(0)
if event is None:
if main.shutdown > 1:
break
- termfilter.updateFooter()
+ if not parseprogress:
+ termfilter.updateFooter()
event = eventHandler.waitEvent(0.25)
if event is None:
continue
@@ -488,26 +624,28 @@ def main(server, eventHandler, params, tf = TerminalFilter):
continue
if isinstance(event, logging.LogRecord):
- if event.levelno >= format.ERROR:
+ lastprint = time.time()
+ printinterval = 5000
+ if event.levelno >= bb.msg.BBLogFormatter.ERROR:
errors = errors + 1
return_value = 1
- elif event.levelno == format.WARNING:
+ elif event.levelno == bb.msg.BBLogFormatter.WARNING:
warnings = warnings + 1
if event.taskpid != 0:
# 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
- if event.levelno <= format.NOTE and (event.levelno < llevel or (event.levelno == format.NOTE and llevel != format.VERBOSE)):
+ if event.levelno <= bb.msg.BBLogFormatter.NOTE and (event.levelno < llevel or (event.levelno == bb.msg.BBLogFormatter.NOTE and llevel != bb.msg.BBLogFormatter.VERBOSE)):
continue
# Prefix task messages with recipe/task
- if event.taskpid in helper.running_tasks and event.levelno != format.PLAIN:
- taskinfo = helper.running_tasks[event.taskpid]
+ if event.taskpid in helper.pidmap and event.levelno != bb.msg.BBLogFormatter.PLAIN:
+ taskinfo = helper.running_tasks[helper.pidmap[event.taskpid]]
event.msg = taskinfo['title'] + ': ' + event.msg
if hasattr(event, 'fn'):
event.msg = event.fn + ': ' + event.msg
- logger.handle(event)
+ logging.getLogger(event.name).handle(event)
continue
if isinstance(event, bb.build.TaskFailedSilent):
@@ -524,6 +662,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
continue
if event.total == 0:
continue
+ termfilter.clearFooter()
parseprogress = new_progress("Parsing recipes", event.total).start()
continue
if isinstance(event, bb.event.ParseProgress):
@@ -574,6 +713,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
if isinstance(event, bb.command.CommandExit):
if not return_value:
return_value = event.exitcode
+ main.shutdown = 2
continue
if isinstance(event, (bb.command.CommandCompleted, bb.cooker.CookerExit)):
main.shutdown = 2
@@ -623,6 +763,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
if isinstance(event, bb.event.ProcessStarted):
if params.options.quiet > 1:
continue
+ termfilter.clearFooter()
parseprogress = new_progress(event.processname, event.total)
parseprogress.start(False)
continue
@@ -645,7 +786,6 @@ def main(server, eventHandler, params, tf = TerminalFilter):
# ignore
if isinstance(event, (bb.event.BuildBase,
bb.event.MetadataEvent,
- bb.event.StampUpdate,
bb.event.ConfigParsed,
bb.event.MultiConfigParsed,
bb.event.RecipeParsed,
@@ -675,17 +815,27 @@ def main(server, eventHandler, params, tf = TerminalFilter):
if params.observe_only:
print("\nKeyboard Interrupt, exiting observer...")
main.shutdown = 2
- if not params.observe_only and main.shutdown == 1:
+
+ def state_force_shutdown():
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 == 1:
+ state_force_shutdown()
+
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)
+ # Capture the second KeyboardInterrupt during stateShutdown is running
+ try:
+ _, error = server.runCommand(["stateShutdown"])
+ if error:
+ logger.error("Unable to cleanly shutdown: %s" % error)
+ except KeyboardInterrupt:
+ state_force_shutdown()
+
main.shutdown = main.shutdown + 1
pass
except Exception as e:
@@ -721,8 +871,6 @@ def main(server, eventHandler, params, tf = TerminalFilter):
if e.errno == errno.EPIPE:
pass
- if consolelog:
- logger.removeHandler(consolelog)
- consolelog.close()
+ logging.shutdown()
return return_value
diff --git a/external/poky/bitbake/lib/bb/ui/ncurses.py b/external/poky/bitbake/lib/bb/ui/ncurses.py
index 8690c529..da4fbeab 100644
--- a/external/poky/bitbake/lib/bb/ui/ncurses.py
+++ b/external/poky/bitbake/lib/bb/ui/ncurses.py
@@ -6,18 +6,8 @@
# Copyright (C) 2006 Michael 'Mickey' Lauer
# Copyright (C) 2006-2007 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
-# published by the Free Software Foundation.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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.
"""
We have the following windows:
@@ -47,7 +37,7 @@
import logging
-import os, sys, itertools, time, subprocess
+import os, sys, itertools, time
try:
import curses
@@ -56,7 +46,6 @@ except ImportError:
import bb
import xmlrpc.client
-from bb import ui
from bb.ui import uihelper
parsespin = itertools.cycle( r'|/-\\' )
@@ -249,7 +238,7 @@ class NCursesUI:
if error:
print("Error running command '%s': %s" % (cmdline, error))
return
- elif ret != True:
+ elif not ret:
print("Couldn't get default commandlind! %s" % ret)
return
except xmlrpc.client.Fault as x:
diff --git a/external/poky/bitbake/lib/bb/ui/taskexp.py b/external/poky/bitbake/lib/bb/ui/taskexp.py
index 8305d70f..05e32338 100644
--- a/external/poky/bitbake/lib/bb/ui/taskexp.py
+++ b/external/poky/bitbake/lib/bb/ui/taskexp.py
@@ -4,27 +4,22 @@
# Copyright (C) 2007 Ross Burton
# Copyright (C) 2007 - 2008 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
-# published by the Free Software Foundation.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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.
import sys
-import gi
-gi.require_version('Gtk', '3.0')
-from gi.repository import Gtk, Gdk, GObject
-from multiprocessing import Queue
+
+try:
+ import gi
+ gi.require_version('Gtk', '3.0')
+ from gi.repository import Gtk, Gdk, GObject
+except ValueError:
+ sys.exit("FATAL: Gtk version needs to be 3.0")
+except ImportError:
+ sys.exit("FATAL: Gtk ui could not load the required gi python module")
+
import threading
from xmlrpc import client
-import time
import bb
import bb.event
@@ -212,7 +207,7 @@ def main(server, eventHandler, params):
if error:
print("Error running command '%s': %s" % (cmdline, error))
return 1
- elif ret != True:
+ elif not ret:
print("Error running command '%s': returned %s" % (cmdline, ret))
return 1
except client.Fault as x:
diff --git a/external/poky/bitbake/lib/bb/ui/teamcity.py b/external/poky/bitbake/lib/bb/ui/teamcity.py
new file mode 100644
index 00000000..fca46c28
--- /dev/null
+++ b/external/poky/bitbake/lib/bb/ui/teamcity.py
@@ -0,0 +1,396 @@
+#
+# TeamCity UI Implementation
+#
+# Implements a TeamCity frontend for the BitBake utility, via service messages.
+# See https://www.jetbrains.com/help/teamcity/build-script-interaction-with-teamcity.html
+#
+# Based on ncurses.py and knotty.py, variously by Michael Lauer and Richard Purdie
+#
+# Copyright (C) 2006 Michael 'Mickey' Lauer
+# Copyright (C) 2006-2012 Richard Purdie
+# Copyright (C) 2018-2020 Agilent Technologies, Inc.
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Author: Chris Laplante <chris.laplante@agilent.com>
+
+from __future__ import division
+
+import datetime
+import logging
+import math
+import os
+import re
+import sys
+import xmlrpc.client
+from collections import deque
+
+import bb
+import bb.build
+import bb.command
+import bb.cooker
+import bb.event
+import bb.exceptions
+import bb.runqueue
+from bb.ui import uihelper
+
+logger = logging.getLogger("BitBake")
+
+
+class TeamCityUI:
+ def __init__(self):
+ self._block_stack = []
+ self._last_progress_state = None
+
+ @classmethod
+ def escape_service_value(cls, value):
+ """
+ Escape a value for inclusion in a service message. TeamCity uses the vertical pipe character for escaping.
+ See: https://confluence.jetbrains.com/display/TCD10/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-Escapedvalues
+ """
+ return re.sub(r"(['|\[\]])", r"|\1", value).replace("\n", "|n").replace("\r", "|r")
+
+ @classmethod
+ def emit_service_message(cls, message_type, **kwargs):
+ print(cls.format_service_message(message_type, **kwargs), flush=True)
+
+ @classmethod
+ def format_service_message(cls, message_type, **kwargs):
+ payload = " ".join(["{0}='{1}'".format(k, cls.escape_service_value(v)) for k, v in kwargs.items()])
+ return "##teamcity[{0} {1}]".format(message_type, payload)
+
+ @classmethod
+ def emit_simple_service_message(cls, message_type, message):
+ print(cls.format_simple_service_message(message_type, message), flush=True)
+
+ @classmethod
+ def format_simple_service_message(cls, message_type, message):
+ return "##teamcity[{0} '{1}']".format(message_type, cls.escape_service_value(message))
+
+ @classmethod
+ def format_build_message(cls, text, status):
+ return cls.format_service_message("message", text=text, status=status)
+
+ def block_start(self, name):
+ self._block_stack.append(name)
+ self.emit_service_message("blockOpened", name=name)
+
+ def block_end(self):
+ if self._block_stack:
+ name = self._block_stack.pop()
+ self.emit_service_message("blockClosed", name=name)
+
+ def progress(self, message, percent, extra=None):
+ now = datetime.datetime.now()
+ percent = "{0: >3.0f}".format(percent)
+
+ report = False
+ if not self._last_progress_state \
+ or (self._last_progress_state[0] == message
+ and self._last_progress_state[1] != percent
+ and (now - self._last_progress_state[2]).microseconds >= 5000) \
+ or self._last_progress_state[0] != message:
+ report = True
+ self._last_progress_state = (message, percent, now)
+
+ if report or percent in [0, 100]:
+ self.emit_simple_service_message("progressMessage", "{0}: {1}%{2}".format(message, percent, extra or ""))
+
+
+class TeamcityLogFormatter(logging.Formatter):
+ def format(self, record):
+ details = ""
+ if hasattr(record, 'bb_exc_formatted'):
+ details = ''.join(record.bb_exc_formatted)
+ elif hasattr(record, 'bb_exc_info'):
+ etype, value, tb = record.bb_exc_info
+ formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
+ details = ''.join(formatted)
+
+ if record.levelno in [bb.msg.BBLogFormatter.ERROR, bb.msg.BBLogFormatter.CRITICAL]:
+ # ERROR gets a separate errorDetails field
+ msg = TeamCityUI.format_service_message("message", text=record.getMessage(), status="ERROR",
+ errorDetails=details)
+ else:
+ payload = record.getMessage()
+ if details:
+ payload += "\n" + details
+ if record.levelno == bb.msg.BBLogFormatter.PLAIN:
+ msg = payload
+ elif record.levelno == bb.msg.BBLogFormatter.WARNING:
+ msg = TeamCityUI.format_service_message("message", text=payload, status="WARNING")
+ else:
+ msg = TeamCityUI.format_service_message("message", text=payload, status="NORMAL")
+
+ return msg
+
+
+_evt_list = ["bb.runqueue.runQueueExitWait", "bb.event.LogExecTTY", "logging.LogRecord",
+ "bb.build.TaskFailed", "bb.build.TaskBase", "bb.event.ParseStarted",
+ "bb.event.ParseProgress", "bb.event.ParseCompleted", "bb.event.CacheLoadStarted",
+ "bb.event.CacheLoadProgress", "bb.event.CacheLoadCompleted", "bb.command.CommandFailed",
+ "bb.command.CommandExit", "bb.command.CommandCompleted", "bb.cooker.CookerExit",
+ "bb.event.MultipleProviders", "bb.event.NoProvider", "bb.runqueue.sceneQueueTaskStarted",
+ "bb.runqueue.runQueueTaskStarted", "bb.runqueue.runQueueTaskFailed", "bb.runqueue.sceneQueueTaskFailed",
+ "bb.event.BuildBase", "bb.build.TaskStarted", "bb.build.TaskSucceeded", "bb.build.TaskFailedSilent",
+ "bb.build.TaskProgress", "bb.event.ProcessStarted", "bb.event.ProcessProgress", "bb.event.ProcessFinished"]
+
+
+def _log_settings_from_server(server):
+ # Get values of variables which control our output
+ includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
+ if error:
+ logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error)
+ raise BaseException(error)
+ loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
+ if error:
+ logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
+ raise BaseException(error)
+ return includelogs, loglines
+
+
+def main(server, eventHandler, params):
+ params.updateToServer(server, os.environ.copy())
+
+ includelogs, loglines = _log_settings_from_server(server)
+
+ ui = TeamCityUI()
+
+ helper = uihelper.BBUIHelper()
+
+ console = logging.StreamHandler(sys.stdout)
+ errconsole = logging.StreamHandler(sys.stderr)
+ format = TeamcityLogFormatter()
+ if params.options.quiet == 0:
+ forcelevel = None
+ elif params.options.quiet > 2:
+ forcelevel = bb.msg.BBLogFormatter.ERROR
+ else:
+ forcelevel = bb.msg.BBLogFormatter.WARNING
+ console.setFormatter(format)
+ errconsole.setFormatter(format)
+ if not bb.msg.has_console_handler(logger):
+ logger.addHandler(console)
+ logger.addHandler(errconsole)
+
+ if params.options.remote_server and params.options.kill_server:
+ server.terminateServer()
+ return
+
+ if params.observe_only:
+ logger.error("Observe-only mode not supported in this UI")
+ return 1
+
+ llevel, debug_domains = bb.msg.constructLogOptions()
+ server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list])
+
+ try:
+ params.updateFromServer(server)
+ cmdline = params.parseActions()
+ if not cmdline:
+ logger.error("No task given")
+ return 1
+ if 'msg' in cmdline and cmdline['msg']:
+ logger.error(cmdline['msg'])
+ return 1
+ cmdline = cmdline['action']
+ ret, error = server.runCommand(cmdline)
+ if error:
+ logger.error("{0}: {1}".format(cmdline, error))
+ return 1
+ elif not ret:
+ logger.error("Couldn't get default commandline: {0}".format(re))
+ return 1
+ except xmlrpc.client.Fault as x:
+ logger.error("XMLRPC Fault getting commandline: {0}".format(x))
+ return 1
+
+ active_process_total = None
+ is_tasks_running = False
+
+ while True:
+ try:
+ event = eventHandler.waitEvent(0.25)
+ if not event:
+ continue
+
+ helper.eventHandler(event)
+
+ if isinstance(event, bb.build.TaskBase):
+ logger.info(event._message)
+ if isinstance(event, logging.LogRecord):
+ # Don't report sstate failures as errors, since Yocto will just run the tasks for real
+ if event.msg == "No suitable staging package found" or (event.msg.startswith(
+ "Fetcher failure: Unable to find file") and "downloadfilename" in event.msg and "sstate" in event.msg):
+ event.levelno = bb.msg.BBLogFormatter.WARNING
+ if event.taskpid != 0:
+ # 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
+ if event.levelno <= bb.msg.BBLogFormatter.NOTE and (event.levelno < llevel or (
+ event.levelno == bb.msg.BBLogFormatter.NOTE and llevel != bb.msg.BBLogFormatter.VERBOSE)):
+ continue
+
+ # Prefix task messages with recipe/task
+ if event.taskpid in helper.running_tasks and event.levelno != bb.msg.BBLogFormatter.PLAIN:
+ taskinfo = helper.running_tasks[event.taskpid]
+ event.msg = taskinfo['title'] + ': ' + event.msg
+ if hasattr(event, 'fn'):
+ event.msg = event.fn + ': ' + event.msg
+ logger.handle(event)
+ if isinstance(event, bb.build.TaskFailedSilent):
+ logger.warning("Logfile for failed setscene task is %s" % event.logfile)
+ continue
+ if isinstance(event, bb.build.TaskFailed):
+ rt = "{0}-{1}:{2}".format(event.pn, event.pv.replace("AUTOINC", "0"), event.task)
+
+ logfile = event.logfile
+ if not logfile or not os.path.exists(logfile):
+ TeamCityUI.emit_service_message("buildProblem", description="{0}\nUnknown failure (no log file available)".format(rt))
+ if not event.task.endswith("_setscene"):
+ server.runCommand(["stateForceShutdown"])
+ continue
+
+ details = deque(maxlen=loglines)
+ error_lines = []
+ if includelogs and not event.errprinted:
+ with open(logfile, "r") as f:
+ while True:
+ line = f.readline()
+ if not line:
+ break
+ line = line.rstrip()
+ details.append(' | %s' % line)
+ # TODO: a less stupid check for errors
+ if (event.task == "do_compile") and ("error:" in line):
+ error_lines.append(line)
+
+ if error_lines:
+ TeamCityUI.emit_service_message("compilationStarted", compiler=rt)
+ for line in error_lines:
+ TeamCityUI.emit_service_message("message", text=line, status="ERROR")
+ TeamCityUI.emit_service_message("compilationFinished", compiler=rt)
+ else:
+ TeamCityUI.emit_service_message("buildProblem", description=rt)
+
+ err = "Logfile of failure stored in: %s" % logfile
+ if details:
+ ui.block_start("{0} task log".format(rt))
+ # TeamCity seems to choke on service messages longer than about 63800 characters, so if error
+ # details is longer than, say, 60000, batch it up into several messages.
+ first_message = True
+ while details:
+ detail_len = 0
+ batch = deque()
+ while details and detail_len < 60000:
+ # TODO: This code doesn't bother to handle lines that themselves are extremely long.
+ line = details.popleft()
+ batch.append(line)
+ detail_len += len(line)
+
+ if first_message:
+ batch.appendleft("Log data follows:")
+ first_message = False
+ TeamCityUI.emit_service_message("message", text=err, status="ERROR",
+ errorDetails="\n".join(batch))
+ else:
+ TeamCityUI.emit_service_message("message", text="[continued]", status="ERROR",
+ errorDetails="\n".join(batch))
+ ui.block_end()
+ else:
+ TeamCityUI.emit_service_message("message", text=err, status="ERROR", errorDetails="")
+
+ if not event.task.endswith("_setscene"):
+ server.runCommand(["stateForceShutdown"])
+
+ if isinstance(event, bb.event.ProcessStarted):
+ if event.processname in ["Initialising tasks", "Checking sstate mirror object availability"]:
+ active_process_total = event.total
+ ui.block_start(event.processname)
+ if isinstance(event, bb.event.ProcessFinished):
+ if event.processname in ["Initialising tasks", "Checking sstate mirror object availability"]:
+ ui.progress(event.processname, 100)
+ ui.block_end()
+ if isinstance(event, bb.event.ProcessProgress):
+ if event.processname in ["Initialising tasks",
+ "Checking sstate mirror object availability"] and active_process_total != 0:
+ ui.progress(event.processname, event.progress * 100 / active_process_total)
+ if isinstance(event, bb.event.CacheLoadStarted):
+ ui.block_start("Loading cache")
+ if isinstance(event, bb.event.CacheLoadProgress):
+ if event.total != 0:
+ ui.progress("Loading cache", math.floor(event.current * 100 / event.total))
+ if isinstance(event, bb.event.CacheLoadCompleted):
+ ui.progress("Loading cache", 100)
+ ui.block_end()
+ if isinstance(event, bb.event.ParseStarted):
+ ui.block_start("Parsing recipes and checking upstream revisions")
+ if isinstance(event, bb.event.ParseProgress):
+ if event.total != 0:
+ ui.progress("Parsing recipes", math.floor(event.current * 100 / event.total))
+ if isinstance(event, bb.event.ParseCompleted):
+ ui.progress("Parsing recipes", 100)
+ ui.block_end()
+ if isinstance(event, bb.command.CommandCompleted):
+ return
+ if isinstance(event, bb.command.CommandFailed):
+ logger.error(str(event))
+ return 1
+ if isinstance(event, bb.event.MultipleProviders):
+ logger.warning(str(event))
+ continue
+ if isinstance(event, bb.event.NoProvider):
+ logger.error(str(event))
+ continue
+ if isinstance(event, bb.command.CommandExit):
+ return
+ if isinstance(event, bb.cooker.CookerExit):
+ return
+ if isinstance(event, bb.runqueue.sceneQueueTaskStarted):
+ if not is_tasks_running:
+ is_tasks_running = True
+ ui.block_start("Running tasks")
+ if event.stats.total != 0:
+ ui.progress("Running setscene tasks", (
+ event.stats.completed + event.stats.active + event.stats.failed + 1) * 100 / event.stats.total)
+ if isinstance(event, bb.runqueue.runQueueTaskStarted):
+ if not is_tasks_running:
+ is_tasks_running = True
+ ui.block_start("Running tasks")
+ if event.stats.total != 0:
+ pseudo_total = event.stats.total - event.stats.skipped
+ pseudo_complete = event.stats.completed + event.stats.active - event.stats.skipped + event.stats.failed + 1
+ # TODO: sometimes this gives over 100%
+ ui.progress("Running runqueue tasks", (pseudo_complete) * 100 / pseudo_total,
+ " ({0}/{1})".format(pseudo_complete, pseudo_total))
+ if isinstance(event, bb.runqueue.sceneQueueTaskFailed):
+ logger.warning(str(event))
+ continue
+ if isinstance(event, bb.runqueue.runQueueTaskFailed):
+ logger.error(str(event))
+ return 1
+ if isinstance(event, bb.event.LogExecTTY):
+ pass
+ except EnvironmentError as ioerror:
+ # ignore interrupted io
+ if ioerror.args[0] == 4:
+ pass
+ except Exception as ex:
+ logger.error(str(ex))
+
+ # except KeyboardInterrupt:
+ # if shutdown == 2:
+ # mw.appendText("Third Keyboard Interrupt, exit.\n")
+ # exitflag = True
+ # if shutdown == 1:
+ # mw.appendText("Second Keyboard Interrupt, stopping...\n")
+ # _, error = server.runCommand(["stateForceShutdown"])
+ # if error:
+ # print("Unable to cleanly stop: %s" % error)
+ # if shutdown == 0:
+ # mw.appendText("Keyboard Interrupt, closing down...\n")
+ # _, error = server.runCommand(["stateShutdown"])
+ # if error:
+ # print("Unable to cleanly shutdown: %s" % error)
+ # shutdown = shutdown + 1
+ # pass
diff --git a/external/poky/bitbake/lib/bb/ui/toasterui.py b/external/poky/bitbake/lib/bb/ui/toasterui.py
index 88cec375..9260f5d9 100644
--- a/external/poky/bitbake/lib/bb/ui/toasterui.py
+++ b/external/poky/bitbake/lib/bb/ui/toasterui.py
@@ -7,18 +7,8 @@
# 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.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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
import time
@@ -186,7 +176,7 @@ def main(server, eventHandler, params):
if error:
logger.error("Command '%s' failed: %s" % (cmdline, error))
return 1
- elif ret != True:
+ elif not ret:
logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
return 1
diff --git a/external/poky/bitbake/lib/bb/ui/uievent.py b/external/poky/bitbake/lib/bb/ui/uievent.py
index 9542b911..13d0d4a0 100644
--- a/external/poky/bitbake/lib/bb/ui/uievent.py
+++ b/external/poky/bitbake/lib/bb/ui/uievent.py
@@ -1,22 +1,9 @@
-# ex:ts=4:sw=4:sts=4:et
-# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
# Copyright (C) 2006 - 2007 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
-# published by the Free Software Foundation.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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.
-
"""
Use this class to fork off a thread to recieve event callbacks from the bitbake
@@ -59,7 +46,7 @@ class BBUIEventQueue:
self.EventHandle = ret
error = ""
- if self.EventHandle != None:
+ if self.EventHandle is not None:
break
errmsg = "Could not register UI event handler. Error: %s, host %s, "\
diff --git a/external/poky/bitbake/lib/bb/ui/uihelper.py b/external/poky/bitbake/lib/bb/ui/uihelper.py
index 963c1ea2..48d808ae 100644
--- a/external/poky/bitbake/lib/bb/ui/uihelper.py
+++ b/external/poky/bitbake/lib/bb/ui/uihelper.py
@@ -1,21 +1,9 @@
-# ex:ts=4:sw=4:sts=4:et
-# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
# Copyright (C) 2006 - 2007 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
-# published by the Free Software Foundation.
+# SPDX-License-Identifier: GPL-2.0-only
#
-# 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.
import bb.build
import time
@@ -27,39 +15,48 @@ class BBUIHelper:
# Running PIDs preserves the order tasks were executed in
self.running_pids = []
self.failed_tasks = []
+ self.pidmap = {}
self.tasknumber_current = 0
self.tasknumber_total = 0
def eventHandler(self, event):
+ # PIDs are a bad idea as they can be reused before we process all UI events.
+ # We maintain a 'fuzzy' match for TaskProgress since there is no other way to match
+ def removetid(pid, tid):
+ self.running_pids.remove(tid)
+ del self.running_tasks[tid]
+ if self.pidmap[pid] == tid:
+ del self.pidmap[pid]
+ self.needUpdate = True
+
if isinstance(event, bb.build.TaskStarted):
+ tid = event._fn + ":" + event._task
if event._mc != "default":
- self.running_tasks[event.pid] = { 'title' : "mc:%s:%s %s" % (event._mc, event._package, event._task), 'starttime' : time.time() }
+ self.running_tasks[tid] = { 'title' : "mc:%s:%s %s" % (event._mc, event._package, event._task), 'starttime' : time.time(), 'pid' : event.pid }
else:
- self.running_tasks[event.pid] = { 'title' : "%s %s" % (event._package, event._task), 'starttime' : time.time() }
- self.running_pids.append(event.pid)
+ self.running_tasks[tid] = { 'title' : "%s %s" % (event._package, event._task), 'starttime' : time.time(), 'pid' : event.pid }
+ self.running_pids.append(tid)
+ self.pidmap[event.pid] = tid
self.needUpdate = True
elif isinstance(event, bb.build.TaskSucceeded):
- del self.running_tasks[event.pid]
- self.running_pids.remove(event.pid)
- self.needUpdate = True
+ tid = event._fn + ":" + event._task
+ removetid(event.pid, tid)
elif isinstance(event, bb.build.TaskFailedSilent):
- del self.running_tasks[event.pid]
- self.running_pids.remove(event.pid)
+ tid = event._fn + ":" + event._task
+ removetid(event.pid, tid)
# Don't add to the failed tasks list since this is e.g. a setscene task failure
- self.needUpdate = True
elif isinstance(event, bb.build.TaskFailed):
- del self.running_tasks[event.pid]
- self.running_pids.remove(event.pid)
+ tid = event._fn + ":" + event._task
+ removetid(event.pid, tid)
self.failed_tasks.append( { 'title' : "%s %s" % (event._package, event._task)})
- self.needUpdate = True
- elif isinstance(event, bb.runqueue.runQueueTaskStarted) or isinstance(event, bb.runqueue.sceneQueueTaskStarted):
+ elif isinstance(event, bb.runqueue.runQueueTaskStarted):
self.tasknumber_current = event.stats.completed + event.stats.active + event.stats.failed + 1
self.tasknumber_total = event.stats.total
self.needUpdate = True
elif isinstance(event, bb.build.TaskProgress):
- if event.pid > 0:
- self.running_tasks[event.pid]['progress'] = event.progress
- self.running_tasks[event.pid]['rate'] = event.rate
+ if event.pid > 0 and event.pid in self.pidmap:
+ self.running_tasks[self.pidmap[event.pid]]['progress'] = event.progress
+ self.running_tasks[self.pidmap[event.pid]]['rate'] = event.rate
self.needUpdate = True
else:
return False