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 """
36 L{WtfContext} object, which is commonly used throughout the roswtf
37 APIs to pass state.
38 """
39
40 import os
41 import sys
42
43 import rospkg
44 import rospkg.environment
45
46 import rosgraph
47
48 import roslaunch.depends
49 import roslaunch.substitution_args
50
51 from roswtf.model import WtfWarning
54 """
55 Base exception class of roswtf-related issues.
56 """
57 pass
58
59 -class WtfContext(object):
60 """
61 WtfContext stores common state about the ROS filesystem and online
62 environment. The primary use of this is for convenience (not
63 having to load this state manually) and performance (not having to
64 do the same calculation repeatedly).
65 """
66 __slots__ = ['pkg', 'pkg_dir', 'pkgs',
67 'stack', 'stack_dir', 'stacks',
68 'manifest_file', 'manifest',
69 'env', 'ros_root', 'ros_package_path', 'pythonpath',
70 'ros_master_uri',
71 'roslaunch_uris',
72 'launch_files',
73 'launch_file_deps',
74 'launch_file_missing_deps',
75 'system_state',
76 'service_providers',
77 'topics', 'services',
78 'nodes', 'uri_node_map',
79 'expected_edges',
80 'actual_edges',
81 'unconnected_subscriptions',
82 'use_sim_time',
83 'warnings', 'errors',
84 'rospack', 'rosstack']
85
87
88 self.pkg = None
89 self.pkg_dir = None
90
91 self.stack = None
92 self.stack_dir = None
93
94
95 self.pkgs = []
96
97 self.stacks = []
98
99
100 self.manifest_file = None
101
102 self.manifest = None
103
104
105 self.env = {}
106
107
108 self.ros_root = None
109 self.ros_package_path = None
110 self.pythonpath = None
111
112
113 self.launch_files = None
114 self.launch_file_deps = None
115 self.launch_file_missing_deps = None
116
117
118 self.roslaunch_uris = None
119 self.system_state = None
120 self.topics = None
121 self.services = None
122 self.service_providers = None
123 self.nodes = None
124 self.uri_node_map = {}
125 self.expected_edges = None
126 self.actual_edges = None
127 self.unconnected_subscriptions = None
128 self.use_sim_time = None
129
130
131 self.rospack = self.rosstack = None
132
133
134 self.warnings = []
135
136 self.errors = []
137
138 - def as_dictionary(self):
139 """
140 @return: dictionary representation of context, which is
141 useful for producing error messages
142 @rtype: dict
143 """
144 return dict((s, getattr(self, s)) for s in self.__slots__)
145
146 @staticmethod
147 - def from_roslaunch(roslaunch_files, env=None):
148 """
149 @param roslaunch_file: roslaunch_file to load from
150 @type roslaunch_file: str
151 """
152 if env is None:
153 env = os.environ
154
155
156 l, c = roslaunch.XmlLoader(), roslaunch.ROSLaunchConfig()
157 for f in roslaunch_files:
158 try:
159 l.load(f, c, verbose=False)
160 except roslaunch.RLException as e:
161 raise WtfException("Unable to load roslaunch file [%s]: %s"%(f, str(e)))
162
163 ctx = WtfContext()
164 ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
165 ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
166
167 ctx.launch_files = roslaunch_files
168 _load_roslaunch(ctx, roslaunch_files)
169
170 _load_pkg(ctx, ctx.pkg)
171 if ctx.stack:
172 _load_stack(ctx, ctx.stack)
173 _load_env(ctx, env)
174 return ctx
175
176 @staticmethod
177 - def from_stack(stack, env=None):
178 """
179 Initialize WtfContext from stack.
180 @param stack: stack name
181 @type stack: str
182 @raise WtfException: if context state cannot be initialized
183 """
184 if env is None:
185 env = os.environ
186
187 ctx = WtfContext()
188 ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
189 ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
190
191 _load_stack(ctx, stack)
192 try:
193 ctx.pkgs = ctx.rosstack.packages_of(stack)
194 except rospkg.ResourceNotFound:
195
196 ctx.pkgs = []
197 _load_env(ctx, env)
198 return ctx
199
200 @staticmethod
201 - def from_package(pkg, env=None):
202 """
203 Initialize WtfContext from package name.
204
205 @param pkg: package name
206 @type pkg: str
207 @raise WtfException: if context state cannot be initialized
208 """
209 if env is None:
210 env = os.environ
211
212 ctx = WtfContext()
213 ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
214 ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
215
216 _load_pkg(ctx, pkg)
217 stack = ctx.rospack.stack_of(pkg)
218 if stack:
219 _load_stack(ctx, stack)
220 _load_env(ctx, env)
221 return ctx
222
223 @staticmethod
224 - def from_env(env=None):
225 """
226 Initialize WtfContext from environment.
227
228 @raise WtfException: if context state cannot be initialized
229 """
230 if env is None:
231 env = os.environ
232
233 ctx = WtfContext()
234 ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
235 ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
236
237 _load_env(ctx, env)
238 return ctx
239
241 """
242 Utility for initializing WtfContext state from roslaunch file
243 """
244 try:
245 base_pkg, file_deps, missing = roslaunch.depends.roslaunch_deps(roslaunch_files)
246 ctx.pkg = base_pkg
247 ctx.launch_file_deps = file_deps
248 ctx.launch_file_missing_deps = missing
249 except roslaunch.substitution_args.SubstitutionException as se:
250 raise WtfException("Cannot load roslaunch file(s): "+str(se))
251 except roslaunch.depends.RoslaunchDepsException as e:
252 raise WtfException(str(e))
253
255 """
256 Utility for initializing WtfContext state
257 @raise WtfException: if context state cannot be initialized
258 """
259 r = ctx.rospack
260 ctx.pkg = pkg
261 try:
262 ctx.pkgs = [pkg] + r.get_depends(pkg)
263 except rospkg.ResourceNotFound as e:
264 raise WtfException("Cannot find dependencies for package [%s]: missing %s"%(pkg, e))
265 try:
266 ctx.pkg_dir = r.get_path(pkg)
267 ctx.manifest_file = os.path.join(ctx.pkg_dir, 'manifest.xml')
268 ctx.manifest = r.get_manifest(pkg)
269 except rospkg.ResourceNotFound:
270 raise WtfException("Cannot locate manifest file for package [%s]"%pkg)
271 except rospkg.InvalidManifest as e:
272 raise WtfException("Package [%s] has an invalid manifest: %s"%(pkg, e))
273
275 """
276 Utility for initializing WtfContext state
277 @raise WtfException: if context state cannot be initialized
278 """
279 r = ctx.rosstack
280 ctx.stack = stack
281 try:
282 ctx.stacks = [stack] + r.get_depends(stack, implicit=True)
283 except rospkg.ResourceNotFound as e:
284 raise WtfException("Cannot load dependencies of stack [%s]: %s"%(stack, e))
285 try:
286 ctx.stack_dir = r.get_path(stack)
287 except rospkg.ResourceNotFound:
288 raise WtfException("[%s] appears to be a stack, but it's not on your ROS_PACKAGE_PATH"%stack)
289
305