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