def main(server, eventHandler, params): # set to a logging.FileHandler instance when a build starts; # see _open_build_log() build_log = None # set to the log path when a build starts build_log_file_path = None helper = uihelper.BBUIHelper() # TODO don't use log output to determine when bitbake has started # # WARNING: this log handler cannot be removed, as localhostbecontroller # relies on output in the toaster_ui.log file to determine whether # the bitbake server has started, which only happens if # this logger is setup here (see the TODO in the loop below) console = logging.StreamHandler(sys.stdout) format_str = "%(levelname)s: %(message)s" formatter = bb.msg.BBLogFormatter(format_str) bb.msg.addDefaultlogFilter(console) console.setFormatter(formatter) logger.addHandler(console) logger.setLevel(logging.INFO) llevel, debug_domains = bb.msg.constructLogOptions() server.runCommand([ "setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list ]) # verify and warn build_history_enabled = True inheritlist, _ = server.runCommand(["getVariable", "INHERIT"]) if not "buildhistory" in inheritlist.split(" "): logger.warn( "buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details." ) build_history_enabled = False if not params.observe_only: logger.error("ToasterUI can only work in observer mode") return 1 # set to 1 when toasterui needs to shut down main.shutdown = 0 interrupted = False return_value = 0 errors = 0 warnings = 0 taskfailures = [] first = True buildinfohelper = BuildInfoHelper(server, build_history_enabled) # write our own log files into bitbake's log directory; # we're only interested in the path to the parent directory of # this file, as we're writing our own logs into the same directory consolelogfile = _log_settings_from_server(server) log_dir = os.path.dirname(consolelogfile) bb.utils.mkdirhier(log_dir) while True: try: event = eventHandler.waitEvent(0.25) if first: first = False # TODO don't use log output to determine when bitbake has started # # this is the line localhostbecontroller needs to # see in toaster_ui.log which it uses to decide whether # the bitbake server has started... logger.info("ToasterUI waiting for events") if event is None: if main.shutdown > 0: # if shutting down, close any open build log first _close_build_log(build_log) break continue helper.eventHandler(event) # pylint: disable=protected-access # the code will look into the protected variables of the event; no easy way around this # we treat ParseStarted as the first event of toaster-triggered # builds; that way we get the Build Configuration included in the log # and any errors that occur before BuildStarted is fired if isinstance(event, bb.event.ParseStarted): if not (build_log and build_log_file_path): build_log, build_log_file_path = _open_build_log(log_dir) continue if isinstance(event, bb.event.BuildStarted): if not (build_log and build_log_file_path): build_log, build_log_file_path = _open_build_log(log_dir) buildinfohelper.store_started_build(event, build_log_file_path) if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): buildinfohelper.update_and_store_task(event) logger.info("Logfile for task %s", event.logfile) continue if isinstance(event, bb.build.TaskBase): logger.info(event._message) if isinstance(event, bb.event.LogExecTTY): logger.info(event.msg) continue if isinstance(event, logging.LogRecord): if event.levelno == -1: event.levelno = formatter.ERROR buildinfohelper.store_log_event(event) if event.levelno >= formatter.ERROR: errors = errors + 1 elif event.levelno == formatter.WARNING: warnings = warnings + 1 # 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.taskpid != 0 and event.levelno <= formatter.NOTE: continue logger.handle(event) continue if isinstance(event, bb.build.TaskFailed): buildinfohelper.update_and_store_task(event) logfile = event.logfile if logfile and os.path.exists(logfile): bb.error("Logfile of failure stored in: %s" % logfile) continue # these events are unprocessed now, but may be used in the future to log # timing and error informations from the parsing phase in Toaster if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): continue if isinstance(event, bb.event.ParseProgress): continue if isinstance(event, bb.event.ParseCompleted): continue if isinstance(event, bb.event.CacheLoadStarted): continue if isinstance(event, bb.event.CacheLoadProgress): continue if isinstance(event, bb.event.CacheLoadCompleted): continue if isinstance(event, bb.event.MultipleProviders): 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) continue if isinstance(event, bb.event.NoProvider): errors = errors + 1 if event._runtime: r = "R" else: r = "" if event._dependees: text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % ( r, event._item, ", ".join(event._dependees), r) else: text = "Nothing %sPROVIDES '%s'" % (r, event._item) logger.error(text) if event._reasons: for reason in event._reasons: logger.error("%s", reason) text += reason buildinfohelper.store_log_error(text) continue if isinstance(event, bb.event.ConfigParsed): continue if isinstance(event, bb.event.RecipeParsed): continue # end of saved events if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)): buildinfohelper.store_started_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskCompleted): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskFailed): buildinfohelper.update_and_store_task(event) taskfailures.append(event.taskstring) logger.error("Task %s (%s) failed with exit code '%s'", event.taskid, event.taskstring, event.exitcode) continue if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)): continue if isinstance(event, (bb.event.BuildCompleted, bb.command.CommandFailed)): errorcode = 0 if isinstance(event, bb.command.CommandFailed): errors += 1 errorcode = 1 logger.error("Command execution failed: %s", event.error) # turn off logging to the current build log _close_build_log(build_log) # reset ready for next BuildStarted build_log = None # update the build info helper on BuildCompleted, not on CommandXXX buildinfohelper.update_build_information( event, errors, warnings, taskfailures) buildinfohelper.close(errorcode) # mark the log output; controllers may kill the toasterUI after seeing this log logger.info("ToasterUI build done 1, brbe: %s", buildinfohelper.brbe) # we start a new build info logger.debug("ToasterUI prepared for new build") errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) logger.info("ToasterUI build done 2") continue if isinstance(event, (bb.command.CommandCompleted, bb.command.CommandFailed, bb.command.CommandExit)): errorcode = 0 continue if isinstance(event, bb.event.MetadataEvent): if event.type == "SinglePackageInfo": buildinfohelper.store_build_package_information(event) elif event.type == "LayerInfo": buildinfohelper.store_layer_info(event) elif event.type == "BuildStatsList": buildinfohelper.store_tasks_stats(event) elif event.type == "ImagePkgList": buildinfohelper.store_target_package_data(event) elif event.type == "MissedSstate": buildinfohelper.store_missed_state_tasks(event) elif event.type == "ImageFileSize": buildinfohelper.update_target_image_file(event) elif event.type == "ArtifactFileSize": buildinfohelper.update_artifact_image_file(event) elif event.type == "LicenseManifestPath": buildinfohelper.store_license_manifest_path(event) elif event.type == "SetBRBE": buildinfohelper.brbe = buildinfohelper._get_data_from_event( event) elif event.type == "OSErrorException": logger.error(event) else: logger.error("Unprocessed MetadataEvent %s ", str(event)) continue if isinstance(event, bb.cooker.CookerExit): # shutdown when bitbake server shuts down main.shutdown = 1 continue # ignore if isinstance( event, (bb.event.BuildBase, bb.event.StampUpdate, bb.event.RecipePreFinalise, bb.runqueue.runQueueEvent, bb.runqueue.runQueueExitWait, bb.event.OperationProgress, bb.command.CommandFailed, bb.command.CommandExit, bb.command.CommandCompleted, bb.event.ReachableStamps)): continue if isinstance(event, bb.event.DepTreeGenerated): buildinfohelper.store_dependency_information(event) continue logger.warn("Unknown event: %s", event) return_value += 1 except EnvironmentError as ioerror: # ignore interrupted io if ioerror.args[0] == 4: pass except KeyboardInterrupt: main.shutdown = 1 except Exception as e: # print errors to log import traceback from pprint import pformat exception_data = traceback.format_exc() logger.error("%s\n%s", e, exception_data) _, _, tb = sys.exc_info() if tb is not None: curr = tb while curr is not None: logger.error("Error data dump %s\n%s\n", traceback.format_tb(curr, 1), pformat(curr.tb_frame.f_locals)) curr = curr.tb_next # save them to database, if possible; if it fails, we already logged to console. try: buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data)) except Exception as ce: logger.error( "CRITICAL - Failed to to save toaster exception to the database: %s", str(ce)) # make sure we return with an error return_value += 1 if interrupted and return_value == 0: return_value += 1 logger.warn("Return value is %d", return_value) return return_value
def main(server, eventHandler, params ): helper = uihelper.BBUIHelper() console = logging.StreamHandler(sys.stdout) format_str = "%(levelname)s: %(message)s" formatter = bb.msg.BBLogFormatter(format_str) bb.msg.addDefaultlogFilter(console) console.setFormatter(formatter) logger.addHandler(console) _, _, consolelogfile = _log_settings_from_server(server) # verify and warn build_history_enabled = True inheritlist, _ = server.runCommand(["getVariable", "INHERIT"]) if not "buildhistory" in inheritlist.split(" "): logger.warn("buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details.") build_history_enabled = False if not params.observe_only: logger.error("ToasterUI can only work in observer mode") return 1 main.shutdown = 0 interrupted = False return_value = 0 errors = 0 warnings = 0 taskfailures = [] first = True buildinfohelper = BuildInfoHelper(server, build_history_enabled) if buildinfohelper.brbe is not None and consolelogfile: # if we are under managed mode we have no other UI and we need to write our own file 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) while True: try: event = eventHandler.waitEvent(0.25) if first: first = False logger.info("ToasterUI waiting for events") if event is None: if main.shutdown > 0: break continue helper.eventHandler(event) # pylint: disable=protected-access # the code will look into the protected variables of the event; no easy way around this if isinstance(event, bb.event.BuildStarted): buildinfohelper.store_started_build(event) if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): buildinfohelper.update_and_store_task(event) logger.warn("Logfile for task %s", event.logfile) continue if isinstance(event, bb.build.TaskBase): logger.info(event._message) if isinstance(event, bb.event.LogExecTTY): logger.warn(event.msg) continue if isinstance(event, logging.LogRecord): if event.levelno == -1: event.levelno = formatter.ERROR buildinfohelper.store_log_event(event) if event.levelno >= formatter.ERROR: errors = errors + 1 elif event.levelno == formatter.WARNING: warnings = warnings + 1 # 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.taskpid != 0 and event.levelno <= formatter.NOTE: continue logger.handle(event) continue if isinstance(event, bb.build.TaskFailed): buildinfohelper.update_and_store_task(event) logfile = event.logfile if logfile and os.path.exists(logfile): bb.error("Logfile of failure stored in: %s" % logfile) continue # these events are unprocessed now, but may be used in the future to log # timing and error informations from the parsing phase in Toaster if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): continue if isinstance(event, bb.event.ParseStarted): continue if isinstance(event, bb.event.ParseProgress): continue if isinstance(event, bb.event.ParseCompleted): continue if isinstance(event, bb.event.CacheLoadStarted): continue if isinstance(event, bb.event.CacheLoadProgress): continue if isinstance(event, bb.event.CacheLoadCompleted): continue if isinstance(event, bb.event.MultipleProviders): 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) continue if isinstance(event, bb.event.NoProvider): errors = errors + 1 if event._runtime: r = "R" else: r = "" if event._dependees: text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r) else: text = "Nothing %sPROVIDES '%s'" % (r, event._item) logger.error(text) if event._reasons: for reason in event._reasons: logger.error("%s", reason) text += reason buildinfohelper.store_log_error(text) continue if isinstance(event, bb.event.ConfigParsed): continue if isinstance(event, bb.event.RecipeParsed): continue # end of saved events if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)): buildinfohelper.store_started_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskCompleted): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskFailed): buildinfohelper.update_and_store_task(event) taskfailures.append(event.taskstring) logger.error("Task %s (%s) failed with exit code '%s'", event.taskid, event.taskstring, event.exitcode) continue if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)): continue if isinstance(event, (bb.event.BuildCompleted, bb.command.CommandFailed)): errorcode = 0 if isinstance(event, bb.command.CommandFailed): errors += 1 errorcode = 1 logger.error("Command execution failed: %s", event.error) # update the build info helper on BuildCompleted, not on CommandXXX buildinfohelper.update_build_information(event, errors, warnings, taskfailures) buildinfohelper.close(errorcode) # mark the log output; controllers may kill the toasterUI after seeing this log logger.info("ToasterUI build done 1, brbe: %s", buildinfohelper.brbe ) # we start a new build info if buildinfohelper.brbe is not None: logger.debug("ToasterUI under BuildEnvironment management - exiting after the build") server.terminateServer() else: logger.debug("ToasterUI prepared for new build") errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) logger.info("ToasterUI build done 2") continue if isinstance(event, (bb.command.CommandCompleted, bb.command.CommandFailed, bb.command.CommandExit)): errorcode = 0 continue if isinstance(event, bb.event.MetadataEvent): if event.type == "SinglePackageInfo": buildinfohelper.store_build_package_information(event) elif event.type == "LayerInfo": buildinfohelper.store_layer_info(event) elif event.type == "BuildStatsList": buildinfohelper.store_tasks_stats(event) elif event.type == "ImagePkgList": buildinfohelper.store_target_package_data(event) elif event.type == "MissedSstate": buildinfohelper.store_missed_state_tasks(event) elif event.type == "ImageFileSize": buildinfohelper.update_target_image_file(event) elif event.type == "ArtifactFileSize": buildinfohelper.update_artifact_image_file(event) elif event.type == "LicenseManifestPath": buildinfohelper.store_license_manifest_path(event) else: logger.error("Unprocessed MetadataEvent %s ", str(event)) continue if isinstance(event, bb.cooker.CookerExit): # exit when the server exits break # ignore if isinstance(event, (bb.event.BuildBase, bb.event.StampUpdate, bb.event.RecipePreFinalise, bb.runqueue.runQueueEvent, bb.runqueue.runQueueExitWait, bb.event.OperationProgress, bb.command.CommandFailed, bb.command.CommandExit, bb.command.CommandCompleted)): continue if isinstance(event, bb.event.DepTreeGenerated): buildinfohelper.store_dependency_information(event) continue logger.error("Unknown event: %s", event) return_value += 1 except EnvironmentError as ioerror: # ignore interrupted io if ioerror.args[0] == 4: pass except KeyboardInterrupt: main.shutdown = 1 except Exception as e: # print errors to log import traceback from pprint import pformat exception_data = traceback.format_exc() logger.error("%s\n%s" , e, exception_data) _, _, tb = sys.exc_info() if tb is not None: curr = tb while curr is not None: logger.warn("Error data dump %s\n%s\n" , traceback.format_tb(curr,1), pformat(curr.tb_frame.f_locals)) curr = curr.tb_next # save them to database, if possible; if it fails, we already logged to console. try: buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data)) except Exception as ce: logger.error("CRITICAL - Failed to to save toaster exception to the database: %s", str(ce)) # make sure we return with an error return_value += 1 if interrupted: if return_value == 0: return_value += 1 logger.warn("Return value is %d", return_value) return return_value
def main(server, eventHandler, params): # set to a logging.FileHandler instance when a build starts; # see _open_build_log() build_log = None # set to the log path when a build starts build_log_file_path = None helper = uihelper.BBUIHelper() # TODO don't use log output to determine when bitbake has started # # WARNING: this log handler cannot be removed, as localhostbecontroller # relies on output in the toaster_ui.log file to determine whether # the bitbake server has started, which only happens if # this logger is setup here (see the TODO in the loop below) console = logging.StreamHandler(sys.stdout) format_str = "%(levelname)s: %(message)s" formatter = bb.msg.BBLogFormatter(format_str) bb.msg.addDefaultlogFilter(console) console.setFormatter(formatter) logger.addHandler(console) logger.setLevel(logging.INFO) llevel, debug_domains = bb.msg.constructLogOptions() result, error = server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list]) if not result or error: logger.error("can't set event mask: %s", error) return 1 # verify and warn build_history_enabled = True inheritlist, _ = server.runCommand(["getVariable", "INHERIT"]) if not "buildhistory" in inheritlist.split(" "): logger.warning("buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details.") build_history_enabled = False if not params.observe_only: params.updateFromServer(server) params.updateToServer(server, os.environ.copy()) cmdline = params.parseActions() if not cmdline: print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.") return 1 if 'msg' in cmdline and cmdline['msg']: logger.error(cmdline['msg']) return 1 ret, error = server.runCommand(cmdline['action']) if error: logger.error("Command '%s' failed: %s" % (cmdline, error)) return 1 elif ret != True: logger.error("Command '%s' failed: returned %s" % (cmdline, ret)) return 1 # set to 1 when toasterui needs to shut down main.shutdown = 0 interrupted = False return_value = 0 errors = 0 warnings = 0 taskfailures = [] first = True buildinfohelper = BuildInfoHelper(server, build_history_enabled, os.getenv('TOASTER_BRBE')) # write our own log files into bitbake's log directory; # we're only interested in the path to the parent directory of # this file, as we're writing our own logs into the same directory consolelogfile = _log_settings_from_server(server) log_dir = os.path.dirname(consolelogfile) bb.utils.mkdirhier(log_dir) while True: try: event = eventHandler.waitEvent(0.25) if first: first = False # TODO don't use log output to determine when bitbake has started # # this is the line localhostbecontroller needs to # see in toaster_ui.log which it uses to decide whether # the bitbake server has started... logger.info("ToasterUI waiting for events") if event is None: if main.shutdown > 0: # if shutting down, close any open build log first _close_build_log(build_log) break continue helper.eventHandler(event) # pylint: disable=protected-access # the code will look into the protected variables of the event; no easy way around this if isinstance(event, bb.event.ParseStarted): if not (build_log and build_log_file_path): build_log, build_log_file_path = _open_build_log(log_dir) buildinfohelper.store_started_build() buildinfohelper.save_build_log_file_path(build_log_file_path) buildinfohelper.set_recipes_to_parse(event.total) continue # create a build object in buildinfohelper from either BuildInit # (if available) or BuildStarted (for jethro and previous versions) if isinstance(event, (bb.event.BuildStarted, bb.event.BuildInit)): if not (build_log and build_log_file_path): build_log, build_log_file_path = _open_build_log(log_dir) buildinfohelper.save_build_targets(event) buildinfohelper.save_build_log_file_path(build_log_file_path) # get additional data from BuildStarted if isinstance(event, bb.event.BuildStarted): buildinfohelper.save_build_layers_and_variables() continue if isinstance(event, bb.event.ParseProgress): buildinfohelper.set_recipes_parsed(event.current) continue if isinstance(event, bb.event.ParseCompleted): buildinfohelper.set_recipes_parsed(event.total) continue if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): buildinfohelper.update_and_store_task(event) logger.info("Logfile for task %s", event.logfile) continue if isinstance(event, bb.build.TaskBase): logger.info(event._message) if isinstance(event, bb.event.LogExecTTY): logger.info(event.msg) continue if isinstance(event, logging.LogRecord): if event.levelno == -1: event.levelno = formatter.ERROR buildinfohelper.store_log_event(event) if event.levelno >= formatter.ERROR: errors = errors + 1 elif event.levelno == formatter.WARNING: warnings = warnings + 1 # 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.taskpid != 0 and event.levelno <= formatter.NOTE: continue logger.handle(event) continue if isinstance(event, bb.build.TaskFailed): buildinfohelper.update_and_store_task(event) logfile = event.logfile if logfile and os.path.exists(logfile): bb.error("Logfile of failure stored in: %s" % logfile) continue # these events are unprocessed now, but may be used in the future to log # timing and error informations from the parsing phase in Toaster if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): continue if isinstance(event, bb.event.CacheLoadStarted): continue if isinstance(event, bb.event.CacheLoadProgress): continue if isinstance(event, bb.event.CacheLoadCompleted): continue if isinstance(event, bb.event.MultipleProviders): 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) continue if isinstance(event, bb.event.NoProvider): errors = errors + 1 if event._runtime: r = "R" else: r = "" if event._dependees: text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r) else: text = "Nothing %sPROVIDES '%s'" % (r, event._item) logger.error(text) if event._reasons: for reason in event._reasons: logger.error("%s", reason) text += reason buildinfohelper.store_log_error(text) continue if isinstance(event, bb.event.ConfigParsed): continue if isinstance(event, bb.event.RecipeParsed): continue # end of saved events if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)): buildinfohelper.store_started_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskCompleted): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskFailed): buildinfohelper.update_and_store_task(event) taskfailures.append(event.taskstring) logger.error("Task (%s) failed with exit code '%s'", event.taskstring, event.exitcode) continue if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)): continue if isinstance(event, (bb.event.BuildCompleted, bb.command.CommandFailed)): errorcode = 0 if isinstance(event, bb.command.CommandFailed): errors += 1 errorcode = 1 logger.error("Command execution failed: %s", event.error) elif isinstance(event, bb.event.BuildCompleted): buildinfohelper.scan_image_artifacts() buildinfohelper.clone_required_sdk_artifacts() # turn off logging to the current build log _close_build_log(build_log) # reset ready for next BuildStarted build_log = None # update the build info helper on BuildCompleted, not on CommandXXX buildinfohelper.update_build_information(event, errors, warnings, taskfailures) brbe = buildinfohelper.brbe buildinfohelper.close(errorcode) # we start a new build info if params.observe_only: logger.debug("ToasterUI prepared for new build") errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) else: main.shutdown = 1 logger.info("ToasterUI build done, brbe: %s", brbe) continue if isinstance(event, (bb.command.CommandCompleted, bb.command.CommandFailed, bb.command.CommandExit)): if params.observe_only: errorcode = 0 else: main.shutdown = 1 continue if isinstance(event, bb.event.MetadataEvent): if event.type == "SinglePackageInfo": buildinfohelper.store_build_package_information(event) elif event.type == "LayerInfo": buildinfohelper.store_layer_info(event) elif event.type == "BuildStatsList": buildinfohelper.store_tasks_stats(event) elif event.type == "ImagePkgList": buildinfohelper.store_target_package_data(event) elif event.type == "MissedSstate": buildinfohelper.store_missed_state_tasks(event) elif event.type == "SDKArtifactInfo": buildinfohelper.scan_sdk_artifacts(event) elif event.type == "SetBRBE": buildinfohelper.brbe = buildinfohelper._get_data_from_event(event) elif event.type == "TaskArtifacts": # not implemented yet # see https://bugzilla.yoctoproject.org/show_bug.cgi?id=10283 for details pass elif event.type == "OSErrorException": logger.error(event) else: logger.error("Unprocessed MetadataEvent %s", event.type) continue if isinstance(event, bb.cooker.CookerExit): # shutdown when bitbake server shuts down main.shutdown = 1 continue if isinstance(event, bb.event.DepTreeGenerated): buildinfohelper.store_dependency_information(event) continue logger.warning("Unknown event: %s", event) return_value += 1 except EnvironmentError as ioerror: logger.warning("EnvironmentError: %s" % ioerror) # ignore interrupted io system calls if ioerror.args[0] == 4: # errno 4 is EINTR logger.warning("Skipped EINTR: %s" % ioerror) else: raise except KeyboardInterrupt: if params.observe_only: print("\nKeyboard Interrupt, exiting observer...") main.shutdown = 2 if not params.observe_only and main.shutdown == 1: print("\nSecond Keyboard Interrupt, stopping...\n") _, error = server.runCommand(["stateForceShutdown"]) if error: logger.error("Unable to cleanly stop: %s" % error) if not params.observe_only and main.shutdown == 0: print("\nKeyboard Interrupt, closing down...\n") interrupted = True _, error = server.runCommand(["stateShutdown"]) if error: logger.error("Unable to cleanly shutdown: %s" % error) buildinfohelper.cancel_cli_build() main.shutdown = main.shutdown + 1 except Exception as e: # print errors to log import traceback from pprint import pformat exception_data = traceback.format_exc() logger.error("%s\n%s" , e, exception_data) # save them to database, if possible; if it fails, we already logged to console. try: buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data)) except Exception as ce: logger.error("CRITICAL - Failed to to save toaster exception to the database: %s", str(ce)) # make sure we return with an error return_value += 1 if interrupted and return_value == 0: return_value += 1 logger.warning("Return value is %d", return_value) return return_value
def main(server, eventHandler, params): # set to a logging.FileHandler instance when a build starts; # see _open_build_log() build_log = None # set to the log path when a build starts build_log_file_path = None helper = uihelper.BBUIHelper() # TODO don't use log output to determine when bitbake has started # # WARNING: this log handler cannot be removed, as localhostbecontroller # relies on output in the toaster_ui.log file to determine whether # the bitbake server has started, which only happens if # this logger is setup here (see the TODO in the loop below) console = logging.StreamHandler(sys.stdout) format_str = "%(levelname)s: %(message)s" formatter = bb.msg.BBLogFormatter(format_str) bb.msg.addDefaultlogFilter(console) console.setFormatter(formatter) logger.addHandler(console) logger.setLevel(logging.INFO) llevel, debug_domains = bb.msg.constructLogOptions() result, error = server.runCommand([ "setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list ]) if not result or error: logger.error("can't set event mask: %s", error) return 1 # verify and warn build_history_enabled = True inheritlist, _ = server.runCommand(["getVariable", "INHERIT"]) if not "buildhistory" in inheritlist.split(" "): logger.warning( "buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details." ) build_history_enabled = False if not params.observe_only: params.updateFromServer(server) params.updateToServer(server, os.environ.copy()) cmdline = params.parseActions() if not cmdline: print( "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information." ) return 1 if 'msg' in cmdline and cmdline['msg']: logger.error(cmdline['msg']) return 1 ret, error = server.runCommand(cmdline['action']) if error: logger.error("Command '%s' failed: %s" % (cmdline, error)) return 1 elif ret != True: logger.error("Command '%s' failed: returned %s" % (cmdline, ret)) return 1 # set to 1 when toasterui needs to shut down main.shutdown = 0 interrupted = False return_value = 0 errors = 0 warnings = 0 taskfailures = [] first = True buildinfohelper = BuildInfoHelper(server, build_history_enabled, os.getenv('TOASTER_BRBE')) # write our own log files into bitbake's log directory; # we're only interested in the path to the parent directory of # this file, as we're writing our own logs into the same directory consolelogfile = _log_settings_from_server(server) log_dir = os.path.dirname(consolelogfile) bb.utils.mkdirhier(log_dir) while True: try: event = eventHandler.waitEvent(0.25) if first: first = False # TODO don't use log output to determine when bitbake has started # # this is the line localhostbecontroller needs to # see in toaster_ui.log which it uses to decide whether # the bitbake server has started... logger.info("ToasterUI waiting for events") if event is None: if main.shutdown > 0: # if shutting down, close any open build log first _close_build_log(build_log) break continue helper.eventHandler(event) # pylint: disable=protected-access # the code will look into the protected variables of the event; no easy way around this if isinstance(event, bb.event.ParseStarted): if not (build_log and build_log_file_path): build_log, build_log_file_path = _open_build_log(log_dir) buildinfohelper.store_started_build() buildinfohelper.save_build_log_file_path(build_log_file_path) buildinfohelper.set_recipes_to_parse(event.total) continue # create a build object in buildinfohelper from either BuildInit # (if available) or BuildStarted (for jethro and previous versions) if isinstance(event, (bb.event.BuildStarted, bb.event.BuildInit)): if not (build_log and build_log_file_path): build_log, build_log_file_path = _open_build_log(log_dir) buildinfohelper.save_build_targets(event) buildinfohelper.save_build_log_file_path(build_log_file_path) # get additional data from BuildStarted if isinstance(event, bb.event.BuildStarted): buildinfohelper.save_build_layers_and_variables() continue if isinstance(event, bb.event.ParseProgress): buildinfohelper.set_recipes_parsed(event.current) continue if isinstance(event, bb.event.ParseCompleted): buildinfohelper.set_recipes_parsed(event.total) continue if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): buildinfohelper.update_and_store_task(event) logger.info("Logfile for task %s", event.logfile) continue if isinstance(event, bb.build.TaskBase): logger.info(event._message) if isinstance(event, bb.event.LogExecTTY): logger.info(event.msg) continue if isinstance(event, logging.LogRecord): if event.levelno == -1: event.levelno = formatter.ERROR buildinfohelper.store_log_event(event) if event.levelno >= formatter.ERROR: errors = errors + 1 elif event.levelno == formatter.WARNING: warnings = warnings + 1 # 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.taskpid != 0 and event.levelno <= formatter.NOTE: continue logger.handle(event) continue if isinstance(event, bb.build.TaskFailed): buildinfohelper.update_and_store_task(event) logfile = event.logfile if logfile and os.path.exists(logfile): bb.error("Logfile of failure stored in: %s" % logfile) continue # these events are unprocessed now, but may be used in the future to log # timing and error informations from the parsing phase in Toaster if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): continue if isinstance(event, bb.event.CacheLoadStarted): continue if isinstance(event, bb.event.CacheLoadProgress): continue if isinstance(event, bb.event.CacheLoadCompleted): continue if isinstance(event, bb.event.MultipleProviders): 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) continue if isinstance(event, bb.event.NoProvider): errors = errors + 1 if event._runtime: r = "R" else: r = "" if event._dependees: text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % ( r, event._item, ", ".join(event._dependees), r) else: text = "Nothing %sPROVIDES '%s'" % (r, event._item) logger.error(text) if event._reasons: for reason in event._reasons: logger.error("%s", reason) text += reason buildinfohelper.store_log_error(text) continue if isinstance(event, bb.event.ConfigParsed): continue if isinstance(event, bb.event.RecipeParsed): continue # end of saved events if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)): buildinfohelper.store_started_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskCompleted): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskFailed): buildinfohelper.update_and_store_task(event) taskfailures.append(event.taskstring) logger.error("Task (%s) failed with exit code '%s'", event.taskstring, event.exitcode) continue if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)): continue if isinstance(event, (bb.event.BuildCompleted, bb.command.CommandFailed)): errorcode = 0 if isinstance(event, bb.command.CommandFailed): errors += 1 errorcode = 1 logger.error("Command execution failed: %s", event.error) elif isinstance(event, bb.event.BuildCompleted): buildinfohelper.scan_image_artifacts() buildinfohelper.clone_required_sdk_artifacts() # turn off logging to the current build log _close_build_log(build_log) # reset ready for next BuildStarted build_log = None # update the build info helper on BuildCompleted, not on CommandXXX buildinfohelper.update_build_information( event, errors, warnings, taskfailures) brbe = buildinfohelper.brbe buildinfohelper.close(errorcode) # we start a new build info if params.observe_only: logger.debug("ToasterUI prepared for new build") errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) else: main.shutdown = 1 logger.info("ToasterUI build done, brbe: %s", brbe) continue if isinstance(event, (bb.command.CommandCompleted, bb.command.CommandFailed, bb.command.CommandExit)): if params.observe_only: errorcode = 0 else: main.shutdown = 1 continue if isinstance(event, bb.event.MetadataEvent): if event.type == "SinglePackageInfo": buildinfohelper.store_build_package_information(event) elif event.type == "LayerInfo": buildinfohelper.store_layer_info(event) elif event.type == "BuildStatsList": buildinfohelper.store_tasks_stats(event) elif event.type == "ImagePkgList": buildinfohelper.store_target_package_data(event) elif event.type == "MissedSstate": buildinfohelper.store_missed_state_tasks(event) elif event.type == "SDKArtifactInfo": buildinfohelper.scan_sdk_artifacts(event) elif event.type == "SetBRBE": buildinfohelper.brbe = buildinfohelper._get_data_from_event( event) elif event.type == "TaskArtifacts": # not implemented yet # see https://bugzilla.yoctoproject.org/show_bug.cgi?id=10283 for details pass elif event.type == "OSErrorException": logger.error(event) else: logger.error("Unprocessed MetadataEvent %s", event.type) continue if isinstance(event, bb.cooker.CookerExit): # shutdown when bitbake server shuts down main.shutdown = 1 continue if isinstance(event, bb.event.DepTreeGenerated): buildinfohelper.store_dependency_information(event) continue logger.warning("Unknown event: %s", event) return_value += 1 except EnvironmentError as ioerror: logger.warning("EnvironmentError: %s" % ioerror) # ignore interrupted io system calls if ioerror.args[0] == 4: # errno 4 is EINTR logger.warning("Skipped EINTR: %s" % ioerror) else: raise except KeyboardInterrupt: if params.observe_only: print("\nKeyboard Interrupt, exiting observer...") main.shutdown = 2 if not params.observe_only and main.shutdown == 1: print("\nSecond Keyboard Interrupt, stopping...\n") _, error = server.runCommand(["stateForceShutdown"]) if error: logger.error("Unable to cleanly stop: %s" % error) if not params.observe_only and main.shutdown == 0: print("\nKeyboard Interrupt, closing down...\n") interrupted = True _, error = server.runCommand(["stateShutdown"]) if error: logger.error("Unable to cleanly shutdown: %s" % error) buildinfohelper.cancel_cli_build() main.shutdown = main.shutdown + 1 except Exception as e: # print errors to log import traceback from pprint import pformat exception_data = traceback.format_exc() logger.error("%s\n%s", e, exception_data) # save them to database, if possible; if it fails, we already logged to console. try: buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data)) except Exception as ce: logger.error( "CRITICAL - Failed to to save toaster exception to the database: %s", str(ce)) # make sure we return with an error return_value += 1 if interrupted and return_value == 0: return_value += 1 logger.warning("Return value is %d", return_value) return return_value
def main(server, eventHandler, params ): includelogs, loglines = _log_settings_from_server(server) # verify and warn build_history_enabled = True inheritlist, error = server.runCommand(["getVariable", "INHERIT"]) if not "buildhistory" in inheritlist.split(" "): logger.warn("buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details.") build_history_enabled = False helper = uihelper.BBUIHelper() console = logging.StreamHandler(sys.stdout) format_str = "%(levelname)s: %(message)s" format = bb.msg.BBLogFormatter(format_str) bb.msg.addDefaultlogFilter(console) console.setFormatter(format) logger.addHandler(console) if not params.observe_only: logger.error("ToasterUI can only work in observer mode") return main.shutdown = 0 interrupted = False return_value = 0 errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) while True: try: event = eventHandler.waitEvent(0.25) if event is None: if main.shutdown > 0: break continue helper.eventHandler(event) if isinstance(event, bb.event.BuildStarted): buildinfohelper.store_started_build(event) if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.event.LogExecTTY): logger.warn(event.msg) continue if isinstance(event, logging.LogRecord): buildinfohelper.store_log_event(event) if event.levelno >= format.ERROR: errors = errors + 1 return_value = 1 elif event.levelno == format.WARNING: warnings = warnings + 1 # 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.taskpid != 0 and event.levelno <= format.NOTE: continue logger.handle(event) continue if isinstance(event, bb.build.TaskFailed): buildinfohelper.update_and_store_task(event) return_value = 1 logfile = event.logfile if logfile and os.path.exists(logfile): bb.error("Logfile of failure stored in: %s" % logfile) continue # these events are unprocessed now, but may be used in the future to log # timing and error informations from the parsing phase in Toaster if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): continue if isinstance(event, bb.event.ParseStarted): continue if isinstance(event, bb.event.ParseProgress): continue if isinstance(event, bb.event.ParseCompleted): continue if isinstance(event, bb.event.CacheLoadStarted): continue if isinstance(event, bb.event.CacheLoadProgress): continue if isinstance(event, bb.event.CacheLoadCompleted): continue if isinstance(event, bb.event.MultipleProviders): continue if isinstance(event, bb.event.NoProvider): return_value = 1 errors = errors + 1 if event._runtime: r = "R" else: r = "" if event._dependees: text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r) else: text = "Nothing %sPROVIDES '%s'" % (r, event._item) logger.error(text) if event._reasons: for reason in event._reasons: logger.error("%s", reason) text += reason buildinfohelper.store_log_error(text) continue if isinstance(event, bb.event.ConfigParsed): continue if isinstance(event, bb.event.RecipeParsed): continue # end of saved events if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)): buildinfohelper.store_started_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskCompleted): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskFailed): buildinfohelper.update_and_store_task(event) taskfailures.append(event.taskstring) logger.error("Task %s (%s) failed with exit code '%s'", event.taskid, event.taskstring, event.exitcode) continue if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)): continue if isinstance(event, (bb.event.BuildCompleted)): continue if isinstance(event, (bb.command.CommandCompleted, bb.command.CommandFailed, bb.command.CommandExit)): if (isinstance(event, bb.command.CommandFailed)): event.levelno = format.ERROR event.msg = event.error event.pathname = "" event.lineno = 0 buildinfohelper.store_log_event(event) errors += 1 buildinfohelper.update_build_information(event, errors, warnings, taskfailures) brbe = server.runCommand(["getVariable", "TOASTER_BRBE"])[0] br_id, be_id = brbe.split(":") # we start a new build info if brbe is not None: buildinfohelper.store_build_done(br_id, be_id) print "we are under BuildEnvironment management - after the build, we exit" server.terminateServer() else: print "prepared for new build" errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) continue if isinstance(event, bb.event.MetadataEvent): if event.type == "SinglePackageInfo": buildinfohelper.store_build_package_information(event) elif event.type == "LayerInfo": buildinfohelper.store_layer_info(event) elif event.type == "BuildStatsList": buildinfohelper.store_tasks_stats(event) elif event.type == "ImagePkgList": buildinfohelper.store_target_package_data(event) elif event.type == "MissedSstate": buildinfohelper.store_missed_state_tasks(event) elif event.type == "ImageFileSize": buildinfohelper.update_target_image_file(event) elif event.type == "LicenseManifestPath": buildinfohelper.store_license_manifest_path(event) continue if isinstance(event, bb.cooker.CookerExit): # exit when the server exits break # ignore if isinstance(event, (bb.event.BuildBase, bb.event.StampUpdate, bb.event.RecipePreFinalise, bb.runqueue.runQueueEvent, bb.runqueue.runQueueExitWait, bb.event.OperationProgress, bb.command.CommandFailed, bb.command.CommandExit, bb.command.CommandCompleted)): continue if isinstance(event, bb.event.DepTreeGenerated): buildinfohelper.store_dependency_information(event) continue logger.error("Unknown event: %s", event) except EnvironmentError as ioerror: # ignore interrupted io if ioerror.args[0] == 4: pass except KeyboardInterrupt: main.shutdown = 1 pass except Exception as e: logger.error(e) import traceback traceback.print_exc() pass if interrupted: if return_value == 0: return_value = 1 return return_value
def main(server, eventHandler, params): includelogs, loglines = _log_settings_from_server(server) # verify and warn build_history_enabled = True inheritlist, error = server.runCommand(["getVariable", "INHERIT"]) if not "buildhistory" in inheritlist.split(" "): logger.warn( "buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details." ) build_history_enabled = False helper = uihelper.BBUIHelper() console = logging.StreamHandler(sys.stdout) format_str = "%(levelname)s: %(message)s" format = bb.msg.BBLogFormatter(format_str) bb.msg.addDefaultlogFilter(console) console.setFormatter(format) logger.addHandler(console) if not params.observe_only: logger.error("ToasterUI can only work in observer mode") return main.shutdown = 0 interrupted = False return_value = 0 errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) while True: try: event = eventHandler.waitEvent(0.25) if event is None: if main.shutdown > 0: break continue helper.eventHandler(event) if isinstance(event, bb.event.BuildStarted): buildinfohelper.store_started_build(event) if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.event.LogExecTTY): logger.warn(event.msg) continue if isinstance(event, logging.LogRecord): buildinfohelper.store_log_event(event) if event.levelno >= format.ERROR: errors = errors + 1 return_value = 1 elif event.levelno == format.WARNING: warnings = warnings + 1 # 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.taskpid != 0 and event.levelno <= format.NOTE: continue logger.handle(event) continue if isinstance(event, bb.build.TaskFailed): buildinfohelper.update_and_store_task(event) return_value = 1 logfile = event.logfile if logfile and os.path.exists(logfile): bb.error("Logfile of failure stored in: %s" % logfile) continue # these events are unprocessed now, but may be used in the future to log # timing and error informations from the parsing phase in Toaster if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): continue if isinstance(event, bb.event.ParseStarted): continue if isinstance(event, bb.event.ParseProgress): continue if isinstance(event, bb.event.ParseCompleted): continue if isinstance(event, bb.event.CacheLoadStarted): continue if isinstance(event, bb.event.CacheLoadProgress): continue if isinstance(event, bb.event.CacheLoadCompleted): continue if isinstance(event, bb.event.MultipleProviders): continue if isinstance(event, bb.event.NoProvider): return_value = 1 errors = errors + 1 if event._runtime: r = "R" else: r = "" if event._dependees: text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % ( r, event._item, ", ".join(event._dependees), r) else: text = "Nothing %sPROVIDES '%s'" % (r, event._item) logger.error(text) if event._reasons: for reason in event._reasons: logger.error("%s", reason) text += reason buildinfohelper.store_log_error(text) continue if isinstance(event, bb.event.ConfigParsed): continue if isinstance(event, bb.event.RecipeParsed): continue # end of saved events if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)): buildinfohelper.store_started_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskCompleted): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskFailed): buildinfohelper.update_and_store_task(event) taskfailures.append(event.taskstring) logger.error("Task %s (%s) failed with exit code '%s'", event.taskid, event.taskstring, event.exitcode) continue if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)): continue if isinstance(event, (bb.event.BuildCompleted)): continue if isinstance(event, (bb.command.CommandCompleted, bb.command.CommandFailed, bb.command.CommandExit)): if (isinstance(event, bb.command.CommandFailed)): event.levelno = format.ERROR event.msg = event.error event.pathname = "" event.lineno = 0 buildinfohelper.store_log_event(event) errors += 1 buildinfohelper.update_build_information( event, errors, warnings, taskfailures) brbe = server.runCommand(["getVariable", "TOASTER_BRBE"])[0] # we start a new build info if brbe is not None: print "we are under BuildEnvironment management - after the build, we exit" server.terminateServer() else: print "prepared for new build" errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) continue if isinstance(event, bb.event.MetadataEvent): if event.type == "SinglePackageInfo": buildinfohelper.store_build_package_information(event) elif event.type == "LayerInfo": buildinfohelper.store_layer_info(event) elif event.type == "BuildStatsList": buildinfohelper.store_tasks_stats(event) elif event.type == "ImagePkgList": buildinfohelper.store_target_package_data(event) elif event.type == "MissedSstate": buildinfohelper.store_missed_state_tasks(event) elif event.type == "ImageFileSize": buildinfohelper.update_target_image_file(event) elif event.type == "LicenseManifestPath": buildinfohelper.store_license_manifest_path(event) continue if isinstance(event, bb.cooker.CookerExit): # exit when the server exits break # ignore if isinstance( event, (bb.event.BuildBase, bb.event.StampUpdate, bb.event.RecipePreFinalise, bb.runqueue.runQueueEvent, bb.runqueue.runQueueExitWait, bb.event.OperationProgress, bb.command.CommandFailed, bb.command.CommandExit, bb.command.CommandCompleted)): continue if isinstance(event, bb.event.DepTreeGenerated): buildinfohelper.store_dependency_information(event) continue logger.error("Unknown event: %s", event) except EnvironmentError as ioerror: # ignore interrupted io if ioerror.args[0] == 4: pass except KeyboardInterrupt: main.shutdown = 1 pass except Exception as e: logger.error(e) import traceback traceback.print_exc() pass if interrupted: if return_value == 0: return_value = 1 return return_value
def main(server, eventHandler, params): helper = uihelper.BBUIHelper() console = logging.StreamHandler(sys.stdout) format_str = "%(levelname)s: %(message)s" format = bb.msg.BBLogFormatter(format_str) bb.msg.addDefaultlogFilter(console) console.setFormatter(format) logger.addHandler(console) includelogs, loglines, consolelogfile = _log_settings_from_server(server) # verify and warn build_history_enabled = True inheritlist, error = server.runCommand(["getVariable", "INHERIT"]) if not "buildhistory" in inheritlist.split(" "): logger.warn( "buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details." ) build_history_enabled = False if not params.observe_only: logger.error("ToasterUI can only work in observer mode") return 1 main.shutdown = 0 interrupted = False return_value = 0 errors = 0 warnings = 0 taskfailures = [] first = True buildinfohelper = BuildInfoHelper(server, build_history_enabled) if buildinfohelper.brbe is not None and consolelogfile: # if we are under managed mode we have no other UI and we need to write our own file 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) while True: try: event = eventHandler.waitEvent(0.25) if first: first = False logger.info("ToasterUI waiting for events") if event is None: if main.shutdown > 0: break continue helper.eventHandler(event) if isinstance(event, bb.event.BuildStarted): buildinfohelper.store_started_build(event) if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): buildinfohelper.update_and_store_task(event) logger.warn("Logfile for task %s" % event.logfile) continue if isinstance(event, bb.build.TaskBase): logger.info(event._message) if isinstance(event, bb.event.LogExecTTY): logger.warn(event.msg) continue if isinstance(event, logging.LogRecord): buildinfohelper.store_log_event(event) if event.levelno >= format.ERROR: errors = errors + 1 elif event.levelno == format.WARNING: warnings = warnings + 1 # 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.taskpid != 0 and event.levelno <= format.NOTE: continue logger.handle(event) continue if isinstance(event, bb.build.TaskFailed): buildinfohelper.update_and_store_task(event) logfile = event.logfile if logfile and os.path.exists(logfile): bb.error("Logfile of failure stored in: %s" % logfile) continue # these events are unprocessed now, but may be used in the future to log # timing and error informations from the parsing phase in Toaster if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): continue if isinstance(event, bb.event.ParseStarted): continue if isinstance(event, bb.event.ParseProgress): continue if isinstance(event, bb.event.ParseCompleted): continue if isinstance(event, bb.event.CacheLoadStarted): continue if isinstance(event, bb.event.CacheLoadProgress): continue if isinstance(event, bb.event.CacheLoadCompleted): continue if isinstance(event, bb.event.MultipleProviders): 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) continue if isinstance(event, bb.event.NoProvider): errors = errors + 1 if event._runtime: r = "R" else: r = "" if event._dependees: text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % ( r, event._item, ", ".join(event._dependees), r) else: text = "Nothing %sPROVIDES '%s'" % (r, event._item) logger.error(text) if event._reasons: for reason in event._reasons: logger.error("%s", reason) text += reason buildinfohelper.store_log_error(text) continue if isinstance(event, bb.event.ConfigParsed): continue if isinstance(event, bb.event.RecipeParsed): continue # end of saved events if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)): buildinfohelper.store_started_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskCompleted): buildinfohelper.update_and_store_task(event) continue if isinstance(event, bb.runqueue.runQueueTaskFailed): buildinfohelper.update_and_store_task(event) taskfailures.append(event.taskstring) logger.error("Task %s (%s) failed with exit code '%s'", event.taskid, event.taskstring, event.exitcode) continue if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)): buildinfohelper.update_and_store_task(event) continue if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)): continue if isinstance(event, (bb.event.BuildCompleted)): # update the build info helper on BuildCompleted, not on CommandXXX buildinfohelper.update_build_information( event, errors, warnings, taskfailures) buildinfohelper.close(errorcode) # mark the log output; controllers may kill the toasterUI after seeing this log logger.info("ToasterUI build done") # we start a new build info if buildinfohelper.brbe is not None: logger.debug( 1, "ToasterUI under BuildEnvironment management - exiting after the build" ) server.terminateServer() else: logger.debug(1, "ToasterUI prepared for new build") errors = 0 warnings = 0 taskfailures = [] buildinfohelper = BuildInfoHelper(server, build_history_enabled) continue if isinstance(event, (bb.command.CommandCompleted, bb.command.CommandFailed, bb.command.CommandExit)): errorcode = 0 if (isinstance(event, bb.command.CommandFailed)): event.levelno = format.ERROR event.msg = "Command Failed " + event.error event.pathname = "" event.lineno = 0 buildinfohelper.store_log_event(event) errors += 1 errorcode = 1 logger.error("Command execution failed: %s", event.error) continue if isinstance(event, bb.event.MetadataEvent): if event.type == "SinglePackageInfo": buildinfohelper.store_build_package_information(event) elif event.type == "LayerInfo": buildinfohelper.store_layer_info(event) elif event.type == "BuildStatsList": buildinfohelper.store_tasks_stats(event) elif event.type == "ImagePkgList": buildinfohelper.store_target_package_data(event) elif event.type == "MissedSstate": buildinfohelper.store_missed_state_tasks(event) elif event.type == "ImageFileSize": buildinfohelper.update_target_image_file(event) elif event.type == "ArtifactFileSize": buildinfohelper.update_artifact_image_file(event) elif event.type == "LicenseManifestPath": buildinfohelper.store_license_manifest_path(event) else: logger.error("Unprocessed MetadataEvent %s " % str(event)) continue if isinstance(event, bb.cooker.CookerExit): # exit when the server exits break # ignore if isinstance( event, (bb.event.BuildBase, bb.event.StampUpdate, bb.event.RecipePreFinalise, bb.runqueue.runQueueEvent, bb.runqueue.runQueueExitWait, bb.event.OperationProgress, bb.command.CommandFailed, bb.command.CommandExit, bb.command.CommandCompleted)): continue if isinstance(event, bb.event.DepTreeGenerated): buildinfohelper.store_dependency_information(event) continue logger.error("Unknown event: %s", event) return_value += 1 except EnvironmentError as ioerror: # ignore interrupted io if ioerror.args[0] == 4: pass except KeyboardInterrupt: main.shutdown = 1 pass except Exception as e: # print errors to log import traceback from pprint import pformat exception_data = traceback.format_exc() logger.error("%s\n%s" % (e, exception_data)) exc_type, exc_value, tb = sys.exc_info() if tb is not None: curr = tb while curr is not None: logger.warn( "Error data dump %s\n%s\n" % (traceback.format_tb( curr, 1), pformat(curr.tb_frame.f_locals))) curr = curr.tb_next # save them to database, if possible; if it fails, we already logged to console. try: buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data)) except Exception as ce: logger.error( "CRITICAL - Failed to to save toaster exception to the database: %s" % str(ce)) # make sure we return with an error return_value += 1 pass if interrupted: if return_value == 0: return_value += 1 logger.warn("Return value is %d", return_value) return return_value