blob: 5b1b094a80686ab4f498b891a203403cefa1b54b [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake 'Event' implementation
5
6Classes and functions for manipulating 'events' in the
7BitBake build tools.
8"""
9
10# Copyright (C) 2003, 2004 Chris Larson
11#
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License version 2 as
14# published by the Free Software Foundation.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License along
22# with this program; if not, write to the Free Software Foundation, Inc.,
23# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
25import os, sys
26import warnings
Patrick Williamsc0f7c042017-02-23 20:41:17 -060027import pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028import logging
29import atexit
30import traceback
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050031import ast
Patrick Williamsc0f7c042017-02-23 20:41:17 -060032import threading
33
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034import bb.utils
35import bb.compat
36import bb.exceptions
37
38# This is the pid for which we should generate the event. This is set when
39# the runqueue forks off.
40worker_pid = 0
41worker_fire = None
42
43logger = logging.getLogger('BitBake.Event')
44
45class Event(object):
46 """Base class for events"""
47
48 def __init__(self):
49 self.pid = worker_pid
50
Brad Bishop6e60e8b2018-02-01 10:27:11 -050051
52class HeartbeatEvent(Event):
53 """Triggered at regular time intervals of 10 seconds. Other events can fire much more often
54 (runQueueTaskStarted when there are many short tasks) or not at all for long periods
55 of time (again runQueueTaskStarted, when there is just one long-running task), so this
56 event is more suitable for doing some task-independent work occassionally."""
57 def __init__(self, time):
58 Event.__init__(self)
59 self.time = time
60
Patrick Williamsc124f4f2015-09-15 14:41:29 -050061Registered = 10
62AlreadyRegistered = 14
63
64def get_class_handlers():
65 return _handlers
66
67def set_class_handlers(h):
68 global _handlers
69 _handlers = h
70
71def clean_class_handlers():
72 return bb.compat.OrderedDict()
73
74# Internal
75_handlers = clean_class_handlers()
76_ui_handlers = {}
77_ui_logfilters = {}
78_ui_handler_seq = 0
79_event_handler_map = {}
80_catchall_handlers = {}
81_eventfilter = None
82_uiready = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -060083_thread_lock = threading.Lock()
84_thread_lock_enabled = False
85
86if hasattr(__builtins__, '__setitem__'):
87 builtins = __builtins__
88else:
89 builtins = __builtins__.__dict__
90
91def enable_threadlock():
92 global _thread_lock_enabled
93 _thread_lock_enabled = True
94
95def disable_threadlock():
96 global _thread_lock_enabled
97 _thread_lock_enabled = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050098
99def execute_handler(name, handler, event, d):
100 event.data = d
101 addedd = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600102 if 'd' not in builtins:
103 builtins['d'] = d
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500104 addedd = True
105 try:
106 ret = handler(event)
107 except (bb.parse.SkipRecipe, bb.BBHandledException):
108 raise
109 except Exception:
110 etype, value, tb = sys.exc_info()
111 logger.error("Execution of event handler '%s' failed" % name,
112 exc_info=(etype, value, tb.tb_next))
113 raise
114 except SystemExit as exc:
115 if exc.code != 0:
116 logger.error("Execution of event handler '%s' failed" % name)
117 raise
118 finally:
119 del event.data
120 if addedd:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600121 del builtins['d']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500122
123def fire_class_handlers(event, d):
124 if isinstance(event, logging.LogRecord):
125 return
126
127 eid = str(event.__class__)[8:-2]
128 evt_hmap = _event_handler_map.get(eid, {})
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600129 for name, handler in list(_handlers.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500130 if name in _catchall_handlers or name in evt_hmap:
131 if _eventfilter:
132 if not _eventfilter(name, handler, event, d):
133 continue
134 execute_handler(name, handler, event, d)
135
136ui_queue = []
137@atexit.register
138def print_ui_queue():
139 """If we're exiting before a UI has been spawned, display any queued
140 LogRecords to the console."""
141 logger = logging.getLogger("BitBake")
142 if not _uiready:
143 from bb.msg import BBLogFormatter
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800144 # Flush any existing buffered content
145 sys.stdout.flush()
146 sys.stderr.flush()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600147 stdout = logging.StreamHandler(sys.stdout)
148 stderr = logging.StreamHandler(sys.stderr)
149 formatter = BBLogFormatter("%(levelname)s: %(message)s")
150 stdout.setFormatter(formatter)
151 stderr.setFormatter(formatter)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152
153 # First check to see if we have any proper messages
154 msgprint = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500155 msgerrs = False
156
157 # Should we print to stderr?
158 for event in ui_queue[:]:
159 if isinstance(event, logging.LogRecord) and event.levelno >= logging.WARNING:
160 msgerrs = True
161 break
162
163 if msgerrs:
164 logger.addHandler(stderr)
165 else:
166 logger.addHandler(stdout)
167
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600168 for event in ui_queue[:]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500169 if isinstance(event, logging.LogRecord):
170 if event.levelno > logging.DEBUG:
171 logger.handle(event)
172 msgprint = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173
174 # Nope, so just print all of the messages we have (including debug messages)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500175 if not msgprint:
176 for event in ui_queue[:]:
177 if isinstance(event, logging.LogRecord):
178 logger.handle(event)
179 if msgerrs:
180 logger.removeHandler(stderr)
181 else:
182 logger.removeHandler(stdout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500183
184def fire_ui_handlers(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600185 global _thread_lock
186 global _thread_lock_enabled
187
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500188 if not _uiready:
189 # No UI handlers registered yet, queue up the messages
190 ui_queue.append(event)
191 return
192
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600193 if _thread_lock_enabled:
194 _thread_lock.acquire()
195
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500196 errors = []
197 for h in _ui_handlers:
198 #print "Sending event %s" % event
199 try:
200 if not _ui_logfilters[h].filter(event):
201 continue
202 # We use pickle here since it better handles object instances
203 # which xmlrpc's marshaller does not. Events *must* be serializable
204 # by pickle.
205 if hasattr(_ui_handlers[h].event, "sendpickle"):
206 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
207 else:
208 _ui_handlers[h].event.send(event)
209 except:
210 errors.append(h)
211 for h in errors:
212 del _ui_handlers[h]
213
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600214 if _thread_lock_enabled:
215 _thread_lock.release()
216
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500217def fire(event, d):
218 """Fire off an Event"""
219
220 # We can fire class handlers in the worker process context and this is
221 # desired so they get the task based datastore.
222 # UI handlers need to be fired in the server context so we defer this. They
223 # don't have a datastore so the datastore context isn't a problem.
224
225 fire_class_handlers(event, d)
226 if worker_fire:
227 worker_fire(event, d)
228 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500229 # If messages have been queued up, clear the queue
230 global _uiready, ui_queue
231 if _uiready and ui_queue:
232 for queue_event in ui_queue:
233 fire_ui_handlers(queue_event, d)
234 ui_queue = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500235 fire_ui_handlers(event, d)
236
237def fire_from_worker(event, d):
238 fire_ui_handlers(event, d)
239
240noop = lambda _: None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500241def register(name, handler, mask=None, filename=None, lineno=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500242 """Register an Event handler"""
243
244 # already registered
245 if name in _handlers:
246 return AlreadyRegistered
247
248 if handler is not None:
249 # handle string containing python code
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600250 if isinstance(handler, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500251 tmp = "def %s(e):\n%s" % (name, handler)
252 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500253 code = bb.methodpool.compile_cache(tmp)
254 if not code:
255 if filename is None:
256 filename = "%s(e)" % name
257 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
258 if lineno is not None:
259 ast.increment_lineno(code, lineno-1)
260 code = compile(code, filename, "exec")
261 bb.methodpool.compile_cache_add(tmp, code)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262 except SyntaxError:
263 logger.error("Unable to register event handler '%s':\n%s", name,
264 ''.join(traceback.format_exc(limit=0)))
265 _handlers[name] = noop
266 return
267 env = {}
268 bb.utils.better_exec(code, env)
269 func = bb.utils.better_eval(name, env)
270 _handlers[name] = func
271 else:
272 _handlers[name] = handler
273
274 if not mask or '*' in mask:
275 _catchall_handlers[name] = True
276 else:
277 for m in mask:
278 if _event_handler_map.get(m, None) is None:
279 _event_handler_map[m] = {}
280 _event_handler_map[m][name] = True
281
282 return Registered
283
284def remove(name, handler):
285 """Remove an Event handler"""
286 _handlers.pop(name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500287 if name in _catchall_handlers:
288 _catchall_handlers.pop(name)
289 for event in _event_handler_map.keys():
290 if name in _event_handler_map[event]:
291 _event_handler_map[event].pop(name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500292
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600293def get_handlers():
294 return _handlers
295
296def set_handlers(handlers):
297 global _handlers
298 _handlers = handlers
299
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500300def set_eventfilter(func):
301 global _eventfilter
302 _eventfilter = func
303
304def register_UIHhandler(handler, mainui=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500305 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
306 _ui_handlers[_ui_handler_seq] = handler
307 level, debug_domains = bb.msg.constructLogOptions()
308 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500309 if mainui:
310 global _uiready
311 _uiready = _ui_handler_seq
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500312 return _ui_handler_seq
313
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500314def unregister_UIHhandler(handlerNum, mainui=False):
315 if mainui:
316 global _uiready
317 _uiready = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500318 if handlerNum in _ui_handlers:
319 del _ui_handlers[handlerNum]
320 return
321
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500322def get_uihandler():
323 if _uiready is False:
324 return None
325 return _uiready
326
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500327# Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC
328class UIEventFilter(object):
329 def __init__(self, level, debug_domains):
330 self.update(None, level, debug_domains)
331
332 def update(self, eventmask, level, debug_domains):
333 self.eventmask = eventmask
334 self.stdlevel = level
335 self.debug_domains = debug_domains
336
337 def filter(self, event):
338 if isinstance(event, logging.LogRecord):
339 if event.levelno >= self.stdlevel:
340 return True
341 if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]:
342 return True
343 return False
344 eid = str(event.__class__)[8:-2]
345 if self.eventmask and eid not in self.eventmask:
346 return False
347 return True
348
349def set_UIHmask(handlerNum, level, debug_domains, mask):
350 if not handlerNum in _ui_handlers:
351 return False
352 if '*' in mask:
353 _ui_logfilters[handlerNum].update(None, level, debug_domains)
354 else:
355 _ui_logfilters[handlerNum].update(mask, level, debug_domains)
356 return True
357
358def getName(e):
359 """Returns the name of a class or class instance"""
360 if getattr(e, "__name__", None) == None:
361 return e.__class__.__name__
362 else:
363 return e.__name__
364
365class OperationStarted(Event):
366 """An operation has begun"""
367 def __init__(self, msg = "Operation Started"):
368 Event.__init__(self)
369 self.msg = msg
370
371class OperationCompleted(Event):
372 """An operation has completed"""
373 def __init__(self, total, msg = "Operation Completed"):
374 Event.__init__(self)
375 self.total = total
376 self.msg = msg
377
378class OperationProgress(Event):
379 """An operation is in progress"""
380 def __init__(self, current, total, msg = "Operation in Progress"):
381 Event.__init__(self)
382 self.current = current
383 self.total = total
384 self.msg = msg + ": %s/%s" % (current, total);
385
386class ConfigParsed(Event):
387 """Configuration Parsing Complete"""
388
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500389class MultiConfigParsed(Event):
390 """Multi-Config Parsing Complete"""
391 def __init__(self, mcdata):
392 self.mcdata = mcdata
393 Event.__init__(self)
394
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500395class RecipeEvent(Event):
396 def __init__(self, fn):
397 self.fn = fn
398 Event.__init__(self)
399
400class RecipePreFinalise(RecipeEvent):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800401 """ Recipe Parsing Complete but not yet finalised"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500402
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500403class RecipeTaskPreProcess(RecipeEvent):
404 """
405 Recipe Tasks about to be finalised
406 The list of tasks should be final at this point and handlers
407 are only able to change interdependencies
408 """
409 def __init__(self, fn, tasklist):
410 self.fn = fn
411 self.tasklist = tasklist
412 Event.__init__(self)
413
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500414class RecipeParsed(RecipeEvent):
415 """ Recipe Parsing Complete """
416
417class StampUpdate(Event):
418 """Trigger for any adjustment of the stamp files to happen"""
419
420 def __init__(self, targets, stampfns):
421 self._targets = targets
422 self._stampfns = stampfns
423 Event.__init__(self)
424
425 def getStampPrefix(self):
426 return self._stampfns
427
428 def getTargets(self):
429 return self._targets
430
431 stampPrefix = property(getStampPrefix)
432 targets = property(getTargets)
433
434class BuildBase(Event):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500435 """Base class for bitbake build events"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436
437 def __init__(self, n, p, failures = 0):
438 self._name = n
439 self._pkgs = p
440 Event.__init__(self)
441 self._failures = failures
442
443 def getPkgs(self):
444 return self._pkgs
445
446 def setPkgs(self, pkgs):
447 self._pkgs = pkgs
448
449 def getName(self):
450 return self._name
451
452 def setName(self, name):
453 self._name = name
454
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500455 def getFailures(self):
456 """
457 Return the number of failed packages
458 """
459 return self._failures
460
461 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
462 name = property(getName, setName, None, "name property")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500463
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600464class BuildInit(BuildBase):
465 """buildFile or buildTargets was invoked"""
466 def __init__(self, p=[]):
467 name = None
468 BuildBase.__init__(self, name, p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500469
470class BuildStarted(BuildBase, OperationStarted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500471 """Event when builds start"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500472 def __init__(self, n, p, failures = 0):
473 OperationStarted.__init__(self, "Building Started")
474 BuildBase.__init__(self, n, p, failures)
475
476class BuildCompleted(BuildBase, OperationCompleted):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500477 """Event when builds have completed"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500478 def __init__(self, total, n, p, failures=0, interrupted=0):
479 if not failures:
480 OperationCompleted.__init__(self, total, "Building Succeeded")
481 else:
482 OperationCompleted.__init__(self, total, "Building Failed")
483 self._interrupted = interrupted
484 BuildBase.__init__(self, n, p, failures)
485
486class DiskFull(Event):
487 """Disk full case build aborted"""
488 def __init__(self, dev, type, freespace, mountpoint):
489 Event.__init__(self)
490 self._dev = dev
491 self._type = type
492 self._free = freespace
493 self._mountpoint = mountpoint
494
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500495class DiskUsageSample:
496 def __init__(self, available_bytes, free_bytes, total_bytes):
497 # Number of bytes available to non-root processes.
498 self.available_bytes = available_bytes
499 # Number of bytes available to root processes.
500 self.free_bytes = free_bytes
501 # Total capacity of the volume.
502 self.total_bytes = total_bytes
503
504class MonitorDiskEvent(Event):
505 """If BB_DISKMON_DIRS is set, then this event gets triggered each time disk space is checked.
506 Provides information about devices that are getting monitored."""
507 def __init__(self, disk_usage):
508 Event.__init__(self)
509 # hash of device root path -> DiskUsageSample
510 self.disk_usage = disk_usage
511
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500512class NoProvider(Event):
513 """No Provider for an Event"""
514
515 def __init__(self, item, runtime=False, dependees=None, reasons=None, close_matches=None):
516 Event.__init__(self)
517 self._item = item
518 self._runtime = runtime
519 self._dependees = dependees
520 self._reasons = reasons
521 self._close_matches = close_matches
522
523 def getItem(self):
524 return self._item
525
526 def isRuntime(self):
527 return self._runtime
528
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500529 def __str__(self):
530 msg = ''
531 if self._runtime:
532 r = "R"
533 else:
534 r = ""
535
536 extra = ''
537 if not self._reasons:
538 if self._close_matches:
539 extra = ". Close matches:\n %s" % '\n '.join(self._close_matches)
540
541 if self._dependees:
542 msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s" % (r, self._item, ", ".join(self._dependees), r, extra)
543 else:
544 msg = "Nothing %sPROVIDES '%s'%s" % (r, self._item, extra)
545 if self._reasons:
546 for reason in self._reasons:
547 msg += '\n' + reason
548 return msg
549
550
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500551class MultipleProviders(Event):
552 """Multiple Providers"""
553
554 def __init__(self, item, candidates, runtime = False):
555 Event.__init__(self)
556 self._item = item
557 self._candidates = candidates
558 self._is_runtime = runtime
559
560 def isRuntime(self):
561 """
562 Is this a runtime issue?
563 """
564 return self._is_runtime
565
566 def getItem(self):
567 """
568 The name for the to be build item
569 """
570 return self._item
571
572 def getCandidates(self):
573 """
574 Get the possible Candidates for a PROVIDER.
575 """
576 return self._candidates
577
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500578 def __str__(self):
579 msg = "Multiple providers are available for %s%s (%s)" % (self._is_runtime and "runtime " or "",
580 self._item,
581 ", ".join(self._candidates))
582 rtime = ""
583 if self._is_runtime:
584 rtime = "R"
585 msg += "\nConsider defining a PREFERRED_%sPROVIDER entry to match %s" % (rtime, self._item)
586 return msg
587
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500588class ParseStarted(OperationStarted):
589 """Recipe parsing for the runqueue has begun"""
590 def __init__(self, total):
591 OperationStarted.__init__(self, "Recipe parsing Started")
592 self.total = total
593
594class ParseCompleted(OperationCompleted):
595 """Recipe parsing for the runqueue has completed"""
596 def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
597 OperationCompleted.__init__(self, total, "Recipe parsing Completed")
598 self.cached = cached
599 self.parsed = parsed
600 self.skipped = skipped
601 self.virtuals = virtuals
602 self.masked = masked
603 self.errors = errors
604 self.sofar = cached + parsed
605
606class ParseProgress(OperationProgress):
607 """Recipe parsing progress"""
608 def __init__(self, current, total):
609 OperationProgress.__init__(self, current, total, "Recipe parsing")
610
611
612class CacheLoadStarted(OperationStarted):
613 """Loading of the dependency cache has begun"""
614 def __init__(self, total):
615 OperationStarted.__init__(self, "Loading cache Started")
616 self.total = total
617
618class CacheLoadProgress(OperationProgress):
619 """Cache loading progress"""
620 def __init__(self, current, total):
621 OperationProgress.__init__(self, current, total, "Loading cache")
622
623class CacheLoadCompleted(OperationCompleted):
624 """Cache loading is complete"""
625 def __init__(self, total, num_entries):
626 OperationCompleted.__init__(self, total, "Loading cache Completed")
627 self.num_entries = num_entries
628
629class TreeDataPreparationStarted(OperationStarted):
630 """Tree data preparation started"""
631 def __init__(self):
632 OperationStarted.__init__(self, "Preparing tree data Started")
633
634class TreeDataPreparationProgress(OperationProgress):
635 """Tree data preparation is in progress"""
636 def __init__(self, current, total):
637 OperationProgress.__init__(self, current, total, "Preparing tree data")
638
639class TreeDataPreparationCompleted(OperationCompleted):
640 """Tree data preparation completed"""
641 def __init__(self, total):
642 OperationCompleted.__init__(self, total, "Preparing tree data Completed")
643
644class DepTreeGenerated(Event):
645 """
646 Event when a dependency tree has been generated
647 """
648
649 def __init__(self, depgraph):
650 Event.__init__(self)
651 self._depgraph = depgraph
652
653class TargetsTreeGenerated(Event):
654 """
655 Event when a set of buildable targets has been generated
656 """
657 def __init__(self, model):
658 Event.__init__(self)
659 self._model = model
660
661class ReachableStamps(Event):
662 """
663 An event listing all stamps reachable after parsing
664 which the metadata may use to clean up stale data
665 """
666
667 def __init__(self, stamps):
668 Event.__init__(self)
669 self.stamps = stamps
670
671class FilesMatchingFound(Event):
672 """
673 Event when a list of files matching the supplied pattern has
674 been generated
675 """
676 def __init__(self, pattern, matches):
677 Event.__init__(self)
678 self._pattern = pattern
679 self._matches = matches
680
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500681class ConfigFilesFound(Event):
682 """
683 Event when a list of appropriate config files has been generated
684 """
685 def __init__(self, variable, values):
686 Event.__init__(self)
687 self._variable = variable
688 self._values = values
689
690class ConfigFilePathFound(Event):
691 """
692 Event when a path for a config file has been found
693 """
694 def __init__(self, path):
695 Event.__init__(self)
696 self._path = path
697
698class MsgBase(Event):
699 """Base class for messages"""
700
701 def __init__(self, msg):
702 self._message = msg
703 Event.__init__(self)
704
705class MsgDebug(MsgBase):
706 """Debug Message"""
707
708class MsgNote(MsgBase):
709 """Note Message"""
710
711class MsgWarn(MsgBase):
712 """Warning Message"""
713
714class MsgError(MsgBase):
715 """Error Message"""
716
717class MsgFatal(MsgBase):
718 """Fatal Message"""
719
720class MsgPlain(MsgBase):
721 """General output"""
722
723class LogExecTTY(Event):
724 """Send event containing program to spawn on tty of the logger"""
725 def __init__(self, msg, prog, sleep_delay, retries):
726 Event.__init__(self)
727 self.msg = msg
728 self.prog = prog
729 self.sleep_delay = sleep_delay
730 self.retries = retries
731
732class LogHandler(logging.Handler):
733 """Dispatch logging messages as bitbake events"""
734
735 def emit(self, record):
736 if record.exc_info:
737 etype, value, tb = record.exc_info
738 if hasattr(tb, 'tb_next'):
739 tb = list(bb.exceptions.extract_traceback(tb, context=3))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500740 # Need to turn the value into something the logging system can pickle
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500741 record.bb_exc_info = (etype, value, tb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600742 record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5)
743 value = str(value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500744 record.exc_info = None
745 fire(record, None)
746
747 def filter(self, record):
748 record.taskpid = worker_pid
749 return True
750
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500751class MetadataEvent(Event):
752 """
753 Generic event that target for OE-Core classes
754 to report information during asynchrous execution
755 """
756 def __init__(self, eventtype, eventdata):
757 Event.__init__(self)
758 self.type = eventtype
759 self._localdata = eventdata
760
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600761class ProcessStarted(Event):
762 """
763 Generic process started event (usually part of the initial startup)
764 where further progress events will be delivered
765 """
766 def __init__(self, processname, total):
767 Event.__init__(self)
768 self.processname = processname
769 self.total = total
770
771class ProcessProgress(Event):
772 """
773 Generic process progress event (usually part of the initial startup)
774 """
775 def __init__(self, processname, progress):
776 Event.__init__(self)
777 self.processname = processname
778 self.progress = progress
779
780class ProcessFinished(Event):
781 """
782 Generic process finished event (usually part of the initial startup)
783 """
784 def __init__(self, processname):
785 Event.__init__(self)
786 self.processname = processname
787
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500788class SanityCheck(Event):
789 """
790 Event to run sanity checks, either raise errors or generate events as return status.
791 """
792 def __init__(self, generateevents = True):
793 Event.__init__(self)
794 self.generateevents = generateevents
795
796class SanityCheckPassed(Event):
797 """
798 Event to indicate sanity check has passed
799 """
800
801class SanityCheckFailed(Event):
802 """
803 Event to indicate sanity check has failed
804 """
805 def __init__(self, msg, network_error=False):
806 Event.__init__(self)
807 self._msg = msg
808 self._network_error = network_error
809
810class NetworkTest(Event):
811 """
812 Event to run network connectivity tests, either raise errors or generate events as return status.
813 """
814 def __init__(self, generateevents = True):
815 Event.__init__(self)
816 self.generateevents = generateevents
817
818class NetworkTestPassed(Event):
819 """
820 Event to indicate network test has passed
821 """
822
823class NetworkTestFailed(Event):
824 """
825 Event to indicate network test has failed
826 """
827
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500828class FindSigInfoResult(Event):
829 """
830 Event to return results from findSigInfo command
831 """
832 def __init__(self, result):
833 Event.__init__(self)
834 self.result = result