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