2008-09-30 15:08:33 +00:00
|
|
|
#
|
|
|
|
# BitBake (No)TTY UI Implementation
|
|
|
|
#
|
|
|
|
# Handling output to TTYs or files (no TTY)
|
|
|
|
#
|
2011-11-26 13:37:52 +00:00
|
|
|
# Copyright (C) 2006-2012 Richard Purdie
|
2008-09-30 15:08:33 +00:00
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
|
2010-06-10 17:23:03 +00:00
|
|
|
from __future__ import division
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2010-06-10 17:23:03 +00:00
|
|
|
import os
|
2008-09-30 15:08:33 +00:00
|
|
|
import sys
|
|
|
|
import xmlrpclib
|
2010-06-10 15:05:52 +00:00
|
|
|
import logging
|
2010-11-19 04:15:07 +00:00
|
|
|
import progressbar
|
2012-08-15 15:58:46 +00:00
|
|
|
import signal
|
2010-12-10 04:38:35 +00:00
|
|
|
import bb.msg
|
2012-09-17 22:43:49 +00:00
|
|
|
import time
|
2012-08-15 16:50:22 +00:00
|
|
|
import fcntl
|
|
|
|
import struct
|
|
|
|
import copy
|
2010-01-21 23:49:17 +00:00
|
|
|
from bb.ui import uihelper
|
|
|
|
|
2010-06-10 15:05:52 +00:00
|
|
|
logger = logging.getLogger("BitBake")
|
2010-11-22 15:13:56 +00:00
|
|
|
interactive = sys.stdout.isatty()
|
2010-12-07 04:06:13 +00:00
|
|
|
|
|
|
|
class BBProgress(progressbar.ProgressBar):
|
|
|
|
def __init__(self, msg, maxval):
|
|
|
|
self.msg = msg
|
2010-11-22 15:13:56 +00:00
|
|
|
widgets = [progressbar.Percentage(), ' ', progressbar.Bar(), ' ',
|
|
|
|
progressbar.ETA()]
|
|
|
|
|
2012-08-15 15:58:46 +00:00
|
|
|
try:
|
|
|
|
self._resize_default = signal.getsignal(signal.SIGWINCH)
|
|
|
|
except:
|
|
|
|
self._resize_default = None
|
2010-12-07 04:06:13 +00:00
|
|
|
progressbar.ProgressBar.__init__(self, maxval, [self.msg + ": "] + widgets)
|
|
|
|
|
2012-08-15 15:58:46 +00:00
|
|
|
def _handle_resize(self, signum, frame):
|
|
|
|
progressbar.ProgressBar._handle_resize(self, signum, frame)
|
|
|
|
if self._resize_default:
|
|
|
|
self._resize_default(signum, frame)
|
|
|
|
def finish(self):
|
|
|
|
progressbar.ProgressBar.finish(self)
|
|
|
|
if self._resize_default:
|
|
|
|
signal.signal(signal.SIGWINCH, self._resize_default)
|
|
|
|
|
2010-12-07 04:06:13 +00:00
|
|
|
class NonInteractiveProgress(object):
|
|
|
|
fobj = sys.stdout
|
|
|
|
|
|
|
|
def __init__(self, msg, maxval):
|
|
|
|
self.msg = msg
|
|
|
|
self.maxval = maxval
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
self.fobj.write("%s..." % self.msg)
|
|
|
|
self.fobj.flush()
|
|
|
|
return self
|
|
|
|
|
|
|
|
def update(self, value):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def finish(self):
|
|
|
|
self.fobj.write("done.\n")
|
|
|
|
self.fobj.flush()
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2010-11-22 15:13:56 +00:00
|
|
|
def new_progress(msg, maxval):
|
|
|
|
if interactive:
|
|
|
|
return BBProgress(msg, maxval)
|
|
|
|
else:
|
|
|
|
return NonInteractiveProgress(msg, maxval)
|
|
|
|
|
2012-01-13 17:01:52 +00:00
|
|
|
def pluralise(singular, plural, qty):
|
|
|
|
if(qty == 1):
|
|
|
|
return singular % qty
|
|
|
|
else:
|
|
|
|
return plural % qty
|
|
|
|
|
2012-08-15 16:50:22 +00:00
|
|
|
|
|
|
|
class InteractConsoleLogFilter(logging.Filter):
|
|
|
|
def __init__(self, tf, format):
|
|
|
|
self.tf = tf
|
|
|
|
self.format = format
|
|
|
|
|
|
|
|
def filter(self, record):
|
2012-08-17 13:53:16 +00:00
|
|
|
if record.levelno == self.format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("recipe ")):
|
2012-08-15 16:50:22 +00:00
|
|
|
return False
|
|
|
|
self.tf.clearFooter()
|
|
|
|
return True
|
|
|
|
|
2011-11-26 13:37:52 +00:00
|
|
|
class TerminalFilter(object):
|
2012-08-15 16:50:22 +00:00
|
|
|
columns = 80
|
|
|
|
|
|
|
|
def sigwinch_handle(self, signum, frame):
|
|
|
|
self.columns = self.getTerminalColumns()
|
|
|
|
if self._sigwinch_default:
|
|
|
|
self._sigwinch_default(signum, frame)
|
|
|
|
|
|
|
|
def getTerminalColumns(self):
|
|
|
|
def ioctl_GWINSZ(fd):
|
|
|
|
try:
|
|
|
|
cr = struct.unpack('hh', fcntl.ioctl(fd, self.termios.TIOCGWINSZ, '1234'))
|
|
|
|
except:
|
|
|
|
return None
|
|
|
|
return cr
|
|
|
|
cr = ioctl_GWINSZ(sys.stdout.fileno())
|
|
|
|
if not cr:
|
|
|
|
try:
|
|
|
|
fd = os.open(os.ctermid(), os.O_RDONLY)
|
|
|
|
cr = ioctl_GWINSZ(fd)
|
|
|
|
os.close(fd)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
if not cr:
|
|
|
|
try:
|
|
|
|
cr = (env['LINES'], env['COLUMNS'])
|
|
|
|
except:
|
|
|
|
cr = (25, 80)
|
|
|
|
return cr[1]
|
|
|
|
|
2011-11-26 13:37:52 +00:00
|
|
|
def __init__(self, main, helper, console, format):
|
|
|
|
self.main = main
|
|
|
|
self.helper = helper
|
2012-08-15 16:50:22 +00:00
|
|
|
self.cuu = None
|
|
|
|
self.stdinbackup = None
|
|
|
|
self.interactive = sys.stdout.isatty()
|
|
|
|
self.footer_present = False
|
|
|
|
self.lastpids = []
|
|
|
|
|
|
|
|
if not self.interactive:
|
|
|
|
return
|
|
|
|
|
2012-08-21 21:05:58 +00:00
|
|
|
try:
|
|
|
|
import curses
|
|
|
|
except ImportError:
|
|
|
|
sys.exit("FATAL: The knotty ui could not load the required curses python module.")
|
2012-12-13 10:55:25 +00:00
|
|
|
|
2012-08-15 16:50:22 +00:00
|
|
|
import termios
|
|
|
|
self.curses = curses
|
|
|
|
self.termios = termios
|
|
|
|
try:
|
|
|
|
fd = sys.stdin.fileno()
|
|
|
|
self.stdinbackup = termios.tcgetattr(fd)
|
|
|
|
new = copy.deepcopy(self.stdinbackup)
|
|
|
|
new[3] = new[3] & ~termios.ECHO
|
|
|
|
termios.tcsetattr(fd, termios.TCSADRAIN, new)
|
|
|
|
curses.setupterm()
|
2012-11-25 21:17:41 +00:00
|
|
|
if curses.tigetnum("colors") > 2:
|
|
|
|
format.enable_color()
|
2012-08-15 16:50:22 +00:00
|
|
|
self.ed = curses.tigetstr("ed")
|
|
|
|
if self.ed:
|
|
|
|
self.cuu = curses.tigetstr("cuu")
|
|
|
|
try:
|
|
|
|
self._sigwinch_default = signal.getsignal(signal.SIGWINCH)
|
|
|
|
signal.signal(signal.SIGWINCH, self.sigwinch_handle)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
self.columns = self.getTerminalColumns()
|
|
|
|
except:
|
|
|
|
self.cuu = None
|
|
|
|
console.addFilter(InteractConsoleLogFilter(self, format))
|
2011-11-26 13:37:52 +00:00
|
|
|
|
|
|
|
def clearFooter(self):
|
2012-08-15 16:50:22 +00:00
|
|
|
if self.footer_present:
|
|
|
|
lines = self.footer_present
|
|
|
|
sys.stdout.write(self.curses.tparm(self.cuu, lines))
|
|
|
|
sys.stdout.write(self.curses.tparm(self.ed))
|
|
|
|
self.footer_present = False
|
2011-11-26 13:37:52 +00:00
|
|
|
|
|
|
|
def updateFooter(self):
|
2012-08-15 16:50:22 +00:00
|
|
|
if not self.cuu:
|
2011-11-26 13:37:52 +00:00
|
|
|
return
|
|
|
|
activetasks = self.helper.running_tasks
|
2012-08-15 16:50:22 +00:00
|
|
|
failedtasks = self.helper.failed_tasks
|
2011-11-26 13:37:52 +00:00
|
|
|
runningpids = self.helper.running_pids
|
2012-09-27 21:56:02 +00:00
|
|
|
if self.footer_present and (self.lastcount == self.helper.tasknumber_current) and (self.lastpids == runningpids):
|
2012-08-15 16:50:22 +00:00
|
|
|
return
|
|
|
|
if self.footer_present:
|
|
|
|
self.clearFooter()
|
2012-10-30 16:39:47 +00:00
|
|
|
if (not self.helper.tasknumber_total or self.helper.tasknumber_current == self.helper.tasknumber_total) and not len(activetasks):
|
2011-11-26 13:37:52 +00:00
|
|
|
return
|
|
|
|
tasks = []
|
|
|
|
for t in runningpids:
|
|
|
|
tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
|
|
|
|
|
2012-08-15 16:50:22 +00:00
|
|
|
if self.main.shutdown:
|
|
|
|
content = "Waiting for %s running tasks to finish:" % len(activetasks)
|
2012-09-27 21:56:02 +00:00
|
|
|
elif not len(activetasks):
|
|
|
|
content = "No currently running tasks (%s of %s)" % (self.helper.tasknumber_current, self.helper.tasknumber_total)
|
2011-11-26 13:37:52 +00:00
|
|
|
else:
|
2012-08-15 16:50:22 +00:00
|
|
|
content = "Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)
|
|
|
|
print content
|
|
|
|
lines = 1 + int(len(content) / (self.columns + 1))
|
2011-11-26 13:37:52 +00:00
|
|
|
for tasknum, task in enumerate(tasks):
|
2012-08-15 16:50:22 +00:00
|
|
|
content = "%s: %s" % (tasknum, task)
|
|
|
|
print content
|
|
|
|
lines = lines + 1 + int(len(content) / (self.columns + 1))
|
|
|
|
self.footer_present = lines
|
|
|
|
self.lastpids = runningpids[:]
|
2012-09-27 21:56:02 +00:00
|
|
|
self.lastcount = self.helper.tasknumber_current
|
2011-11-26 13:37:52 +00:00
|
|
|
|
|
|
|
def finish(self):
|
2012-08-15 16:50:22 +00:00
|
|
|
if self.stdinbackup:
|
|
|
|
fd = sys.stdin.fileno()
|
|
|
|
self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
|
2011-11-26 13:37:52 +00:00
|
|
|
|
|
|
|
def main(server, eventHandler, tf = TerminalFilter):
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
# Get values of variables which control our output
|
bitbake: command: add error to return of runCommand
Currently, command.py can return an error message from runCommand, due to
being unable to run the command, yet few of our UIs (just hob) can handle it
today. This can result in seeing a TypeError with traceback in certain rare
circumstances.
To resolve this, we need a clean way to get errors back from runCommand,
without having to isinstance() the return value. This implements such a thing
by making runCommand also return an error (or None if no error occurred).
As runCommand now has a method of returning errors, we can also alter the
getCmdLineAction bits such that the returned value is just the action, not an
additional message. If a sync command wants to return an error, it raises
CommandError(message), and the message will be passed to the caller
appropriately.
Example Usage:
result, error = server.runCommand(...)
if error:
log.error('Unable to run command: %s' % error)
return 1
(Bitbake rev: 717831b8315cb3904d9b590e633000bc897e8fb6)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-29 20:01:23 +00:00
|
|
|
includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error)
|
|
|
|
return 1
|
|
|
|
loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
|
|
|
|
return 1
|
|
|
|
consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error)
|
|
|
|
return 1
|
|
|
|
|
2012-09-17 22:43:49 +00:00
|
|
|
if sys.stdin.isatty() and sys.stdout.isatty():
|
|
|
|
log_exec_tty = True
|
|
|
|
else:
|
|
|
|
log_exec_tty = False
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2010-01-21 23:49:17 +00:00
|
|
|
helper = uihelper.BBUIHelper()
|
|
|
|
|
2010-06-10 15:05:52 +00:00
|
|
|
console = logging.StreamHandler(sys.stdout)
|
2012-11-16 01:29:40 +00:00
|
|
|
format_str = "%(levelname)s: %(message)s"
|
|
|
|
format = bb.msg.BBLogFormatter(format_str)
|
2011-08-12 22:24:43 +00:00
|
|
|
bb.msg.addDefaultlogFilter(console)
|
2010-06-10 15:05:52 +00:00
|
|
|
console.setFormatter(format)
|
|
|
|
logger.addHandler(console)
|
2011-11-24 14:45:37 +00:00
|
|
|
if consolelogfile:
|
2012-07-30 11:11:46 +00:00
|
|
|
bb.utils.mkdirhier(os.path.dirname(consolelogfile))
|
2012-11-25 21:17:41 +00:00
|
|
|
conlogformat = bb.msg.BBLogFormatter(format_str)
|
2011-11-24 14:45:37 +00:00
|
|
|
consolelog = logging.FileHandler(consolelogfile)
|
|
|
|
bb.msg.addDefaultlogFilter(consolelog)
|
2012-11-25 21:17:41 +00:00
|
|
|
consolelog.setFormatter(conlogformat)
|
2011-11-24 14:45:37 +00:00
|
|
|
logger.addHandler(consolelog)
|
2010-06-10 15:05:52 +00:00
|
|
|
|
2008-09-30 15:08:33 +00:00
|
|
|
try:
|
bitbake: command: add error to return of runCommand
Currently, command.py can return an error message from runCommand, due to
being unable to run the command, yet few of our UIs (just hob) can handle it
today. This can result in seeing a TypeError with traceback in certain rare
circumstances.
To resolve this, we need a clean way to get errors back from runCommand,
without having to isinstance() the return value. This implements such a thing
by making runCommand also return an error (or None if no error occurred).
As runCommand now has a method of returning errors, we can also alter the
getCmdLineAction bits such that the returned value is just the action, not an
additional message. If a sync command wants to return an error, it raises
CommandError(message), and the message will be passed to the caller
appropriately.
Example Usage:
result, error = server.runCommand(...)
if error:
log.error('Unable to run command: %s' % error)
return 1
(Bitbake rev: 717831b8315cb3904d9b590e633000bc897e8fb6)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-29 20:01:23 +00:00
|
|
|
cmdline, error = server.runCommand(["getCmdLineAction"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to get bitbake commandline arguments: %s" % error)
|
|
|
|
return 1
|
|
|
|
elif not cmdline:
|
2011-06-14 07:12:16 +00:00
|
|
|
print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
|
2008-09-30 15:08:33 +00:00
|
|
|
return 1
|
bitbake: command: add error to return of runCommand
Currently, command.py can return an error message from runCommand, due to
being unable to run the command, yet few of our UIs (just hob) can handle it
today. This can result in seeing a TypeError with traceback in certain rare
circumstances.
To resolve this, we need a clean way to get errors back from runCommand,
without having to isinstance() the return value. This implements such a thing
by making runCommand also return an error (or None if no error occurred).
As runCommand now has a method of returning errors, we can also alter the
getCmdLineAction bits such that the returned value is just the action, not an
additional message. If a sync command wants to return an error, it raises
CommandError(message), and the message will be passed to the caller
appropriately.
Example Usage:
result, error = server.runCommand(...)
if error:
log.error('Unable to run command: %s' % error)
return 1
(Bitbake rev: 717831b8315cb3904d9b590e633000bc897e8fb6)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-29 20:01:23 +00:00
|
|
|
ret, error = server.runCommand(cmdline)
|
|
|
|
if error:
|
|
|
|
logger.error("Command '%s' failed: %s" % (cmdline, error))
|
2011-06-14 07:12:16 +00:00
|
|
|
return 1
|
bitbake: command: add error to return of runCommand
Currently, command.py can return an error message from runCommand, due to
being unable to run the command, yet few of our UIs (just hob) can handle it
today. This can result in seeing a TypeError with traceback in certain rare
circumstances.
To resolve this, we need a clean way to get errors back from runCommand,
without having to isinstance() the return value. This implements such a thing
by making runCommand also return an error (or None if no error occurred).
As runCommand now has a method of returning errors, we can also alter the
getCmdLineAction bits such that the returned value is just the action, not an
additional message. If a sync command wants to return an error, it raises
CommandError(message), and the message will be passed to the caller
appropriately.
Example Usage:
result, error = server.runCommand(...)
if error:
log.error('Unable to run command: %s' % error)
return 1
(Bitbake rev: 717831b8315cb3904d9b590e633000bc897e8fb6)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-29 20:01:23 +00:00
|
|
|
elif ret != True:
|
|
|
|
logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
|
2008-09-30 15:08:33 +00:00
|
|
|
return 1
|
2010-04-12 00:03:55 +00:00
|
|
|
except xmlrpclib.Fault as x:
|
bitbake: command: add error to return of runCommand
Currently, command.py can return an error message from runCommand, due to
being unable to run the command, yet few of our UIs (just hob) can handle it
today. This can result in seeing a TypeError with traceback in certain rare
circumstances.
To resolve this, we need a clean way to get errors back from runCommand,
without having to isinstance() the return value. This implements such a thing
by making runCommand also return an error (or None if no error occurred).
As runCommand now has a method of returning errors, we can also alter the
getCmdLineAction bits such that the returned value is just the action, not an
additional message. If a sync command wants to return an error, it raises
CommandError(message), and the message will be passed to the caller
appropriately.
Example Usage:
result, error = server.runCommand(...)
if error:
log.error('Unable to run command: %s' % error)
return 1
(Bitbake rev: 717831b8315cb3904d9b590e633000bc897e8fb6)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-29 20:01:23 +00:00
|
|
|
logger.error("XMLRPC Fault getting commandline:\n %s" % x)
|
2008-09-30 15:08:33 +00:00
|
|
|
return 1
|
|
|
|
|
2010-12-07 04:06:13 +00:00
|
|
|
parseprogress = None
|
2010-11-22 15:13:56 +00:00
|
|
|
cacheprogress = None
|
2011-11-26 13:37:52 +00:00
|
|
|
main.shutdown = 0
|
2012-02-22 21:24:41 +00:00
|
|
|
interrupted = False
|
2008-09-30 15:08:33 +00:00
|
|
|
return_value = 0
|
2012-01-09 17:00:53 +00:00
|
|
|
errors = 0
|
|
|
|
warnings = 0
|
2012-01-13 17:01:52 +00:00
|
|
|
taskfailures = []
|
2011-11-26 13:37:52 +00:00
|
|
|
|
|
|
|
termfilter = tf(main, helper, console, format)
|
|
|
|
|
2008-09-30 15:08:33 +00:00
|
|
|
while True:
|
|
|
|
try:
|
2011-11-26 13:37:52 +00:00
|
|
|
termfilter.updateFooter()
|
2008-09-30 15:08:33 +00:00
|
|
|
event = eventHandler.waitEvent(0.25)
|
|
|
|
if event is None:
|
2011-11-26 13:37:52 +00:00
|
|
|
if main.shutdown > 1:
|
2012-02-07 18:07:40 +00:00
|
|
|
break
|
2008-09-30 15:08:33 +00:00
|
|
|
continue
|
2010-01-21 23:49:17 +00:00
|
|
|
helper.eventHandler(event)
|
|
|
|
if isinstance(event, bb.runqueue.runQueueExitWait):
|
2011-11-26 13:37:52 +00:00
|
|
|
if not main.shutdown:
|
|
|
|
main.shutdown = 1
|
2010-01-21 23:49:17 +00:00
|
|
|
|
2012-09-17 22:43:49 +00:00
|
|
|
if isinstance(event, bb.event.LogExecTTY):
|
|
|
|
if log_exec_tty:
|
|
|
|
tries = event.retries
|
|
|
|
while tries:
|
|
|
|
print "Trying to run: %s" % event.prog
|
|
|
|
if os.system(event.prog) == 0:
|
|
|
|
break
|
|
|
|
time.sleep(event.sleep_delay)
|
|
|
|
tries -= 1
|
|
|
|
if tries:
|
|
|
|
continue
|
|
|
|
logger.warn(event.msg)
|
|
|
|
continue
|
|
|
|
|
2010-06-10 15:05:52 +00:00
|
|
|
if isinstance(event, logging.LogRecord):
|
2011-01-07 23:54:42 +00:00
|
|
|
if event.levelno >= format.ERROR:
|
2012-01-09 17:00:53 +00:00
|
|
|
errors = errors + 1
|
2010-06-10 15:05:52 +00:00
|
|
|
return_value = 1
|
2012-01-13 17:01:45 +00:00
|
|
|
elif event.levelno == format.WARNING:
|
2012-01-09 17:00:53 +00:00
|
|
|
warnings = warnings + 1
|
2011-01-12 13:45:39 +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
|
2011-08-12 22:24:43 +00:00
|
|
|
if event.taskpid != 0 and event.levelno <= format.NOTE:
|
2012-01-09 17:00:53 +00:00
|
|
|
continue
|
2010-06-10 15:05:52 +00:00
|
|
|
logger.handle(event)
|
2010-08-20 11:24:13 +00:00
|
|
|
continue
|
2010-06-10 15:05:52 +00:00
|
|
|
|
2010-01-19 14:48:19 +00:00
|
|
|
if isinstance(event, bb.build.TaskFailed):
|
2008-09-30 15:08:33 +00:00
|
|
|
return_value = 1
|
2010-01-19 14:48:19 +00:00
|
|
|
logfile = event.logfile
|
2010-06-10 17:44:20 +00:00
|
|
|
if logfile and os.path.exists(logfile):
|
2011-11-26 13:37:52 +00:00
|
|
|
termfilter.clearFooter()
|
2012-12-13 10:55:25 +00:00
|
|
|
bb.error("Logfile of failure stored in: %s" % logfile)
|
2012-01-13 17:01:49 +00:00
|
|
|
if includelogs and not event.errprinted:
|
2010-04-10 02:46:14 +00:00
|
|
|
print("Log data follows:")
|
2008-09-30 15:08:33 +00:00
|
|
|
f = open(logfile, "r")
|
|
|
|
lines = []
|
|
|
|
while True:
|
|
|
|
l = f.readline()
|
|
|
|
if l == '':
|
|
|
|
break
|
|
|
|
l = l.rstrip()
|
|
|
|
if loglines:
|
|
|
|
lines.append(' | %s' % l)
|
|
|
|
if len(lines) > int(loglines):
|
|
|
|
lines.pop(0)
|
|
|
|
else:
|
2010-04-10 02:46:14 +00:00
|
|
|
print('| %s' % l)
|
2008-09-30 15:08:33 +00:00
|
|
|
f.close()
|
|
|
|
if lines:
|
|
|
|
for line in lines:
|
2010-04-10 02:46:14 +00:00
|
|
|
print(line)
|
2010-01-19 14:48:19 +00:00
|
|
|
if isinstance(event, bb.build.TaskBase):
|
2010-06-10 15:05:52 +00:00
|
|
|
logger.info(event._message)
|
2008-09-30 15:08:33 +00:00
|
|
|
continue
|
2010-11-19 05:47:36 +00:00
|
|
|
if isinstance(event, bb.event.ParseStarted):
|
2011-04-10 17:55:48 +00:00
|
|
|
if event.total == 0:
|
|
|
|
continue
|
2010-11-22 15:13:56 +00:00
|
|
|
parseprogress = new_progress("Parsing recipes", event.total).start()
|
2010-11-19 05:47:36 +00:00
|
|
|
continue
|
2010-01-19 14:48:19 +00:00
|
|
|
if isinstance(event, bb.event.ParseProgress):
|
2010-12-07 04:06:13 +00:00
|
|
|
parseprogress.update(event.current)
|
2010-11-19 05:47:36 +00:00
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.ParseCompleted):
|
2011-04-10 17:55:48 +00:00
|
|
|
if not parseprogress:
|
|
|
|
continue
|
|
|
|
|
2010-12-07 04:06:13 +00:00
|
|
|
parseprogress.finish()
|
|
|
|
print(("Parsing of %d .bb files complete (%d cached, %d parsed). %d targets, %d skipped, %d masked, %d errors."
|
2010-11-19 05:47:36 +00:00
|
|
|
% ( event.total, event.cached, event.parsed, event.virtuals, event.skipped, event.masked, event.errors)))
|
2008-09-30 15:08:33 +00:00
|
|
|
continue
|
|
|
|
|
2010-11-22 15:13:56 +00:00
|
|
|
if isinstance(event, bb.event.CacheLoadStarted):
|
|
|
|
cacheprogress = new_progress("Loading cache", event.total).start()
|
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.CacheLoadProgress):
|
|
|
|
cacheprogress.update(event.current)
|
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.CacheLoadCompleted):
|
|
|
|
cacheprogress.finish()
|
|
|
|
print("Loaded %d entries from dependency cache." % event.num_entries)
|
|
|
|
continue
|
|
|
|
|
2010-12-10 23:53:19 +00:00
|
|
|
if isinstance(event, bb.command.CommandFailed):
|
2010-01-19 14:48:19 +00:00
|
|
|
return_value = event.exitcode
|
2012-02-13 11:41:33 +00:00
|
|
|
errors = errors + 1
|
2010-12-17 21:46:41 +00:00
|
|
|
logger.error("Command execution failed: %s", event.error)
|
2011-11-26 13:37:52 +00:00
|
|
|
main.shutdown = 2
|
2012-02-07 18:07:40 +00:00
|
|
|
continue
|
2010-12-10 23:53:19 +00:00
|
|
|
if isinstance(event, bb.command.CommandExit):
|
2011-08-09 11:34:11 +00:00
|
|
|
if not return_value:
|
|
|
|
return_value = event.exitcode
|
2010-12-10 23:53:19 +00:00
|
|
|
continue
|
2012-02-07 18:07:40 +00:00
|
|
|
if isinstance(event, (bb.command.CommandCompleted, bb.cooker.CookerExit)):
|
2011-11-26 13:37:52 +00:00
|
|
|
main.shutdown = 2
|
2012-02-07 18:07:40 +00:00
|
|
|
continue
|
2010-06-08 20:20:35 +00:00
|
|
|
if isinstance(event, bb.event.MultipleProviders):
|
2010-06-10 15:05:52 +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)
|
2010-06-08 20:20:35 +00:00
|
|
|
continue
|
|
|
|
if isinstance(event, bb.event.NoProvider):
|
2011-08-09 11:29:17 +00:00
|
|
|
return_value = 1
|
2012-01-09 17:00:53 +00:00
|
|
|
errors = errors + 1
|
2010-06-08 20:20:35 +00:00
|
|
|
if event._runtime:
|
|
|
|
r = "R"
|
|
|
|
else:
|
|
|
|
r = ""
|
|
|
|
|
|
|
|
if event._dependees:
|
2010-06-10 15:05:52 +00:00
|
|
|
logger.error("Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)", r, event._item, ", ".join(event._dependees), r)
|
2010-06-08 20:20:35 +00:00
|
|
|
else:
|
2010-06-10 15:05:52 +00:00
|
|
|
logger.error("Nothing %sPROVIDES '%s'", r, event._item)
|
2011-07-25 13:54:41 +00:00
|
|
|
if event._reasons:
|
|
|
|
for reason in event._reasons:
|
|
|
|
logger.error("%s", reason)
|
2010-06-08 20:20:35 +00:00
|
|
|
continue
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2012-02-27 18:54:11 +00:00
|
|
|
if isinstance(event, bb.runqueue.sceneQueueTaskStarted):
|
|
|
|
logger.info("Running setscene task %d of %d (%s)" % (event.stats.completed + event.stats.active + event.stats.failed + 1, event.stats.total, event.taskstring))
|
|
|
|
continue
|
|
|
|
|
2010-12-06 21:58:55 +00:00
|
|
|
if isinstance(event, bb.runqueue.runQueueTaskStarted):
|
2011-01-01 14:36:38 +00:00
|
|
|
if event.noexec:
|
|
|
|
tasktype = 'noexec task'
|
|
|
|
else:
|
|
|
|
tasktype = 'task'
|
|
|
|
logger.info("Running %s %s of %s (ID: %s, %s)",
|
|
|
|
tasktype,
|
|
|
|
event.stats.completed + event.stats.active +
|
|
|
|
event.stats.failed + 1,
|
2010-12-06 21:58:55 +00:00
|
|
|
event.stats.total, event.taskid, event.taskstring)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if isinstance(event, bb.runqueue.runQueueTaskFailed):
|
2012-01-13 17:01:52 +00:00
|
|
|
taskfailures.append(event.taskstring)
|
2010-12-06 21:58:55 +00:00
|
|
|
logger.error("Task %s (%s) failed with exit code '%s'",
|
|
|
|
event.taskid, event.taskstring, event.exitcode)
|
|
|
|
continue
|
|
|
|
|
2012-02-27 18:54:11 +00:00
|
|
|
if isinstance(event, bb.runqueue.sceneQueueTaskFailed):
|
|
|
|
logger.warn("Setscene task %s (%s) failed with exit code '%s' - real task will be run instead",
|
|
|
|
event.taskid, event.taskstring, event.exitcode)
|
|
|
|
continue
|
|
|
|
|
2008-09-30 15:08:33 +00:00
|
|
|
# ignore
|
2010-06-08 18:42:49 +00:00
|
|
|
if isinstance(event, (bb.event.BuildBase,
|
|
|
|
bb.event.StampUpdate,
|
|
|
|
bb.event.ConfigParsed,
|
|
|
|
bb.event.RecipeParsed,
|
2011-06-09 16:30:17 +00:00
|
|
|
bb.event.RecipePreFinalise,
|
2010-06-08 18:42:49 +00:00
|
|
|
bb.runqueue.runQueueEvent,
|
2012-02-23 13:47:16 +00:00
|
|
|
bb.runqueue.runQueueExitWait,
|
|
|
|
bb.event.OperationStarted,
|
|
|
|
bb.event.OperationCompleted,
|
2013-02-01 08:56:45 +00:00
|
|
|
bb.event.OperationProgress,
|
|
|
|
bb.event.DiskFull)):
|
2009-10-17 19:11:27 +00:00
|
|
|
continue
|
2010-06-08 20:20:35 +00:00
|
|
|
|
2010-06-10 15:05:52 +00:00
|
|
|
logger.error("Unknown event: %s", event)
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2010-12-17 15:20:39 +00:00
|
|
|
except EnvironmentError as ioerror:
|
2011-11-26 13:37:52 +00:00
|
|
|
termfilter.clearFooter()
|
2010-12-17 15:20:39 +00:00
|
|
|
# ignore interrupted io
|
|
|
|
if ioerror.args[0] == 4:
|
|
|
|
pass
|
2008-09-30 15:08:33 +00:00
|
|
|
except KeyboardInterrupt:
|
2011-11-26 13:37:52 +00:00
|
|
|
termfilter.clearFooter()
|
|
|
|
if main.shutdown == 1:
|
2010-04-10 02:46:14 +00:00
|
|
|
print("\nSecond Keyboard Interrupt, stopping...\n")
|
bitbake: command: add error to return of runCommand
Currently, command.py can return an error message from runCommand, due to
being unable to run the command, yet few of our UIs (just hob) can handle it
today. This can result in seeing a TypeError with traceback in certain rare
circumstances.
To resolve this, we need a clean way to get errors back from runCommand,
without having to isinstance() the return value. This implements such a thing
by making runCommand also return an error (or None if no error occurred).
As runCommand now has a method of returning errors, we can also alter the
getCmdLineAction bits such that the returned value is just the action, not an
additional message. If a sync command wants to return an error, it raises
CommandError(message), and the message will be passed to the caller
appropriately.
Example Usage:
result, error = server.runCommand(...)
if error:
log.error('Unable to run command: %s' % error)
return 1
(Bitbake rev: 717831b8315cb3904d9b590e633000bc897e8fb6)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-29 20:01:23 +00:00
|
|
|
_, error = server.runCommand(["stateStop"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to cleanly stop: %s" % error)
|
2011-11-26 13:37:52 +00:00
|
|
|
if main.shutdown == 0:
|
2010-04-10 02:46:14 +00:00
|
|
|
print("\nKeyboard Interrupt, closing down...\n")
|
bitbake: command: add error to return of runCommand
Currently, command.py can return an error message from runCommand, due to
being unable to run the command, yet few of our UIs (just hob) can handle it
today. This can result in seeing a TypeError with traceback in certain rare
circumstances.
To resolve this, we need a clean way to get errors back from runCommand,
without having to isinstance() the return value. This implements such a thing
by making runCommand also return an error (or None if no error occurred).
As runCommand now has a method of returning errors, we can also alter the
getCmdLineAction bits such that the returned value is just the action, not an
additional message. If a sync command wants to return an error, it raises
CommandError(message), and the message will be passed to the caller
appropriately.
Example Usage:
result, error = server.runCommand(...)
if error:
log.error('Unable to run command: %s' % error)
return 1
(Bitbake rev: 717831b8315cb3904d9b590e633000bc897e8fb6)
Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-29 20:01:23 +00:00
|
|
|
interrupted = True
|
|
|
|
_, error = server.runCommand(["stateShutdown"])
|
|
|
|
if error:
|
|
|
|
logger.error("Unable to cleanly shutdown: %s" % error)
|
2011-11-26 13:37:52 +00:00
|
|
|
main.shutdown = main.shutdown + 1
|
2008-09-30 15:08:33 +00:00
|
|
|
pass
|
2012-01-13 17:01:52 +00:00
|
|
|
|
|
|
|
summary = ""
|
|
|
|
if taskfailures:
|
|
|
|
summary += pluralise("\nSummary: %s task failed:",
|
|
|
|
"\nSummary: %s tasks failed:", len(taskfailures))
|
|
|
|
for failure in taskfailures:
|
|
|
|
summary += "\n %s" % failure
|
2012-01-09 17:00:53 +00:00
|
|
|
if warnings:
|
2012-01-13 17:01:52 +00:00
|
|
|
summary += pluralise("\nSummary: There was %s WARNING message shown.",
|
|
|
|
"\nSummary: There were %s WARNING messages shown.", warnings)
|
2012-01-09 17:00:53 +00:00
|
|
|
if return_value:
|
2012-01-13 17:01:52 +00:00
|
|
|
summary += pluralise("\nSummary: There was %s ERROR message shown, returning a non-zero exit code.",
|
|
|
|
"\nSummary: There were %s ERROR messages shown, returning a non-zero exit code.", errors)
|
|
|
|
if summary:
|
|
|
|
print(summary)
|
|
|
|
|
2012-02-22 21:24:41 +00:00
|
|
|
if interrupted:
|
2012-02-13 11:41:32 +00:00
|
|
|
print("Execution was interrupted, returning a non-zero exit code.")
|
|
|
|
if return_value == 0:
|
|
|
|
return_value = 1
|
|
|
|
|
2011-11-26 13:37:52 +00:00
|
|
|
termfilter.finish()
|
|
|
|
|
2008-09-30 15:08:33 +00:00
|
|
|
return return_value
|