1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 import roslib
36 import roslib.packages
37 from rosh.impl.exceptions import ROSHException, InvalidPlugin, NoPlugin
38
39
40 -class PluginContext(object):
41
42 - def __init__(self, rosh_globals, rosh_context, rosh_lock):
43
44 self.rosh_globals = rosh_globals
45
46 self.ctx = rosh_context
47
48 self.rosh_lock = rosh_lock
49
50 self._apis = {}
51
52 - def _register_api(self, plugin_api_id, callback):
53 self._apis[plugin_api_id] = callback
54
55 - def _register_handler(self, plugin_api_id, args):
56 callback = self._apis[plugin_api_id]
57 callback(*args)
58
60
62 self.apis = {}
63 self.handlers = {}
64
66 """
67 @param plugin_api_id: identifier for API to register with
68 @type plugin_api_id: str
69 @param args: arguments for plugin API
70 @type args: [any]
71 """
72 if plugin_api_id not in self.handlers:
73 self.handlers[plugin_api_id] = []
74 self.handlers[plugin_api_id].append(args)
75
76 - def add_api(self, plugin_api_id, callback):
77 """
78 Register plugin API that downstream plugins can add handlers for.
79
80 @param plugin_api_id: identifier for this API
81 @type plugin_api_id: str
82 @param callback: callback function to invoke when handlers register with this API
83 @type callback: fn
84 """
85 self.apis[plugin_api_id] = callback
86
88 """
89 Utility routine to allow plugins that have already loaded to
90 initialize a new globals_ dictionary.
91 """
92 if loaded_symbols is not None:
93 if globals_ is not None:
94 globals_.update(loaded_symbols)
95 return True
96 else:
97 return False
98
100 """
101 Utility routine for plugins to load their symbols into the
102 appropriate global symbol tables
103 """
104 for g in [plugin_context.rosh_globals, globals_]:
105 if g is not None:
106 g.update(symbols)
107
109 """
110 Load ROSH plugin from another ROS package.
111
112 load_plugin() loads the plugin into the rosh global symbol
113 table. If globals_ is specified, plugin symbols will also be
114 loaded into the provided dictionary.
115
116 @param globals_: global symbol table to additionally load plugin to.
117 @type globals_: dict
118 @raise NoPlugin: if plugin does not exist
119 @raise InvalidPlugin: if plugin fails to load properly
120 """
121
122
123
124
125
126
127 if name == 'rosh.impl.testing':
128 import rosh.impl.testing
129 rosh.impl.testing.load_rosh_plugin('rosh.impl.ros_testing', plugin_context, globals_)
130 return
131
132 try:
133
134 roslib.packages.get_pkg_dir(name)
135 except roslib.packages.InvalidROSPkgException, e:
136 raise NoPlugin("invalid plugin [%s]: no ROS package named [%s]"%(name, name))
137 try:
138 roslib.load_manifest(name)
139 except roslib.packages.InvalidROSPkgException, e:
140 raise InvalidPlugin("Failed to locate dependencies of plugin [%s]: \n[%s]"%(name, str(e)))
141 try:
142 m = __import__(name)
143 except ImportError:
144 raise InvalidPlugin("invalid plugin [%s]: python module [%s] import failed"%(name, name))
145 try:
146 loader = getattr(m, 'rosh_plugin_load')
147 except AttributeError, e:
148 raise InvalidPlugin("invalid plugin [%s]: plugin is missing rosh_plugin_load() entry point"%(name))
149
150 try:
151 plugin_data = loader(plugin_context, globals_)
152 except Exception, e:
153 raise InvalidPlugin("invalid plugin [%s]: plugin raised Exception on load: %s"%(name, e))
154 errors = []
155 if plugin_data is not None:
156
157
158
159
160
161
162
163
164 for plugin_api_id, callback in plugin_data.apis.iteritems():
165 try:
166 plugin_context._register_api(plugin_api_id, callback)
167 except Exception, e:
168 errors.append(e)
169
170 for plugin_api_id, args in plugin_data.handlers.iteritems():
171 try:
172 plugin_context._register_handler(plugin_api_id, args)
173 except Exception, e:
174 errors.append(e)
175
176 if errors:
177 error_str = [str(e) for e in errors]
178 raise ROSHException("errors loading plugin [%s]: \n%s"%(name, '\n'.join(error_str)))
179