blob: d1359f01008d21ccbd49e33f5bb2fa8c17cd500e [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
Andrew Geissler82c905d2020-04-13 13:39:40 -050013import sys
Patrick Williamsc0f7c042017-02-23 20:41:17 -060014import pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015import logging
16import atexit
17import traceback
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050018import ast
Patrick Williamsc0f7c042017-02-23 20:41:17 -060019import threading
20
Patrick Williamsc124f4f2015-09-15 14:41:29 -050021import bb.utils
22import bb.compat
23import bb.exceptions
24
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():
59 return bb.compat.OrderedDict()
60
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
121 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
133 sys.stdout.flush()
134 sys.stderr.flush()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600135 stdout = logging.StreamHandler(sys.stdout)
136 stderr = logging.StreamHandler(sys.stderr)
137 formatter = BBLogFormatter("%(levelname)s: %(message)s")
138 stdout.setFormatter(formatter)
139 stderr.setFormatter(formatter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500140
141 # First check to see if we have any proper messages
142 msgprint = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500143 msgerrs = False
144
145 # Should we print to stderr?
146 for event in ui_queue[:]:
147 if isinstance(event, logging.LogRecord) and event.levelno >= logging.WARNING:
148 msgerrs = True
149 break
150
151 if msgerrs:
152 logger.addHandler(stderr)
153 else:
154 logger.addHandler(stdout)
155
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600156 for event in ui_queue[:]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157 if isinstance(event, logging.LogRecord):
158 if event.levelno > logging.DEBUG:
159 logger.handle(event)
160 msgprint = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161
162 # Nope, so just print all of the messages we have (including debug messages)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500163 if not msgprint:
164 for event in ui_queue[:]:
165 if isinstance(event, logging.LogRecord):
166 logger.handle(event)
167 if msgerrs:
168 logger.removeHandler(stderr)
169 else:
170 logger.removeHandler(stdout)
Brad Bishop96ff1982019-08-19 13:50:42 -0400171 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172
173def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600174 global _thread_lock
175 global _thread_lock_enabled
176
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500177 if not _uiready:
178 # No UI handlers registered yet, queue up the messages
179 ui_queue.append(event)
180 return
181
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600182 if _thread_lock_enabled:
183 _thread_lock.acquire()
184
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185 errors = []
186 for h in _ui_handlers:
187 #print "Sending event %s" % event
188 try:
189 if not _ui_logfilters[h].filter(event):
190 continue
191 # We use pickle here since it better handles object instances
192 # which xmlrpc's marshaller does not. Events *must* be serializable
193 # by pickle.
194 if hasattr(_ui_handlers[h].event, "sendpickle"):
195 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
196 else:
197 _ui_handlers[h].event.send(event)
198 except:
199 errors.append(h)
200 for h in errors:
201 del _ui_handlers[h]
202
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600203 if _thread_lock_enabled:
204 _thread_lock.release()
205
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
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500230def register(name, handler, mask=None, filename=None, lineno=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500231 """Register an Event handler"""
232
233 # already registered
234 if name in _handlers:
235 return AlreadyRegistered
236
237 if handler is not None:
238 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600239 if isinstance(handler, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500240 tmp = "def %s(e):\n%s" % (name, handler)
241 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500242 code = bb.methodpool.compile_cache(tmp)
243 if not code:
244 if filename is None:
245 filename = "%s(e)" % name
246 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
247 if lineno is not None:
248 ast.increment_lineno(code, lineno-1)
249 code = compile(code, filename, "exec")
250 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500251 except SyntaxError:
252 logger.error("Unable to register event handler '%s':\n%s", name,
253 ''.join(traceback.format_exc(limit=0)))
254 _handlers[name] = noop
255 return
256 env = {}
257 bb.utils.better_exec(code, env)
258 func = bb.utils.better_eval(name, env)
259 _handlers[name] = func
260 else:
261 _handlers[name] = handler
262
263 if not mask or '*' in mask:
264 _catchall_handlers[name] = True
265 else:
266 for m in mask:
267 if _event_handler_map.get(m, None) is None:
268 _event_handler_map[m] = {}
269 _event_handler_map[m][name] = True
270
271 return Registered
272
273def remove(name, handler):
274 """Remove an Event handler"""
275 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500276 if name in _catchall_handlers:
277 _catchall_handlers.pop(name)
278 for event in _event_handler_map.keys():
279 if name in _event_handler_map[event]:
280 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500281
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600282def get_handlers():
283 return _handlers
284
285def set_handlers(handlers):
286 global _handlers
287 _handlers = handlers
288
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500289def set_eventfilter(func):
290 global _eventfilter
291 _eventfilter = func
292
293def register_UIHhandler(handler, mainui=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500294 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
295 _ui_handlers[_ui_handler_seq] = handler
296 level, debug_domains = bb.msg.constructLogOptions()
297 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500298 if mainui:
299 global _uiready
300 _uiready = _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500301 return _ui_handler_seq
302
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500303def unregister_UIHhandler(handlerNum, mainui=False):
304 if mainui:
305 global _uiready
306 _uiready = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500307 if handlerNum in _ui_handlers:
308 del _ui_handlers[handlerNum]
309 return
310
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500311def get_uihandler():
312 if _uiready is False:
313 return None
314 return _uiready
315
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500316# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
317class UIEventFilter(object):
318 def __init__(self, level, debug_domains):
319 self.update(None, level, debug_domains)
320
321 def update(self, eventmask, level, debug_domains):
322 self.eventmask = eventmask
323 self.stdlevel = level
324 self.debug_domains = debug_domains
325
326 def filter(self, event):
327 if isinstance(event, logging.LogRecord):
328 if event.levelno >= self.stdlevel:
329 return True
330 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
331 return True
332 return False
333 eid = str(event.__class__)[8:-2]
334 if self.eventmask and eid not in self.eventmask:
335 return False
336 return True
337
338def set_UIHmask(handlerNum, level, debug_domains, mask):
339 if not handlerNum in _ui_handlers:
340 return False
341 if '*' in mask:
342 _ui_logfilters[handlerNum].update(None, level, debug_domains)
343 else:
344 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
345 return True
346
347def getName(e):
348 """Returns the name of a class or class instance"""
Andrew Geissler82c905d2020-04-13 13:39:40 -0500349 if getattr(e, "__name__", None) is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500350 return e.__class__.__name__
351 else:
352 return e.__name__
353
354class OperationStarted(Event):
355 """An operation has begun"""
356 def __init__(self, msg = "Operation Started"):
357 Event.__init__(self)
358 self.msg = msg
359
360class OperationCompleted(Event):
361 """An operation has completed"""
362 def __init__(self, total, msg = "Operation Completed"):
363 Event.__init__(self)
364 self.total = total
365 self.msg = msg
366
367class OperationProgress(Event):
368 """An operation is in progress"""
369 def __init__(self, current, total, msg = "Operation in Progress"):
370 Event.__init__(self)
371 self.current = current
372 self.total = total
373 self.msg = msg + ": %s/%s" % (current, total);
374
375class ConfigParsed(Event):
376 """Configuration Parsing Complete"""
377
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500378class MultiConfigParsed(Event):
379 """Multi-Config Parsing Complete"""
380 def __init__(self, mcdata):
381 self.mcdata = mcdata
382 Event.__init__(self)
383
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500384class RecipeEvent(Event):
385 def __init__(self, fn):
386 self.fn = fn
387 Event.__init__(self)
388
389class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800390 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500391
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500392class RecipeTaskPreProcess(RecipeEvent):
393 """
394 Recipe Tasks about to be finalised
395 The list of tasks should be final at this point and handlers
396 are only able to change interdependencies
397 """
398 def __init__(self, fn, tasklist):
399 self.fn = fn
400 self.tasklist = tasklist
401 Event.__init__(self)
402
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403class RecipeParsed(RecipeEvent):
404 """ Recipe Parsing Complete """
405
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500406class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500407 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500408
409 def __init__(self, n, p, failures = 0):
410 self._name = n
411 self._pkgs = p
412 Event.__init__(self)
413 self._failures = failures
414
415 def getPkgs(self):
416 return self._pkgs
417
418 def setPkgs(self, pkgs):
419 self._pkgs = pkgs
420
421 def getName(self):
422 return self._name
423
424 def setName(self, name):
425 self._name = name
426
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500427 def getFailures(self):
428 """
429 Return the number of failed packages
430 """
431 return self._failures
432
433 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
434 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600436class BuildInit(BuildBase):
437 """buildFile or buildTargets was invoked"""
438 def __init__(self, p=[]):
439 name = None
440 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500441
442class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500443 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444 def __init__(self, n, p, failures = 0):
445 OperationStarted.__init__(self, "Building Started")
446 BuildBase.__init__(self, n, p, failures)
447
448class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500449 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500450 def __init__(self, total, n, p, failures=0, interrupted=0):
451 if not failures:
452 OperationCompleted.__init__(self, total, "Building Succeeded")
453 else:
454 OperationCompleted.__init__(self, total, "Building Failed")
455 self._interrupted = interrupted
456 BuildBase.__init__(self, n, p, failures)
457
458class DiskFull(Event):
459 """Disk full case build aborted"""
460 def __init__(self, dev, type, freespace, mountpoint):
461 Event.__init__(self)
462 self._dev = dev
463 self._type = type
464 self._free = freespace
465 self._mountpoint = mountpoint
466
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500467class DiskUsageSample:
468 def __init__(self, available_bytes, free_bytes, total_bytes):
469 # Number of bytes available to non-root processes.
470 self.available_bytes = available_bytes
471 # Number of bytes available to root processes.
472 self.free_bytes = free_bytes
473 # Total capacity of the volume.
474 self.total_bytes = total_bytes
475
476class MonitorDiskEvent(Event):
477 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
478 Provides information about devices that are getting monitored."""
479 def __init__(self, disk_usage):
480 Event.__init__(self)
481 # hash of device root path -> DiskUsageSample
482 self.disk_usage = disk_usage
483
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500484class NoProvider(Event):
485 """No Provider for an Event"""
486
487 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
488 Event.__init__(self)
489 self._item = item
490 self._runtime = runtime
491 self._dependees = dependees
492 self._reasons = reasons
493 self._close_matches = close_matches
494
495 def getItem(self):
496 return self._item
497
498 def isRuntime(self):
499 return self._runtime
500
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500501 def __str__(self):
502 msg = ''
503 if self._runtime:
504 r = "R"
505 else:
506 r = ""
507
508 extra = ''
509 if not self._reasons:
510 if self._close_matches:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500511 extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500512
513 if self._dependees:
514 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
515 else:
516 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
517 if self._reasons:
518 for reason in self._reasons:
519 msg += '\n' + reason
520 return msg
521
522
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500523class MultipleProviders(Event):
524 """Multiple Providers"""
525
526 def __init__(self, item, candidates, runtime = False):
527 Event.__init__(self)
528 self._item = item
529 self._candidates = candidates
530 self._is_runtime = runtime
531
532 def isRuntime(self):
533 """
534 Is this a runtime issue?
535 """
536 return self._is_runtime
537
538 def getItem(self):
539 """
540 The name for the to be build item
541 """
542 return self._item
543
544 def getCandidates(self):
545 """
546 Get the possible Candidates for a PROVIDER.
547 """
548 return self._candidates
549
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500550 def __str__(self):
551 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
552 self._item,
553 ", ".join(self._candidates))
554 rtime = ""
555 if self._is_runtime:
556 rtime = "R"
557 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
558 return msg
559
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500560class ParseStarted(OperationStarted):
561 """Recipe parsing for the runqueue has begun"""
562 def __init__(self, total):
563 OperationStarted.__init__(self, "Recipe parsing Started")
564 self.total = total
565
566class ParseCompleted(OperationCompleted):
567 """Recipe parsing for the runqueue has completed"""
568 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
569 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
570 self.cached = cached
571 self.parsed = parsed
572 self.skipped = skipped
573 self.virtuals = virtuals
574 self.masked = masked
575 self.errors = errors
576 self.sofar = cached + parsed
577
578class ParseProgress(OperationProgress):
579 """Recipe parsing progress"""
580 def __init__(self, current, total):
581 OperationProgress.__init__(self, current, total, "Recipe parsing")
582
583
584class CacheLoadStarted(OperationStarted):
585 """Loading of the dependency cache has begun"""
586 def __init__(self, total):
587 OperationStarted.__init__(self, "Loading cache Started")
588 self.total = total
589
590class CacheLoadProgress(OperationProgress):
591 """Cache loading progress"""
592 def __init__(self, current, total):
593 OperationProgress.__init__(self, current, total, "Loading cache")
594
595class CacheLoadCompleted(OperationCompleted):
596 """Cache loading is complete"""
597 def __init__(self, total, num_entries):
598 OperationCompleted.__init__(self, total, "Loading cache Completed")
599 self.num_entries = num_entries
600
601class TreeDataPreparationStarted(OperationStarted):
602 """Tree data preparation started"""
603 def __init__(self):
604 OperationStarted.__init__(self, "Preparing tree data Started")
605
606class TreeDataPreparationProgress(OperationProgress):
607 """Tree data preparation is in progress"""
608 def __init__(self, current, total):
609 OperationProgress.__init__(self, current, total, "Preparing tree data")
610
611class TreeDataPreparationCompleted(OperationCompleted):
612 """Tree data preparation completed"""
613 def __init__(self, total):
614 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
615
616class DepTreeGenerated(Event):
617 """
618 Event when a dependency tree has been generated
619 """
620
621 def __init__(self, depgraph):
622 Event.__init__(self)
623 self._depgraph = depgraph
624
625class TargetsTreeGenerated(Event):
626 """
627 Event when a set of buildable targets has been generated
628 """
629 def __init__(self, model):
630 Event.__init__(self)
631 self._model = model
632
633class ReachableStamps(Event):
634 """
635 An event listing all stamps reachable after parsing
636 which the metadata may use to clean up stale data
637 """
638
639 def __init__(self, stamps):
640 Event.__init__(self)
641 self.stamps = stamps
642
643class FilesMatchingFound(Event):
644 """
645 Event when a list of files matching the supplied pattern has
646 been generated
647 """
648 def __init__(self, pattern, matches):
649 Event.__init__(self)
650 self._pattern = pattern
651 self._matches = matches
652
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500653class ConfigFilesFound(Event):
654 """
655 Event when a list of appropriate config files has been generated
656 """
657 def __init__(self, variable, values):
658 Event.__init__(self)
659 self._variable = variable
660 self._values = values
661
662class ConfigFilePathFound(Event):
663 """
664 Event when a path for a config file has been found
665 """
666 def __init__(self, path):
667 Event.__init__(self)
668 self._path = path
669
670class MsgBase(Event):
671 """Base class for messages"""
672
673 def __init__(self, msg):
674 self._message = msg
675 Event.__init__(self)
676
677class MsgDebug(MsgBase):
678 """Debug Message"""
679
680class MsgNote(MsgBase):
681 """Note Message"""
682
683class MsgWarn(MsgBase):
684 """Warning Message"""
685
686class MsgError(MsgBase):
687 """Error Message"""
688
689class MsgFatal(MsgBase):
690 """Fatal Message"""
691
692class MsgPlain(MsgBase):
693 """General output"""
694
695class LogExecTTY(Event):
696 """Send event containing program to spawn on tty of the logger"""
697 def __init__(self, msg, prog, sleep_delay, retries):
698 Event.__init__(self)
699 self.msg = msg
700 self.prog = prog
701 self.sleep_delay = sleep_delay
702 self.retries = retries
703
704class LogHandler(logging.Handler):
705 """Dispatch logging messages as bitbake events"""
706
707 def emit(self, record):
708 if record.exc_info:
709 etype, value, tb = record.exc_info
710 if hasattr(tb, 'tb_next'):
711 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500712 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500713 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600714 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
715 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500716 record.exc_info = None
717 fire(record, None)
718
719 def filter(self, record):
720 record.taskpid = worker_pid
721 return True
722
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500723class MetadataEvent(Event):
724 """
725 Generic event that target for OE-Core classes
726 to report information during asynchrous execution
727 """
728 def __init__(self, eventtype, eventdata):
729 Event.__init__(self)
730 self.type = eventtype
731 self._localdata = eventdata
732
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600733class ProcessStarted(Event):
734 """
735 Generic process started event (usually part of the initial startup)
736 where further progress events will be delivered
737 """
738 def __init__(self, processname, total):
739 Event.__init__(self)
740 self.processname = processname
741 self.total = total
742
743class ProcessProgress(Event):
744 """
745 Generic process progress event (usually part of the initial startup)
746 """
747 def __init__(self, processname, progress):
748 Event.__init__(self)
749 self.processname = processname
750 self.progress = progress
751
752class ProcessFinished(Event):
753 """
754 Generic process finished event (usually part of the initial startup)
755 """
756 def __init__(self, processname):
757 Event.__init__(self)
758 self.processname = processname
759
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500760class SanityCheck(Event):
761 """
762 Event to run sanity checks, either raise errors or generate events as return status.
763 """
764 def __init__(self, generateevents = True):
765 Event.__init__(self)
766 self.generateevents = generateevents
767
768class SanityCheckPassed(Event):
769 """
770 Event to indicate sanity check has passed
771 """
772
773class SanityCheckFailed(Event):
774 """
775 Event to indicate sanity check has failed
776 """
777 def __init__(self, msg, network_error=False):
778 Event.__init__(self)
779 self._msg = msg
780 self._network_error = network_error
781
782class NetworkTest(Event):
783 """
784 Event to run network connectivity tests, either raise errors or generate events as return status.
785 """
786 def __init__(self, generateevents = True):
787 Event.__init__(self)
788 self.generateevents = generateevents
789
790class NetworkTestPassed(Event):
791 """
792 Event to indicate network test has passed
793 """
794
795class NetworkTestFailed(Event):
796 """
797 Event to indicate network test has failed
798 """
799
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500800class FindSigInfoResult(Event):
801 """
802 Event to return results from findSigInfo command
803 """
804 def __init__(self, result):
805 Event.__init__(self)
806 self.result = result