s="n">event) msgprint = True # Nope, so just print all of the messages we have (including debug messages) if not msgprint: for event in ui_queue[:]: if isinstance(event, logging.LogRecord): logger.handle(event) if msgerrs: logger.removeHandler(stderr) else: logger.removeHandler(stdout) ui_queue = [] def fire_ui_handlers(event, d): global _thread_lock global _thread_lock_enabled if not _uiready: # No UI handlers registered yet, queue up the messages ui_queue.append(event) return if _thread_lock_enabled: _thread_lock.acquire() errors = [] for h in _ui_handlers: #print "Sending event %s" % event try: if not _ui_logfilters[h].filter(event): continue # We use pickle here since it better handles object instances # which xmlrpc's marshaller does not. Events *must* be serializable # by pickle. if hasattr(_ui_handlers[h].event, "sendpickle"): _ui_handlers[h].event.sendpickle((pickle.dumps(event))) else: _ui_handlers[h].event.send(event) except: errors.append(h) for h in errors: del _ui_handlers[h] if _thread_lock_enabled: _thread_lock.release() def fire(event, d): """Fire off an Event""" # We can fire class handlers in the worker process context and this is # desired so they get the task based datastore. # UI handlers need to be fired in the server context so we defer this. They # don't have a datastore so the datastore context isn't a problem. fire_class_handlers(event, d) if worker_fire: worker_fire(event, d) else: # If messages have been queued up, clear the queue global _uiready, ui_queue if _uiready and ui_queue: for queue_event in ui_queue: fire_ui_handlers(queue_event, d) ui_queue = [] fire_ui_handlers(event, d) def fire_from_worker(event, d): fire_ui_handlers(event, d) noop = lambda _: None def register(name, handler, mask=None, filename=None, lineno=None): """Register an Event handler""" # already registered if name in _handlers: return AlreadyRegistered if handler is not None: # handle string containing python code if isinstance(handler, str): tmp = "def %s(e):\n%s" % (name, handler) try: code = bb.methodpool.compile_cache(tmp) if not code: if filename is None: filename = "%s(e)" % name code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST) if lineno is not None: ast.increment_lineno(code, lineno-1) code = compile(code, filename, "exec") bb.methodpool.compile_cache_add(tmp, code) except SyntaxError: logger.error("Unable to register event handler '%s':\n%s", name, ''.join(traceback.format_exc(limit=0))) _handlers[name] = noop return env = {} bb.utils.better_exec(code, env) func = bb.utils.better_eval(name, env) _handlers[name] = func else: _handlers[name] = handler if not mask or '*' in mask: _catchall_handlers[name] = True else: for m in mask: if _event_handler_map.get(m, None) is None: _event_handler_map[m] = {} _event_handler_map[m][name] = True return Registered def remove(name, handler): """Remove an Event handler""" _handlers.pop(name) if name in _catchall_handlers: _catchall_handlers.pop(name) for event in _event_handler_map.keys(): if name in _event_handler_map[event]: _event_handler_map[event].pop(name) def get_handlers(): return _handlers def set_handlers(handlers): global _handlers _handlers = handlers def set_eventfilter(func): global _eventfilter _eventfilter = func def register_UIHhandler(handler, mainui=False): bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 _ui_handlers[_ui_handler_seq] = handler level, debug_domains = bb.msg.constructLogOptions() _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains) if mainui: global _uiready _uiready = _ui_handler_seq return _ui_handler_seq def unregister_UIHhandler(handlerNum, mainui=False): if mainui: global _uiready _uiready = False if handlerNum in _ui_handlers: del _ui_handlers[handlerNum] return def get_uihandler(): if _uiready is False: return None return _uiready # Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC class UIEventFilter(object): def __init__(self, level, debug_domains): self.update(None, level, debug_domains) def update(self, eventmask, level, debug_domains): self.eventmask = eventmask self.stdlevel = level self.debug_domains = debug_domains def filter(self, event): if isinstance(event, logging.LogRecord): if event.levelno >= self.stdlevel: return True if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]: return True return False eid = str(event.__class__)[8:-2] if self.eventmask and eid not in self.eventmask: return False return True def set_UIHmask(handlerNum, level, debug_domains, mask): if not handlerNum in _ui_handlers: return False if '*' in mask: _ui_logfilters[handlerNum].update(None, level, debug_domains) else: _ui_logfilters[handlerNum].update(mask, level, debug_domains) return True def getName(e): """Returns the name of a class or class instance""" if getattr(e, "__name__", None) is None: return e.__class__.__name__ else: return e.__name__ class OperationStarted(Event): """An operation has begun""" def __init__(self, msg = "Operation Started"): Event.__init__(self) self.msg = msg class OperationCompleted(Event): """An operation has completed""" def __init__(self, total, msg = "Operation Completed"): Event.__init__(self) self.total = total self.msg = msg class OperationProgress(Event): """An operation is in progress""" def __init__(self, current, total, msg = "Operation in Progress"): Event.__init__(self) self.current = current self.total = total self.msg = msg + ": %s/%s" % (current, total); class ConfigParsed(Event): """Configuration Parsing Complete""" class MultiConfigParsed(Event): """Multi-Config Parsing Complete""" def __init__(self, mcdata): self.mcdata = mcdata Event.__init__(self) class RecipeEvent(Event): def __init__(self, fn): self.fn = fn Event.__init__(self) class RecipePreFinalise(RecipeEvent): """ Recipe Parsing Complete but not yet finalised""" class RecipeTaskPreProcess(RecipeEvent): """ Recipe Tasks about to be finalised The list of tasks should be final at this point and handlers are only able to change interdependencies """ def __init__(self, fn, tasklist): self.fn = fn self.tasklist = tasklist Event.__init__(self) class RecipeParsed(RecipeEvent): """ Recipe Parsing Complete """ class BuildBase(Event): """Base class for bitbake build events""" def __init__(self, n, p, failures = 0): self._name = n self._pkgs = p Event.__init__(self) self._failures = failures def getPkgs(self): return self._pkgs def setPkgs(self, pkgs): self._pkgs = pkgs def getName(self): return self._name def setName(self, name): self._name = name def getFailures(self): """ Return the number of failed packages """ return self._failures pkgs = property(getPkgs, setPkgs, None, "pkgs property") name = property(getName, setName, None, "name property") class BuildInit(BuildBase): """buildFile or buildTargets was invoked""" def __init__(self, p=[]): name = None BuildBase.__init__(self, name, p) class BuildStarted(BuildBase, OperationStarted): """Event when builds start""" def __init__(self, n, p, failures = 0): OperationStarted.__init__(self, "Building Started") BuildBase.__init__(self, n, p, failures) class BuildCompleted(BuildBase, OperationCompleted): """Event when builds have completed""" def __init__(self, total, n, p, failures=0, interrupted=0): if not failures: OperationCompleted.__init__(self, total, "Building Succeeded") else: OperationCompleted.__init__(self, total, "Building Failed") self._interrupted = interrupted BuildBase.__init__(self, n, p, failures) class DiskFull(Event): """Disk full case build aborted""" def __init__(self, dev, type, freespace, mountpoint): Event.__init__(self) self._dev = dev self._type = type self._free = freespace self._mountpoint = mountpoint class DiskUsageSample: def __init__(self, available_bytes, free_bytes, total_bytes): # Number of bytes available to non-root processes. self.available_bytes = available_bytes # Number of bytes available to root processes. self.free_bytes = free_bytes # Total capacity of the volume. self.total_bytes = total_bytes class MonitorDiskEvent(Event): """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked. Provides information about devices that are getting monitored.""" def __init__(self, disk_usage): Event.__init__(self) # hash of device root path -> DiskUsageSample self.disk_usage = disk_usage class NoProvider(Event): """No Provider for an Event""" def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None): Event.__init__(self) self._item = item self._runtime = runtime self._dependees = dependees self._reasons = reasons self._close_matches = close_matches def getItem(self): return self._item def isRuntime(self): return self._runtime def __str__(self): msg = '' if self._runtime: r = "R" else: r = "" extra = '' if not self._reasons: if self._close_matches: extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches))) if self._dependees: msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra) else: msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra) if self._reasons: for reason in self._reasons: msg += '\n' + reason return msg class MultipleProviders(Event): """Multiple Providers""" def __init__(self, item, candidates, runtime = False): Event.__init__(self) self._item = item self._candidates = candidates self._is_runtime = runtime def isRuntime(self): """ Is this a runtime issue? """ return self._is_runtime def getItem(self): """ The name for the to be build item """ return self._item def getCandidates(self): """ Get the possible Candidates for a PROVIDER. """ return self._candidates def __str__(self): msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "", self._item, ", ".join(self._candidates)) rtime = "" if self._is_runtime: rtime = "R" msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item) return msg class ParseStarted(OperationStarted): """Recipe parsing for the runqueue has begun""" def __init__(self, total): OperationStarted.__init__(self, "Recipe parsing Started") self.total = total class ParseCompleted(OperationCompleted): """Recipe parsing for the runqueue has completed""" def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total): OperationCompleted.__init__(self, total, "Recipe parsing Completed") self.cached = cached self.parsed = parsed self.skipped = skipped self.virtuals = virtuals self.masked = masked self.errors = errors self.sofar = cached + parsed class ParseProgress(OperationProgress): """Recipe parsing progress""" def __init__(self, current, total): OperationProgress.__init__(self, current, total, "Recipe parsing") class CacheLoadStarted(OperationStarted): """Loading of the dependency cache has begun""" def __init__(self, total): OperationStarted.__init__(self, "Loading cache Started") self.total = total class CacheLoadProgress(OperationProgress): """Cache loading progress""" def __init__(self, current, total): OperationProgress.__init__(self, current, total, "Loading cache") class CacheLoadCompleted(OperationCompleted): """Cache loading is complete""" def __init__(self, total, num_entries): OperationCompleted.__init__(self, total, "Loading cache Completed") self.num_entries = num_entries class TreeDataPreparationStarted(OperationStarted): """Tree data preparation started""" def __init__(self): OperationStarted.__init__(self, "Preparing tree data Started") class TreeDataPreparationProgress(OperationProgress): """Tree data preparation is in progress""" def __init__(self, current, total): OperationProgress.__init__(self, current, total, "Preparing tree data") class TreeDataPreparationCompleted(OperationCompleted): """Tree data preparation completed""" def __init__(self, total): OperationCompleted.__init__(self, total, "Preparing tree data Completed") class DepTreeGenerated(Event): """ Event when a dependency tree has been generated """ def __init__(self, depgraph): Event.__init__(self) self._depgraph = depgraph class TargetsTreeGenerated(Event): """ Event when a set of buildable targets has been generated """ def __init__(self, model): Event.__init__(self) self._model = model class ReachableStamps(Event): """ An event listing all stamps reachable after parsing which the metadata may use to clean up stale data """ def __init__(self, stamps): Event.__init__(self) self.stamps = stamps class FilesMatchingFound(Event): """ Event when a list of files matching the supplied pattern has been generated """ def __init__(self, pattern, matches): Event.__init__(self) self._pattern = pattern self._matches = matches class ConfigFilesFound(Event): """ Event when a list of appropriate config files has been generated """ def __init__(self, variable, values): Event.__init__(self) self._variable = variable self._values = values class ConfigFilePathFound(Event): """ Event when a path for a config file has been found """ def __init__(self, path): Event.__init__(self) self._path = path class MsgBase(Event): """Base class for messages""" def __init__(self, msg): self._message = msg Event.__init__(self) class MsgDebug(MsgBase): """Debug Message""" class MsgNote(MsgBase): """Note Message""" class MsgWarn(MsgBase): """Warning Message""" class MsgError(MsgBase): """Error Message""" class MsgFatal(MsgBase): """Fatal Message""" class MsgPlain(MsgBase): """General output""" class LogExecTTY(Event): """Send event containing program to spawn on tty of the logger""" def __init__(self, msg, prog, sleep_delay, retries): Event.__init__(self) self.msg = msg self.prog = prog self.sleep_delay = sleep_delay self.retries = retries class LogHandler(logging.Handler): """Dispatch logging messages as bitbake events""" def emit(self, record): if record.exc_info: etype, value, tb = record.exc_info if hasattr(tb, 'tb_next'): tb = list(bb.exceptions.extract_traceback(tb, context=3)) # Need to turn the value into something the logging system can pickle record.bb_exc_info = (etype, value, tb) record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5) value = str(value) record.exc_info = None fire(record, None) def filter(self, record): record.taskpid = worker_pid return True class MetadataEvent(Event): """ Generic event that target for OE-Core classes to report information during asynchrous execution """ def __init__(self, eventtype, eventdata): Event.__init__(self) self.type = eventtype self._localdata = eventdata class ProcessStarted(Event): """ Generic process started event (usually part of the initial startup) where further progress events will be delivered """ def __init__(self, processname, total): Event.__init__(self) self.processname = processname self.total = total class ProcessProgress(Event): """ Generic process progress event (usually part of the initial startup) """ def __init__(self, processname, progress): Event.__init__(self) self.processname = processname self.progress = progress class ProcessFinished(Event): """ Generic process finished event (usually part of the initial startup) """ def __init__(self, processname): Event.__init__(self) self.processname = processname class SanityCheck(Event): """ Event to run sanity checks, either raise errors or generate events as return status. """ def __init__(self, generateevents = True): Event.__init__(self) self.generateevents = generateevents class SanityCheckPassed(Event): """ Event to indicate sanity check has passed """ class SanityCheckFailed(Event): """ Event to indicate sanity check has failed """ def __init__(self, msg, network_error=False): Event.__init__(self) self._msg = msg self._network_error = network_error class NetworkTest(Event): """ Event to run network connectivity tests, either raise errors or generate events as return status. """ def __init__(self, generateevents = True): Event.__init__(self) self.generateevents = generateevents class NetworkTestPassed(Event): """ Event to indicate network test has passed """ class NetworkTestFailed(Event): """ Event to indicate network test has failed """ class FindSigInfoResult(Event): """ Event to return results from findSigInfo command """ def __init__(self, result): Event.__init__(self) self.result = result