diff options
Diffstat (limited to 'bitbake/lib/bb/event.py')
-rw-r--r-- | bitbake/lib/bb/event.py | 639 |
1 files changed, 639 insertions, 0 deletions
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py new file mode 100644 index 0000000000..6cbd0d55db --- /dev/null +++ b/bitbake/lib/bb/event.py | |||
@@ -0,0 +1,639 @@ | |||
1 | # ex:ts=4:sw=4:sts=4:et | ||
2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
3 | """ | ||
4 | BitBake 'Event' implementation | ||
5 | |||
6 | Classes and functions for manipulating 'events' in the | ||
7 | BitBake 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 | |||
25 | import os, sys | ||
26 | import warnings | ||
27 | try: | ||
28 | import cPickle as pickle | ||
29 | except ImportError: | ||
30 | import pickle | ||
31 | import logging | ||
32 | import atexit | ||
33 | import traceback | ||
34 | import bb.utils | ||
35 | import bb.compat | ||
36 | import bb.exceptions | ||
37 | |||
38 | # This is the pid for which we should generate the event. This is set when | ||
39 | # the runqueue forks off. | ||
40 | worker_pid = 0 | ||
41 | worker_fire = None | ||
42 | |||
43 | logger = logging.getLogger('BitBake.Event') | ||
44 | |||
45 | class Event(object): | ||
46 | """Base class for events""" | ||
47 | |||
48 | def __init__(self): | ||
49 | self.pid = worker_pid | ||
50 | |||
51 | Registered = 10 | ||
52 | AlreadyRegistered = 14 | ||
53 | |||
54 | def get_class_handlers(): | ||
55 | return _handlers | ||
56 | |||
57 | def set_class_handlers(h): | ||
58 | global _handlers | ||
59 | _handlers = h | ||
60 | |||
61 | def clean_class_handlers(): | ||
62 | return bb.compat.OrderedDict() | ||
63 | |||
64 | # Internal | ||
65 | _handlers = clean_class_handlers() | ||
66 | _ui_handlers = {} | ||
67 | _ui_logfilters = {} | ||
68 | _ui_handler_seq = 0 | ||
69 | _event_handler_map = {} | ||
70 | _catchall_handlers = {} | ||
71 | |||
72 | def execute_handler(name, handler, event, d): | ||
73 | event.data = d | ||
74 | try: | ||
75 | ret = handler(event) | ||
76 | except (bb.parse.SkipRecipe, bb.BBHandledException): | ||
77 | raise | ||
78 | except Exception: | ||
79 | etype, value, tb = sys.exc_info() | ||
80 | logger.error("Execution of event handler '%s' failed" % name, | ||
81 | exc_info=(etype, value, tb.tb_next)) | ||
82 | raise | ||
83 | except SystemExit as exc: | ||
84 | if exc.code != 0: | ||
85 | logger.error("Execution of event handler '%s' failed" % name) | ||
86 | raise | ||
87 | finally: | ||
88 | del event.data | ||
89 | |||
90 | def fire_class_handlers(event, d): | ||
91 | if isinstance(event, logging.LogRecord): | ||
92 | return | ||
93 | |||
94 | eid = str(event.__class__)[8:-2] | ||
95 | evt_hmap = _event_handler_map.get(eid, {}) | ||
96 | for name, handler in _handlers.iteritems(): | ||
97 | if name in _catchall_handlers or name in evt_hmap: | ||
98 | execute_handler(name, handler, event, d) | ||
99 | |||
100 | ui_queue = [] | ||
101 | @atexit.register | ||
102 | def print_ui_queue(): | ||
103 | """If we're exiting before a UI has been spawned, display any queued | ||
104 | LogRecords to the console.""" | ||
105 | logger = logging.getLogger("BitBake") | ||
106 | if not _ui_handlers: | ||
107 | from bb.msg import BBLogFormatter | ||
108 | console = logging.StreamHandler(sys.stdout) | ||
109 | console.setFormatter(BBLogFormatter("%(levelname)s: %(message)s")) | ||
110 | logger.handlers = [console] | ||
111 | |||
112 | # First check to see if we have any proper messages | ||
113 | msgprint = False | ||
114 | for event in ui_queue: | ||
115 | if isinstance(event, logging.LogRecord): | ||
116 | if event.levelno > logging.DEBUG: | ||
117 | logger.handle(event) | ||
118 | msgprint = True | ||
119 | if msgprint: | ||
120 | return | ||
121 | |||
122 | # Nope, so just print all of the messages we have (including debug messages) | ||
123 | for event in ui_queue: | ||
124 | if isinstance(event, logging.LogRecord): | ||
125 | logger.handle(event) | ||
126 | |||
127 | def fire_ui_handlers(event, d): | ||
128 | if not _ui_handlers: | ||
129 | # No UI handlers registered yet, queue up the messages | ||
130 | ui_queue.append(event) | ||
131 | return | ||
132 | |||
133 | errors = [] | ||
134 | for h in _ui_handlers: | ||
135 | #print "Sending event %s" % event | ||
136 | try: | ||
137 | if not _ui_logfilters[h].filter(event): | ||
138 | continue | ||
139 | # We use pickle here since it better handles object instances | ||
140 | # which xmlrpc's marshaller does not. Events *must* be serializable | ||
141 | # by pickle. | ||
142 | if hasattr(_ui_handlers[h].event, "sendpickle"): | ||
143 | _ui_handlers[h].event.sendpickle((pickle.dumps(event))) | ||
144 | else: | ||
145 | _ui_handlers[h].event.send(event) | ||
146 | except: | ||
147 | errors.append(h) | ||
148 | for h in errors: | ||
149 | del _ui_handlers[h] | ||
150 | |||
151 | def fire(event, d): | ||
152 | """Fire off an Event""" | ||
153 | |||
154 | # We can fire class handlers in the worker process context and this is | ||
155 | # desired so they get the task based datastore. | ||
156 | # UI handlers need to be fired in the server context so we defer this. They | ||
157 | # don't have a datastore so the datastore context isn't a problem. | ||
158 | |||
159 | fire_class_handlers(event, d) | ||
160 | if worker_fire: | ||
161 | worker_fire(event, d) | ||
162 | else: | ||
163 | fire_ui_handlers(event, d) | ||
164 | |||
165 | def fire_from_worker(event, d): | ||
166 | fire_ui_handlers(event, d) | ||
167 | |||
168 | noop = lambda _: None | ||
169 | def register(name, handler, mask=[]): | ||
170 | """Register an Event handler""" | ||
171 | |||
172 | # already registered | ||
173 | if name in _handlers: | ||
174 | return AlreadyRegistered | ||
175 | |||
176 | if handler is not None: | ||
177 | # handle string containing python code | ||
178 | if isinstance(handler, basestring): | ||
179 | tmp = "def %s(e):\n%s" % (name, handler) | ||
180 | try: | ||
181 | code = compile(tmp, "%s(e)" % name, "exec") | ||
182 | except SyntaxError: | ||
183 | logger.error("Unable to register event handler '%s':\n%s", name, | ||
184 | ''.join(traceback.format_exc(limit=0))) | ||
185 | _handlers[name] = noop | ||
186 | return | ||
187 | env = {} | ||
188 | bb.utils.better_exec(code, env) | ||
189 | func = bb.utils.better_eval(name, env) | ||
190 | _handlers[name] = func | ||
191 | else: | ||
192 | _handlers[name] = handler | ||
193 | |||
194 | if not mask or '*' in mask: | ||
195 | _catchall_handlers[name] = True | ||
196 | else: | ||
197 | for m in mask: | ||
198 | if _event_handler_map.get(m, None) is None: | ||
199 | _event_handler_map[m] = {} | ||
200 | _event_handler_map[m][name] = True | ||
201 | |||
202 | return Registered | ||
203 | |||
204 | def remove(name, handler): | ||
205 | """Remove an Event handler""" | ||
206 | _handlers.pop(name) | ||
207 | |||
208 | def register_UIHhandler(handler): | ||
209 | bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 | ||
210 | _ui_handlers[_ui_handler_seq] = handler | ||
211 | level, debug_domains = bb.msg.constructLogOptions() | ||
212 | _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains) | ||
213 | return _ui_handler_seq | ||
214 | |||
215 | def unregister_UIHhandler(handlerNum): | ||
216 | if handlerNum in _ui_handlers: | ||
217 | del _ui_handlers[handlerNum] | ||
218 | return | ||
219 | |||
220 | # Class to allow filtering of events and specific filtering of LogRecords *before* we put them over the IPC | ||
221 | class UIEventFilter(object): | ||
222 | def __init__(self, level, debug_domains): | ||
223 | self.update(None, level, debug_domains) | ||
224 | |||
225 | def update(self, eventmask, level, debug_domains): | ||
226 | self.eventmask = eventmask | ||
227 | self.stdlevel = level | ||
228 | self.debug_domains = debug_domains | ||
229 | |||
230 | def filter(self, event): | ||
231 | if isinstance(event, logging.LogRecord): | ||
232 | if event.levelno >= self.stdlevel: | ||
233 | return True | ||
234 | if event.name in self.debug_domains and event.levelno >= self.debug_domains[event.name]: | ||
235 | return True | ||
236 | return False | ||
237 | eid = str(event.__class__)[8:-2] | ||
238 | if self.eventmask and eid not in self.eventmask: | ||
239 | return False | ||
240 | return True | ||
241 | |||
242 | def set_UIHmask(handlerNum, level, debug_domains, mask): | ||
243 | if not handlerNum in _ui_handlers: | ||
244 | return False | ||
245 | if '*' in mask: | ||
246 | _ui_logfilters[handlerNum].update(None, level, debug_domains) | ||
247 | else: | ||
248 | _ui_logfilters[handlerNum].update(mask, level, debug_domains) | ||
249 | return True | ||
250 | |||
251 | def getName(e): | ||
252 | """Returns the name of a class or class instance""" | ||
253 | if getattr(e, "__name__", None) == None: | ||
254 | return e.__class__.__name__ | ||
255 | else: | ||
256 | return e.__name__ | ||
257 | |||
258 | class OperationStarted(Event): | ||
259 | """An operation has begun""" | ||
260 | def __init__(self, msg = "Operation Started"): | ||
261 | Event.__init__(self) | ||
262 | self.msg = msg | ||
263 | |||
264 | class OperationCompleted(Event): | ||
265 | """An operation has completed""" | ||
266 | def __init__(self, total, msg = "Operation Completed"): | ||
267 | Event.__init__(self) | ||
268 | self.total = total | ||
269 | self.msg = msg | ||
270 | |||
271 | class OperationProgress(Event): | ||
272 | """An operation is in progress""" | ||
273 | def __init__(self, current, total, msg = "Operation in Progress"): | ||
274 | Event.__init__(self) | ||
275 | self.current = current | ||
276 | self.total = total | ||
277 | self.msg = msg + ": %s/%s" % (current, total); | ||
278 | |||
279 | class ConfigParsed(Event): | ||
280 | """Configuration Parsing Complete""" | ||
281 | |||
282 | class RecipeEvent(Event): | ||
283 | def __init__(self, fn): | ||
284 | self.fn = fn | ||
285 | Event.__init__(self) | ||
286 | |||
287 | class RecipePreFinalise(RecipeEvent): | ||
288 | """ Recipe Parsing Complete but not yet finialised""" | ||
289 | |||
290 | class RecipeParsed(RecipeEvent): | ||
291 | """ Recipe Parsing Complete """ | ||
292 | |||
293 | class StampUpdate(Event): | ||
294 | """Trigger for any adjustment of the stamp files to happen""" | ||
295 | |||
296 | def __init__(self, targets, stampfns): | ||
297 | self._targets = targets | ||
298 | self._stampfns = stampfns | ||
299 | Event.__init__(self) | ||
300 | |||
301 | def getStampPrefix(self): | ||
302 | return self._stampfns | ||
303 | |||
304 | def getTargets(self): | ||
305 | return self._targets | ||
306 | |||
307 | stampPrefix = property(getStampPrefix) | ||
308 | targets = property(getTargets) | ||
309 | |||
310 | class BuildBase(Event): | ||
311 | """Base class for bbmake run events""" | ||
312 | |||
313 | def __init__(self, n, p, failures = 0): | ||
314 | self._name = n | ||
315 | self._pkgs = p | ||
316 | Event.__init__(self) | ||
317 | self._failures = failures | ||
318 | |||
319 | def getPkgs(self): | ||
320 | return self._pkgs | ||
321 | |||
322 | def setPkgs(self, pkgs): | ||
323 | self._pkgs = pkgs | ||
324 | |||
325 | def getName(self): | ||
326 | return self._name | ||
327 | |||
328 | def setName(self, name): | ||
329 | self._name = name | ||
330 | |||
331 | def getCfg(self): | ||
332 | return self.data | ||
333 | |||
334 | def setCfg(self, cfg): | ||
335 | self.data = cfg | ||
336 | |||
337 | def getFailures(self): | ||
338 | """ | ||
339 | Return the number of failed packages | ||
340 | """ | ||
341 | return self._failures | ||
342 | |||
343 | pkgs = property(getPkgs, setPkgs, None, "pkgs property") | ||
344 | name = property(getName, setName, None, "name property") | ||
345 | cfg = property(getCfg, setCfg, None, "cfg property") | ||
346 | |||
347 | |||
348 | |||
349 | |||
350 | |||
351 | class BuildStarted(BuildBase, OperationStarted): | ||
352 | """bbmake build run started""" | ||
353 | def __init__(self, n, p, failures = 0): | ||
354 | OperationStarted.__init__(self, "Building Started") | ||
355 | BuildBase.__init__(self, n, p, failures) | ||
356 | |||
357 | class BuildCompleted(BuildBase, OperationCompleted): | ||
358 | """bbmake build run completed""" | ||
359 | def __init__(self, total, n, p, failures = 0): | ||
360 | if not failures: | ||
361 | OperationCompleted.__init__(self, total, "Building Succeeded") | ||
362 | else: | ||
363 | OperationCompleted.__init__(self, total, "Building Failed") | ||
364 | BuildBase.__init__(self, n, p, failures) | ||
365 | |||
366 | class DiskFull(Event): | ||
367 | """Disk full case build aborted""" | ||
368 | def __init__(self, dev, type, freespace, mountpoint): | ||
369 | Event.__init__(self) | ||
370 | self._dev = dev | ||
371 | self._type = type | ||
372 | self._free = freespace | ||
373 | self._mountpoint = mountpoint | ||
374 | |||
375 | class NoProvider(Event): | ||
376 | """No Provider for an Event""" | ||
377 | |||
378 | def __init__(self, item, runtime=False, dependees=None, reasons=[], close_matches=[]): | ||
379 | Event.__init__(self) | ||
380 | self._item = item | ||
381 | self._runtime = runtime | ||
382 | self._dependees = dependees | ||
383 | self._reasons = reasons | ||
384 | self._close_matches = close_matches | ||
385 | |||
386 | def getItem(self): | ||
387 | return self._item | ||
388 | |||
389 | def isRuntime(self): | ||
390 | return self._runtime | ||
391 | |||
392 | class MultipleProviders(Event): | ||
393 | """Multiple Providers""" | ||
394 | |||
395 | def __init__(self, item, candidates, runtime = False): | ||
396 | Event.__init__(self) | ||
397 | self._item = item | ||
398 | self._candidates = candidates | ||
399 | self._is_runtime = runtime | ||
400 | |||
401 | def isRuntime(self): | ||
402 | """ | ||
403 | Is this a runtime issue? | ||
404 | """ | ||
405 | return self._is_runtime | ||
406 | |||
407 | def getItem(self): | ||
408 | """ | ||
409 | The name for the to be build item | ||
410 | """ | ||
411 | return self._item | ||
412 | |||
413 | def getCandidates(self): | ||
414 | """ | ||
415 | Get the possible Candidates for a PROVIDER. | ||
416 | """ | ||
417 | return self._candidates | ||
418 | |||
419 | class ParseStarted(OperationStarted): | ||
420 | """Recipe parsing for the runqueue has begun""" | ||
421 | def __init__(self, total): | ||
422 | OperationStarted.__init__(self, "Recipe parsing Started") | ||
423 | self.total = total | ||
424 | |||
425 | class ParseCompleted(OperationCompleted): | ||
426 | """Recipe parsing for the runqueue has completed""" | ||
427 | def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total): | ||
428 | OperationCompleted.__init__(self, total, "Recipe parsing Completed") | ||
429 | self.cached = cached | ||
430 | self.parsed = parsed | ||
431 | self.skipped = skipped | ||
432 | self.virtuals = virtuals | ||
433 | self.masked = masked | ||
434 | self.errors = errors | ||
435 | self.sofar = cached + parsed | ||
436 | |||
437 | class ParseProgress(OperationProgress): | ||
438 | """Recipe parsing progress""" | ||
439 | def __init__(self, current, total): | ||
440 | OperationProgress.__init__(self, current, total, "Recipe parsing") | ||
441 | |||
442 | |||
443 | class CacheLoadStarted(OperationStarted): | ||
444 | """Loading of the dependency cache has begun""" | ||
445 | def __init__(self, total): | ||
446 | OperationStarted.__init__(self, "Loading cache Started") | ||
447 | self.total = total | ||
448 | |||
449 | class CacheLoadProgress(OperationProgress): | ||
450 | """Cache loading progress""" | ||
451 | def __init__(self, current, total): | ||
452 | OperationProgress.__init__(self, current, total, "Loading cache") | ||
453 | |||
454 | class CacheLoadCompleted(OperationCompleted): | ||
455 | """Cache loading is complete""" | ||
456 | def __init__(self, total, num_entries): | ||
457 | OperationCompleted.__init__(self, total, "Loading cache Completed") | ||
458 | self.num_entries = num_entries | ||
459 | |||
460 | class TreeDataPreparationStarted(OperationStarted): | ||
461 | """Tree data preparation started""" | ||
462 | def __init__(self): | ||
463 | OperationStarted.__init__(self, "Preparing tree data Started") | ||
464 | |||
465 | class TreeDataPreparationProgress(OperationProgress): | ||
466 | """Tree data preparation is in progress""" | ||
467 | def __init__(self, current, total): | ||
468 | OperationProgress.__init__(self, current, total, "Preparing tree data") | ||
469 | |||
470 | class TreeDataPreparationCompleted(OperationCompleted): | ||
471 | """Tree data preparation completed""" | ||
472 | def __init__(self, total): | ||
473 | OperationCompleted.__init__(self, total, "Preparing tree data Completed") | ||
474 | |||
475 | class DepTreeGenerated(Event): | ||
476 | """ | ||
477 | Event when a dependency tree has been generated | ||
478 | """ | ||
479 | |||
480 | def __init__(self, depgraph): | ||
481 | Event.__init__(self) | ||
482 | self._depgraph = depgraph | ||
483 | |||
484 | class TargetsTreeGenerated(Event): | ||
485 | """ | ||
486 | Event when a set of buildable targets has been generated | ||
487 | """ | ||
488 | def __init__(self, model): | ||
489 | Event.__init__(self) | ||
490 | self._model = model | ||
491 | |||
492 | class FilesMatchingFound(Event): | ||
493 | """ | ||
494 | Event when a list of files matching the supplied pattern has | ||
495 | been generated | ||
496 | """ | ||
497 | def __init__(self, pattern, matches): | ||
498 | Event.__init__(self) | ||
499 | self._pattern = pattern | ||
500 | self._matches = matches | ||
501 | |||
502 | class CoreBaseFilesFound(Event): | ||
503 | """ | ||
504 | Event when a list of appropriate config files has been generated | ||
505 | """ | ||
506 | def __init__(self, paths): | ||
507 | Event.__init__(self) | ||
508 | self._paths = paths | ||
509 | |||
510 | class ConfigFilesFound(Event): | ||
511 | """ | ||
512 | Event when a list of appropriate config files has been generated | ||
513 | """ | ||
514 | def __init__(self, variable, values): | ||
515 | Event.__init__(self) | ||
516 | self._variable = variable | ||
517 | self._values = values | ||
518 | |||
519 | class ConfigFilePathFound(Event): | ||
520 | """ | ||
521 | Event when a path for a config file has been found | ||
522 | """ | ||
523 | def __init__(self, path): | ||
524 | Event.__init__(self) | ||
525 | self._path = path | ||
526 | |||
527 | class MsgBase(Event): | ||
528 | """Base class for messages""" | ||
529 | |||
530 | def __init__(self, msg): | ||
531 | self._message = msg | ||
532 | Event.__init__(self) | ||
533 | |||
534 | class MsgDebug(MsgBase): | ||
535 | """Debug Message""" | ||
536 | |||
537 | class MsgNote(MsgBase): | ||
538 | """Note Message""" | ||
539 | |||
540 | class MsgWarn(MsgBase): | ||
541 | """Warning Message""" | ||
542 | |||
543 | class MsgError(MsgBase): | ||
544 | """Error Message""" | ||
545 | |||
546 | class MsgFatal(MsgBase): | ||
547 | """Fatal Message""" | ||
548 | |||
549 | class MsgPlain(MsgBase): | ||
550 | """General output""" | ||
551 | |||
552 | class LogExecTTY(Event): | ||
553 | """Send event containing program to spawn on tty of the logger""" | ||
554 | def __init__(self, msg, prog, sleep_delay, retries): | ||
555 | Event.__init__(self) | ||
556 | self.msg = msg | ||
557 | self.prog = prog | ||
558 | self.sleep_delay = sleep_delay | ||
559 | self.retries = retries | ||
560 | |||
561 | class LogHandler(logging.Handler): | ||
562 | """Dispatch logging messages as bitbake events""" | ||
563 | |||
564 | def emit(self, record): | ||
565 | if record.exc_info: | ||
566 | etype, value, tb = record.exc_info | ||
567 | if hasattr(tb, 'tb_next'): | ||
568 | tb = list(bb.exceptions.extract_traceback(tb, context=3)) | ||
569 | record.bb_exc_info = (etype, value, tb) | ||
570 | record.exc_info = None | ||
571 | fire(record, None) | ||
572 | |||
573 | def filter(self, record): | ||
574 | record.taskpid = worker_pid | ||
575 | return True | ||
576 | |||
577 | class RequestPackageInfo(Event): | ||
578 | """ | ||
579 | Event to request package information | ||
580 | """ | ||
581 | |||
582 | class PackageInfo(Event): | ||
583 | """ | ||
584 | Package information for GUI | ||
585 | """ | ||
586 | def __init__(self, pkginfolist): | ||
587 | Event.__init__(self) | ||
588 | self._pkginfolist = pkginfolist | ||
589 | |||
590 | class MetadataEvent(Event): | ||
591 | """ | ||
592 | Generic event that target for OE-Core classes | ||
593 | to report information during asynchrous execution | ||
594 | """ | ||
595 | def __init__(self, eventtype, eventdata): | ||
596 | Event.__init__(self) | ||
597 | self.type = eventtype | ||
598 | self._localdata = eventdata | ||
599 | |||
600 | class SanityCheck(Event): | ||
601 | """ | ||
602 | Event to run sanity checks, either raise errors or generate events as return status. | ||
603 | """ | ||
604 | def __init__(self, generateevents = True): | ||
605 | Event.__init__(self) | ||
606 | self.generateevents = generateevents | ||
607 | |||
608 | class SanityCheckPassed(Event): | ||
609 | """ | ||
610 | Event to indicate sanity check has passed | ||
611 | """ | ||
612 | |||
613 | class SanityCheckFailed(Event): | ||
614 | """ | ||
615 | Event to indicate sanity check has failed | ||
616 | """ | ||
617 | def __init__(self, msg, network_error=False): | ||
618 | Event.__init__(self) | ||
619 | self._msg = msg | ||
620 | self._network_error = network_error | ||
621 | |||
622 | class NetworkTest(Event): | ||
623 | """ | ||
624 | Event to run network connectivity tests, either raise errors or generate events as return status. | ||
625 | """ | ||
626 | def __init__(self, generateevents = True): | ||
627 | Event.__init__(self) | ||
628 | self.generateevents = generateevents | ||
629 | |||
630 | class NetworkTestPassed(Event): | ||
631 | """ | ||
632 | Event to indicate network test has passed | ||
633 | """ | ||
634 | |||
635 | class NetworkTestFailed(Event): | ||
636 | """ | ||
637 | Event to indicate network test has failed | ||
638 | """ | ||
639 | |||