[kupfer] core: Guard plugin loading and guard plugin intialization better
- From: Ulrik Sverdrup <usverdrup src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [kupfer] core: Guard plugin loading and guard plugin intialization better
- Date: Sat, 6 Feb 2010 17:46:40 +0000 (UTC)
commit 9edf307b8733783c85c73acb05bd870e709737ad
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date: Sat Feb 6 15:04:53 2010 +0100
core: Guard plugin loading and guard plugin intialization better
We guard plugin loading so that plugins that raise exceptions when its
attributes (sources, actions etc) are instantiated are disabled safely
and don't cause Kupfer to stop functioning.
We also guard source initialization and remove content decorators from
the same plugin if we raise an exception.
This solves the current evilplugin testcase, so that this debug plugin
can be installed without breaking kupfer.
kupfer/core/data.py | 14 +++++++++-----
kupfer/core/pluginload.py | 17 +++++++++++++++++
kupfer/core/sources.py | 25 ++++++++++---------------
3 files changed, 36 insertions(+), 20 deletions(-)
---
diff --git a/kupfer/core/data.py b/kupfer/core/data.py
index 105ec0c..63c136b 100644
--- a/kupfer/core/data.py
+++ b/kupfer/core/data.py
@@ -1,3 +1,5 @@
+from __future__ import with_statement
+
import itertools
import operator
import os
@@ -557,11 +559,13 @@ class DataController (gobject.GObject, pretty.OutputMixin):
Load @plugin_id, register all its Actions, Content and TextSources.
Return its sources.
"""
- plugin = pluginload.load_plugin(plugin_id)
- self.register_text_sources(plugin.text_sources)
- self.register_action_decorators(plugin.action_decorators)
- self.register_content_decorators(plugin.content_decorators)
- return set(plugin.sources)
+ with pluginload.exception_guard(plugin_id):
+ plugin = pluginload.load_plugin(plugin_id)
+ self.register_text_sources(plugin.text_sources)
+ self.register_action_decorators(plugin.action_decorators)
+ self.register_content_decorators(plugin.content_decorators)
+ return set(plugin.sources)
+ return set()
def _plugin_enabled(self, setctl, plugin_id, enabled):
from kupfer.core import plugins
diff --git a/kupfer/core/pluginload.py b/kupfer/core/pluginload.py
index 1b4f91e..c914352 100644
--- a/kupfer/core/pluginload.py
+++ b/kupfer/core/pluginload.py
@@ -1,3 +1,7 @@
+import contextlib
+
+from kupfer import pretty
+
from kupfer.core import plugins
from kupfer.core.plugins import (load_plugin_sources, sources_attribute,
action_decorators_attribute, text_sources_attribute,
@@ -44,3 +48,16 @@ def load_plugin(plugin_id):
desc.sources = sources
return desc
+ contextlib contextmanager
+def exception_guard(name, callback=None, *args):
+ "Guard for exceptions, print traceback and call @callback if any is raised"
+ try:
+ yield
+ except Exception:
+ import traceback
+ pretty.print_error(__name__, "Loading %s raised an exception:" % name)
+ traceback.print_exc()
+ pretty.print_error(__name__, "This error is probably a bug in", name)
+ pretty.print_error(__name__, "Please file a bug report")
+ if callback is not None:
+ callback(*args)
diff --git a/kupfer/core/sources.py b/kupfer/core/sources.py
index 0e7163f..a8d4fd2 100644
--- a/kupfer/core/sources.py
+++ b/kupfer/core/sources.py
@@ -11,6 +11,7 @@ import time
from kupfer import config, pretty, scheduler
from kupfer.obj import base, sources
+from kupfer.core import pluginload
class PeriodicRescanner (pretty.OutputMixin):
"""
@@ -433,19 +434,13 @@ class SourceController (pretty.OutputMixin):
continue
sourcepickler.pickle_source(source)
- @contextlib.contextmanager
- def _exception_guard(self, source):
- "Guard for exceptions, ousting @source from catalog if any is raised"
- try:
- yield
- except Exception:
- import traceback
- self.output_error("Loading %s raised an exception:" % source)
- traceback.print_exc()
- self.output_error("This error is probably a bug in %s" % source)
- self.output_error("Please file a bug report")
- self.sources.discard(source)
- self.toplevel_sources.discard(source)
+ def _remove_source(self, source):
+ "Oust @source from catalog if any exception is raised"
+ self.sources.discard(source)
+ self.toplevel_sources.discard(source)
+ source_type = type(source)
+ for typ in self.content_decorators:
+ self.content_decorators[typ].discard(source_type)
def initialize(self):
"Initialize all sources and cache toplevel sources"
@@ -456,14 +451,14 @@ class SourceController (pretty.OutputMixin):
def _initialize_sources(self, sources):
for src in set(sources):
- with self._exception_guard(src):
+ with pluginload.exception_guard(src, self._remove_source, src):
src.initialize()
def _cache_sources(self, sources):
# Make sure that the toplevel sources are chached
# either newly rescanned or the cache is fully loaded
for src in set(sources):
- with self._exception_guard(src):
+ with pluginload.exception_guard(src, self._remove_source, src):
force = (src not in self._restored_sources)
self.rescanner.rescan_now(src, force_update=force)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]