blob: d44621edf417cf9249392a16c02bd8cdda241a5d [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
13import os, sys
14import warnings
Patrick Williamsc0f7c042017-02-23 20:41:17 -060015import pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016import logging
17import atexit
18import traceback
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050019import ast
Patrick Williamsc0f7c042017-02-23 20:41:17 -060020import threading
21
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022import bb.utils
23import bb.compat
24import bb.exceptions
25
26# This is the pid for which we should generate the event. This is set when
27# the runqueue forks off.
28worker_pid = 0
29worker_fire = None
30
31logger = logging.getLogger('BitBake.Event')
32
33class Event(object):
34 """Base class for events"""
35
36 def __init__(self):
37 self.pid = worker_pid
38
Brad Bishop6e60e8b2018-02-01 10:27:11 -050039
40class HeartbeatEvent(Event):
41 """Triggered at regular time intervals of 10 seconds. Other events can fire much more often
42 (runQueueTaskStarted when there are many short tasks) or not at all for long periods
43 of time (again runQueueTaskStarted, when there is just one long-running task), so this
44 event is more suitable for doing some task-independent work occassionally."""
45 def __init__(self, time):
46 Event.__init__(self)
47 self.time = time
48
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049Registered = 10
50AlreadyRegistered = 14
51
52def get_class_handlers():
53 return _handlers
54
55def set_class_handlers(h):
56 global _handlers
57 _handlers = h
58
59def clean_class_handlers():
60 return bb.compat.OrderedDict()
61
62# Internal
63_handlers = clean_class_handlers()
64_ui_handlers = {}
65_ui_logfilters = {}
66_ui_handler_seq = 0
67_event_handler_map = {}
68_catchall_handlers = {}
69_eventfilter = None
70_uiready = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -060071_thread_lock = threading.Lock()
72_thread_lock_enabled = False
73
74if hasattr(__builtins__, '__setitem__'):
75 builtins = __builtins__
76else:
77 builtins = __builtins__.__dict__
78
79def enable_threadlock():
80 global _thread_lock_enabled
81 _thread_lock_enabled = True
82
83def disable_threadlock():
84 global _thread_lock_enabled
85 _thread_lock_enabled = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050086
87def execute_handler(name, handler, event, d):
88 event.data = d
89 addedd = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -060090 if 'd' not in builtins:
91 builtins['d'] = d
Patrick Williamsc124f4f2015-09-15 14:41:29 -050092 addedd = True
93 try:
94 ret = handler(event)
95 except (bb.parse.SkipRecipe, bb.BBHandledException):
96 raise
97 except Exception:
98 etype, value, tb = sys.exc_info()
99 logger.error("Execution of event handler '%s' failed" % name,
100 exc_info=(etype, value, tb.tb_next))
101 raise
102 except SystemExit as exc:
103 if exc.code != 0:
104 logger.error("Execution of event handler '%s' failed" % name)
105 raise
106 finally:
107 del event.data
108 if addedd:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600109 del builtins['d']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500110
111def fire_class_handlers(event, d):
112 if isinstance(event, logging.LogRecord):
113 return
114
115 eid = str(event.__class__)[8:-2]
116 evt_hmap = _event_handler_map.get(eid, {})
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600117 for name, handler in list(_handlers.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500118 if name in _catchall_handlers or name in evt_hmap:
119 if _eventfilter:
120 if not _eventfilter(name, handler, event, d):
121 continue
122 execute_handler(name, handler, event, d)
123
124ui_queue = []
125@atexit.register
126def print_ui_queue():
Brad Bishop96ff1982019-08-19 13:50:42 -0400127 global ui_queue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500128 """If we're exiting before a UI has been spawned, display any queued
129 LogRecords to the console."""
130 logger = logging.getLogger("BitBake")
131 if not _uiready:
132 from bb.msg import BBLogFormatter
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800133 # Flush any existing buffered content
134 sys.stdout.flush()
135 sys.stderr.flush()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600136 stdout = logging.StreamHandler(sys.stdout)
137 stderr = logging.StreamHandler(sys.stderr)
138 formatter = BBLogFormatter("%(levelname)s: %(message)s")
139 stdout.setFormatter(formatter)
140 stderr.setFormatter(formatter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141
142 # First check to see if we have any proper messages
143 msgprint = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500144 msgerrs = False
145
146 # Should we print to stderr?
147 for event in ui_queue[:]:
148 if isinstance(event, logging.LogRecord) and event.levelno >= logging.WARNING:
149 msgerrs = True
150 break
151
152 if msgerrs:
153 logger.addHandler(stderr)
154 else:
155 logger.addHandler(stdout)
156
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600157 for event in ui_queue[:]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500158 if isinstance(event, logging.LogRecord):
159 if event.levelno > logging.DEBUG:
160 logger.handle(event)
161 msgprint = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162
163 # Nope, so just print all of the messages we have (including debug messages)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500164 if not msgprint:
165 for event in ui_queue[:]:
166 if isinstance(event, logging.LogRecord):
167 logger.handle(event)
168 if msgerrs:
169 logger.removeHandler(stderr)
170 else:
171 logger.removeHandler(stdout)
Brad Bishop96ff1982019-08-19 13:50:42 -0400172 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173
174def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600175 global _thread_lock
176 global _thread_lock_enabled
177
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178 if not _uiready:
179 # No UI handlers registered yet, queue up the messages
180 ui_queue.append(event)
181 return
182
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600183 if _thread_lock_enabled:
184 _thread_lock.acquire()
185
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500186 errors = []
187 for h in _ui_handlers:
188 #print "Sending event %s" % event
189 try:
190 if not _ui_logfilters[h].filter(event):
191 continue
192 # We use pickle here since it better handles object instances
193 # which xmlrpc's marshaller does not. Events *must* be serializable
194 # by pickle.
195 if hasattr(_ui_handlers[h].event, "sendpickle"):
196 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
197 else:
198 _ui_handlers[h].event.send(event)
199 except:
200 errors.append(h)
201 for h in errors:
202 del _ui_handlers[h]
203
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600204 if _thread_lock_enabled:
205 _thread_lock.release()
206
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500207def fire(event, d):
208 """Fire off an Event"""
209
210 # We can fire class handlers in the worker process context and this is
211 # desired so they get the task based datastore.
212 # UI handlers need to be fired in the server context so we defer this. They
213 # don't have a datastore so the datastore context isn't a problem.
214
215 fire_class_handlers(event, d)
216 if worker_fire:
217 worker_fire(event, d)
218 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500219 # If messages have been queued up, clear the queue
220 global _uiready, ui_queue
221 if _uiready and ui_queue:
222 for queue_event in ui_queue:
223 fire_ui_handlers(queue_event, d)
224 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500225 fire_ui_handlers(event, d)
226
227def fire_from_worker(event, d):
228 fire_ui_handlers(event, d)
229
230noop = lambda _: None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500231def register(name, handler, mask=None, filename=None, lineno=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500232 """Register an Event handler"""
233
234 # already registered
235 if name in _handlers:
236 return AlreadyRegistered
237
238 if handler is not None:
239 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600240 if isinstance(handler, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500241 tmp = "def %s(e):\n%s" % (name, handler)
242 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500243 code = bb.methodpool.compile_cache(tmp)
244 if not code:
245 if filename is None:
246 filename = "%s(e)" % name
247 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
248 if lineno is not None:
249 ast.increment_lineno(code, lineno-1)
250 code = compile(code, filename, "exec")
251 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500252 except SyntaxError:
253 logger.error("Unable to register event handler '%s':\n%s", name,
254 ''.join(traceback.format_exc(limit=0)))
255 _handlers[name] = noop
256 return
257 env = {}
258 bb.utils.better_exec(code, env)
259 func = bb.utils.better_eval(name, env)
260 _handlers[name] = func
261 else:
262 _handlers[name] = handler
263
264 if not mask or '*' in mask:
265 _catchall_handlers[name] = True
266 else:
267 for m in mask:
268 if _event_handler_map.get(m, None) is None:
269 _event_handler_map[m] = {}
270 _event_handler_map[m][name] = True
271
272 return Registered
273
274def remove(name, handler):
275 """Remove an Event handler"""
276 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500277 if name in _catchall_handlers:
278 _catchall_handlers.pop(name)
279 for event in _event_handler_map.keys():
280 if name in _event_handler_map[event]:
281 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500282
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600283def get_handlers():
284 return _handlers
285
286def set_handlers(handlers):
287 global _handlers
288 _handlers = handlers
289
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500290def set_eventfilter(func):
291 global _eventfilter
292 _eventfilter = func
293
294def register_UIHhandler(handler, mainui=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500295 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
296 _ui_handlers[_ui_handler_seq] = handler
297 level, debug_domains = bb.msg.constructLogOptions()
298 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500299 if mainui:
300 global _uiready
301 _uiready = _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500302 return _ui_handler_seq
303
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500304def unregister_UIHhandler(handlerNum, mainui=False):
305 if mainui:
306 global _uiready
307 _uiready = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500308 if handlerNum in _ui_handlers:
309 del _ui_handlers[handlerNum]
310 return
311
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500312def get_uihandler():
313 if _uiready is False:
314 return None
315 return _uiready
316
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500317# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
318class UIEventFilter(object):
319 def __init__(self, level, debug_domains):
320 self.update(None, level, debug_domains)
321
322 def update(self, eventmask, level, debug_domains):
323 self.eventmask = eventmask
324 self.stdlevel = level
325 self.debug_domains = debug_domains
326
327 def filter(self, event):
328 if isinstance(event, logging.LogRecord):
329 if event.levelno >= self.stdlevel:
330 return True
331 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
332 return True
333 return False
334 eid = str(event.__class__)[8:-2]
335 if self.eventmask and eid not in self.eventmask:
336 return False
337 return True
338
339def set_UIHmask(handlerNum, level, debug_domains, mask):
340 if not handlerNum in _ui_handlers:
341 return False
342 if '*' in mask:
343 _ui_logfilters[handlerNum].update(None, level, debug_domains)
344 else:
345 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
346 return True
347
348def getName(e):
349 """Returns the name of a class or class instance"""
350 if getattr(e, "__name__", None) == None:
351 return e.__class__.__name__
352 else:
353 return e.__name__
354
355class OperationStarted(Event):
356 """An operation has begun"""
357 def __init__(self, msg = "Operation Started"):
358 Event.__init__(self)
359 self.msg = msg
360
361class OperationCompleted(Event):
362 """An operation has completed"""
363 def __init__(self, total, msg = "Operation Completed"):
364 Event.__init__(self)
365 self.total = total
366 self.msg = msg
367
368class OperationProgress(Event):
369 """An operation is in progress"""
370 def __init__(self, current, total, msg = "Operation in Progress"):
371 Event.__init__(self)
372 self.current = current
373 self.total = total
374 self.msg = msg + ": %s/%s" % (current, total);
375
376class ConfigParsed(Event):
377 """Configuration Parsing Complete"""
378
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500379class MultiConfigParsed(Event):
380 """Multi-Config Parsing Complete"""
381 def __init__(self, mcdata):
382 self.mcdata = mcdata
383 Event.__init__(self)
384
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500385class RecipeEvent(Event):
386 def __init__(self, fn):
387 self.fn = fn
388 Event.__init__(self)
389
390class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800391 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500392
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500393class RecipeTaskPreProcess(RecipeEvent):
394 """
395 Recipe Tasks about to be finalised
396 The list of tasks should be final at this point and handlers
397 are only able to change interdependencies
398 """
399 def __init__(self, fn, tasklist):
400 self.fn = fn
401 self.tasklist = tasklist
402 Event.__init__(self)
403
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500404class RecipeParsed(RecipeEvent):
405 """ Recipe Parsing Complete """
406
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500407class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500408 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500409
410 def __init__(self, n, p, failures = 0):
411 self._name = n
412 self._pkgs = p
413 Event.__init__(self)
414 self._failures = failures
415
416 def getPkgs(self):
417 return self._pkgs
418
419 def setPkgs(self, pkgs):
420 self._pkgs = pkgs
421
422 def getName(self):
423 return self._name
424
425 def setName(self, name):
426 self._name = name
427
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500428 def getFailures(self):
429 """
430 Return the number of failed packages
431 """
432 return self._failures
433
434 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
435 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600437class BuildInit(BuildBase):
438 """buildFile or buildTargets was invoked"""
439 def __init__(self, p=[]):
440 name = None
441 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500442
443class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500444 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445 def __init__(self, n, p, failures = 0):
446 OperationStarted.__init__(self, "Building Started")
447 BuildBase.__init__(self, n, p, failures)
448
449class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500450 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500451 def __init__(self, total, n, p, failures=0, interrupted=0):
452 if not failures:
453 OperationCompleted.__init__(self, total, "Building Succeeded")
454 else:
455 OperationCompleted.__init__(self, total, "Building Failed")
456 self._interrupted = interrupted
457 BuildBase.__init__(self, n, p, failures)
458
459class DiskFull(Event):
460 """Disk full case build aborted"""
461 def __init__(self, dev, type, freespace, mountpoint):
462 Event.__init__(self)
463 self._dev = dev
464 self._type = type
465 self._free = freespace
466 self._mountpoint = mountpoint
467
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500468class DiskUsageSample:
469 def __init__(self, available_bytes, free_bytes, total_bytes):
470 # Number of bytes available to non-root processes.
471 self.available_bytes = available_bytes
472 # Number of bytes available to root processes.
473 self.free_bytes = free_bytes
474 # Total capacity of the volume.
475 self.total_bytes = total_bytes
476
477class MonitorDiskEvent(Event):
478 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
479 Provides information about devices that are getting monitored."""
480 def __init__(self, disk_usage):
481 Event.__init__(self)
482 # hash of device root path -> DiskUsageSample
483 self.disk_usage = disk_usage
484
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500485class NoProvider(Event):
486 """No Provider for an Event"""
487
488 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
489 Event.__init__(self)
490 self._item = item
491 self._runtime = runtime
492 self._dependees = dependees
493 self._reasons = reasons
494 self._close_matches = close_matches
495
496 def getItem(self):
497 return self._item
498
499 def isRuntime(self):
500 return self._runtime
501
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500502 def __str__(self):
503 msg = ''
504 if self._runtime:
505 r = "R"
506 else:
507 r = ""
508
509 extra = ''
510 if not self._reasons:
511 if self._close_matches:
512 extra = ". Close matches:\n %s" % '\n '.join(self._close_matches)
513
514 if self._dependees:
515 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
516 else:
517 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
518 if self._reasons:
519 for reason in self._reasons:
520 msg += '\n' + reason
521 return msg
522
523
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500524class MultipleProviders(Event):
525 """Multiple Providers"""
526
527 def __init__(self, item, candidates, runtime = False):
528 Event.__init__(self)
529 self._item = item
530 self._candidates = candidates
531 self._is_runtime = runtime
532
533 def isRuntime(self):
534 """
535 Is this a runtime issue?
536 """
537 return self._is_runtime
538
539 def getItem(self):
540 """
541 The name for the to be build item
542 """
543 return self._item
544
545 def getCandidates(self):
546 """
547 Get the possible Candidates for a PROVIDER.
548 """
549 return self._candidates
550
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500551 def __str__(self):
552 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
553 self._item,
554 ", ".join(self._candidates))
555 rtime = ""
556 if self._is_runtime:
557 rtime = "R"
558 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
559 return msg
560
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500561class ParseStarted(OperationStarted):
562 """Recipe parsing for the runqueue has begun"""
563 def __init__(self, total):
564 OperationStarted.__init__(self, "Recipe parsing Started")
565 self.total = total
566
567class ParseCompleted(OperationCompleted):
568 """Recipe parsing for the runqueue has completed"""
569 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
570 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
571 self.cached = cached
572 self.parsed = parsed
573 self.skipped = skipped
574 self.virtuals = virtuals
575 self.masked = masked
576 self.errors = errors
577 self.sofar = cached + parsed
578
579class ParseProgress(OperationProgress):
580 """Recipe parsing progress"""
581 def __init__(self, current, total):
582 OperationProgress.__init__(self, current, total, "Recipe parsing")
583
584
585class CacheLoadStarted(OperationStarted):
586 """Loading of the dependency cache has begun"""
587 def __init__(self, total):
588 OperationStarted.__init__(self, "Loading cache Started")
589 self.total = total
590
591class CacheLoadProgress(OperationProgress):
592 """Cache loading progress"""
593 def __init__(self, current, total):
594 OperationProgress.__init__(self, current, total, "Loading cache")
595
596class CacheLoadCompleted(OperationCompleted):
597 """Cache loading is complete"""
598 def __init__(self, total, num_entries):
599 OperationCompleted.__init__(self, total, "Loading cache Completed")
600 self.num_entries = num_entries
601
602class TreeDataPreparationStarted(OperationStarted):
603 """Tree data preparation started"""
604 def __init__(self):
605 OperationStarted.__init__(self, "Preparing tree data Started")
606
607class TreeDataPreparationProgress(OperationProgress):
608 """Tree data preparation is in progress"""
609 def __init__(self, current, total):
610 OperationProgress.__init__(self, current, total, "Preparing tree data")
611
612class TreeDataPreparationCompleted(OperationCompleted):
613 """Tree data preparation completed"""
614 def __init__(self, total):
615 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
616
617class DepTreeGenerated(Event):
618 """
619 Event when a dependency tree has been generated
620 """
621
622 def __init__(self, depgraph):
623 Event.__init__(self)
624 self._depgraph = depgraph
625
626class TargetsTreeGenerated(Event):
627 """
628 Event when a set of buildable targets has been generated
629 """
630 def __init__(self, model):
631 Event.__init__(self)
632 self._model = model
633
634class ReachableStamps(Event):
635 """
636 An event listing all stamps reachable after parsing
637 which the metadata may use to clean up stale data
638 """
639
640 def __init__(self, stamps):
641 Event.__init__(self)
642 self.stamps = stamps
643
644class FilesMatchingFound(Event):
645 """
646 Event when a list of files matching the supplied pattern has
647 been generated
648 """
649 def __init__(self, pattern, matches):
650 Event.__init__(self)
651 self._pattern = pattern
652 self._matches = matches
653
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500654class ConfigFilesFound(Event):
655 """
656 Event when a list of appropriate config files has been generated
657 """
658 def __init__(self, variable, values):
659 Event.__init__(self)
660 self._variable = variable
661 self._values = values
662
663class ConfigFilePathFound(Event):
664 """
665 Event when a path for a config file has been found
666 """
667 def __init__(self, path):
668 Event.__init__(self)
669 self._path = path
670
671class MsgBase(Event):
672 """Base class for messages"""
673
674 def __init__(self, msg):
675 self._message = msg
676 Event.__init__(self)
677
678class MsgDebug(MsgBase):
679 """Debug Message"""
680
681class MsgNote(MsgBase):
682 """Note Message"""
683
684class MsgWarn(MsgBase):
685 """Warning Message"""
686
687class MsgError(MsgBase):
688 """Error Message"""
689
690class MsgFatal(MsgBase):
691 """Fatal Message"""
692
693class MsgPlain(MsgBase):
694 """General output"""
695
696class LogExecTTY(Event):
697 """Send event containing program to spawn on tty of the logger"""
698 def __init__(self, msg, prog, sleep_delay, retries):
699 Event.__init__(self)
700 self.msg = msg
701 self.prog = prog
702 self.sleep_delay = sleep_delay
703 self.retries = retries
704
705class LogHandler(logging.Handler):
706 """Dispatch logging messages as bitbake events"""
707
708 def emit(self, record):
709 if record.exc_info:
710 etype, value, tb = record.exc_info
711 if hasattr(tb, 'tb_next'):
712 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500713 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500714 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600715 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
716 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500717 record.exc_info = None
718 fire(record, None)
719
720 def filter(self, record):
721 record.taskpid = worker_pid
722 return True
723
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500724class MetadataEvent(Event):
725 """
726 Generic event that target for OE-Core classes
727 to report information during asynchrous execution
728 """
729 def __init__(self, eventtype, eventdata):
730 Event.__init__(self)
731 self.type = eventtype
732 self._localdata = eventdata
733
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600734class ProcessStarted(Event):
735 """
736 Generic process started event (usually part of the initial startup)
737 where further progress events will be delivered
738 """
739 def __init__(self, processname, total):
740 Event.__init__(self)
741 self.processname = processname
742 self.total = total
743
744class ProcessProgress(Event):
745 """
746 Generic process progress event (usually part of the initial startup)
747 """
748 def __init__(self, processname, progress):
749 Event.__init__(self)
750 self.processname = processname
751 self.progress = progress
752
753class ProcessFinished(Event):
754 """
755 Generic process finished event (usually part of the initial startup)
756 """
757 def __init__(self, processname):
758 Event.__init__(self)
759 self.processname = processname
760
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500761class SanityCheck(Event):
762 """
763 Event to run sanity checks, either raise errors or generate events as return status.
764 """
765 def __init__(self, generateevents = True):
766 Event.__init__(self)
767 self.generateevents = generateevents
768
769class SanityCheckPassed(Event):
770 """
771 Event to indicate sanity check has passed
772 """
773
774class SanityCheckFailed(Event):
775 """
776 Event to indicate sanity check has failed
777 """
778 def __init__(self, msg, network_error=False):
779 Event.__init__(self)
780 self._msg = msg
781 self._network_error = network_error
782
783class NetworkTest(Event):
784 """
785 Event to run network connectivity tests, either raise errors or generate events as return status.
786 """
787 def __init__(self, generateevents = True):
788 Event.__init__(self)
789 self.generateevents = generateevents
790
791class NetworkTestPassed(Event):
792 """
793 Event to indicate network test has passed
794 """
795
796class NetworkTestFailed(Event):
797 """
798 Event to indicate network test has failed
799 """
800
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500801class FindSigInfoResult(Event):
802 """
803 Event to return results from findSigInfo command
804 """
805 def __init__(self, result):
806 Event.__init__(self)
807 self.result = result