blob: 7cbb5ca47e61ce078d5c7a0085e5240370d30e6b [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():
127 """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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500171
172def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600173 global _thread_lock
174 global _thread_lock_enabled
175
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176 if not _uiready:
177 # No UI handlers registered yet, queue up the messages
178 ui_queue.append(event)
179 return
180
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600181 if _thread_lock_enabled:
182 _thread_lock.acquire()
183
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500184 errors = []
185 for h in _ui_handlers:
186 #print "Sending event %s" % event
187 try:
188 if not _ui_logfilters[h].filter(event):
189 continue
190 # We use pickle here since it better handles object instances
191 # which xmlrpc's marshaller does not. Events *must* be serializable
192 # by pickle.
193 if hasattr(_ui_handlers[h].event, "sendpickle"):
194 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
195 else:
196 _ui_handlers[h].event.send(event)
197 except:
198 errors.append(h)
199 for h in errors:
200 del _ui_handlers[h]
201
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600202 if _thread_lock_enabled:
203 _thread_lock.release()
204
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500205def fire(event, d):
206 """Fire off an Event"""
207
208 # We can fire class handlers in the worker process context and this is
209 # desired so they get the task based datastore.
210 # UI handlers need to be fired in the server context so we defer this. They
211 # don't have a datastore so the datastore context isn't a problem.
212
213 fire_class_handlers(event, d)
214 if worker_fire:
215 worker_fire(event, d)
216 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500217 # If messages have been queued up, clear the queue
218 global _uiready, ui_queue
219 if _uiready and ui_queue:
220 for queue_event in ui_queue:
221 fire_ui_handlers(queue_event, d)
222 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500223 fire_ui_handlers(event, d)
224
225def fire_from_worker(event, d):
226 fire_ui_handlers(event, d)
227
228noop = lambda _: None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500229def register(name, handler, mask=None, filename=None, lineno=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500230 """Register an Event handler"""
231
232 # already registered
233 if name in _handlers:
234 return AlreadyRegistered
235
236 if handler is not None:
237 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600238 if isinstance(handler, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500239 tmp = "def %s(e):\n%s" % (name, handler)
240 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500241 code = bb.methodpool.compile_cache(tmp)
242 if not code:
243 if filename is None:
244 filename = "%s(e)" % name
245 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
246 if lineno is not None:
247 ast.increment_lineno(code, lineno-1)
248 code = compile(code, filename, "exec")
249 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250 except SyntaxError:
251 logger.error("Unable to register event handler '%s':\n%s", name,
252 ''.join(traceback.format_exc(limit=0)))
253 _handlers[name] = noop
254 return
255 env = {}
256 bb.utils.better_exec(code, env)
257 func = bb.utils.better_eval(name, env)
258 _handlers[name] = func
259 else:
260 _handlers[name] = handler
261
262 if not mask or '*' in mask:
263 _catchall_handlers[name] = True
264 else:
265 for m in mask:
266 if _event_handler_map.get(m, None) is None:
267 _event_handler_map[m] = {}
268 _event_handler_map[m][name] = True
269
270 return Registered
271
272def remove(name, handler):
273 """Remove an Event handler"""
274 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500275 if name in _catchall_handlers:
276 _catchall_handlers.pop(name)
277 for event in _event_handler_map.keys():
278 if name in _event_handler_map[event]:
279 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600281def get_handlers():
282 return _handlers
283
284def set_handlers(handlers):
285 global _handlers
286 _handlers = handlers
287
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500288def set_eventfilter(func):
289 global _eventfilter
290 _eventfilter = func
291
292def register_UIHhandler(handler, mainui=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500293 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
294 _ui_handlers[_ui_handler_seq] = handler
295 level, debug_domains = bb.msg.constructLogOptions()
296 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500297 if mainui:
298 global _uiready
299 _uiready = _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500300 return _ui_handler_seq
301
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500302def unregister_UIHhandler(handlerNum, mainui=False):
303 if mainui:
304 global _uiready
305 _uiready = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500306 if handlerNum in _ui_handlers:
307 del _ui_handlers[handlerNum]
308 return
309
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310def get_uihandler():
311 if _uiready is False:
312 return None
313 return _uiready
314
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500315# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
316class UIEventFilter(object):
317 def __init__(self, level, debug_domains):
318 self.update(None, level, debug_domains)
319
320 def update(self, eventmask, level, debug_domains):
321 self.eventmask = eventmask
322 self.stdlevel = level
323 self.debug_domains = debug_domains
324
325 def filter(self, event):
326 if isinstance(event, logging.LogRecord):
327 if event.levelno >= self.stdlevel:
328 return True
329 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
330 return True
331 return False
332 eid = str(event.__class__)[8:-2]
333 if self.eventmask and eid not in self.eventmask:
334 return False
335 return True
336
337def set_UIHmask(handlerNum, level, debug_domains, mask):
338 if not handlerNum in _ui_handlers:
339 return False
340 if '*' in mask:
341 _ui_logfilters[handlerNum].update(None, level, debug_domains)
342 else:
343 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
344 return True
345
346def getName(e):
347 """Returns the name of a class or class instance"""
348 if getattr(e, "__name__", None) == None:
349 return e.__class__.__name__
350 else:
351 return e.__name__
352
353class OperationStarted(Event):
354 """An operation has begun"""
355 def __init__(self, msg = "Operation Started"):
356 Event.__init__(self)
357 self.msg = msg
358
359class OperationCompleted(Event):
360 """An operation has completed"""
361 def __init__(self, total, msg = "Operation Completed"):
362 Event.__init__(self)
363 self.total = total
364 self.msg = msg
365
366class OperationProgress(Event):
367 """An operation is in progress"""
368 def __init__(self, current, total, msg = "Operation in Progress"):
369 Event.__init__(self)
370 self.current = current
371 self.total = total
372 self.msg = msg + ": %s/%s" % (current, total);
373
374class ConfigParsed(Event):
375 """Configuration Parsing Complete"""
376
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500377class MultiConfigParsed(Event):
378 """Multi-Config Parsing Complete"""
379 def __init__(self, mcdata):
380 self.mcdata = mcdata
381 Event.__init__(self)
382
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500383class RecipeEvent(Event):
384 def __init__(self, fn):
385 self.fn = fn
386 Event.__init__(self)
387
388class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800389 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500390
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500391class RecipeTaskPreProcess(RecipeEvent):
392 """
393 Recipe Tasks about to be finalised
394 The list of tasks should be final at this point and handlers
395 are only able to change interdependencies
396 """
397 def __init__(self, fn, tasklist):
398 self.fn = fn
399 self.tasklist = tasklist
400 Event.__init__(self)
401
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500402class RecipeParsed(RecipeEvent):
403 """ Recipe Parsing Complete """
404
405class StampUpdate(Event):
406 """Trigger for any adjustment of the stamp files to happen"""
407
408 def __init__(self, targets, stampfns):
409 self._targets = targets
410 self._stampfns = stampfns
411 Event.__init__(self)
412
413 def getStampPrefix(self):
414 return self._stampfns
415
416 def getTargets(self):
417 return self._targets
418
419 stampPrefix = property(getStampPrefix)
420 targets = property(getTargets)
421
422class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500423 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500424
425 def __init__(self, n, p, failures = 0):
426 self._name = n
427 self._pkgs = p
428 Event.__init__(self)
429 self._failures = failures
430
431 def getPkgs(self):
432 return self._pkgs
433
434 def setPkgs(self, pkgs):
435 self._pkgs = pkgs
436
437 def getName(self):
438 return self._name
439
440 def setName(self, name):
441 self._name = name
442
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500443 def getFailures(self):
444 """
445 Return the number of failed packages
446 """
447 return self._failures
448
449 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
450 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500451
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600452class BuildInit(BuildBase):
453 """buildFile or buildTargets was invoked"""
454 def __init__(self, p=[]):
455 name = None
456 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500457
458class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500459 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500460 def __init__(self, n, p, failures = 0):
461 OperationStarted.__init__(self, "Building Started")
462 BuildBase.__init__(self, n, p, failures)
463
464class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500465 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466 def __init__(self, total, n, p, failures=0, interrupted=0):
467 if not failures:
468 OperationCompleted.__init__(self, total, "Building Succeeded")
469 else:
470 OperationCompleted.__init__(self, total, "Building Failed")
471 self._interrupted = interrupted
472 BuildBase.__init__(self, n, p, failures)
473
474class DiskFull(Event):
475 """Disk full case build aborted"""
476 def __init__(self, dev, type, freespace, mountpoint):
477 Event.__init__(self)
478 self._dev = dev
479 self._type = type
480 self._free = freespace
481 self._mountpoint = mountpoint
482
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500483class DiskUsageSample:
484 def __init__(self, available_bytes, free_bytes, total_bytes):
485 # Number of bytes available to non-root processes.
486 self.available_bytes = available_bytes
487 # Number of bytes available to root processes.
488 self.free_bytes = free_bytes
489 # Total capacity of the volume.
490 self.total_bytes = total_bytes
491
492class MonitorDiskEvent(Event):
493 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
494 Provides information about devices that are getting monitored."""
495 def __init__(self, disk_usage):
496 Event.__init__(self)
497 # hash of device root path -> DiskUsageSample
498 self.disk_usage = disk_usage
499
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500500class NoProvider(Event):
501 """No Provider for an Event"""
502
503 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
504 Event.__init__(self)
505 self._item = item
506 self._runtime = runtime
507 self._dependees = dependees
508 self._reasons = reasons
509 self._close_matches = close_matches
510
511 def getItem(self):
512 return self._item
513
514 def isRuntime(self):
515 return self._runtime
516
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500517 def __str__(self):
518 msg = ''
519 if self._runtime:
520 r = "R"
521 else:
522 r = ""
523
524 extra = ''
525 if not self._reasons:
526 if self._close_matches:
527 extra = ". Close matches:\n %s" % '\n '.join(self._close_matches)
528
529 if self._dependees:
530 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
531 else:
532 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
533 if self._reasons:
534 for reason in self._reasons:
535 msg += '\n' + reason
536 return msg
537
538
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500539class MultipleProviders(Event):
540 """Multiple Providers"""
541
542 def __init__(self, item, candidates, runtime = False):
543 Event.__init__(self)
544 self._item = item
545 self._candidates = candidates
546 self._is_runtime = runtime
547
548 def isRuntime(self):
549 """
550 Is this a runtime issue?
551 """
552 return self._is_runtime
553
554 def getItem(self):
555 """
556 The name for the to be build item
557 """
558 return self._item
559
560 def getCandidates(self):
561 """
562 Get the possible Candidates for a PROVIDER.
563 """
564 return self._candidates
565
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500566 def __str__(self):
567 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
568 self._item,
569 ", ".join(self._candidates))
570 rtime = ""
571 if self._is_runtime:
572 rtime = "R"
573 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
574 return msg
575
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500576class ParseStarted(OperationStarted):
577 """Recipe parsing for the runqueue has begun"""
578 def __init__(self, total):
579 OperationStarted.__init__(self, "Recipe parsing Started")
580 self.total = total
581
582class ParseCompleted(OperationCompleted):
583 """Recipe parsing for the runqueue has completed"""
584 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
585 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
586 self.cached = cached
587 self.parsed = parsed
588 self.skipped = skipped
589 self.virtuals = virtuals
590 self.masked = masked
591 self.errors = errors
592 self.sofar = cached + parsed
593
594class ParseProgress(OperationProgress):
595 """Recipe parsing progress"""
596 def __init__(self, current, total):
597 OperationProgress.__init__(self, current, total, "Recipe parsing")
598
599
600class CacheLoadStarted(OperationStarted):
601 """Loading of the dependency cache has begun"""
602 def __init__(self, total):
603 OperationStarted.__init__(self, "Loading cache Started")
604 self.total = total
605
606class CacheLoadProgress(OperationProgress):
607 """Cache loading progress"""
608 def __init__(self, current, total):
609 OperationProgress.__init__(self, current, total, "Loading cache")
610
611class CacheLoadCompleted(OperationCompleted):
612 """Cache loading is complete"""
613 def __init__(self, total, num_entries):
614 OperationCompleted.__init__(self, total, "Loading cache Completed")
615 self.num_entries = num_entries
616
617class TreeDataPreparationStarted(OperationStarted):
618 """Tree data preparation started"""
619 def __init__(self):
620 OperationStarted.__init__(self, "Preparing tree data Started")
621
622class TreeDataPreparationProgress(OperationProgress):
623 """Tree data preparation is in progress"""
624 def __init__(self, current, total):
625 OperationProgress.__init__(self, current, total, "Preparing tree data")
626
627class TreeDataPreparationCompleted(OperationCompleted):
628 """Tree data preparation completed"""
629 def __init__(self, total):
630 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
631
632class DepTreeGenerated(Event):
633 """
634 Event when a dependency tree has been generated
635 """
636
637 def __init__(self, depgraph):
638 Event.__init__(self)
639 self._depgraph = depgraph
640
641class TargetsTreeGenerated(Event):
642 """
643 Event when a set of buildable targets has been generated
644 """
645 def __init__(self, model):
646 Event.__init__(self)
647 self._model = model
648
649class ReachableStamps(Event):
650 """
651 An event listing all stamps reachable after parsing
652 which the metadata may use to clean up stale data
653 """
654
655 def __init__(self, stamps):
656 Event.__init__(self)
657 self.stamps = stamps
658
659class FilesMatchingFound(Event):
660 """
661 Event when a list of files matching the supplied pattern has
662 been generated
663 """
664 def __init__(self, pattern, matches):
665 Event.__init__(self)
666 self._pattern = pattern
667 self._matches = matches
668
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500669class ConfigFilesFound(Event):
670 """
671 Event when a list of appropriate config files has been generated
672 """
673 def __init__(self, variable, values):
674 Event.__init__(self)
675 self._variable = variable
676 self._values = values
677
678class ConfigFilePathFound(Event):
679 """
680 Event when a path for a config file has been found
681 """
682 def __init__(self, path):
683 Event.__init__(self)
684 self._path = path
685
686class MsgBase(Event):
687 """Base class for messages"""
688
689 def __init__(self, msg):
690 self._message = msg
691 Event.__init__(self)
692
693class MsgDebug(MsgBase):
694 """Debug Message"""
695
696class MsgNote(MsgBase):
697 """Note Message"""
698
699class MsgWarn(MsgBase):
700 """Warning Message"""
701
702class MsgError(MsgBase):
703 """Error Message"""
704
705class MsgFatal(MsgBase):
706 """Fatal Message"""
707
708class MsgPlain(MsgBase):
709 """General output"""
710
711class LogExecTTY(Event):
712 """Send event containing program to spawn on tty of the logger"""
713 def __init__(self, msg, prog, sleep_delay, retries):
714 Event.__init__(self)
715 self.msg = msg
716 self.prog = prog
717 self.sleep_delay = sleep_delay
718 self.retries = retries
719
720class LogHandler(logging.Handler):
721 """Dispatch logging messages as bitbake events"""
722
723 def emit(self, record):
724 if record.exc_info:
725 etype, value, tb = record.exc_info
726 if hasattr(tb, 'tb_next'):
727 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500728 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500729 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600730 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
731 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500732 record.exc_info = None
733 fire(record, None)
734
735 def filter(self, record):
736 record.taskpid = worker_pid
737 return True
738
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500739class MetadataEvent(Event):
740 """
741 Generic event that target for OE-Core classes
742 to report information during asynchrous execution
743 """
744 def __init__(self, eventtype, eventdata):
745 Event.__init__(self)
746 self.type = eventtype
747 self._localdata = eventdata
748
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600749class ProcessStarted(Event):
750 """
751 Generic process started event (usually part of the initial startup)
752 where further progress events will be delivered
753 """
754 def __init__(self, processname, total):
755 Event.__init__(self)
756 self.processname = processname
757 self.total = total
758
759class ProcessProgress(Event):
760 """
761 Generic process progress event (usually part of the initial startup)
762 """
763 def __init__(self, processname, progress):
764 Event.__init__(self)
765 self.processname = processname
766 self.progress = progress
767
768class ProcessFinished(Event):
769 """
770 Generic process finished event (usually part of the initial startup)
771 """
772 def __init__(self, processname):
773 Event.__init__(self)
774 self.processname = processname
775
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500776class SanityCheck(Event):
777 """
778 Event to run sanity checks, either raise errors or generate events as return status.
779 """
780 def __init__(self, generateevents = True):
781 Event.__init__(self)
782 self.generateevents = generateevents
783
784class SanityCheckPassed(Event):
785 """
786 Event to indicate sanity check has passed
787 """
788
789class SanityCheckFailed(Event):
790 """
791 Event to indicate sanity check has failed
792 """
793 def __init__(self, msg, network_error=False):
794 Event.__init__(self)
795 self._msg = msg
796 self._network_error = network_error
797
798class NetworkTest(Event):
799 """
800 Event to run network connectivity tests, either raise errors or generate events as return status.
801 """
802 def __init__(self, generateevents = True):
803 Event.__init__(self)
804 self.generateevents = generateevents
805
806class NetworkTestPassed(Event):
807 """
808 Event to indicate network test has passed
809 """
810
811class NetworkTestFailed(Event):
812 """
813 Event to indicate network test has failed
814 """
815
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500816class FindSigInfoResult(Event):
817 """
818 Event to return results from findSigInfo command
819 """
820 def __init__(self, result):
821 Event.__init__(self)
822 self.result = result