blob: df020551e3fd6189df4d00c9ae157b9f8e1f3e05 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"""
2BitBake 'Event' implementation
3
4Classes and functions for manipulating 'events' in the
5BitBake build tools.
6"""
7
8# Copyright (C) 2003, 2004 Chris Larson
9#
Brad Bishopc342db32019-05-15 21:57:59 -040010# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050011#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050013import ast
Andrew Geisslerc9f78652020-09-18 14:11:35 -050014import atexit
15import collections
16import logging
17import pickle
18import sys
Patrick Williamsc0f7c042017-02-23 20:41:17 -060019import threading
Andrew Geisslerc9f78652020-09-18 14:11:35 -050020import traceback
Patrick Williamsc0f7c042017-02-23 20:41:17 -060021
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022import bb.exceptions
Andrew Geisslerc9f78652020-09-18 14:11:35 -050023import bb.utils
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024
25# This is the pid for which we should generate the event. This is set when
26# the runqueue forks off.
27worker_pid = 0
28worker_fire = None
29
30logger = logging.getLogger('BitBake.Event')
31
32class Event(object):
33 """Base class for events"""
34
35 def __init__(self):
36 self.pid = worker_pid
37
Brad Bishop6e60e8b2018-02-01 10:27:11 -050038
39class HeartbeatEvent(Event):
40 """Triggered at regular time intervals of 10 seconds. Other events can fire much more often
41 (runQueueTaskStarted when there are many short tasks) or not at all for long periods
42 of time (again runQueueTaskStarted, when there is just one long-running task), so this
Andrew Geissler7e0e3c02022-02-25 20:34:39 +000043 event is more suitable for doing some task-independent work occasionally."""
Brad Bishop6e60e8b2018-02-01 10:27:11 -050044 def __init__(self, time):
45 Event.__init__(self)
46 self.time = time
47
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048Registered = 10
49AlreadyRegistered = 14
50
51def get_class_handlers():
52 return _handlers
53
54def set_class_handlers(h):
55 global _handlers
56 _handlers = h
57
58def clean_class_handlers():
Andrew Geisslerc9f78652020-09-18 14:11:35 -050059 return collections.OrderedDict()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060
61# Internal
62_handlers = clean_class_handlers()
63_ui_handlers = {}
64_ui_logfilters = {}
65_ui_handler_seq = 0
66_event_handler_map = {}
67_catchall_handlers = {}
68_eventfilter = None
69_uiready = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -060070_thread_lock = threading.Lock()
71_thread_lock_enabled = False
72
73if hasattr(__builtins__, '__setitem__'):
74 builtins = __builtins__
75else:
76 builtins = __builtins__.__dict__
77
78def enable_threadlock():
79 global _thread_lock_enabled
80 _thread_lock_enabled = True
81
82def disable_threadlock():
83 global _thread_lock_enabled
84 _thread_lock_enabled = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050085
86def execute_handler(name, handler, event, d):
87 event.data = d
88 addedd = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -060089 if 'd' not in builtins:
90 builtins['d'] = d
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091 addedd = True
92 try:
93 ret = handler(event)
94 except (bb.parse.SkipRecipe, bb.BBHandledException):
95 raise
96 except Exception:
97 etype, value, tb = sys.exc_info()
98 logger.error("Execution of event handler '%s' failed" % name,
99 exc_info=(etype, value, tb.tb_next))
100 raise
101 except SystemExit as exc:
102 if exc.code != 0:
103 logger.error("Execution of event handler '%s' failed" % name)
104 raise
105 finally:
106 del event.data
107 if addedd:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600108 del builtins['d']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500109
110def fire_class_handlers(event, d):
111 if isinstance(event, logging.LogRecord):
112 return
113
114 eid = str(event.__class__)[8:-2]
115 evt_hmap = _event_handler_map.get(eid, {})
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600116 for name, handler in list(_handlers.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117 if name in _catchall_handlers or name in evt_hmap:
118 if _eventfilter:
119 if not _eventfilter(name, handler, event, d):
120 continue
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500121 if d is not None and not name in (d.getVar("__BBHANDLERS_MC") or set()):
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600122 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500123 execute_handler(name, handler, event, d)
124
125ui_queue = []
126@atexit.register
127def print_ui_queue():
Brad Bishop96ff1982019-08-19 13:50:42 -0400128 global ui_queue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 """If we're exiting before a UI has been spawned, display any queued
130 LogRecords to the console."""
131 logger = logging.getLogger("BitBake")
132 if not _uiready:
133 from bb.msg import BBLogFormatter
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800134 # Flush any existing buffered content
135 sys.stdout.flush()
136 sys.stderr.flush()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600137 stdout = logging.StreamHandler(sys.stdout)
138 stderr = logging.StreamHandler(sys.stderr)
139 formatter = BBLogFormatter("%(levelname)s: %(message)s")
140 stdout.setFormatter(formatter)
141 stderr.setFormatter(formatter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142
143 # First check to see if we have any proper messages
144 msgprint = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500145 msgerrs = False
146
147 # Should we print to stderr?
148 for event in ui_queue[:]:
149 if isinstance(event, logging.LogRecord) and event.levelno >= logging.WARNING:
150 msgerrs = True
151 break
152
153 if msgerrs:
154 logger.addHandler(stderr)
155 else:
156 logger.addHandler(stdout)
157
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600158 for event in ui_queue[:]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500159 if isinstance(event, logging.LogRecord):
160 if event.levelno > logging.DEBUG:
161 logger.handle(event)
162 msgprint = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163
164 # Nope, so just print all of the messages we have (including debug messages)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500165 if not msgprint:
166 for event in ui_queue[:]:
167 if isinstance(event, logging.LogRecord):
168 logger.handle(event)
169 if msgerrs:
170 logger.removeHandler(stderr)
171 else:
172 logger.removeHandler(stdout)
Brad Bishop96ff1982019-08-19 13:50:42 -0400173 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174
175def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600176 global _thread_lock
177 global _thread_lock_enabled
178
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500179 if not _uiready:
180 # No UI handlers registered yet, queue up the messages
181 ui_queue.append(event)
182 return
183
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600184 if _thread_lock_enabled:
185 _thread_lock.acquire()
186
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500187 errors = []
188 for h in _ui_handlers:
189 #print "Sending event %s" % event
190 try:
191 if not _ui_logfilters[h].filter(event):
192 continue
193 # We use pickle here since it better handles object instances
194 # which xmlrpc's marshaller does not. Events *must* be serializable
195 # by pickle.
196 if hasattr(_ui_handlers[h].event, "sendpickle"):
197 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
198 else:
199 _ui_handlers[h].event.send(event)
200 except:
201 errors.append(h)
202 for h in errors:
203 del _ui_handlers[h]
204
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600205 if _thread_lock_enabled:
206 _thread_lock.release()
207
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500208def fire(event, d):
209 """Fire off an Event"""
210
211 # We can fire class handlers in the worker process context and this is
212 # desired so they get the task based datastore.
213 # UI handlers need to be fired in the server context so we defer this. They
214 # don't have a datastore so the datastore context isn't a problem.
215
216 fire_class_handlers(event, d)
217 if worker_fire:
218 worker_fire(event, d)
219 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500220 # If messages have been queued up, clear the queue
221 global _uiready, ui_queue
222 if _uiready and ui_queue:
223 for queue_event in ui_queue:
224 fire_ui_handlers(queue_event, d)
225 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500226 fire_ui_handlers(event, d)
227
228def fire_from_worker(event, d):
229 fire_ui_handlers(event, d)
230
231noop = lambda _: None
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600232def register(name, handler, mask=None, filename=None, lineno=None, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500233 """Register an Event handler"""
234
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500235 if data is not None and data.getVar("BB_CURRENT_MC"):
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600236 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600237 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600238
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500239 # already registered
240 if name in _handlers:
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500241 if data is not None:
242 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
243 bbhands_mc.add(name)
244 data.setVar("__BBHANDLERS_MC", bbhands_mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500245 return AlreadyRegistered
246
247 if handler is not None:
248 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600249 if isinstance(handler, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250 tmp = "def %s(e):\n%s" % (name, handler)
251 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500252 code = bb.methodpool.compile_cache(tmp)
253 if not code:
254 if filename is None:
255 filename = "%s(e)" % name
256 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
257 if lineno is not None:
258 ast.increment_lineno(code, lineno-1)
259 code = compile(code, filename, "exec")
260 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500261 except SyntaxError:
262 logger.error("Unable to register event handler '%s':\n%s", name,
263 ''.join(traceback.format_exc(limit=0)))
264 _handlers[name] = noop
265 return
266 env = {}
267 bb.utils.better_exec(code, env)
268 func = bb.utils.better_eval(name, env)
269 _handlers[name] = func
270 else:
271 _handlers[name] = handler
272
273 if not mask or '*' in mask:
274 _catchall_handlers[name] = True
275 else:
276 for m in mask:
277 if _event_handler_map.get(m, None) is None:
278 _event_handler_map[m] = {}
279 _event_handler_map[m][name] = True
280
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500281 if data is not None:
282 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
283 bbhands_mc.add(name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600284 data.setVar("__BBHANDLERS_MC", bbhands_mc)
285
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500286 return Registered
287
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600288def remove(name, handler, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500289 """Remove an Event handler"""
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500290 if data is not None:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600291 if data.getVar("BB_CURRENT_MC"):
292 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600293 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600294
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500295 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500296 if name in _catchall_handlers:
297 _catchall_handlers.pop(name)
298 for event in _event_handler_map.keys():
299 if name in _event_handler_map[event]:
300 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500301
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500302 if data is not None:
303 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600304 if name in bbhands_mc:
305 bbhands_mc.remove(name)
306 data.setVar("__BBHANDLERS_MC", bbhands_mc)
307
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600308def get_handlers():
309 return _handlers
310
311def set_handlers(handlers):
312 global _handlers
313 _handlers = handlers
314
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500315def set_eventfilter(func):
316 global _eventfilter
317 _eventfilter = func
318
319def register_UIHhandler(handler, mainui=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500320 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
321 _ui_handlers[_ui_handler_seq] = handler
322 level, debug_domains = bb.msg.constructLogOptions()
323 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500324 if mainui:
325 global _uiready
326 _uiready = _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500327 return _ui_handler_seq
328
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500329def unregister_UIHhandler(handlerNum, mainui=False):
330 if mainui:
331 global _uiready
332 _uiready = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500333 if handlerNum in _ui_handlers:
334 del _ui_handlers[handlerNum]
335 return
336
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500337def get_uihandler():
338 if _uiready is False:
339 return None
340 return _uiready
341
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500342# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
343class UIEventFilter(object):
344 def __init__(self, level, debug_domains):
345 self.update(None, level, debug_domains)
346
347 def update(self, eventmask, level, debug_domains):
348 self.eventmask = eventmask
349 self.stdlevel = level
350 self.debug_domains = debug_domains
351
352 def filter(self, event):
353 if isinstance(event, logging.LogRecord):
354 if event.levelno >= self.stdlevel:
355 return True
356 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
357 return True
358 return False
359 eid = str(event.__class__)[8:-2]
360 if self.eventmask and eid not in self.eventmask:
361 return False
362 return True
363
364def set_UIHmask(handlerNum, level, debug_domains, mask):
365 if not handlerNum in _ui_handlers:
366 return False
367 if '*' in mask:
368 _ui_logfilters[handlerNum].update(None, level, debug_domains)
369 else:
370 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
371 return True
372
373def getName(e):
374 """Returns the name of a class or class instance"""
Andrew Geissler82c905d2020-04-13 13:39:40 -0500375 if getattr(e, "__name__", None) is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500376 return e.__class__.__name__
377 else:
378 return e.__name__
379
380class OperationStarted(Event):
381 """An operation has begun"""
382 def __init__(self, msg = "Operation Started"):
383 Event.__init__(self)
384 self.msg = msg
385
386class OperationCompleted(Event):
387 """An operation has completed"""
388 def __init__(self, total, msg = "Operation Completed"):
389 Event.__init__(self)
390 self.total = total
391 self.msg = msg
392
393class OperationProgress(Event):
394 """An operation is in progress"""
395 def __init__(self, current, total, msg = "Operation in Progress"):
396 Event.__init__(self)
397 self.current = current
398 self.total = total
399 self.msg = msg + ": %s/%s" % (current, total);
400
401class ConfigParsed(Event):
402 """Configuration Parsing Complete"""
403
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500404class MultiConfigParsed(Event):
405 """Multi-Config Parsing Complete"""
406 def __init__(self, mcdata):
407 self.mcdata = mcdata
408 Event.__init__(self)
409
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500410class RecipeEvent(Event):
411 def __init__(self, fn):
412 self.fn = fn
413 Event.__init__(self)
414
415class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800416 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500417
Andrew Geissler1e34c2d2020-05-29 16:02:59 -0500418class RecipePostKeyExpansion(RecipeEvent):
419 """ Recipe Parsing Complete but not yet finalised"""
420
421
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500422class RecipeTaskPreProcess(RecipeEvent):
423 """
424 Recipe Tasks about to be finalised
425 The list of tasks should be final at this point and handlers
426 are only able to change interdependencies
427 """
428 def __init__(self, fn, tasklist):
429 self.fn = fn
430 self.tasklist = tasklist
431 Event.__init__(self)
432
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500433class RecipeParsed(RecipeEvent):
434 """ Recipe Parsing Complete """
435
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500437 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500438
439 def __init__(self, n, p, failures = 0):
440 self._name = n
441 self._pkgs = p
442 Event.__init__(self)
443 self._failures = failures
444
445 def getPkgs(self):
446 return self._pkgs
447
448 def setPkgs(self, pkgs):
449 self._pkgs = pkgs
450
451 def getName(self):
452 return self._name
453
454 def setName(self, name):
455 self._name = name
456
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500457 def getFailures(self):
458 """
459 Return the number of failed packages
460 """
461 return self._failures
462
463 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
464 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500465
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600466class BuildInit(BuildBase):
467 """buildFile or buildTargets was invoked"""
468 def __init__(self, p=[]):
469 name = None
470 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500471
472class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500473 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500474 def __init__(self, n, p, failures = 0):
475 OperationStarted.__init__(self, "Building Started")
476 BuildBase.__init__(self, n, p, failures)
477
478class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500479 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500480 def __init__(self, total, n, p, failures=0, interrupted=0):
481 if not failures:
482 OperationCompleted.__init__(self, total, "Building Succeeded")
483 else:
484 OperationCompleted.__init__(self, total, "Building Failed")
485 self._interrupted = interrupted
486 BuildBase.__init__(self, n, p, failures)
487
488class DiskFull(Event):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000489 """Disk full case build halted"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500490 def __init__(self, dev, type, freespace, mountpoint):
491 Event.__init__(self)
492 self._dev = dev
493 self._type = type
494 self._free = freespace
495 self._mountpoint = mountpoint
496
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500497class DiskUsageSample:
498 def __init__(self, available_bytes, free_bytes, total_bytes):
499 # Number of bytes available to non-root processes.
500 self.available_bytes = available_bytes
501 # Number of bytes available to root processes.
502 self.free_bytes = free_bytes
503 # Total capacity of the volume.
504 self.total_bytes = total_bytes
505
506class MonitorDiskEvent(Event):
507 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
508 Provides information about devices that are getting monitored."""
509 def __init__(self, disk_usage):
510 Event.__init__(self)
511 # hash of device root path -> DiskUsageSample
512 self.disk_usage = disk_usage
513
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500514class NoProvider(Event):
515 """No Provider for an Event"""
516
517 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
518 Event.__init__(self)
519 self._item = item
520 self._runtime = runtime
521 self._dependees = dependees
522 self._reasons = reasons
523 self._close_matches = close_matches
524
525 def getItem(self):
526 return self._item
527
528 def isRuntime(self):
529 return self._runtime
530
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500531 def __str__(self):
532 msg = ''
533 if self._runtime:
534 r = "R"
535 else:
536 r = ""
537
538 extra = ''
539 if not self._reasons:
540 if self._close_matches:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500541 extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500542
543 if self._dependees:
544 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
545 else:
546 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
547 if self._reasons:
548 for reason in self._reasons:
549 msg += '\n' + reason
550 return msg
551
552
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500553class MultipleProviders(Event):
554 """Multiple Providers"""
555
556 def __init__(self, item, candidates, runtime = False):
557 Event.__init__(self)
558 self._item = item
559 self._candidates = candidates
560 self._is_runtime = runtime
561
562 def isRuntime(self):
563 """
564 Is this a runtime issue?
565 """
566 return self._is_runtime
567
568 def getItem(self):
569 """
570 The name for the to be build item
571 """
572 return self._item
573
574 def getCandidates(self):
575 """
576 Get the possible Candidates for a PROVIDER.
577 """
578 return self._candidates
579
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500580 def __str__(self):
581 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
582 self._item,
583 ", ".join(self._candidates))
584 rtime = ""
585 if self._is_runtime:
586 rtime = "R"
587 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
588 return msg
589
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500590class ParseStarted(OperationStarted):
591 """Recipe parsing for the runqueue has begun"""
592 def __init__(self, total):
593 OperationStarted.__init__(self, "Recipe parsing Started")
594 self.total = total
595
596class ParseCompleted(OperationCompleted):
597 """Recipe parsing for the runqueue has completed"""
598 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
599 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
600 self.cached = cached
601 self.parsed = parsed
602 self.skipped = skipped
603 self.virtuals = virtuals
604 self.masked = masked
605 self.errors = errors
606 self.sofar = cached + parsed
607
608class ParseProgress(OperationProgress):
609 """Recipe parsing progress"""
610 def __init__(self, current, total):
611 OperationProgress.__init__(self, current, total, "Recipe parsing")
612
613
614class CacheLoadStarted(OperationStarted):
615 """Loading of the dependency cache has begun"""
616 def __init__(self, total):
617 OperationStarted.__init__(self, "Loading cache Started")
618 self.total = total
619
620class CacheLoadProgress(OperationProgress):
621 """Cache loading progress"""
622 def __init__(self, current, total):
623 OperationProgress.__init__(self, current, total, "Loading cache")
624
625class CacheLoadCompleted(OperationCompleted):
626 """Cache loading is complete"""
627 def __init__(self, total, num_entries):
628 OperationCompleted.__init__(self, total, "Loading cache Completed")
629 self.num_entries = num_entries
630
631class TreeDataPreparationStarted(OperationStarted):
632 """Tree data preparation started"""
633 def __init__(self):
634 OperationStarted.__init__(self, "Preparing tree data Started")
635
636class TreeDataPreparationProgress(OperationProgress):
637 """Tree data preparation is in progress"""
638 def __init__(self, current, total):
639 OperationProgress.__init__(self, current, total, "Preparing tree data")
640
641class TreeDataPreparationCompleted(OperationCompleted):
642 """Tree data preparation completed"""
643 def __init__(self, total):
644 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
645
646class DepTreeGenerated(Event):
647 """
648 Event when a dependency tree has been generated
649 """
650
651 def __init__(self, depgraph):
652 Event.__init__(self)
653 self._depgraph = depgraph
654
655class TargetsTreeGenerated(Event):
656 """
657 Event when a set of buildable targets has been generated
658 """
659 def __init__(self, model):
660 Event.__init__(self)
661 self._model = model
662
663class ReachableStamps(Event):
664 """
665 An event listing all stamps reachable after parsing
666 which the metadata may use to clean up stale data
667 """
668
669 def __init__(self, stamps):
670 Event.__init__(self)
671 self.stamps = stamps
672
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500673class StaleSetSceneTasks(Event):
674 """
675 An event listing setscene tasks which are 'stale' and will
676 be rerun. The metadata may use to clean up stale data.
677 tasks is a mapping of tasks and matching stale stamps.
678 """
679
680 def __init__(self, tasks):
681 Event.__init__(self)
682 self.tasks = tasks
683
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684class FilesMatchingFound(Event):
685 """
686 Event when a list of files matching the supplied pattern has
687 been generated
688 """
689 def __init__(self, pattern, matches):
690 Event.__init__(self)
691 self._pattern = pattern
692 self._matches = matches
693
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500694class ConfigFilesFound(Event):
695 """
696 Event when a list of appropriate config files has been generated
697 """
698 def __init__(self, variable, values):
699 Event.__init__(self)
700 self._variable = variable
701 self._values = values
702
703class ConfigFilePathFound(Event):
704 """
705 Event when a path for a config file has been found
706 """
707 def __init__(self, path):
708 Event.__init__(self)
709 self._path = path
710
711class MsgBase(Event):
712 """Base class for messages"""
713
714 def __init__(self, msg):
715 self._message = msg
716 Event.__init__(self)
717
718class MsgDebug(MsgBase):
719 """Debug Message"""
720
721class MsgNote(MsgBase):
722 """Note Message"""
723
724class MsgWarn(MsgBase):
725 """Warning Message"""
726
727class MsgError(MsgBase):
728 """Error Message"""
729
730class MsgFatal(MsgBase):
731 """Fatal Message"""
732
733class MsgPlain(MsgBase):
734 """General output"""
735
736class LogExecTTY(Event):
737 """Send event containing program to spawn on tty of the logger"""
738 def __init__(self, msg, prog, sleep_delay, retries):
739 Event.__init__(self)
740 self.msg = msg
741 self.prog = prog
742 self.sleep_delay = sleep_delay
743 self.retries = retries
744
745class LogHandler(logging.Handler):
746 """Dispatch logging messages as bitbake events"""
747
748 def emit(self, record):
749 if record.exc_info:
750 etype, value, tb = record.exc_info
751 if hasattr(tb, 'tb_next'):
752 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500753 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500754 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600755 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
756 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500757 record.exc_info = None
758 fire(record, None)
759
760 def filter(self, record):
761 record.taskpid = worker_pid
762 return True
763
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500764class MetadataEvent(Event):
765 """
766 Generic event that target for OE-Core classes
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000767 to report information during asynchronous execution
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500768 """
769 def __init__(self, eventtype, eventdata):
770 Event.__init__(self)
771 self.type = eventtype
772 self._localdata = eventdata
773
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600774class ProcessStarted(Event):
775 """
776 Generic process started event (usually part of the initial startup)
777 where further progress events will be delivered
778 """
779 def __init__(self, processname, total):
780 Event.__init__(self)
781 self.processname = processname
782 self.total = total
783
784class ProcessProgress(Event):
785 """
786 Generic process progress event (usually part of the initial startup)
787 """
788 def __init__(self, processname, progress):
789 Event.__init__(self)
790 self.processname = processname
791 self.progress = progress
792
793class ProcessFinished(Event):
794 """
795 Generic process finished event (usually part of the initial startup)
796 """
797 def __init__(self, processname):
798 Event.__init__(self)
799 self.processname = processname
800
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500801class SanityCheck(Event):
802 """
803 Event to run sanity checks, either raise errors or generate events as return status.
804 """
805 def __init__(self, generateevents = True):
806 Event.__init__(self)
807 self.generateevents = generateevents
808
809class SanityCheckPassed(Event):
810 """
811 Event to indicate sanity check has passed
812 """
813
814class SanityCheckFailed(Event):
815 """
816 Event to indicate sanity check has failed
817 """
818 def __init__(self, msg, network_error=False):
819 Event.__init__(self)
820 self._msg = msg
821 self._network_error = network_error
822
823class NetworkTest(Event):
824 """
825 Event to run network connectivity tests, either raise errors or generate events as return status.
826 """
827 def __init__(self, generateevents = True):
828 Event.__init__(self)
829 self.generateevents = generateevents
830
831class NetworkTestPassed(Event):
832 """
833 Event to indicate network test has passed
834 """
835
836class NetworkTestFailed(Event):
837 """
838 Event to indicate network test has failed
839 """
840
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500841class FindSigInfoResult(Event):
842 """
843 Event to return results from findSigInfo command
844 """
845 def __init__(self, result):
846 Event.__init__(self)
847 self.result = result