blob: 0d0e0a68aac672e5bf21ddf4b178ea36928bc800 [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()
Andrew Geissler517393d2023-01-13 08:55:19 -060071_heartbeat_enabled = False
Andrew Geissler6aa7eec2023-03-03 12:41:14 -060072_should_exit = threading.Event()
Patrick Williamsc0f7c042017-02-23 20:41:17 -060073
74def enable_threadlock():
Andrew Geissler517393d2023-01-13 08:55:19 -060075 # Always needed now
76 return
Patrick Williamsc0f7c042017-02-23 20:41:17 -060077
78def disable_threadlock():
Andrew Geissler517393d2023-01-13 08:55:19 -060079 # Always needed now
80 return
81
82def enable_heartbeat():
83 global _heartbeat_enabled
84 _heartbeat_enabled = True
85
86def disable_heartbeat():
87 global _heartbeat_enabled
88 _heartbeat_enabled = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089
Andrew Geissler6aa7eec2023-03-03 12:41:14 -060090#
91# In long running code, this function should be called periodically
92# to check if we should exit due to an interuption (.e.g Ctrl+C from the UI)
93#
94def check_for_interrupts(d):
95 global _should_exit
96 if _should_exit.is_set():
97 bb.warn("Exiting due to interrupt.")
98 raise bb.BBHandledException()
99
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100def execute_handler(name, handler, event, d):
101 event.data = d
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500102 try:
Andrew Geissler517393d2023-01-13 08:55:19 -0600103 ret = handler(event, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500104 except (bb.parse.SkipRecipe, bb.BBHandledException):
105 raise
106 except Exception:
107 etype, value, tb = sys.exc_info()
108 logger.error("Execution of event handler '%s' failed" % name,
109 exc_info=(etype, value, tb.tb_next))
110 raise
111 except SystemExit as exc:
112 if exc.code != 0:
113 logger.error("Execution of event handler '%s' failed" % name)
114 raise
115 finally:
116 del event.data
Andrew Geissler517393d2023-01-13 08:55:19 -0600117
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500118
119def fire_class_handlers(event, d):
120 if isinstance(event, logging.LogRecord):
121 return
122
123 eid = str(event.__class__)[8:-2]
124 evt_hmap = _event_handler_map.get(eid, {})
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600125 for name, handler in list(_handlers.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500126 if name in _catchall_handlers or name in evt_hmap:
127 if _eventfilter:
128 if not _eventfilter(name, handler, event, d):
129 continue
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500130 if d is not None and not name in (d.getVar("__BBHANDLERS_MC") or set()):
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600131 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132 execute_handler(name, handler, event, d)
133
134ui_queue = []
135@atexit.register
136def print_ui_queue():
Brad Bishop96ff1982019-08-19 13:50:42 -0400137 global ui_queue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500138 """If we're exiting before a UI has been spawned, display any queued
139 LogRecords to the console."""
140 logger = logging.getLogger("BitBake")
141 if not _uiready:
142 from bb.msg import BBLogFormatter
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800143 # Flush any existing buffered content
Andrew Geissler78b72792022-06-14 06:47:25 -0500144 try:
145 sys.stdout.flush()
146 except:
147 pass
148 try:
149 sys.stderr.flush()
150 except:
151 pass
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600152 stdout = logging.StreamHandler(sys.stdout)
153 stderr = logging.StreamHandler(sys.stderr)
154 formatter = BBLogFormatter("%(levelname)s: %(message)s")
155 stdout.setFormatter(formatter)
156 stderr.setFormatter(formatter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157
158 # First check to see if we have any proper messages
159 msgprint = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500160 msgerrs = False
161
162 # Should we print to stderr?
163 for event in ui_queue[:]:
164 if isinstance(event, logging.LogRecord) and event.levelno >= logging.WARNING:
165 msgerrs = True
166 break
167
168 if msgerrs:
169 logger.addHandler(stderr)
170 else:
171 logger.addHandler(stdout)
172
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600173 for event in ui_queue[:]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174 if isinstance(event, logging.LogRecord):
175 if event.levelno > logging.DEBUG:
176 logger.handle(event)
177 msgprint = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178
179 # Nope, so just print all of the messages we have (including debug messages)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500180 if not msgprint:
181 for event in ui_queue[:]:
182 if isinstance(event, logging.LogRecord):
183 logger.handle(event)
184 if msgerrs:
185 logger.removeHandler(stderr)
186 else:
187 logger.removeHandler(stdout)
Brad Bishop96ff1982019-08-19 13:50:42 -0400188 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500189
190def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600191 global _thread_lock
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600192
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 if not _uiready:
194 # No UI handlers registered yet, queue up the messages
195 ui_queue.append(event)
196 return
197
Andrew Geissler517393d2023-01-13 08:55:19 -0600198 with bb.utils.lock_timeout(_thread_lock):
199 errors = []
200 for h in _ui_handlers:
201 #print "Sending event %s" % event
202 try:
203 if not _ui_logfilters[h].filter(event):
204 continue
205 # We use pickle here since it better handles object instances
206 # which xmlrpc's marshaller does not. Events *must* be serializable
207 # by pickle.
208 if hasattr(_ui_handlers[h].event, "sendpickle"):
209 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
210 else:
211 _ui_handlers[h].event.send(event)
212 except:
213 errors.append(h)
214 for h in errors:
215 del _ui_handlers[h]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600216
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500217def fire(event, d):
218 """Fire off an Event"""
219
220 # We can fire class handlers in the worker process context and this is
221 # desired so they get the task based datastore.
222 # UI handlers need to be fired in the server context so we defer this. They
223 # don't have a datastore so the datastore context isn't a problem.
224
225 fire_class_handlers(event, d)
226 if worker_fire:
227 worker_fire(event, d)
228 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500229 # If messages have been queued up, clear the queue
230 global _uiready, ui_queue
231 if _uiready and ui_queue:
232 for queue_event in ui_queue:
233 fire_ui_handlers(queue_event, d)
234 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500235 fire_ui_handlers(event, d)
236
237def fire_from_worker(event, d):
238 fire_ui_handlers(event, d)
239
240noop = lambda _: None
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600241def register(name, handler, mask=None, filename=None, lineno=None, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500242 """Register an Event handler"""
243
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500244 if data is not None and data.getVar("BB_CURRENT_MC"):
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600245 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600246 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600247
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500248 # already registered
249 if name in _handlers:
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500250 if data is not None:
251 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
252 bbhands_mc.add(name)
253 data.setVar("__BBHANDLERS_MC", bbhands_mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500254 return AlreadyRegistered
255
256 if handler is not None:
257 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600258 if isinstance(handler, str):
Andrew Geissler517393d2023-01-13 08:55:19 -0600259 tmp = "def %s(e, d):\n%s" % (name, handler)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500260 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500261 code = bb.methodpool.compile_cache(tmp)
262 if not code:
263 if filename is None:
Andrew Geissler517393d2023-01-13 08:55:19 -0600264 filename = "%s(e, d)" % name
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500265 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
266 if lineno is not None:
267 ast.increment_lineno(code, lineno-1)
268 code = compile(code, filename, "exec")
269 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500270 except SyntaxError:
271 logger.error("Unable to register event handler '%s':\n%s", name,
272 ''.join(traceback.format_exc(limit=0)))
273 _handlers[name] = noop
274 return
275 env = {}
276 bb.utils.better_exec(code, env)
277 func = bb.utils.better_eval(name, env)
278 _handlers[name] = func
279 else:
280 _handlers[name] = handler
281
282 if not mask or '*' in mask:
283 _catchall_handlers[name] = True
284 else:
285 for m in mask:
286 if _event_handler_map.get(m, None) is None:
287 _event_handler_map[m] = {}
288 _event_handler_map[m][name] = True
289
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500290 if data is not None:
291 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
292 bbhands_mc.add(name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600293 data.setVar("__BBHANDLERS_MC", bbhands_mc)
294
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500295 return Registered
296
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600297def remove(name, handler, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500298 """Remove an Event handler"""
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500299 if data is not None:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600300 if data.getVar("BB_CURRENT_MC"):
301 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600302 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600303
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500304 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500305 if name in _catchall_handlers:
306 _catchall_handlers.pop(name)
307 for event in _event_handler_map.keys():
308 if name in _event_handler_map[event]:
309 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500310
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500311 if data is not None:
312 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600313 if name in bbhands_mc:
314 bbhands_mc.remove(name)
315 data.setVar("__BBHANDLERS_MC", bbhands_mc)
316
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600317def get_handlers():
318 return _handlers
319
320def set_handlers(handlers):
321 global _handlers
322 _handlers = handlers
323
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500324def set_eventfilter(func):
325 global _eventfilter
326 _eventfilter = func
327
328def register_UIHhandler(handler, mainui=False):
Andrew Geissler517393d2023-01-13 08:55:19 -0600329 with bb.utils.lock_timeout(_thread_lock):
330 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
331 _ui_handlers[_ui_handler_seq] = handler
332 level, debug_domains = bb.msg.constructLogOptions()
333 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
334 if mainui:
335 global _uiready
336 _uiready = _ui_handler_seq
337 return _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500338
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500339def unregister_UIHhandler(handlerNum, mainui=False):
340 if mainui:
341 global _uiready
342 _uiready = False
Andrew Geissler517393d2023-01-13 08:55:19 -0600343 with bb.utils.lock_timeout(_thread_lock):
344 if handlerNum in _ui_handlers:
345 del _ui_handlers[handlerNum]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500346 return
347
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500348def get_uihandler():
349 if _uiready is False:
350 return None
351 return _uiready
352
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500353# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
354class UIEventFilter(object):
355 def __init__(self, level, debug_domains):
356 self.update(None, level, debug_domains)
357
358 def update(self, eventmask, level, debug_domains):
359 self.eventmask = eventmask
360 self.stdlevel = level
361 self.debug_domains = debug_domains
362
363 def filter(self, event):
364 if isinstance(event, logging.LogRecord):
365 if event.levelno >= self.stdlevel:
366 return True
367 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
368 return True
369 return False
370 eid = str(event.__class__)[8:-2]
371 if self.eventmask and eid not in self.eventmask:
372 return False
373 return True
374
375def set_UIHmask(handlerNum, level, debug_domains, mask):
376 if not handlerNum in _ui_handlers:
377 return False
378 if '*' in mask:
379 _ui_logfilters[handlerNum].update(None, level, debug_domains)
380 else:
381 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
382 return True
383
384def getName(e):
385 """Returns the name of a class or class instance"""
Andrew Geissler82c905d2020-04-13 13:39:40 -0500386 if getattr(e, "__name__", None) is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500387 return e.__class__.__name__
388 else:
389 return e.__name__
390
391class OperationStarted(Event):
392 """An operation has begun"""
393 def __init__(self, msg = "Operation Started"):
394 Event.__init__(self)
395 self.msg = msg
396
397class OperationCompleted(Event):
398 """An operation has completed"""
399 def __init__(self, total, msg = "Operation Completed"):
400 Event.__init__(self)
401 self.total = total
402 self.msg = msg
403
404class OperationProgress(Event):
405 """An operation is in progress"""
406 def __init__(self, current, total, msg = "Operation in Progress"):
407 Event.__init__(self)
408 self.current = current
409 self.total = total
410 self.msg = msg + ": %s/%s" % (current, total);
411
412class ConfigParsed(Event):
413 """Configuration Parsing Complete"""
414
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500415class MultiConfigParsed(Event):
416 """Multi-Config Parsing Complete"""
417 def __init__(self, mcdata):
418 self.mcdata = mcdata
419 Event.__init__(self)
420
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500421class RecipeEvent(Event):
422 def __init__(self, fn):
423 self.fn = fn
424 Event.__init__(self)
425
426class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800427 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500428
Andrew Geissler1e34c2d2020-05-29 16:02:59 -0500429class RecipePostKeyExpansion(RecipeEvent):
430 """ Recipe Parsing Complete but not yet finalised"""
431
432
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500433class RecipeTaskPreProcess(RecipeEvent):
434 """
435 Recipe Tasks about to be finalised
436 The list of tasks should be final at this point and handlers
437 are only able to change interdependencies
438 """
439 def __init__(self, fn, tasklist):
440 self.fn = fn
441 self.tasklist = tasklist
442 Event.__init__(self)
443
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444class RecipeParsed(RecipeEvent):
445 """ Recipe Parsing Complete """
446
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500447class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500448 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500449
450 def __init__(self, n, p, failures = 0):
451 self._name = n
452 self._pkgs = p
453 Event.__init__(self)
454 self._failures = failures
455
456 def getPkgs(self):
457 return self._pkgs
458
459 def setPkgs(self, pkgs):
460 self._pkgs = pkgs
461
462 def getName(self):
463 return self._name
464
465 def setName(self, name):
466 self._name = name
467
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500468 def getFailures(self):
469 """
470 Return the number of failed packages
471 """
472 return self._failures
473
474 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
475 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500476
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600477class BuildInit(BuildBase):
478 """buildFile or buildTargets was invoked"""
479 def __init__(self, p=[]):
480 name = None
481 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500482
483class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500484 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500485 def __init__(self, n, p, failures = 0):
486 OperationStarted.__init__(self, "Building Started")
487 BuildBase.__init__(self, n, p, failures)
488
489class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500490 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500491 def __init__(self, total, n, p, failures=0, interrupted=0):
492 if not failures:
493 OperationCompleted.__init__(self, total, "Building Succeeded")
494 else:
495 OperationCompleted.__init__(self, total, "Building Failed")
496 self._interrupted = interrupted
497 BuildBase.__init__(self, n, p, failures)
498
499class DiskFull(Event):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000500 """Disk full case build halted"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500501 def __init__(self, dev, type, freespace, mountpoint):
502 Event.__init__(self)
503 self._dev = dev
504 self._type = type
505 self._free = freespace
506 self._mountpoint = mountpoint
507
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500508class DiskUsageSample:
509 def __init__(self, available_bytes, free_bytes, total_bytes):
510 # Number of bytes available to non-root processes.
511 self.available_bytes = available_bytes
512 # Number of bytes available to root processes.
513 self.free_bytes = free_bytes
514 # Total capacity of the volume.
515 self.total_bytes = total_bytes
516
517class MonitorDiskEvent(Event):
518 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
519 Provides information about devices that are getting monitored."""
520 def __init__(self, disk_usage):
521 Event.__init__(self)
522 # hash of device root path -> DiskUsageSample
523 self.disk_usage = disk_usage
524
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500525class NoProvider(Event):
526 """No Provider for an Event"""
527
528 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
529 Event.__init__(self)
530 self._item = item
531 self._runtime = runtime
532 self._dependees = dependees
533 self._reasons = reasons
534 self._close_matches = close_matches
535
536 def getItem(self):
537 return self._item
538
539 def isRuntime(self):
540 return self._runtime
541
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500542 def __str__(self):
543 msg = ''
544 if self._runtime:
545 r = "R"
546 else:
547 r = ""
548
549 extra = ''
550 if not self._reasons:
551 if self._close_matches:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500552 extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500553
554 if self._dependees:
555 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
556 else:
557 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
558 if self._reasons:
559 for reason in self._reasons:
560 msg += '\n' + reason
561 return msg
562
563
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564class MultipleProviders(Event):
565 """Multiple Providers"""
566
567 def __init__(self, item, candidates, runtime = False):
568 Event.__init__(self)
569 self._item = item
570 self._candidates = candidates
571 self._is_runtime = runtime
572
573 def isRuntime(self):
574 """
575 Is this a runtime issue?
576 """
577 return self._is_runtime
578
579 def getItem(self):
580 """
581 The name for the to be build item
582 """
583 return self._item
584
585 def getCandidates(self):
586 """
587 Get the possible Candidates for a PROVIDER.
588 """
589 return self._candidates
590
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500591 def __str__(self):
592 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
593 self._item,
594 ", ".join(self._candidates))
595 rtime = ""
596 if self._is_runtime:
597 rtime = "R"
598 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
599 return msg
600
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500601class ParseStarted(OperationStarted):
602 """Recipe parsing for the runqueue has begun"""
603 def __init__(self, total):
604 OperationStarted.__init__(self, "Recipe parsing Started")
605 self.total = total
606
607class ParseCompleted(OperationCompleted):
608 """Recipe parsing for the runqueue has completed"""
609 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
610 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
611 self.cached = cached
612 self.parsed = parsed
613 self.skipped = skipped
614 self.virtuals = virtuals
615 self.masked = masked
616 self.errors = errors
617 self.sofar = cached + parsed
618
619class ParseProgress(OperationProgress):
620 """Recipe parsing progress"""
621 def __init__(self, current, total):
622 OperationProgress.__init__(self, current, total, "Recipe parsing")
623
624
625class CacheLoadStarted(OperationStarted):
626 """Loading of the dependency cache has begun"""
627 def __init__(self, total):
628 OperationStarted.__init__(self, "Loading cache Started")
629 self.total = total
630
631class CacheLoadProgress(OperationProgress):
632 """Cache loading progress"""
633 def __init__(self, current, total):
634 OperationProgress.__init__(self, current, total, "Loading cache")
635
636class CacheLoadCompleted(OperationCompleted):
637 """Cache loading is complete"""
638 def __init__(self, total, num_entries):
639 OperationCompleted.__init__(self, total, "Loading cache Completed")
640 self.num_entries = num_entries
641
642class TreeDataPreparationStarted(OperationStarted):
643 """Tree data preparation started"""
644 def __init__(self):
645 OperationStarted.__init__(self, "Preparing tree data Started")
646
647class TreeDataPreparationProgress(OperationProgress):
648 """Tree data preparation is in progress"""
649 def __init__(self, current, total):
650 OperationProgress.__init__(self, current, total, "Preparing tree data")
651
652class TreeDataPreparationCompleted(OperationCompleted):
653 """Tree data preparation completed"""
654 def __init__(self, total):
655 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
656
657class DepTreeGenerated(Event):
658 """
659 Event when a dependency tree has been generated
660 """
661
662 def __init__(self, depgraph):
663 Event.__init__(self)
664 self._depgraph = depgraph
665
666class TargetsTreeGenerated(Event):
667 """
668 Event when a set of buildable targets has been generated
669 """
670 def __init__(self, model):
671 Event.__init__(self)
672 self._model = model
673
674class ReachableStamps(Event):
675 """
676 An event listing all stamps reachable after parsing
677 which the metadata may use to clean up stale data
678 """
679
680 def __init__(self, stamps):
681 Event.__init__(self)
682 self.stamps = stamps
683
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500684class StaleSetSceneTasks(Event):
685 """
686 An event listing setscene tasks which are 'stale' and will
687 be rerun. The metadata may use to clean up stale data.
688 tasks is a mapping of tasks and matching stale stamps.
689 """
690
691 def __init__(self, tasks):
692 Event.__init__(self)
693 self.tasks = tasks
694
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500695class FilesMatchingFound(Event):
696 """
697 Event when a list of files matching the supplied pattern has
698 been generated
699 """
700 def __init__(self, pattern, matches):
701 Event.__init__(self)
702 self._pattern = pattern
703 self._matches = matches
704
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500705class ConfigFilesFound(Event):
706 """
707 Event when a list of appropriate config files has been generated
708 """
709 def __init__(self, variable, values):
710 Event.__init__(self)
711 self._variable = variable
712 self._values = values
713
714class ConfigFilePathFound(Event):
715 """
716 Event when a path for a config file has been found
717 """
718 def __init__(self, path):
719 Event.__init__(self)
720 self._path = path
721
722class MsgBase(Event):
723 """Base class for messages"""
724
725 def __init__(self, msg):
726 self._message = msg
727 Event.__init__(self)
728
729class MsgDebug(MsgBase):
730 """Debug Message"""
731
732class MsgNote(MsgBase):
733 """Note Message"""
734
735class MsgWarn(MsgBase):
736 """Warning Message"""
737
738class MsgError(MsgBase):
739 """Error Message"""
740
741class MsgFatal(MsgBase):
742 """Fatal Message"""
743
744class MsgPlain(MsgBase):
745 """General output"""
746
747class LogExecTTY(Event):
748 """Send event containing program to spawn on tty of the logger"""
749 def __init__(self, msg, prog, sleep_delay, retries):
750 Event.__init__(self)
751 self.msg = msg
752 self.prog = prog
753 self.sleep_delay = sleep_delay
754 self.retries = retries
755
756class LogHandler(logging.Handler):
757 """Dispatch logging messages as bitbake events"""
758
759 def emit(self, record):
760 if record.exc_info:
761 etype, value, tb = record.exc_info
762 if hasattr(tb, 'tb_next'):
763 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500764 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500765 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600766 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
767 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500768 record.exc_info = None
769 fire(record, None)
770
771 def filter(self, record):
772 record.taskpid = worker_pid
773 return True
774
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500775class MetadataEvent(Event):
776 """
777 Generic event that target for OE-Core classes
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000778 to report information during asynchronous execution
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500779 """
780 def __init__(self, eventtype, eventdata):
781 Event.__init__(self)
782 self.type = eventtype
783 self._localdata = eventdata
784
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600785class ProcessStarted(Event):
786 """
787 Generic process started event (usually part of the initial startup)
788 where further progress events will be delivered
789 """
790 def __init__(self, processname, total):
791 Event.__init__(self)
792 self.processname = processname
793 self.total = total
794
795class ProcessProgress(Event):
796 """
797 Generic process progress event (usually part of the initial startup)
798 """
799 def __init__(self, processname, progress):
800 Event.__init__(self)
801 self.processname = processname
802 self.progress = progress
803
804class ProcessFinished(Event):
805 """
806 Generic process finished event (usually part of the initial startup)
807 """
808 def __init__(self, processname):
809 Event.__init__(self)
810 self.processname = processname
811
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500812class SanityCheck(Event):
813 """
814 Event to run sanity checks, either raise errors or generate events as return status.
815 """
816 def __init__(self, generateevents = True):
817 Event.__init__(self)
818 self.generateevents = generateevents
819
820class SanityCheckPassed(Event):
821 """
822 Event to indicate sanity check has passed
823 """
824
825class SanityCheckFailed(Event):
826 """
827 Event to indicate sanity check has failed
828 """
829 def __init__(self, msg, network_error=False):
830 Event.__init__(self)
831 self._msg = msg
832 self._network_error = network_error
833
834class NetworkTest(Event):
835 """
836 Event to run network connectivity tests, either raise errors or generate events as return status.
837 """
838 def __init__(self, generateevents = True):
839 Event.__init__(self)
840 self.generateevents = generateevents
841
842class NetworkTestPassed(Event):
843 """
844 Event to indicate network test has passed
845 """
846
847class NetworkTestFailed(Event):
848 """
849 Event to indicate network test has failed
850 """
851
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500852class FindSigInfoResult(Event):
853 """
854 Event to return results from findSigInfo command
855 """
856 def __init__(self, result):
857 Event.__init__(self)
858 self.result = result
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500859
860class ParseError(Event):
861 """
862 Event to indicate parse failed
863 """
864 def __init__(self, msg):
865 super().__init__()
866 self._msg = msg