blob: 4761c868800835865074e10d50f34f2579f0ce2f [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 Williams705982a2024-01-12 09:51:57 -0600260 # Inject empty lines to make code match lineno in filename
261 if lineno is not None:
262 tmp = "\n" * (lineno-1) + tmp
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500263 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500264 code = bb.methodpool.compile_cache(tmp)
265 if not code:
266 if filename is None:
Andrew Geissler517393d2023-01-13 08:55:19 -0600267 filename = "%s(e, d)" % name
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500268 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500269 code = compile(code, filename, "exec")
270 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500271 except SyntaxError:
272 logger.error("Unable to register event handler '%s':\n%s", name,
273 ''.join(traceback.format_exc(limit=0)))
274 _handlers[name] = noop
275 return
276 env = {}
277 bb.utils.better_exec(code, env)
278 func = bb.utils.better_eval(name, env)
279 _handlers[name] = func
280 else:
281 _handlers[name] = handler
282
283 if not mask or '*' in mask:
284 _catchall_handlers[name] = True
285 else:
286 for m in mask:
287 if _event_handler_map.get(m, None) is None:
288 _event_handler_map[m] = {}
289 _event_handler_map[m][name] = True
290
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500291 if data is not None:
292 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
293 bbhands_mc.add(name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600294 data.setVar("__BBHANDLERS_MC", bbhands_mc)
295
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500296 return Registered
297
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600298def remove(name, handler, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500299 """Remove an Event handler"""
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500300 if data is not None:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600301 if data.getVar("BB_CURRENT_MC"):
302 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600303 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600304
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500305 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500306 if name in _catchall_handlers:
307 _catchall_handlers.pop(name)
308 for event in _event_handler_map.keys():
309 if name in _event_handler_map[event]:
310 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500311
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500312 if data is not None:
313 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600314 if name in bbhands_mc:
315 bbhands_mc.remove(name)
316 data.setVar("__BBHANDLERS_MC", bbhands_mc)
317
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600318def get_handlers():
319 return _handlers
320
321def set_handlers(handlers):
322 global _handlers
323 _handlers = handlers
324
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500325def set_eventfilter(func):
326 global _eventfilter
327 _eventfilter = func
328
329def register_UIHhandler(handler, mainui=False):
Andrew Geissler517393d2023-01-13 08:55:19 -0600330 with bb.utils.lock_timeout(_thread_lock):
331 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
332 _ui_handlers[_ui_handler_seq] = handler
333 level, debug_domains = bb.msg.constructLogOptions()
334 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
335 if mainui:
336 global _uiready
337 _uiready = _ui_handler_seq
338 return _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500339
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500340def unregister_UIHhandler(handlerNum, mainui=False):
341 if mainui:
342 global _uiready
343 _uiready = False
Andrew Geissler517393d2023-01-13 08:55:19 -0600344 with bb.utils.lock_timeout(_thread_lock):
345 if handlerNum in _ui_handlers:
346 del _ui_handlers[handlerNum]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500347 return
348
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500349def get_uihandler():
350 if _uiready is False:
351 return None
352 return _uiready
353
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500354# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
355class UIEventFilter(object):
356 def __init__(self, level, debug_domains):
357 self.update(None, level, debug_domains)
358
359 def update(self, eventmask, level, debug_domains):
360 self.eventmask = eventmask
361 self.stdlevel = level
362 self.debug_domains = debug_domains
363
364 def filter(self, event):
365 if isinstance(event, logging.LogRecord):
366 if event.levelno >= self.stdlevel:
367 return True
368 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
369 return True
370 return False
371 eid = str(event.__class__)[8:-2]
372 if self.eventmask and eid not in self.eventmask:
373 return False
374 return True
375
376def set_UIHmask(handlerNum, level, debug_domains, mask):
377 if not handlerNum in _ui_handlers:
378 return False
379 if '*' in mask:
380 _ui_logfilters[handlerNum].update(None, level, debug_domains)
381 else:
382 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
383 return True
384
385def getName(e):
386 """Returns the name of a class or class instance"""
Andrew Geissler82c905d2020-04-13 13:39:40 -0500387 if getattr(e, "__name__", None) is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500388 return e.__class__.__name__
389 else:
390 return e.__name__
391
392class OperationStarted(Event):
393 """An operation has begun"""
394 def __init__(self, msg = "Operation Started"):
395 Event.__init__(self)
396 self.msg = msg
397
398class OperationCompleted(Event):
399 """An operation has completed"""
400 def __init__(self, total, msg = "Operation Completed"):
401 Event.__init__(self)
402 self.total = total
403 self.msg = msg
404
405class OperationProgress(Event):
406 """An operation is in progress"""
407 def __init__(self, current, total, msg = "Operation in Progress"):
408 Event.__init__(self)
409 self.current = current
410 self.total = total
411 self.msg = msg + ": %s/%s" % (current, total);
412
413class ConfigParsed(Event):
414 """Configuration Parsing Complete"""
415
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500416class MultiConfigParsed(Event):
417 """Multi-Config Parsing Complete"""
418 def __init__(self, mcdata):
419 self.mcdata = mcdata
420 Event.__init__(self)
421
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500422class RecipeEvent(Event):
423 def __init__(self, fn):
424 self.fn = fn
425 Event.__init__(self)
426
427class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800428 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500429
Andrew Geissler1e34c2d2020-05-29 16:02:59 -0500430class RecipePostKeyExpansion(RecipeEvent):
431 """ Recipe Parsing Complete but not yet finalised"""
432
433
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500434class RecipeTaskPreProcess(RecipeEvent):
435 """
436 Recipe Tasks about to be finalised
437 The list of tasks should be final at this point and handlers
438 are only able to change interdependencies
439 """
440 def __init__(self, fn, tasklist):
441 self.fn = fn
442 self.tasklist = tasklist
443 Event.__init__(self)
444
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445class RecipeParsed(RecipeEvent):
446 """ Recipe Parsing Complete """
447
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500448class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500449 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500450
451 def __init__(self, n, p, failures = 0):
452 self._name = n
453 self._pkgs = p
454 Event.__init__(self)
455 self._failures = failures
456
457 def getPkgs(self):
458 return self._pkgs
459
460 def setPkgs(self, pkgs):
461 self._pkgs = pkgs
462
463 def getName(self):
464 return self._name
465
466 def setName(self, name):
467 self._name = name
468
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500469 def getFailures(self):
470 """
471 Return the number of failed packages
472 """
473 return self._failures
474
475 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
476 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500477
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600478class BuildInit(BuildBase):
479 """buildFile or buildTargets was invoked"""
480 def __init__(self, p=[]):
481 name = None
482 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483
484class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500485 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500486 def __init__(self, n, p, failures = 0):
487 OperationStarted.__init__(self, "Building Started")
488 BuildBase.__init__(self, n, p, failures)
489
490class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500491 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500492 def __init__(self, total, n, p, failures=0, interrupted=0):
493 if not failures:
494 OperationCompleted.__init__(self, total, "Building Succeeded")
495 else:
496 OperationCompleted.__init__(self, total, "Building Failed")
497 self._interrupted = interrupted
498 BuildBase.__init__(self, n, p, failures)
499
500class DiskFull(Event):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000501 """Disk full case build halted"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500502 def __init__(self, dev, type, freespace, mountpoint):
503 Event.__init__(self)
504 self._dev = dev
505 self._type = type
506 self._free = freespace
507 self._mountpoint = mountpoint
508
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500509class DiskUsageSample:
510 def __init__(self, available_bytes, free_bytes, total_bytes):
511 # Number of bytes available to non-root processes.
512 self.available_bytes = available_bytes
513 # Number of bytes available to root processes.
514 self.free_bytes = free_bytes
515 # Total capacity of the volume.
516 self.total_bytes = total_bytes
517
518class MonitorDiskEvent(Event):
519 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
520 Provides information about devices that are getting monitored."""
521 def __init__(self, disk_usage):
522 Event.__init__(self)
523 # hash of device root path -> DiskUsageSample
524 self.disk_usage = disk_usage
525
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500526class NoProvider(Event):
527 """No Provider for an Event"""
528
529 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
530 Event.__init__(self)
531 self._item = item
532 self._runtime = runtime
533 self._dependees = dependees
534 self._reasons = reasons
535 self._close_matches = close_matches
536
537 def getItem(self):
538 return self._item
539
540 def isRuntime(self):
541 return self._runtime
542
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500543 def __str__(self):
544 msg = ''
545 if self._runtime:
546 r = "R"
547 else:
548 r = ""
549
550 extra = ''
551 if not self._reasons:
552 if self._close_matches:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500553 extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500554
555 if self._dependees:
556 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
557 else:
558 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
559 if self._reasons:
560 for reason in self._reasons:
561 msg += '\n' + reason
562 return msg
563
564
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500565class MultipleProviders(Event):
566 """Multiple Providers"""
567
568 def __init__(self, item, candidates, runtime = False):
569 Event.__init__(self)
570 self._item = item
571 self._candidates = candidates
572 self._is_runtime = runtime
573
574 def isRuntime(self):
575 """
576 Is this a runtime issue?
577 """
578 return self._is_runtime
579
580 def getItem(self):
581 """
582 The name for the to be build item
583 """
584 return self._item
585
586 def getCandidates(self):
587 """
588 Get the possible Candidates for a PROVIDER.
589 """
590 return self._candidates
591
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500592 def __str__(self):
593 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
594 self._item,
595 ", ".join(self._candidates))
596 rtime = ""
597 if self._is_runtime:
598 rtime = "R"
599 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
600 return msg
601
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500602class ParseStarted(OperationStarted):
603 """Recipe parsing for the runqueue has begun"""
604 def __init__(self, total):
605 OperationStarted.__init__(self, "Recipe parsing Started")
606 self.total = total
607
608class ParseCompleted(OperationCompleted):
609 """Recipe parsing for the runqueue has completed"""
610 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
611 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
612 self.cached = cached
613 self.parsed = parsed
614 self.skipped = skipped
615 self.virtuals = virtuals
616 self.masked = masked
617 self.errors = errors
618 self.sofar = cached + parsed
619
620class ParseProgress(OperationProgress):
621 """Recipe parsing progress"""
622 def __init__(self, current, total):
623 OperationProgress.__init__(self, current, total, "Recipe parsing")
624
625
626class CacheLoadStarted(OperationStarted):
627 """Loading of the dependency cache has begun"""
628 def __init__(self, total):
629 OperationStarted.__init__(self, "Loading cache Started")
630 self.total = total
631
632class CacheLoadProgress(OperationProgress):
633 """Cache loading progress"""
634 def __init__(self, current, total):
635 OperationProgress.__init__(self, current, total, "Loading cache")
636
637class CacheLoadCompleted(OperationCompleted):
638 """Cache loading is complete"""
639 def __init__(self, total, num_entries):
640 OperationCompleted.__init__(self, total, "Loading cache Completed")
641 self.num_entries = num_entries
642
643class TreeDataPreparationStarted(OperationStarted):
644 """Tree data preparation started"""
645 def __init__(self):
646 OperationStarted.__init__(self, "Preparing tree data Started")
647
648class TreeDataPreparationProgress(OperationProgress):
649 """Tree data preparation is in progress"""
650 def __init__(self, current, total):
651 OperationProgress.__init__(self, current, total, "Preparing tree data")
652
653class TreeDataPreparationCompleted(OperationCompleted):
654 """Tree data preparation completed"""
655 def __init__(self, total):
656 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
657
658class DepTreeGenerated(Event):
659 """
660 Event when a dependency tree has been generated
661 """
662
663 def __init__(self, depgraph):
664 Event.__init__(self)
665 self._depgraph = depgraph
666
667class TargetsTreeGenerated(Event):
668 """
669 Event when a set of buildable targets has been generated
670 """
671 def __init__(self, model):
672 Event.__init__(self)
673 self._model = model
674
675class ReachableStamps(Event):
676 """
677 An event listing all stamps reachable after parsing
678 which the metadata may use to clean up stale data
679 """
680
681 def __init__(self, stamps):
682 Event.__init__(self)
683 self.stamps = stamps
684
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500685class StaleSetSceneTasks(Event):
686 """
687 An event listing setscene tasks which are 'stale' and will
688 be rerun. The metadata may use to clean up stale data.
689 tasks is a mapping of tasks and matching stale stamps.
690 """
691
692 def __init__(self, tasks):
693 Event.__init__(self)
694 self.tasks = tasks
695
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500696class FilesMatchingFound(Event):
697 """
698 Event when a list of files matching the supplied pattern has
699 been generated
700 """
701 def __init__(self, pattern, matches):
702 Event.__init__(self)
703 self._pattern = pattern
704 self._matches = matches
705
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500706class ConfigFilesFound(Event):
707 """
708 Event when a list of appropriate config files has been generated
709 """
710 def __init__(self, variable, values):
711 Event.__init__(self)
712 self._variable = variable
713 self._values = values
714
715class ConfigFilePathFound(Event):
716 """
717 Event when a path for a config file has been found
718 """
719 def __init__(self, path):
720 Event.__init__(self)
721 self._path = path
722
723class MsgBase(Event):
724 """Base class for messages"""
725
726 def __init__(self, msg):
727 self._message = msg
728 Event.__init__(self)
729
730class MsgDebug(MsgBase):
731 """Debug Message"""
732
733class MsgNote(MsgBase):
734 """Note Message"""
735
736class MsgWarn(MsgBase):
737 """Warning Message"""
738
739class MsgError(MsgBase):
740 """Error Message"""
741
742class MsgFatal(MsgBase):
743 """Fatal Message"""
744
745class MsgPlain(MsgBase):
746 """General output"""
747
748class LogExecTTY(Event):
749 """Send event containing program to spawn on tty of the logger"""
750 def __init__(self, msg, prog, sleep_delay, retries):
751 Event.__init__(self)
752 self.msg = msg
753 self.prog = prog
754 self.sleep_delay = sleep_delay
755 self.retries = retries
756
757class LogHandler(logging.Handler):
758 """Dispatch logging messages as bitbake events"""
759
760 def emit(self, record):
761 if record.exc_info:
762 etype, value, tb = record.exc_info
763 if hasattr(tb, 'tb_next'):
764 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500765 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500766 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600767 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
768 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500769 record.exc_info = None
770 fire(record, None)
771
772 def filter(self, record):
773 record.taskpid = worker_pid
774 return True
775
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500776class MetadataEvent(Event):
777 """
778 Generic event that target for OE-Core classes
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000779 to report information during asynchronous execution
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500780 """
781 def __init__(self, eventtype, eventdata):
782 Event.__init__(self)
783 self.type = eventtype
784 self._localdata = eventdata
785
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600786class ProcessStarted(Event):
787 """
788 Generic process started event (usually part of the initial startup)
789 where further progress events will be delivered
790 """
791 def __init__(self, processname, total):
792 Event.__init__(self)
793 self.processname = processname
794 self.total = total
795
796class ProcessProgress(Event):
797 """
798 Generic process progress event (usually part of the initial startup)
799 """
800 def __init__(self, processname, progress):
801 Event.__init__(self)
802 self.processname = processname
803 self.progress = progress
804
805class ProcessFinished(Event):
806 """
807 Generic process finished event (usually part of the initial startup)
808 """
809 def __init__(self, processname):
810 Event.__init__(self)
811 self.processname = processname
812
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500813class SanityCheck(Event):
814 """
815 Event to run sanity checks, either raise errors or generate events as return status.
816 """
817 def __init__(self, generateevents = True):
818 Event.__init__(self)
819 self.generateevents = generateevents
820
821class SanityCheckPassed(Event):
822 """
823 Event to indicate sanity check has passed
824 """
825
826class SanityCheckFailed(Event):
827 """
828 Event to indicate sanity check has failed
829 """
830 def __init__(self, msg, network_error=False):
831 Event.__init__(self)
832 self._msg = msg
833 self._network_error = network_error
834
835class NetworkTest(Event):
836 """
837 Event to run network connectivity tests, either raise errors or generate events as return status.
838 """
839 def __init__(self, generateevents = True):
840 Event.__init__(self)
841 self.generateevents = generateevents
842
843class NetworkTestPassed(Event):
844 """
845 Event to indicate network test has passed
846 """
847
848class NetworkTestFailed(Event):
849 """
850 Event to indicate network test has failed
851 """
852
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500853class FindSigInfoResult(Event):
854 """
855 Event to return results from findSigInfo command
856 """
857 def __init__(self, result):
858 Event.__init__(self)
859 self.result = result
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500860
Andrew Geissler220dafd2023-10-04 10:18:08 -0500861class GetTaskSignatureResult(Event):
862 """
863 Event to return results from GetTaskSignatures command
864 """
865 def __init__(self, sig):
866 Event.__init__(self)
867 self.sig = sig
868
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500869class ParseError(Event):
870 """
871 Event to indicate parse failed
872 """
873 def __init__(self, msg):
874 super().__init__()
875 self._msg = msg