blob: 97668601a15191eb8a15e92250462ceee1022847 [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
Andrew Geissler78b72792022-06-14 06:47:25 -0500135 try:
136 sys.stdout.flush()
137 except:
138 pass
139 try:
140 sys.stderr.flush()
141 except:
142 pass
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600143 stdout = logging.StreamHandler(sys.stdout)
144 stderr = logging.StreamHandler(sys.stderr)
145 formatter = BBLogFormatter("%(levelname)s: %(message)s")
146 stdout.setFormatter(formatter)
147 stderr.setFormatter(formatter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500148
149 # First check to see if we have any proper messages
150 msgprint = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500151 msgerrs = False
152
153 # Should we print to stderr?
154 for event in ui_queue[:]:
155 if isinstance(event, logging.LogRecord) and event.levelno >= logging.WARNING:
156 msgerrs = True
157 break
158
159 if msgerrs:
160 logger.addHandler(stderr)
161 else:
162 logger.addHandler(stdout)
163
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600164 for event in ui_queue[:]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500165 if isinstance(event, logging.LogRecord):
166 if event.levelno > logging.DEBUG:
167 logger.handle(event)
168 msgprint = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500169
170 # Nope, so just print all of the messages we have (including debug messages)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500171 if not msgprint:
172 for event in ui_queue[:]:
173 if isinstance(event, logging.LogRecord):
174 logger.handle(event)
175 if msgerrs:
176 logger.removeHandler(stderr)
177 else:
178 logger.removeHandler(stdout)
Brad Bishop96ff1982019-08-19 13:50:42 -0400179 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500180
181def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600182 global _thread_lock
183 global _thread_lock_enabled
184
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185 if not _uiready:
186 # No UI handlers registered yet, queue up the messages
187 ui_queue.append(event)
188 return
189
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 if _thread_lock_enabled:
191 _thread_lock.acquire()
192
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 errors = []
194 for h in _ui_handlers:
195 #print "Sending event %s" % event
196 try:
197 if not _ui_logfilters[h].filter(event):
198 continue
199 # We use pickle here since it better handles object instances
200 # which xmlrpc's marshaller does not. Events *must* be serializable
201 # by pickle.
202 if hasattr(_ui_handlers[h].event, "sendpickle"):
203 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
204 else:
205 _ui_handlers[h].event.send(event)
206 except:
207 errors.append(h)
208 for h in errors:
209 del _ui_handlers[h]
210
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600211 if _thread_lock_enabled:
212 _thread_lock.release()
213
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500214def fire(event, d):
215 """Fire off an Event"""
216
217 # We can fire class handlers in the worker process context and this is
218 # desired so they get the task based datastore.
219 # UI handlers need to be fired in the server context so we defer this. They
220 # don't have a datastore so the datastore context isn't a problem.
221
222 fire_class_handlers(event, d)
223 if worker_fire:
224 worker_fire(event, d)
225 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500226 # If messages have been queued up, clear the queue
227 global _uiready, ui_queue
228 if _uiready and ui_queue:
229 for queue_event in ui_queue:
230 fire_ui_handlers(queue_event, d)
231 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500232 fire_ui_handlers(event, d)
233
234def fire_from_worker(event, d):
235 fire_ui_handlers(event, d)
236
237noop = lambda _: None
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600238def register(name, handler, mask=None, filename=None, lineno=None, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500239 """Register an Event handler"""
240
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500241 if data is not None and data.getVar("BB_CURRENT_MC"):
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600242 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600243 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600244
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500245 # already registered
246 if name in _handlers:
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500247 if data is not None:
248 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
249 bbhands_mc.add(name)
250 data.setVar("__BBHANDLERS_MC", bbhands_mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500251 return AlreadyRegistered
252
253 if handler is not None:
254 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600255 if isinstance(handler, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500256 tmp = "def %s(e):\n%s" % (name, handler)
257 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500258 code = bb.methodpool.compile_cache(tmp)
259 if not code:
260 if filename is None:
261 filename = "%s(e)" % name
262 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
263 if lineno is not None:
264 ast.increment_lineno(code, lineno-1)
265 code = compile(code, filename, "exec")
266 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500267 except SyntaxError:
268 logger.error("Unable to register event handler '%s':\n%s", name,
269 ''.join(traceback.format_exc(limit=0)))
270 _handlers[name] = noop
271 return
272 env = {}
273 bb.utils.better_exec(code, env)
274 func = bb.utils.better_eval(name, env)
275 _handlers[name] = func
276 else:
277 _handlers[name] = handler
278
279 if not mask or '*' in mask:
280 _catchall_handlers[name] = True
281 else:
282 for m in mask:
283 if _event_handler_map.get(m, None) is None:
284 _event_handler_map[m] = {}
285 _event_handler_map[m][name] = True
286
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500287 if data is not None:
288 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
289 bbhands_mc.add(name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600290 data.setVar("__BBHANDLERS_MC", bbhands_mc)
291
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500292 return Registered
293
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600294def remove(name, handler, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500295 """Remove an Event handler"""
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500296 if data is not None:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600297 if data.getVar("BB_CURRENT_MC"):
298 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600299 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600300
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500301 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500302 if name in _catchall_handlers:
303 _catchall_handlers.pop(name)
304 for event in _event_handler_map.keys():
305 if name in _event_handler_map[event]:
306 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500307
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500308 if data is not None:
309 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600310 if name in bbhands_mc:
311 bbhands_mc.remove(name)
312 data.setVar("__BBHANDLERS_MC", bbhands_mc)
313
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600314def get_handlers():
315 return _handlers
316
317def set_handlers(handlers):
318 global _handlers
319 _handlers = handlers
320
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500321def set_eventfilter(func):
322 global _eventfilter
323 _eventfilter = func
324
325def register_UIHhandler(handler, mainui=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500326 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
327 _ui_handlers[_ui_handler_seq] = handler
328 level, debug_domains = bb.msg.constructLogOptions()
329 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500330 if mainui:
331 global _uiready
332 _uiready = _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500333 return _ui_handler_seq
334
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500335def unregister_UIHhandler(handlerNum, mainui=False):
336 if mainui:
337 global _uiready
338 _uiready = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500339 if handlerNum in _ui_handlers:
340 del _ui_handlers[handlerNum]
341 return
342
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500343def get_uihandler():
344 if _uiready is False:
345 return None
346 return _uiready
347
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500348# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
349class UIEventFilter(object):
350 def __init__(self, level, debug_domains):
351 self.update(None, level, debug_domains)
352
353 def update(self, eventmask, level, debug_domains):
354 self.eventmask = eventmask
355 self.stdlevel = level
356 self.debug_domains = debug_domains
357
358 def filter(self, event):
359 if isinstance(event, logging.LogRecord):
360 if event.levelno >= self.stdlevel:
361 return True
362 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
363 return True
364 return False
365 eid = str(event.__class__)[8:-2]
366 if self.eventmask and eid not in self.eventmask:
367 return False
368 return True
369
370def set_UIHmask(handlerNum, level, debug_domains, mask):
371 if not handlerNum in _ui_handlers:
372 return False
373 if '*' in mask:
374 _ui_logfilters[handlerNum].update(None, level, debug_domains)
375 else:
376 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
377 return True
378
379def getName(e):
380 """Returns the name of a class or class instance"""
Andrew Geissler82c905d2020-04-13 13:39:40 -0500381 if getattr(e, "__name__", None) is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500382 return e.__class__.__name__
383 else:
384 return e.__name__
385
386class OperationStarted(Event):
387 """An operation has begun"""
388 def __init__(self, msg = "Operation Started"):
389 Event.__init__(self)
390 self.msg = msg
391
392class OperationCompleted(Event):
393 """An operation has completed"""
394 def __init__(self, total, msg = "Operation Completed"):
395 Event.__init__(self)
396 self.total = total
397 self.msg = msg
398
399class OperationProgress(Event):
400 """An operation is in progress"""
401 def __init__(self, current, total, msg = "Operation in Progress"):
402 Event.__init__(self)
403 self.current = current
404 self.total = total
405 self.msg = msg + ": %s/%s" % (current, total);
406
407class ConfigParsed(Event):
408 """Configuration Parsing Complete"""
409
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500410class MultiConfigParsed(Event):
411 """Multi-Config Parsing Complete"""
412 def __init__(self, mcdata):
413 self.mcdata = mcdata
414 Event.__init__(self)
415
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500416class RecipeEvent(Event):
417 def __init__(self, fn):
418 self.fn = fn
419 Event.__init__(self)
420
421class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800422 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500423
Andrew Geissler1e34c2d2020-05-29 16:02:59 -0500424class RecipePostKeyExpansion(RecipeEvent):
425 """ Recipe Parsing Complete but not yet finalised"""
426
427
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500428class RecipeTaskPreProcess(RecipeEvent):
429 """
430 Recipe Tasks about to be finalised
431 The list of tasks should be final at this point and handlers
432 are only able to change interdependencies
433 """
434 def __init__(self, fn, tasklist):
435 self.fn = fn
436 self.tasklist = tasklist
437 Event.__init__(self)
438
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500439class RecipeParsed(RecipeEvent):
440 """ Recipe Parsing Complete """
441
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500442class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500443 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444
445 def __init__(self, n, p, failures = 0):
446 self._name = n
447 self._pkgs = p
448 Event.__init__(self)
449 self._failures = failures
450
451 def getPkgs(self):
452 return self._pkgs
453
454 def setPkgs(self, pkgs):
455 self._pkgs = pkgs
456
457 def getName(self):
458 return self._name
459
460 def setName(self, name):
461 self._name = name
462
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500463 def getFailures(self):
464 """
465 Return the number of failed packages
466 """
467 return self._failures
468
469 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
470 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500471
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600472class BuildInit(BuildBase):
473 """buildFile or buildTargets was invoked"""
474 def __init__(self, p=[]):
475 name = None
476 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500477
478class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500479 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500480 def __init__(self, n, p, failures = 0):
481 OperationStarted.__init__(self, "Building Started")
482 BuildBase.__init__(self, n, p, failures)
483
484class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500485 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500486 def __init__(self, total, n, p, failures=0, interrupted=0):
487 if not failures:
488 OperationCompleted.__init__(self, total, "Building Succeeded")
489 else:
490 OperationCompleted.__init__(self, total, "Building Failed")
491 self._interrupted = interrupted
492 BuildBase.__init__(self, n, p, failures)
493
494class DiskFull(Event):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000495 """Disk full case build halted"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500496 def __init__(self, dev, type, freespace, mountpoint):
497 Event.__init__(self)
498 self._dev = dev
499 self._type = type
500 self._free = freespace
501 self._mountpoint = mountpoint
502
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500503class DiskUsageSample:
504 def __init__(self, available_bytes, free_bytes, total_bytes):
505 # Number of bytes available to non-root processes.
506 self.available_bytes = available_bytes
507 # Number of bytes available to root processes.
508 self.free_bytes = free_bytes
509 # Total capacity of the volume.
510 self.total_bytes = total_bytes
511
512class MonitorDiskEvent(Event):
513 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
514 Provides information about devices that are getting monitored."""
515 def __init__(self, disk_usage):
516 Event.__init__(self)
517 # hash of device root path -> DiskUsageSample
518 self.disk_usage = disk_usage
519
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500520class NoProvider(Event):
521 """No Provider for an Event"""
522
523 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
524 Event.__init__(self)
525 self._item = item
526 self._runtime = runtime
527 self._dependees = dependees
528 self._reasons = reasons
529 self._close_matches = close_matches
530
531 def getItem(self):
532 return self._item
533
534 def isRuntime(self):
535 return self._runtime
536
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500537 def __str__(self):
538 msg = ''
539 if self._runtime:
540 r = "R"
541 else:
542 r = ""
543
544 extra = ''
545 if not self._reasons:
546 if self._close_matches:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500547 extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500548
549 if self._dependees:
550 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
551 else:
552 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
553 if self._reasons:
554 for reason in self._reasons:
555 msg += '\n' + reason
556 return msg
557
558
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500559class MultipleProviders(Event):
560 """Multiple Providers"""
561
562 def __init__(self, item, candidates, runtime = False):
563 Event.__init__(self)
564 self._item = item
565 self._candidates = candidates
566 self._is_runtime = runtime
567
568 def isRuntime(self):
569 """
570 Is this a runtime issue?
571 """
572 return self._is_runtime
573
574 def getItem(self):
575 """
576 The name for the to be build item
577 """
578 return self._item
579
580 def getCandidates(self):
581 """
582 Get the possible Candidates for a PROVIDER.
583 """
584 return self._candidates
585
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500586 def __str__(self):
587 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
588 self._item,
589 ", ".join(self._candidates))
590 rtime = ""
591 if self._is_runtime:
592 rtime = "R"
593 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
594 return msg
595
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500596class ParseStarted(OperationStarted):
597 """Recipe parsing for the runqueue has begun"""
598 def __init__(self, total):
599 OperationStarted.__init__(self, "Recipe parsing Started")
600 self.total = total
601
602class ParseCompleted(OperationCompleted):
603 """Recipe parsing for the runqueue has completed"""
604 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
605 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
606 self.cached = cached
607 self.parsed = parsed
608 self.skipped = skipped
609 self.virtuals = virtuals
610 self.masked = masked
611 self.errors = errors
612 self.sofar = cached + parsed
613
614class ParseProgress(OperationProgress):
615 """Recipe parsing progress"""
616 def __init__(self, current, total):
617 OperationProgress.__init__(self, current, total, "Recipe parsing")
618
619
620class CacheLoadStarted(OperationStarted):
621 """Loading of the dependency cache has begun"""
622 def __init__(self, total):
623 OperationStarted.__init__(self, "Loading cache Started")
624 self.total = total
625
626class CacheLoadProgress(OperationProgress):
627 """Cache loading progress"""
628 def __init__(self, current, total):
629 OperationProgress.__init__(self, current, total, "Loading cache")
630
631class CacheLoadCompleted(OperationCompleted):
632 """Cache loading is complete"""
633 def __init__(self, total, num_entries):
634 OperationCompleted.__init__(self, total, "Loading cache Completed")
635 self.num_entries = num_entries
636
637class TreeDataPreparationStarted(OperationStarted):
638 """Tree data preparation started"""
639 def __init__(self):
640 OperationStarted.__init__(self, "Preparing tree data Started")
641
642class TreeDataPreparationProgress(OperationProgress):
643 """Tree data preparation is in progress"""
644 def __init__(self, current, total):
645 OperationProgress.__init__(self, current, total, "Preparing tree data")
646
647class TreeDataPreparationCompleted(OperationCompleted):
648 """Tree data preparation completed"""
649 def __init__(self, total):
650 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
651
652class DepTreeGenerated(Event):
653 """
654 Event when a dependency tree has been generated
655 """
656
657 def __init__(self, depgraph):
658 Event.__init__(self)
659 self._depgraph = depgraph
660
661class TargetsTreeGenerated(Event):
662 """
663 Event when a set of buildable targets has been generated
664 """
665 def __init__(self, model):
666 Event.__init__(self)
667 self._model = model
668
669class ReachableStamps(Event):
670 """
671 An event listing all stamps reachable after parsing
672 which the metadata may use to clean up stale data
673 """
674
675 def __init__(self, stamps):
676 Event.__init__(self)
677 self.stamps = stamps
678
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500679class StaleSetSceneTasks(Event):
680 """
681 An event listing setscene tasks which are 'stale' and will
682 be rerun. The metadata may use to clean up stale data.
683 tasks is a mapping of tasks and matching stale stamps.
684 """
685
686 def __init__(self, tasks):
687 Event.__init__(self)
688 self.tasks = tasks
689
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500690class FilesMatchingFound(Event):
691 """
692 Event when a list of files matching the supplied pattern has
693 been generated
694 """
695 def __init__(self, pattern, matches):
696 Event.__init__(self)
697 self._pattern = pattern
698 self._matches = matches
699
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500700class ConfigFilesFound(Event):
701 """
702 Event when a list of appropriate config files has been generated
703 """
704 def __init__(self, variable, values):
705 Event.__init__(self)
706 self._variable = variable
707 self._values = values
708
709class ConfigFilePathFound(Event):
710 """
711 Event when a path for a config file has been found
712 """
713 def __init__(self, path):
714 Event.__init__(self)
715 self._path = path
716
717class MsgBase(Event):
718 """Base class for messages"""
719
720 def __init__(self, msg):
721 self._message = msg
722 Event.__init__(self)
723
724class MsgDebug(MsgBase):
725 """Debug Message"""
726
727class MsgNote(MsgBase):
728 """Note Message"""
729
730class MsgWarn(MsgBase):
731 """Warning Message"""
732
733class MsgError(MsgBase):
734 """Error Message"""
735
736class MsgFatal(MsgBase):
737 """Fatal Message"""
738
739class MsgPlain(MsgBase):
740 """General output"""
741
742class LogExecTTY(Event):
743 """Send event containing program to spawn on tty of the logger"""
744 def __init__(self, msg, prog, sleep_delay, retries):
745 Event.__init__(self)
746 self.msg = msg
747 self.prog = prog
748 self.sleep_delay = sleep_delay
749 self.retries = retries
750
751class LogHandler(logging.Handler):
752 """Dispatch logging messages as bitbake events"""
753
754 def emit(self, record):
755 if record.exc_info:
756 etype, value, tb = record.exc_info
757 if hasattr(tb, 'tb_next'):
758 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500759 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500760 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600761 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
762 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500763 record.exc_info = None
764 fire(record, None)
765
766 def filter(self, record):
767 record.taskpid = worker_pid
768 return True
769
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500770class MetadataEvent(Event):
771 """
772 Generic event that target for OE-Core classes
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000773 to report information during asynchronous execution
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500774 """
775 def __init__(self, eventtype, eventdata):
776 Event.__init__(self)
777 self.type = eventtype
778 self._localdata = eventdata
779
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600780class ProcessStarted(Event):
781 """
782 Generic process started event (usually part of the initial startup)
783 where further progress events will be delivered
784 """
785 def __init__(self, processname, total):
786 Event.__init__(self)
787 self.processname = processname
788 self.total = total
789
790class ProcessProgress(Event):
791 """
792 Generic process progress event (usually part of the initial startup)
793 """
794 def __init__(self, processname, progress):
795 Event.__init__(self)
796 self.processname = processname
797 self.progress = progress
798
799class ProcessFinished(Event):
800 """
801 Generic process finished event (usually part of the initial startup)
802 """
803 def __init__(self, processname):
804 Event.__init__(self)
805 self.processname = processname
806
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500807class SanityCheck(Event):
808 """
809 Event to run sanity checks, either raise errors or generate events as return status.
810 """
811 def __init__(self, generateevents = True):
812 Event.__init__(self)
813 self.generateevents = generateevents
814
815class SanityCheckPassed(Event):
816 """
817 Event to indicate sanity check has passed
818 """
819
820class SanityCheckFailed(Event):
821 """
822 Event to indicate sanity check has failed
823 """
824 def __init__(self, msg, network_error=False):
825 Event.__init__(self)
826 self._msg = msg
827 self._network_error = network_error
828
829class NetworkTest(Event):
830 """
831 Event to run network connectivity tests, either raise errors or generate events as return status.
832 """
833 def __init__(self, generateevents = True):
834 Event.__init__(self)
835 self.generateevents = generateevents
836
837class NetworkTestPassed(Event):
838 """
839 Event to indicate network test has passed
840 """
841
842class NetworkTestFailed(Event):
843 """
844 Event to indicate network test has failed
845 """
846
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500847class FindSigInfoResult(Event):
848 """
849 Event to return results from findSigInfo command
850 """
851 def __init__(self, result):
852 Event.__init__(self)
853 self.result = result