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