blob: 8b05f93e2ff6066ba88c7c3da58d81a873bad62a [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
Patrick Williamsc0f7c042017-02-23 20:41:17 -060072
73def enable_threadlock():
Andrew Geissler517393d2023-01-13 08:55:19 -060074 # Always needed now
75 return
Patrick Williamsc0f7c042017-02-23 20:41:17 -060076
77def disable_threadlock():
Andrew Geissler517393d2023-01-13 08:55:19 -060078 # Always needed now
79 return
80
81def enable_heartbeat():
82 global _heartbeat_enabled
83 _heartbeat_enabled = True
84
85def disable_heartbeat():
86 global _heartbeat_enabled
87 _heartbeat_enabled = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050088
89def execute_handler(name, handler, event, d):
90 event.data = d
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091 try:
Andrew Geissler517393d2023-01-13 08:55:19 -060092 ret = handler(event, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093 except (bb.parse.SkipRecipe, bb.BBHandledException):
94 raise
95 except Exception:
96 etype, value, tb = sys.exc_info()
97 logger.error("Execution of event handler '%s' failed" % name,
98 exc_info=(etype, value, tb.tb_next))
99 raise
100 except SystemExit as exc:
101 if exc.code != 0:
102 logger.error("Execution of event handler '%s' failed" % name)
103 raise
104 finally:
105 del event.data
Andrew Geissler517393d2023-01-13 08:55:19 -0600106
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500107
108def fire_class_handlers(event, d):
109 if isinstance(event, logging.LogRecord):
110 return
111
112 eid = str(event.__class__)[8:-2]
113 evt_hmap = _event_handler_map.get(eid, {})
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600114 for name, handler in list(_handlers.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500115 if name in _catchall_handlers or name in evt_hmap:
116 if _eventfilter:
117 if not _eventfilter(name, handler, event, d):
118 continue
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500119 if d is not None and not name in (d.getVar("__BBHANDLERS_MC") or set()):
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600120 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121 execute_handler(name, handler, event, d)
122
123ui_queue = []
124@atexit.register
125def print_ui_queue():
Brad Bishop96ff1982019-08-19 13:50:42 -0400126 global ui_queue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500127 """If we're exiting before a UI has been spawned, display any queued
128 LogRecords to the console."""
129 logger = logging.getLogger("BitBake")
130 if not _uiready:
131 from bb.msg import BBLogFormatter
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800132 # Flush any existing buffered content
Andrew Geissler78b72792022-06-14 06:47:25 -0500133 try:
134 sys.stdout.flush()
135 except:
136 pass
137 try:
138 sys.stderr.flush()
139 except:
140 pass
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600141 stdout = logging.StreamHandler(sys.stdout)
142 stderr = logging.StreamHandler(sys.stderr)
143 formatter = BBLogFormatter("%(levelname)s: %(message)s")
144 stdout.setFormatter(formatter)
145 stderr.setFormatter(formatter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500146
147 # First check to see if we have any proper messages
148 msgprint = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500149 msgerrs = False
150
151 # Should we print to stderr?
152 for event in ui_queue[:]:
153 if isinstance(event, logging.LogRecord) and event.levelno >= logging.WARNING:
154 msgerrs = True
155 break
156
157 if msgerrs:
158 logger.addHandler(stderr)
159 else:
160 logger.addHandler(stdout)
161
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600162 for event in ui_queue[:]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163 if isinstance(event, logging.LogRecord):
164 if event.levelno > logging.DEBUG:
165 logger.handle(event)
166 msgprint = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500167
168 # Nope, so just print all of the messages we have (including debug messages)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500169 if not msgprint:
170 for event in ui_queue[:]:
171 if isinstance(event, logging.LogRecord):
172 logger.handle(event)
173 if msgerrs:
174 logger.removeHandler(stderr)
175 else:
176 logger.removeHandler(stdout)
Brad Bishop96ff1982019-08-19 13:50:42 -0400177 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178
179def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600180 global _thread_lock
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600181
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500182 if not _uiready:
183 # No UI handlers registered yet, queue up the messages
184 ui_queue.append(event)
185 return
186
Andrew Geissler517393d2023-01-13 08:55:19 -0600187 with bb.utils.lock_timeout(_thread_lock):
188 errors = []
189 for h in _ui_handlers:
190 #print "Sending event %s" % event
191 try:
192 if not _ui_logfilters[h].filter(event):
193 continue
194 # We use pickle here since it better handles object instances
195 # which xmlrpc's marshaller does not. Events *must* be serializable
196 # by pickle.
197 if hasattr(_ui_handlers[h].event, "sendpickle"):
198 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
199 else:
200 _ui_handlers[h].event.send(event)
201 except:
202 errors.append(h)
203 for h in errors:
204 del _ui_handlers[h]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600205
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500206def fire(event, d):
207 """Fire off an Event"""
208
209 # We can fire class handlers in the worker process context and this is
210 # desired so they get the task based datastore.
211 # UI handlers need to be fired in the server context so we defer this. They
212 # don't have a datastore so the datastore context isn't a problem.
213
214 fire_class_handlers(event, d)
215 if worker_fire:
216 worker_fire(event, d)
217 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500218 # If messages have been queued up, clear the queue
219 global _uiready, ui_queue
220 if _uiready and ui_queue:
221 for queue_event in ui_queue:
222 fire_ui_handlers(queue_event, d)
223 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224 fire_ui_handlers(event, d)
225
226def fire_from_worker(event, d):
227 fire_ui_handlers(event, d)
228
229noop = lambda _: None
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600230def register(name, handler, mask=None, filename=None, lineno=None, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500231 """Register an Event handler"""
232
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500233 if data is not None and data.getVar("BB_CURRENT_MC"):
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600234 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600235 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600236
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500237 # already registered
238 if name in _handlers:
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500239 if data is not None:
240 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
241 bbhands_mc.add(name)
242 data.setVar("__BBHANDLERS_MC", bbhands_mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243 return AlreadyRegistered
244
245 if handler is not None:
246 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600247 if isinstance(handler, str):
Andrew Geissler517393d2023-01-13 08:55:19 -0600248 tmp = "def %s(e, d):\n%s" % (name, handler)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500249 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500250 code = bb.methodpool.compile_cache(tmp)
251 if not code:
252 if filename is None:
Andrew Geissler517393d2023-01-13 08:55:19 -0600253 filename = "%s(e, d)" % name
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500254 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
255 if lineno is not None:
256 ast.increment_lineno(code, lineno-1)
257 code = compile(code, filename, "exec")
258 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500259 except SyntaxError:
260 logger.error("Unable to register event handler '%s':\n%s", name,
261 ''.join(traceback.format_exc(limit=0)))
262 _handlers[name] = noop
263 return
264 env = {}
265 bb.utils.better_exec(code, env)
266 func = bb.utils.better_eval(name, env)
267 _handlers[name] = func
268 else:
269 _handlers[name] = handler
270
271 if not mask or '*' in mask:
272 _catchall_handlers[name] = True
273 else:
274 for m in mask:
275 if _event_handler_map.get(m, None) is None:
276 _event_handler_map[m] = {}
277 _event_handler_map[m][name] = True
278
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500279 if data is not None:
280 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
281 bbhands_mc.add(name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600282 data.setVar("__BBHANDLERS_MC", bbhands_mc)
283
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500284 return Registered
285
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600286def remove(name, handler, data=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500287 """Remove an Event handler"""
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500288 if data is not None:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600289 if data.getVar("BB_CURRENT_MC"):
290 mc = data.getVar("BB_CURRENT_MC")
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600291 name = '%s%s' % (mc.replace('-', '_'), name)
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600292
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500293 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500294 if name in _catchall_handlers:
295 _catchall_handlers.pop(name)
296 for event in _event_handler_map.keys():
297 if name in _event_handler_map[event]:
298 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500299
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500300 if data is not None:
301 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600302 if name in bbhands_mc:
303 bbhands_mc.remove(name)
304 data.setVar("__BBHANDLERS_MC", bbhands_mc)
305
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600306def get_handlers():
307 return _handlers
308
309def set_handlers(handlers):
310 global _handlers
311 _handlers = handlers
312
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500313def set_eventfilter(func):
314 global _eventfilter
315 _eventfilter = func
316
317def register_UIHhandler(handler, mainui=False):
Andrew Geissler517393d2023-01-13 08:55:19 -0600318 with bb.utils.lock_timeout(_thread_lock):
319 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
320 _ui_handlers[_ui_handler_seq] = handler
321 level, debug_domains = bb.msg.constructLogOptions()
322 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
323 if mainui:
324 global _uiready
325 _uiready = _ui_handler_seq
326 return _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500327
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500328def unregister_UIHhandler(handlerNum, mainui=False):
329 if mainui:
330 global _uiready
331 _uiready = False
Andrew Geissler517393d2023-01-13 08:55:19 -0600332 with bb.utils.lock_timeout(_thread_lock):
333 if handlerNum in _ui_handlers:
334 del _ui_handlers[handlerNum]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500335 return
336
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500337def get_uihandler():
338 if _uiready is False:
339 return None
340 return _uiready
341
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500342# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
343class UIEventFilter(object):
344 def __init__(self, level, debug_domains):
345 self.update(None, level, debug_domains)
346
347 def update(self, eventmask, level, debug_domains):
348 self.eventmask = eventmask
349 self.stdlevel = level
350 self.debug_domains = debug_domains
351
352 def filter(self, event):
353 if isinstance(event, logging.LogRecord):
354 if event.levelno >= self.stdlevel:
355 return True
356 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
357 return True
358 return False
359 eid = str(event.__class__)[8:-2]
360 if self.eventmask and eid not in self.eventmask:
361 return False
362 return True
363
364def set_UIHmask(handlerNum, level, debug_domains, mask):
365 if not handlerNum in _ui_handlers:
366 return False
367 if '*' in mask:
368 _ui_logfilters[handlerNum].update(None, level, debug_domains)
369 else:
370 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
371 return True
372
373def getName(e):
374 """Returns the name of a class or class instance"""
Andrew Geissler82c905d2020-04-13 13:39:40 -0500375 if getattr(e, "__name__", None) is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500376 return e.__class__.__name__
377 else:
378 return e.__name__
379
380class OperationStarted(Event):
381 """An operation has begun"""
382 def __init__(self, msg = "Operation Started"):
383 Event.__init__(self)
384 self.msg = msg
385
386class OperationCompleted(Event):
387 """An operation has completed"""
388 def __init__(self, total, msg = "Operation Completed"):
389 Event.__init__(self)
390 self.total = total
391 self.msg = msg
392
393class OperationProgress(Event):
394 """An operation is in progress"""
395 def __init__(self, current, total, msg = "Operation in Progress"):
396 Event.__init__(self)
397 self.current = current
398 self.total = total
399 self.msg = msg + ": %s/%s" % (current, total);
400
401class ConfigParsed(Event):
402 """Configuration Parsing Complete"""
403
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500404class MultiConfigParsed(Event):
405 """Multi-Config Parsing Complete"""
406 def __init__(self, mcdata):
407 self.mcdata = mcdata
408 Event.__init__(self)
409
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500410class RecipeEvent(Event):
411 def __init__(self, fn):
412 self.fn = fn
413 Event.__init__(self)
414
415class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800416 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500417
Andrew Geissler1e34c2d2020-05-29 16:02:59 -0500418class RecipePostKeyExpansion(RecipeEvent):
419 """ Recipe Parsing Complete but not yet finalised"""
420
421
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500422class RecipeTaskPreProcess(RecipeEvent):
423 """
424 Recipe Tasks about to be finalised
425 The list of tasks should be final at this point and handlers
426 are only able to change interdependencies
427 """
428 def __init__(self, fn, tasklist):
429 self.fn = fn
430 self.tasklist = tasklist
431 Event.__init__(self)
432
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500433class RecipeParsed(RecipeEvent):
434 """ Recipe Parsing Complete """
435
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500437 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500438
439 def __init__(self, n, p, failures = 0):
440 self._name = n
441 self._pkgs = p
442 Event.__init__(self)
443 self._failures = failures
444
445 def getPkgs(self):
446 return self._pkgs
447
448 def setPkgs(self, pkgs):
449 self._pkgs = pkgs
450
451 def getName(self):
452 return self._name
453
454 def setName(self, name):
455 self._name = name
456
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500457 def getFailures(self):
458 """
459 Return the number of failed packages
460 """
461 return self._failures
462
463 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
464 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500465
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600466class BuildInit(BuildBase):
467 """buildFile or buildTargets was invoked"""
468 def __init__(self, p=[]):
469 name = None
470 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500471
472class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500473 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500474 def __init__(self, n, p, failures = 0):
475 OperationStarted.__init__(self, "Building Started")
476 BuildBase.__init__(self, n, p, failures)
477
478class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500479 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500480 def __init__(self, total, n, p, failures=0, interrupted=0):
481 if not failures:
482 OperationCompleted.__init__(self, total, "Building Succeeded")
483 else:
484 OperationCompleted.__init__(self, total, "Building Failed")
485 self._interrupted = interrupted
486 BuildBase.__init__(self, n, p, failures)
487
488class DiskFull(Event):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000489 """Disk full case build halted"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500490 def __init__(self, dev, type, freespace, mountpoint):
491 Event.__init__(self)
492 self._dev = dev
493 self._type = type
494 self._free = freespace
495 self._mountpoint = mountpoint
496
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500497class DiskUsageSample:
498 def __init__(self, available_bytes, free_bytes, total_bytes):
499 # Number of bytes available to non-root processes.
500 self.available_bytes = available_bytes
501 # Number of bytes available to root processes.
502 self.free_bytes = free_bytes
503 # Total capacity of the volume.
504 self.total_bytes = total_bytes
505
506class MonitorDiskEvent(Event):
507 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
508 Provides information about devices that are getting monitored."""
509 def __init__(self, disk_usage):
510 Event.__init__(self)
511 # hash of device root path -> DiskUsageSample
512 self.disk_usage = disk_usage
513
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500514class NoProvider(Event):
515 """No Provider for an Event"""
516
517 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
518 Event.__init__(self)
519 self._item = item
520 self._runtime = runtime
521 self._dependees = dependees
522 self._reasons = reasons
523 self._close_matches = close_matches
524
525 def getItem(self):
526 return self._item
527
528 def isRuntime(self):
529 return self._runtime
530
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500531 def __str__(self):
532 msg = ''
533 if self._runtime:
534 r = "R"
535 else:
536 r = ""
537
538 extra = ''
539 if not self._reasons:
540 if self._close_matches:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500541 extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500542
543 if self._dependees:
544 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
545 else:
546 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
547 if self._reasons:
548 for reason in self._reasons:
549 msg += '\n' + reason
550 return msg
551
552
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500553class MultipleProviders(Event):
554 """Multiple Providers"""
555
556 def __init__(self, item, candidates, runtime = False):
557 Event.__init__(self)
558 self._item = item
559 self._candidates = candidates
560 self._is_runtime = runtime
561
562 def isRuntime(self):
563 """
564 Is this a runtime issue?
565 """
566 return self._is_runtime
567
568 def getItem(self):
569 """
570 The name for the to be build item
571 """
572 return self._item
573
574 def getCandidates(self):
575 """
576 Get the possible Candidates for a PROVIDER.
577 """
578 return self._candidates
579
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500580 def __str__(self):
581 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
582 self._item,
583 ", ".join(self._candidates))
584 rtime = ""
585 if self._is_runtime:
586 rtime = "R"
587 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
588 return msg
589
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500590class ParseStarted(OperationStarted):
591 """Recipe parsing for the runqueue has begun"""
592 def __init__(self, total):
593 OperationStarted.__init__(self, "Recipe parsing Started")
594 self.total = total
595
596class ParseCompleted(OperationCompleted):
597 """Recipe parsing for the runqueue has completed"""
598 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
599 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
600 self.cached = cached
601 self.parsed = parsed
602 self.skipped = skipped
603 self.virtuals = virtuals
604 self.masked = masked
605 self.errors = errors
606 self.sofar = cached + parsed
607
608class ParseProgress(OperationProgress):
609 """Recipe parsing progress"""
610 def __init__(self, current, total):
611 OperationProgress.__init__(self, current, total, "Recipe parsing")
612
613
614class CacheLoadStarted(OperationStarted):
615 """Loading of the dependency cache has begun"""
616 def __init__(self, total):
617 OperationStarted.__init__(self, "Loading cache Started")
618 self.total = total
619
620class CacheLoadProgress(OperationProgress):
621 """Cache loading progress"""
622 def __init__(self, current, total):
623 OperationProgress.__init__(self, current, total, "Loading cache")
624
625class CacheLoadCompleted(OperationCompleted):
626 """Cache loading is complete"""
627 def __init__(self, total, num_entries):
628 OperationCompleted.__init__(self, total, "Loading cache Completed")
629 self.num_entries = num_entries
630
631class TreeDataPreparationStarted(OperationStarted):
632 """Tree data preparation started"""
633 def __init__(self):
634 OperationStarted.__init__(self, "Preparing tree data Started")
635
636class TreeDataPreparationProgress(OperationProgress):
637 """Tree data preparation is in progress"""
638 def __init__(self, current, total):
639 OperationProgress.__init__(self, current, total, "Preparing tree data")
640
641class TreeDataPreparationCompleted(OperationCompleted):
642 """Tree data preparation completed"""
643 def __init__(self, total):
644 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
645
646class DepTreeGenerated(Event):
647 """
648 Event when a dependency tree has been generated
649 """
650
651 def __init__(self, depgraph):
652 Event.__init__(self)
653 self._depgraph = depgraph
654
655class TargetsTreeGenerated(Event):
656 """
657 Event when a set of buildable targets has been generated
658 """
659 def __init__(self, model):
660 Event.__init__(self)
661 self._model = model
662
663class ReachableStamps(Event):
664 """
665 An event listing all stamps reachable after parsing
666 which the metadata may use to clean up stale data
667 """
668
669 def __init__(self, stamps):
670 Event.__init__(self)
671 self.stamps = stamps
672
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500673class StaleSetSceneTasks(Event):
674 """
675 An event listing setscene tasks which are 'stale' and will
676 be rerun. The metadata may use to clean up stale data.
677 tasks is a mapping of tasks and matching stale stamps.
678 """
679
680 def __init__(self, tasks):
681 Event.__init__(self)
682 self.tasks = tasks
683
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684class FilesMatchingFound(Event):
685 """
686 Event when a list of files matching the supplied pattern has
687 been generated
688 """
689 def __init__(self, pattern, matches):
690 Event.__init__(self)
691 self._pattern = pattern
692 self._matches = matches
693
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500694class ConfigFilesFound(Event):
695 """
696 Event when a list of appropriate config files has been generated
697 """
698 def __init__(self, variable, values):
699 Event.__init__(self)
700 self._variable = variable
701 self._values = values
702
703class ConfigFilePathFound(Event):
704 """
705 Event when a path for a config file has been found
706 """
707 def __init__(self, path):
708 Event.__init__(self)
709 self._path = path
710
711class MsgBase(Event):
712 """Base class for messages"""
713
714 def __init__(self, msg):
715 self._message = msg
716 Event.__init__(self)
717
718class MsgDebug(MsgBase):
719 """Debug Message"""
720
721class MsgNote(MsgBase):
722 """Note Message"""
723
724class MsgWarn(MsgBase):
725 """Warning Message"""
726
727class MsgError(MsgBase):
728 """Error Message"""
729
730class MsgFatal(MsgBase):
731 """Fatal Message"""
732
733class MsgPlain(MsgBase):
734 """General output"""
735
736class LogExecTTY(Event):
737 """Send event containing program to spawn on tty of the logger"""
738 def __init__(self, msg, prog, sleep_delay, retries):
739 Event.__init__(self)
740 self.msg = msg
741 self.prog = prog
742 self.sleep_delay = sleep_delay
743 self.retries = retries
744
745class LogHandler(logging.Handler):
746 """Dispatch logging messages as bitbake events"""
747
748 def emit(self, record):
749 if record.exc_info:
750 etype, value, tb = record.exc_info
751 if hasattr(tb, 'tb_next'):
752 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500753 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500754 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600755 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
756 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500757 record.exc_info = None
758 fire(record, None)
759
760 def filter(self, record):
761 record.taskpid = worker_pid
762 return True
763
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500764class MetadataEvent(Event):
765 """
766 Generic event that target for OE-Core classes
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000767 to report information during asynchronous execution
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500768 """
769 def __init__(self, eventtype, eventdata):
770 Event.__init__(self)
771 self.type = eventtype
772 self._localdata = eventdata
773
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600774class ProcessStarted(Event):
775 """
776 Generic process started event (usually part of the initial startup)
777 where further progress events will be delivered
778 """
779 def __init__(self, processname, total):
780 Event.__init__(self)
781 self.processname = processname
782 self.total = total
783
784class ProcessProgress(Event):
785 """
786 Generic process progress event (usually part of the initial startup)
787 """
788 def __init__(self, processname, progress):
789 Event.__init__(self)
790 self.processname = processname
791 self.progress = progress
792
793class ProcessFinished(Event):
794 """
795 Generic process finished event (usually part of the initial startup)
796 """
797 def __init__(self, processname):
798 Event.__init__(self)
799 self.processname = processname
800
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500801class SanityCheck(Event):
802 """
803 Event to run sanity checks, either raise errors or generate events as return status.
804 """
805 def __init__(self, generateevents = True):
806 Event.__init__(self)
807 self.generateevents = generateevents
808
809class SanityCheckPassed(Event):
810 """
811 Event to indicate sanity check has passed
812 """
813
814class SanityCheckFailed(Event):
815 """
816 Event to indicate sanity check has failed
817 """
818 def __init__(self, msg, network_error=False):
819 Event.__init__(self)
820 self._msg = msg
821 self._network_error = network_error
822
823class NetworkTest(Event):
824 """
825 Event to run network connectivity tests, either raise errors or generate events as return status.
826 """
827 def __init__(self, generateevents = True):
828 Event.__init__(self)
829 self.generateevents = generateevents
830
831class NetworkTestPassed(Event):
832 """
833 Event to indicate network test has passed
834 """
835
836class NetworkTestFailed(Event):
837 """
838 Event to indicate network test has failed
839 """
840
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500841class FindSigInfoResult(Event):
842 """
843 Event to return results from findSigInfo command
844 """
845 def __init__(self, result):
846 Event.__init__(self)
847 self.result = result