blob: 694b4705202f873ae93d7d0d8bf382615515d4eb [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
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
Andrew Geissler1e34c2d2020-05-29 16:02:59 -0500392class RecipePostKeyExpansion(RecipeEvent):
393 """ Recipe Parsing Complete but not yet finalised"""
394
395
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500396class RecipeTaskPreProcess(RecipeEvent):
397 """
398 Recipe Tasks about to be finalised
399 The list of tasks should be final at this point and handlers
400 are only able to change interdependencies
401 """
402 def __init__(self, fn, tasklist):
403 self.fn = fn
404 self.tasklist = tasklist
405 Event.__init__(self)
406
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500407class RecipeParsed(RecipeEvent):
408 """ Recipe Parsing Complete """
409
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500410class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500411 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500412
413 def __init__(self, n, p, failures = 0):
414 self._name = n
415 self._pkgs = p
416 Event.__init__(self)
417 self._failures = failures
418
419 def getPkgs(self):
420 return self._pkgs
421
422 def setPkgs(self, pkgs):
423 self._pkgs = pkgs
424
425 def getName(self):
426 return self._name
427
428 def setName(self, name):
429 self._name = name
430
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500431 def getFailures(self):
432 """
433 Return the number of failed packages
434 """
435 return self._failures
436
437 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
438 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500439
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600440class BuildInit(BuildBase):
441 """buildFile or buildTargets was invoked"""
442 def __init__(self, p=[]):
443 name = None
444 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445
446class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500447 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500448 def __init__(self, n, p, failures = 0):
449 OperationStarted.__init__(self, "Building Started")
450 BuildBase.__init__(self, n, p, failures)
451
452class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500453 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500454 def __init__(self, total, n, p, failures=0, interrupted=0):
455 if not failures:
456 OperationCompleted.__init__(self, total, "Building Succeeded")
457 else:
458 OperationCompleted.__init__(self, total, "Building Failed")
459 self._interrupted = interrupted
460 BuildBase.__init__(self, n, p, failures)
461
462class DiskFull(Event):
463 """Disk full case build aborted"""
464 def __init__(self, dev, type, freespace, mountpoint):
465 Event.__init__(self)
466 self._dev = dev
467 self._type = type
468 self._free = freespace
469 self._mountpoint = mountpoint
470
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500471class DiskUsageSample:
472 def __init__(self, available_bytes, free_bytes, total_bytes):
473 # Number of bytes available to non-root processes.
474 self.available_bytes = available_bytes
475 # Number of bytes available to root processes.
476 self.free_bytes = free_bytes
477 # Total capacity of the volume.
478 self.total_bytes = total_bytes
479
480class MonitorDiskEvent(Event):
481 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
482 Provides information about devices that are getting monitored."""
483 def __init__(self, disk_usage):
484 Event.__init__(self)
485 # hash of device root path -> DiskUsageSample
486 self.disk_usage = disk_usage
487
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500488class NoProvider(Event):
489 """No Provider for an Event"""
490
491 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
492 Event.__init__(self)
493 self._item = item
494 self._runtime = runtime
495 self._dependees = dependees
496 self._reasons = reasons
497 self._close_matches = close_matches
498
499 def getItem(self):
500 return self._item
501
502 def isRuntime(self):
503 return self._runtime
504
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500505 def __str__(self):
506 msg = ''
507 if self._runtime:
508 r = "R"
509 else:
510 r = ""
511
512 extra = ''
513 if not self._reasons:
514 if self._close_matches:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500515 extra = ". Close matches:\n %s" % '\n '.join(sorted(set(self._close_matches)))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500516
517 if self._dependees:
518 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
519 else:
520 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
521 if self._reasons:
522 for reason in self._reasons:
523 msg += '\n' + reason
524 return msg
525
526
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500527class MultipleProviders(Event):
528 """Multiple Providers"""
529
530 def __init__(self, item, candidates, runtime = False):
531 Event.__init__(self)
532 self._item = item
533 self._candidates = candidates
534 self._is_runtime = runtime
535
536 def isRuntime(self):
537 """
538 Is this a runtime issue?
539 """
540 return self._is_runtime
541
542 def getItem(self):
543 """
544 The name for the to be build item
545 """
546 return self._item
547
548 def getCandidates(self):
549 """
550 Get the possible Candidates for a PROVIDER.
551 """
552 return self._candidates
553
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500554 def __str__(self):
555 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
556 self._item,
557 ", ".join(self._candidates))
558 rtime = ""
559 if self._is_runtime:
560 rtime = "R"
561 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
562 return msg
563
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564class ParseStarted(OperationStarted):
565 """Recipe parsing for the runqueue has begun"""
566 def __init__(self, total):
567 OperationStarted.__init__(self, "Recipe parsing Started")
568 self.total = total
569
570class ParseCompleted(OperationCompleted):
571 """Recipe parsing for the runqueue has completed"""
572 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
573 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
574 self.cached = cached
575 self.parsed = parsed
576 self.skipped = skipped
577 self.virtuals = virtuals
578 self.masked = masked
579 self.errors = errors
580 self.sofar = cached + parsed
581
582class ParseProgress(OperationProgress):
583 """Recipe parsing progress"""
584 def __init__(self, current, total):
585 OperationProgress.__init__(self, current, total, "Recipe parsing")
586
587
588class CacheLoadStarted(OperationStarted):
589 """Loading of the dependency cache has begun"""
590 def __init__(self, total):
591 OperationStarted.__init__(self, "Loading cache Started")
592 self.total = total
593
594class CacheLoadProgress(OperationProgress):
595 """Cache loading progress"""
596 def __init__(self, current, total):
597 OperationProgress.__init__(self, current, total, "Loading cache")
598
599class CacheLoadCompleted(OperationCompleted):
600 """Cache loading is complete"""
601 def __init__(self, total, num_entries):
602 OperationCompleted.__init__(self, total, "Loading cache Completed")
603 self.num_entries = num_entries
604
605class TreeDataPreparationStarted(OperationStarted):
606 """Tree data preparation started"""
607 def __init__(self):
608 OperationStarted.__init__(self, "Preparing tree data Started")
609
610class TreeDataPreparationProgress(OperationProgress):
611 """Tree data preparation is in progress"""
612 def __init__(self, current, total):
613 OperationProgress.__init__(self, current, total, "Preparing tree data")
614
615class TreeDataPreparationCompleted(OperationCompleted):
616 """Tree data preparation completed"""
617 def __init__(self, total):
618 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
619
620class DepTreeGenerated(Event):
621 """
622 Event when a dependency tree has been generated
623 """
624
625 def __init__(self, depgraph):
626 Event.__init__(self)
627 self._depgraph = depgraph
628
629class TargetsTreeGenerated(Event):
630 """
631 Event when a set of buildable targets has been generated
632 """
633 def __init__(self, model):
634 Event.__init__(self)
635 self._model = model
636
637class ReachableStamps(Event):
638 """
639 An event listing all stamps reachable after parsing
640 which the metadata may use to clean up stale data
641 """
642
643 def __init__(self, stamps):
644 Event.__init__(self)
645 self.stamps = stamps
646
647class FilesMatchingFound(Event):
648 """
649 Event when a list of files matching the supplied pattern has
650 been generated
651 """
652 def __init__(self, pattern, matches):
653 Event.__init__(self)
654 self._pattern = pattern
655 self._matches = matches
656
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500657class ConfigFilesFound(Event):
658 """
659 Event when a list of appropriate config files has been generated
660 """
661 def __init__(self, variable, values):
662 Event.__init__(self)
663 self._variable = variable
664 self._values = values
665
666class ConfigFilePathFound(Event):
667 """
668 Event when a path for a config file has been found
669 """
670 def __init__(self, path):
671 Event.__init__(self)
672 self._path = path
673
674class MsgBase(Event):
675 """Base class for messages"""
676
677 def __init__(self, msg):
678 self._message = msg
679 Event.__init__(self)
680
681class MsgDebug(MsgBase):
682 """Debug Message"""
683
684class MsgNote(MsgBase):
685 """Note Message"""
686
687class MsgWarn(MsgBase):
688 """Warning Message"""
689
690class MsgError(MsgBase):
691 """Error Message"""
692
693class MsgFatal(MsgBase):
694 """Fatal Message"""
695
696class MsgPlain(MsgBase):
697 """General output"""
698
699class LogExecTTY(Event):
700 """Send event containing program to spawn on tty of the logger"""
701 def __init__(self, msg, prog, sleep_delay, retries):
702 Event.__init__(self)
703 self.msg = msg
704 self.prog = prog
705 self.sleep_delay = sleep_delay
706 self.retries = retries
707
708class LogHandler(logging.Handler):
709 """Dispatch logging messages as bitbake events"""
710
711 def emit(self, record):
712 if record.exc_info:
713 etype, value, tb = record.exc_info
714 if hasattr(tb, 'tb_next'):
715 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500716 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500717 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600718 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
719 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500720 record.exc_info = None
721 fire(record, None)
722
723 def filter(self, record):
724 record.taskpid = worker_pid
725 return True
726
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500727class MetadataEvent(Event):
728 """
729 Generic event that target for OE-Core classes
730 to report information during asynchrous execution
731 """
732 def __init__(self, eventtype, eventdata):
733 Event.__init__(self)
734 self.type = eventtype
735 self._localdata = eventdata
736
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600737class ProcessStarted(Event):
738 """
739 Generic process started event (usually part of the initial startup)
740 where further progress events will be delivered
741 """
742 def __init__(self, processname, total):
743 Event.__init__(self)
744 self.processname = processname
745 self.total = total
746
747class ProcessProgress(Event):
748 """
749 Generic process progress event (usually part of the initial startup)
750 """
751 def __init__(self, processname, progress):
752 Event.__init__(self)
753 self.processname = processname
754 self.progress = progress
755
756class ProcessFinished(Event):
757 """
758 Generic process finished event (usually part of the initial startup)
759 """
760 def __init__(self, processname):
761 Event.__init__(self)
762 self.processname = processname
763
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500764class SanityCheck(Event):
765 """
766 Event to run sanity checks, either raise errors or generate events as return status.
767 """
768 def __init__(self, generateevents = True):
769 Event.__init__(self)
770 self.generateevents = generateevents
771
772class SanityCheckPassed(Event):
773 """
774 Event to indicate sanity check has passed
775 """
776
777class SanityCheckFailed(Event):
778 """
779 Event to indicate sanity check has failed
780 """
781 def __init__(self, msg, network_error=False):
782 Event.__init__(self)
783 self._msg = msg
784 self._network_error = network_error
785
786class NetworkTest(Event):
787 """
788 Event to run network connectivity tests, 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 NetworkTestPassed(Event):
795 """
796 Event to indicate network test has passed
797 """
798
799class NetworkTestFailed(Event):
800 """
801 Event to indicate network test has failed
802 """
803
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500804class FindSigInfoResult(Event):
805 """
806 Event to return results from findSigInfo command
807 """
808 def __init__(self, result):
809 Event.__init__(self)
810 self.result = result