blob: 88f638fb3832a853d65ffa03677febc4ab74c909 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# BitBake (No)TTY UI Implementation
3#
4# Handling output to TTYs or files (no TTY)
5#
6# Copyright (C) 2006-2012 Richard Purdie
7#
Brad Bishopc342db32019-05-15 21:57:59 -04008# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -05009#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010
11from __future__ import division
12
13import os
14import sys
Patrick Williamsc0f7c042017-02-23 20:41:17 -060015import xmlrpc.client as xmlrpclib
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016import logging
17import progressbar
18import signal
19import bb.msg
20import time
21import fcntl
22import struct
23import copy
24import atexit
Patrick Williamsc0f7c042017-02-23 20:41:17 -060025
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026from bb.ui import uihelper
27
28featureSet = [bb.cooker.CookerFeatures.SEND_SANITYEVENTS]
29
30logger = logging.getLogger("BitBake")
31interactive = sys.stdout.isatty()
32
33class BBProgress(progressbar.ProgressBar):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060034 def __init__(self, msg, maxval, widgets=None, extrapos=-1, resize_handler=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035 self.msg = msg
Patrick Williamsc0f7c042017-02-23 20:41:17 -060036 self.extrapos = extrapos
37 if not widgets:
38 widgets = [progressbar.Percentage(), ' ', progressbar.Bar(), ' ',
39 progressbar.ETA()]
40 self.extrapos = 4
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041
Patrick Williamsc0f7c042017-02-23 20:41:17 -060042 if resize_handler:
43 self._resize_default = resize_handler
44 else:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045 self._resize_default = signal.getsignal(signal.SIGWINCH)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046 progressbar.ProgressBar.__init__(self, maxval, [self.msg + ": "] + widgets, fd=sys.stdout)
47
Patrick Williamsc0f7c042017-02-23 20:41:17 -060048 def _handle_resize(self, signum=None, frame=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049 progressbar.ProgressBar._handle_resize(self, signum, frame)
50 if self._resize_default:
51 self._resize_default(signum, frame)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060052
Patrick Williamsc124f4f2015-09-15 14:41:29 -050053 def finish(self):
54 progressbar.ProgressBar.finish(self)
55 if self._resize_default:
56 signal.signal(signal.SIGWINCH, self._resize_default)
57
Patrick Williamsc0f7c042017-02-23 20:41:17 -060058 def setmessage(self, msg):
59 self.msg = msg
60 self.widgets[0] = msg
61
62 def setextra(self, extra):
63 if self.extrapos > -1:
64 if extra:
65 extrastr = str(extra)
66 if extrastr[0] != ' ':
67 extrastr = ' ' + extrastr
Patrick Williamsc0f7c042017-02-23 20:41:17 -060068 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050069 extrastr = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -060070 self.widgets[self.extrapos] = extrastr
71
72 def _need_update(self):
73 # We always want the bar to print when update() is called
74 return True
75
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076class NonInteractiveProgress(object):
77 fobj = sys.stdout
78
79 def __init__(self, msg, maxval):
80 self.msg = msg
81 self.maxval = maxval
Patrick Williamsc0f7c042017-02-23 20:41:17 -060082 self.finished = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050083
Patrick Williamsc0f7c042017-02-23 20:41:17 -060084 def start(self, update=True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050085 self.fobj.write("%s..." % self.msg)
86 self.fobj.flush()
87 return self
88
89 def update(self, value):
90 pass
91
92 def finish(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060093 if self.finished:
94 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -050095 self.fobj.write("done.\n")
96 self.fobj.flush()
Patrick Williamsc0f7c042017-02-23 20:41:17 -060097 self.finished = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -050098
99def new_progress(msg, maxval):
100 if interactive:
101 return BBProgress(msg, maxval)
102 else:
103 return NonInteractiveProgress(msg, maxval)
104
105def pluralise(singular, plural, qty):
106 if(qty == 1):
107 return singular % qty
108 else:
109 return plural % qty
110
111
112class InteractConsoleLogFilter(logging.Filter):
113 def __init__(self, tf, format):
114 self.tf = tf
115 self.format = format
116
117 def filter(self, record):
118 if record.levelno == self.format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("recipe ")):
119 return False
120 self.tf.clearFooter()
121 return True
122
123class TerminalFilter(object):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500124 rows = 25
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 columns = 80
126
127 def sigwinch_handle(self, signum, frame):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500128 self.rows, self.columns = self.getTerminalColumns()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 if self._sigwinch_default:
130 self._sigwinch_default(signum, frame)
131
132 def getTerminalColumns(self):
133 def ioctl_GWINSZ(fd):
134 try:
135 cr = struct.unpack('hh', fcntl.ioctl(fd, self.termios.TIOCGWINSZ, '1234'))
136 except:
137 return None
138 return cr
139 cr = ioctl_GWINSZ(sys.stdout.fileno())
140 if not cr:
141 try:
142 fd = os.open(os.ctermid(), os.O_RDONLY)
143 cr = ioctl_GWINSZ(fd)
144 os.close(fd)
145 except:
146 pass
147 if not cr:
148 try:
149 cr = (env['LINES'], env['COLUMNS'])
150 except:
151 cr = (25, 80)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500152 return cr
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500153
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600154 def __init__(self, main, helper, console, errconsole, format, quiet):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500155 self.main = main
156 self.helper = helper
157 self.cuu = None
158 self.stdinbackup = None
159 self.interactive = sys.stdout.isatty()
160 self.footer_present = False
161 self.lastpids = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600162 self.lasttime = None
163 self.quiet = quiet
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500164
165 if not self.interactive:
166 return
167
168 try:
169 import curses
170 except ImportError:
171 sys.exit("FATAL: The knotty ui could not load the required curses python module.")
172
173 import termios
174 self.curses = curses
175 self.termios = termios
176 try:
177 fd = sys.stdin.fileno()
178 self.stdinbackup = termios.tcgetattr(fd)
179 new = copy.deepcopy(self.stdinbackup)
180 new[3] = new[3] & ~termios.ECHO
181 termios.tcsetattr(fd, termios.TCSADRAIN, new)
182 curses.setupterm()
183 if curses.tigetnum("colors") > 2:
184 format.enable_color()
185 self.ed = curses.tigetstr("ed")
186 if self.ed:
187 self.cuu = curses.tigetstr("cuu")
188 try:
189 self._sigwinch_default = signal.getsignal(signal.SIGWINCH)
190 signal.signal(signal.SIGWINCH, self.sigwinch_handle)
191 except:
192 pass
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500193 self.rows, self.columns = self.getTerminalColumns()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500194 except:
195 self.cuu = None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500196 if not self.cuu:
197 self.interactive = False
198 bb.note("Unable to use interactive mode for this terminal, using fallback")
199 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500200 if console:
201 console.addFilter(InteractConsoleLogFilter(self, format))
202 if errconsole:
203 errconsole.addFilter(InteractConsoleLogFilter(self, format))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500204
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600205 self.main_progress = None
206
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500207 def clearFooter(self):
208 if self.footer_present:
209 lines = self.footer_present
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600210 sys.stdout.buffer.write(self.curses.tparm(self.cuu, lines))
211 sys.stdout.buffer.write(self.curses.tparm(self.ed))
212 sys.stdout.flush()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500213 self.footer_present = False
214
Brad Bishopc342db32019-05-15 21:57:59 -0400215 def elapsed(self, sec):
216 hrs = int(sec / 3600.0)
217 sec -= hrs * 3600
218 min = int(sec / 60.0)
219 sec -= min * 60
220 if hrs > 0:
221 return "%dh%dm%ds" % (hrs, min, sec)
222 elif min > 0:
223 return "%dm%ds" % (min, sec)
224 else:
225 return "%ds" % (sec)
226
227 def keepAlive(self, t):
228 if not self.cuu:
229 print("Bitbake still alive (%ds)" % t)
230 sys.stdout.flush()
231
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500232 def updateFooter(self):
233 if not self.cuu:
234 return
235 activetasks = self.helper.running_tasks
236 failedtasks = self.helper.failed_tasks
237 runningpids = self.helper.running_pids
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600238 currenttime = time.time()
239 if not self.lasttime or (currenttime - self.lasttime > 5):
240 self.helper.needUpdate = True
241 self.lasttime = currenttime
242 if self.footer_present and not self.helper.needUpdate:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243 return
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600244 self.helper.needUpdate = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500245 if self.footer_present:
246 self.clearFooter()
247 if (not self.helper.tasknumber_total or self.helper.tasknumber_current == self.helper.tasknumber_total) and not len(activetasks):
248 return
249 tasks = []
250 for t in runningpids:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600251 progress = activetasks[t].get("progress", None)
252 if progress is not None:
253 pbar = activetasks[t].get("progressbar", None)
254 rate = activetasks[t].get("rate", None)
255 start_time = activetasks[t].get("starttime", None)
256 if not pbar or pbar.bouncing != (progress < 0):
257 if progress < 0:
258 pbar = BBProgress("0: %s (pid %s) " % (activetasks[t]["title"], t), 100, widgets=[progressbar.BouncingSlider(), ''], extrapos=2, resize_handler=self.sigwinch_handle)
259 pbar.bouncing = True
260 else:
261 pbar = BBProgress("0: %s (pid %s) " % (activetasks[t]["title"], t), 100, widgets=[progressbar.Percentage(), ' ', progressbar.Bar(), ''], extrapos=4, resize_handler=self.sigwinch_handle)
262 pbar.bouncing = False
263 activetasks[t]["progressbar"] = pbar
264 tasks.append((pbar, progress, rate, start_time))
265 else:
266 start_time = activetasks[t].get("starttime", None)
267 if start_time:
Brad Bishopc342db32019-05-15 21:57:59 -0400268 tasks.append("%s - %s (pid %s)" % (activetasks[t]["title"], self.elapsed(currenttime - start_time), t))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600269 else:
270 tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500271
272 if self.main.shutdown:
273 content = "Waiting for %s running tasks to finish:" % len(activetasks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500274 print(content)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600275 else:
276 if self.quiet:
277 content = "Running tasks (%s of %s)" % (self.helper.tasknumber_current, self.helper.tasknumber_total)
278 elif not len(activetasks):
279 content = "No currently running tasks (%s of %s)" % (self.helper.tasknumber_current, self.helper.tasknumber_total)
280 else:
281 content = "Currently %2s running tasks (%s of %s)" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)
282 maxtask = self.helper.tasknumber_total
283 if not self.main_progress or self.main_progress.maxval != maxtask:
284 widgets = [' ', progressbar.Percentage(), ' ', progressbar.Bar()]
285 self.main_progress = BBProgress("Running tasks", maxtask, widgets=widgets, resize_handler=self.sigwinch_handle)
286 self.main_progress.start(False)
287 self.main_progress.setmessage(content)
288 progress = self.helper.tasknumber_current - 1
289 if progress < 0:
290 progress = 0
291 content = self.main_progress.update(progress)
292 print('')
293 lines = 1 + int(len(content) / (self.columns + 1))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500294 if self.quiet == 0:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600295 for tasknum, task in enumerate(tasks[:(self.rows - 2)]):
296 if isinstance(task, tuple):
297 pbar, progress, rate, start_time = task
298 if not pbar.start_time:
299 pbar.start(False)
300 if start_time:
301 pbar.start_time = start_time
302 pbar.setmessage('%s:%s' % (tasknum, pbar.msg.split(':', 1)[1]))
Brad Bishop15ae2502019-06-18 21:44:24 -0400303 pbar.setextra(rate)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600304 if progress > -1:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600305 content = pbar.update(progress)
306 else:
307 content = pbar.update(1)
308 print('')
309 else:
310 content = "%s: %s" % (tasknum, task)
311 print(content)
312 lines = lines + 1 + int(len(content) / (self.columns + 1))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500313 self.footer_present = lines
314 self.lastpids = runningpids[:]
315 self.lastcount = self.helper.tasknumber_current
316
317 def finish(self):
318 if self.stdinbackup:
319 fd = sys.stdin.fileno()
320 self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
321
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500322def print_event_log(event, includelogs, loglines, termfilter):
323 # FIXME refactor this out further
324 logfile = event.logfile
325 if logfile and os.path.exists(logfile):
326 termfilter.clearFooter()
327 bb.error("Logfile of failure stored in: %s" % logfile)
328 if includelogs and not event.errprinted:
329 print("Log data follows:")
330 f = open(logfile, "r")
331 lines = []
332 while True:
333 l = f.readline()
334 if l == '':
335 break
336 l = l.rstrip()
337 if loglines:
338 lines.append(' | %s' % l)
339 if len(lines) > int(loglines):
340 lines.pop(0)
341 else:
342 print('| %s' % l)
343 f.close()
344 if lines:
345 for line in lines:
346 print(line)
347
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500348def _log_settings_from_server(server, observe_only):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500349 # Get values of variables which control our output
350 includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
351 if error:
352 logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error)
353 raise BaseException(error)
354 loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
355 if error:
356 logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
357 raise BaseException(error)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500358 if observe_only:
359 cmd = 'getVariable'
360 else:
361 cmd = 'getSetVariable'
362 consolelogfile, error = server.runCommand([cmd, "BB_CONSOLELOG"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500363 if error:
364 logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error)
365 raise BaseException(error)
366 return includelogs, loglines, consolelogfile
367
368_evt_list = [ "bb.runqueue.runQueueExitWait", "bb.event.LogExecTTY", "logging.LogRecord",
369 "bb.build.TaskFailed", "bb.build.TaskBase", "bb.event.ParseStarted",
370 "bb.event.ParseProgress", "bb.event.ParseCompleted", "bb.event.CacheLoadStarted",
371 "bb.event.CacheLoadProgress", "bb.event.CacheLoadCompleted", "bb.command.CommandFailed",
372 "bb.command.CommandExit", "bb.command.CommandCompleted", "bb.cooker.CookerExit",
373 "bb.event.MultipleProviders", "bb.event.NoProvider", "bb.runqueue.sceneQueueTaskStarted",
374 "bb.runqueue.runQueueTaskStarted", "bb.runqueue.runQueueTaskFailed", "bb.runqueue.sceneQueueTaskFailed",
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600375 "bb.event.BuildBase", "bb.build.TaskStarted", "bb.build.TaskSucceeded", "bb.build.TaskFailedSilent",
376 "bb.build.TaskProgress", "bb.event.ProcessStarted", "bb.event.ProcessProgress", "bb.event.ProcessFinished"]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500377
378def main(server, eventHandler, params, tf = TerminalFilter):
379
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500380 if not params.observe_only:
381 params.updateToServer(server, os.environ.copy())
382
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500383 includelogs, loglines, consolelogfile = _log_settings_from_server(server, params.observe_only)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500384
385 if sys.stdin.isatty() and sys.stdout.isatty():
386 log_exec_tty = True
387 else:
388 log_exec_tty = False
389
390 helper = uihelper.BBUIHelper()
391
392 console = logging.StreamHandler(sys.stdout)
393 errconsole = logging.StreamHandler(sys.stderr)
394 format_str = "%(levelname)s: %(message)s"
395 format = bb.msg.BBLogFormatter(format_str)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500396 if params.options.quiet == 0:
397 forcelevel = None
398 elif params.options.quiet > 2:
399 forcelevel = bb.msg.BBLogFormatter.ERROR
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600400 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500401 forcelevel = bb.msg.BBLogFormatter.WARNING
402 bb.msg.addDefaultlogFilter(console, bb.msg.BBLogFilterStdOut, forcelevel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403 bb.msg.addDefaultlogFilter(errconsole, bb.msg.BBLogFilterStdErr)
404 console.setFormatter(format)
405 errconsole.setFormatter(format)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500406 if not bb.msg.has_console_handler(logger):
407 logger.addHandler(console)
408 logger.addHandler(errconsole)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500409
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500410 bb.utils.set_process_name("KnottyUI")
411
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500412 if params.options.remote_server and params.options.kill_server:
413 server.terminateServer()
414 return
415
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600416 consolelog = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500417 if consolelogfile and not params.options.show_environment and not params.options.show_versions:
418 bb.utils.mkdirhier(os.path.dirname(consolelogfile))
419 conlogformat = bb.msg.BBLogFormatter(format_str)
420 consolelog = logging.FileHandler(consolelogfile)
421 bb.msg.addDefaultlogFilter(consolelog)
422 consolelog.setFormatter(conlogformat)
423 logger.addHandler(consolelog)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600424 loglink = os.path.join(os.path.dirname(consolelogfile), 'console-latest.log')
425 bb.utils.remove(loglink)
426 try:
427 os.symlink(os.path.basename(consolelogfile), loglink)
428 except OSError:
429 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500430
431 llevel, debug_domains = bb.msg.constructLogOptions()
432 server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list])
433
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500434 universe = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435 if not params.observe_only:
436 params.updateFromServer(server)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500437 cmdline = params.parseActions()
438 if not cmdline:
439 print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
440 return 1
441 if 'msg' in cmdline and cmdline['msg']:
442 logger.error(cmdline['msg'])
443 return 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500444 if cmdline['action'][0] == "buildTargets" and "universe" in cmdline['action'][1]:
445 universe = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500446
447 ret, error = server.runCommand(cmdline['action'])
448 if error:
449 logger.error("Command '%s' failed: %s" % (cmdline, error))
450 return 1
451 elif ret != True:
452 logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
453 return 1
454
455
456 parseprogress = None
457 cacheprogress = None
458 main.shutdown = 0
459 interrupted = False
460 return_value = 0
461 errors = 0
462 warnings = 0
463 taskfailures = []
464
Brad Bishopc342db32019-05-15 21:57:59 -0400465 printinterval = 5000
466 lastprint = time.time()
467
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600468 termfilter = tf(main, helper, console, errconsole, format, params.options.quiet)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500469 atexit.register(termfilter.finish)
470
471 while True:
472 try:
Brad Bishopc342db32019-05-15 21:57:59 -0400473 if (lastprint + printinterval) <= time.time():
474 termfilter.keepAlive(printinterval)
475 printinterval += 5000
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500476 event = eventHandler.waitEvent(0)
477 if event is None:
478 if main.shutdown > 1:
479 break
480 termfilter.updateFooter()
481 event = eventHandler.waitEvent(0.25)
482 if event is None:
483 continue
484 helper.eventHandler(event)
485 if isinstance(event, bb.runqueue.runQueueExitWait):
486 if not main.shutdown:
487 main.shutdown = 1
488 continue
489 if isinstance(event, bb.event.LogExecTTY):
490 if log_exec_tty:
491 tries = event.retries
492 while tries:
493 print("Trying to run: %s" % event.prog)
494 if os.system(event.prog) == 0:
495 break
496 time.sleep(event.sleep_delay)
497 tries -= 1
498 if tries:
499 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600500 logger.warning(event.msg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500501 continue
502
503 if isinstance(event, logging.LogRecord):
Brad Bishopc342db32019-05-15 21:57:59 -0400504 lastprint = time.time()
505 printinterval = 5000
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500506 if event.levelno >= format.ERROR:
507 errors = errors + 1
508 return_value = 1
509 elif event.levelno == format.WARNING:
510 warnings = warnings + 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500511
512 if event.taskpid != 0:
513 # For "normal" logging conditions, don't show note logs from tasks
514 # but do show them if the user has changed the default log level to
515 # include verbose/debug messages
516 if event.levelno <= format.NOTE and (event.levelno < llevel or (event.levelno == format.NOTE and llevel != format.VERBOSE)):
517 continue
518
519 # Prefix task messages with recipe/task
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500520 if event.taskpid in helper.running_tasks and event.levelno != format.PLAIN:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500521 taskinfo = helper.running_tasks[event.taskpid]
522 event.msg = taskinfo['title'] + ': ' + event.msg
523 if hasattr(event, 'fn'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500524 event.msg = event.fn + ': ' + event.msg
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500525 logger.handle(event)
526 continue
527
528 if isinstance(event, bb.build.TaskFailedSilent):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600529 logger.warning("Logfile for failed setscene task is %s" % event.logfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500530 continue
531 if isinstance(event, bb.build.TaskFailed):
532 return_value = 1
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500533 print_event_log(event, includelogs, loglines, termfilter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500534 if isinstance(event, bb.build.TaskBase):
535 logger.info(event._message)
536 continue
537 if isinstance(event, bb.event.ParseStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500538 if params.options.quiet > 1:
539 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500540 if event.total == 0:
541 continue
542 parseprogress = new_progress("Parsing recipes", event.total).start()
543 continue
544 if isinstance(event, bb.event.ParseProgress):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500545 if params.options.quiet > 1:
546 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600547 if parseprogress:
548 parseprogress.update(event.current)
549 else:
550 bb.warn("Got ParseProgress event for parsing that never started?")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500551 continue
552 if isinstance(event, bb.event.ParseCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500553 if params.options.quiet > 1:
554 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500555 if not parseprogress:
556 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500557 parseprogress.finish()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600558 pasreprogress = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500559 if params.options.quiet == 0:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600560 print(("Parsing of %d .bb files complete (%d cached, %d parsed). %d targets, %d skipped, %d masked, %d errors."
561 % ( event.total, event.cached, event.parsed, event.virtuals, event.skipped, event.masked, event.errors)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500562 continue
563
564 if isinstance(event, bb.event.CacheLoadStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500565 if params.options.quiet > 1:
566 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500567 cacheprogress = new_progress("Loading cache", event.total).start()
568 continue
569 if isinstance(event, bb.event.CacheLoadProgress):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500570 if params.options.quiet > 1:
571 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500572 cacheprogress.update(event.current)
573 continue
574 if isinstance(event, bb.event.CacheLoadCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500575 if params.options.quiet > 1:
576 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500577 cacheprogress.finish()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500578 if params.options.quiet == 0:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600579 print("Loaded %d entries from dependency cache." % event.num_entries)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500580 continue
581
582 if isinstance(event, bb.command.CommandFailed):
583 return_value = event.exitcode
584 if event.error:
585 errors = errors + 1
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500586 logger.error(str(event))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500587 main.shutdown = 2
588 continue
589 if isinstance(event, bb.command.CommandExit):
590 if not return_value:
591 return_value = event.exitcode
592 continue
593 if isinstance(event, (bb.command.CommandCompleted, bb.cooker.CookerExit)):
594 main.shutdown = 2
595 continue
596 if isinstance(event, bb.event.MultipleProviders):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500597 logger.info(str(event))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500598 continue
599 if isinstance(event, bb.event.NoProvider):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500600 # For universe builds, only show these as warnings, not errors
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500601 if not universe:
602 return_value = 1
603 errors = errors + 1
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500604 logger.error(str(event))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500605 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500606 logger.warning(str(event))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500607 continue
608
609 if isinstance(event, bb.runqueue.sceneQueueTaskStarted):
610 logger.info("Running setscene task %d of %d (%s)" % (event.stats.completed + event.stats.active + event.stats.failed + 1, event.stats.total, event.taskstring))
611 continue
612
613 if isinstance(event, bb.runqueue.runQueueTaskStarted):
614 if event.noexec:
615 tasktype = 'noexec task'
616 else:
617 tasktype = 'task'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600618 logger.info("Running %s %d of %d (%s)",
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500619 tasktype,
620 event.stats.completed + event.stats.active +
621 event.stats.failed + 1,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600622 event.stats.total, event.taskstring)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500623 continue
624
625 if isinstance(event, bb.runqueue.runQueueTaskFailed):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500626 return_value = 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500627 taskfailures.append(event.taskstring)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500628 logger.error(str(event))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500629 continue
630
631 if isinstance(event, bb.runqueue.sceneQueueTaskFailed):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500632 logger.warning(str(event))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500633 continue
634
635 if isinstance(event, bb.event.DepTreeGenerated):
636 continue
637
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600638 if isinstance(event, bb.event.ProcessStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500639 if params.options.quiet > 1:
640 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600641 parseprogress = new_progress(event.processname, event.total)
642 parseprogress.start(False)
643 continue
644 if isinstance(event, bb.event.ProcessProgress):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500645 if params.options.quiet > 1:
646 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600647 if parseprogress:
648 parseprogress.update(event.progress)
649 else:
650 bb.warn("Got ProcessProgress event for someting that never started?")
651 continue
652 if isinstance(event, bb.event.ProcessFinished):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500653 if params.options.quiet > 1:
654 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600655 if parseprogress:
656 parseprogress.finish()
657 parseprogress = None
658 continue
659
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500660 # ignore
661 if isinstance(event, (bb.event.BuildBase,
662 bb.event.MetadataEvent,
663 bb.event.StampUpdate,
664 bb.event.ConfigParsed,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500665 bb.event.MultiConfigParsed,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500666 bb.event.RecipeParsed,
667 bb.event.RecipePreFinalise,
668 bb.runqueue.runQueueEvent,
669 bb.event.OperationStarted,
670 bb.event.OperationCompleted,
671 bb.event.OperationProgress,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600672 bb.event.DiskFull,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500673 bb.event.HeartbeatEvent,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600674 bb.build.TaskProgress)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500675 continue
676
677 logger.error("Unknown event: %s", event)
678
679 except EnvironmentError as ioerror:
680 termfilter.clearFooter()
681 # ignore interrupted io
682 if ioerror.args[0] == 4:
683 continue
684 sys.stderr.write(str(ioerror))
685 if not params.observe_only:
686 _, error = server.runCommand(["stateForceShutdown"])
687 main.shutdown = 2
688 except KeyboardInterrupt:
689 termfilter.clearFooter()
690 if params.observe_only:
691 print("\nKeyboard Interrupt, exiting observer...")
692 main.shutdown = 2
693 if not params.observe_only and main.shutdown == 1:
694 print("\nSecond Keyboard Interrupt, stopping...\n")
695 _, error = server.runCommand(["stateForceShutdown"])
696 if error:
697 logger.error("Unable to cleanly stop: %s" % error)
698 if not params.observe_only and main.shutdown == 0:
699 print("\nKeyboard Interrupt, closing down...\n")
700 interrupted = True
701 _, error = server.runCommand(["stateShutdown"])
702 if error:
703 logger.error("Unable to cleanly shutdown: %s" % error)
704 main.shutdown = main.shutdown + 1
705 pass
706 except Exception as e:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500707 import traceback
708 sys.stderr.write(traceback.format_exc())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500709 if not params.observe_only:
710 _, error = server.runCommand(["stateForceShutdown"])
711 main.shutdown = 2
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500712 return_value = 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500713 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600714 termfilter.clearFooter()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500715 summary = ""
716 if taskfailures:
717 summary += pluralise("\nSummary: %s task failed:",
718 "\nSummary: %s tasks failed:", len(taskfailures))
719 for failure in taskfailures:
720 summary += "\n %s" % failure
721 if warnings:
722 summary += pluralise("\nSummary: There was %s WARNING message shown.",
723 "\nSummary: There were %s WARNING messages shown.", warnings)
724 if return_value and errors:
725 summary += pluralise("\nSummary: There was %s ERROR message shown, returning a non-zero exit code.",
726 "\nSummary: There were %s ERROR messages shown, returning a non-zero exit code.", errors)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500727 if summary and params.options.quiet == 0:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500728 print(summary)
729
730 if interrupted:
731 print("Execution was interrupted, returning a non-zero exit code.")
732 if return_value == 0:
733 return_value = 1
734 except IOError as e:
735 import errno
736 if e.errno == errno.EPIPE:
737 pass
738
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600739 if consolelog:
740 logger.removeHandler(consolelog)
741 consolelog.close()
742
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500743 return return_value