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
37 """
38 Library for supporting message and service generation for all ROS
39 client libraries. This is mainly responsible for calculating the
40 md5sums and message definitions of classes.
41 """
42
43
44
45
46 import sys
47 import cStringIO
48
49 import roslib.msgs
50 import roslib.names
51 import roslib.packages
52 import roslib.srvs
53
54
55 _header_type_name = 'std_msgs/Header'
56
58 """
59 Add the list of message types that spec depends on to depends.
60 @param spec: message to compute dependencies for
61 @type spec: roslib.msgs.MsgSpec/roslib.srvs.SrvSpec
62 @param deps [str]: list of dependencies. This list will be updated
63 with the dependencies of spec when the method completes
64 @type deps: [str]
65 """
66 for t in spec.types:
67 t = roslib.msgs.base_msg_type(t)
68 if not roslib.msgs.is_builtin(t):
69
70 if t == roslib.msgs.HEADER:
71
72 deps.append(_header_type_name)
73 if roslib.msgs.is_registered(t):
74 depspec = roslib.msgs.get_registered(t)
75 if t != roslib.msgs.HEADER:
76 if '/' in t:
77 deps.append(t)
78 else:
79 deps.append(package_context+'/'+t)
80 else:
81
82 key, depspec = roslib.msgs.load_by_type(t, package_context)
83 if t != roslib.msgs.HEADER:
84 deps.append(key)
85 roslib.msgs.register(key, depspec)
86 _add_msgs_depends(depspec, deps, package_context)
87
88 -def compute_md5_text(get_deps_dict, spec):
89 """
90 Compute the text used for md5 calculation. MD5 spec states that we
91 removes comments and non-meaningful whitespace. We also strip
92 packages names from type names. For convenience sake, constants are
93 reordered ahead of other declarations, in the order that they were
94 originally defined.
95
96 @return: text for ROS MD5-processing
97 @rtype: str
98 """
99 uniquedeps = get_deps_dict['uniquedeps']
100 package = get_deps_dict['package']
101
102 compute_files = 'files' in get_deps_dict
103
104 buff = cStringIO.StringIO()
105
106 for c in spec.constants:
107 buff.write("%s %s=%s\n"%(c.type, c.name, c.val_text))
108 for type_, name in zip(spec.types, spec.names):
109 base_msg_type = roslib.msgs.base_msg_type(type_)
110
111 if roslib.msgs.is_builtin(base_msg_type):
112 buff.write("%s %s\n"%(type_, name))
113 else:
114
115
116
117
118
119 if base_msg_type == roslib.msgs.HEADER:
120 base_msg_type = _header_type_name
121
122 sub_pkg, _ = roslib.names.package_resource_name(base_msg_type)
123 sub_pkg = sub_pkg or package
124 sub_spec = roslib.msgs.get_registered(base_msg_type, package)
125 sub_deps = get_dependencies(sub_spec, sub_pkg, compute_files=compute_files)
126 sub_md5 = compute_md5(sub_deps)
127 buff.write("%s %s\n"%(sub_md5, name))
128
129 return buff.getvalue().strip()
130
132 """
133 subroutine of compute_md5()
134 @param get_deps_dict: dictionary returned by get_dependencies call
135 @type get_deps_dict: dict
136 @param hash: hash instance
137 @type hash: hash instance
138 """
139
140
141 from roslib.msgs import MsgSpec
142 from roslib.srvs import SrvSpec
143 spec = get_deps_dict['spec']
144 if isinstance(spec, MsgSpec):
145 hash.update(compute_md5_text(get_deps_dict, spec))
146 elif isinstance(spec, SrvSpec):
147 hash.update(compute_md5_text(get_deps_dict, spec.request))
148 hash.update(compute_md5_text(get_deps_dict, spec.response))
149 else:
150 raise Exception("[%s] is not a message or service"%spec)
151 return hash.hexdigest()
152
154 """
155 subroutine of compute_md5_v1()
156 @param get_deps_dict: dictionary returned by get_dependencies call
157 @type get_deps_dict: dict
158 @param hash: hash instance
159 @type hash: hash instance
160 """
161 uniquedeps = get_deps_dict['uniquedeps']
162 spec = get_deps_dict['spec']
163
164
165 hash.update(spec.text)
166
167 for d in uniquedeps:
168 hash.update(roslib.msgs.get_registered(d).text)
169 return hash.hexdigest()
170
172 """
173 Compute original V1 md5 hash for message/service. This was replaced with V2 in ROS 0.6.
174 @param get_deps_dict: dictionary returned by get_dependencies call
175 @type get_deps_dict: dict
176 @return: md5 hash
177 @rtype: str
178 """
179 try:
180
181
182 import hashlib
183 return _compute_hash_v1(get_deps_dict, hashlib.md5())
184 except ImportError:
185 import md5
186 return _compute_hash_v1(get_deps_dict, md5.new())
187
189 """
190 Compute md5 hash for message/service
191 @param get_deps_dict dict: dictionary returned by get_dependencies call
192 @type get_deps_dict: dict
193 @return: md5 hash
194 @rtype: str
195 """
196 try:
197
198
199 import hashlib
200 return _compute_hash(get_deps_dict, hashlib.md5())
201 except ImportError:
202 import md5
203 return _compute_hash(get_deps_dict, md5.new())
204
205
206 compute_md5_v2 = compute_md5
207
208 -def compute_full_text(get_deps_dict):
209 """
210 Compute full text of message/service, including text of embedded
211 types. The text of the main msg/srv is listed first. Embedded
212 msg/srv files are denoted first by an 80-character '=' separator,
213 followed by a type declaration line,'MSG: pkg/type', followed by
214 the text of the embedded type.
215
216 @param get_deps_dict dict: dictionary returned by get_dependencies call
217 @type get_deps_dict: dict
218 @return: concatenated text for msg/srv file and embedded msg/srv types.
219 @rtype: str
220 """
221 buff = cStringIO.StringIO()
222 sep = '='*80+'\n'
223
224
225 buff.write(get_deps_dict['spec'].text)
226 buff.write('\n')
227
228 for d in get_deps_dict['uniquedeps']:
229 buff.write(sep)
230 buff.write("MSG: %s\n"%d)
231 buff.write(roslib.msgs.get_registered(d).text)
232 buff.write('\n')
233
234 return buff.getvalue()[:-1]
235
237 """
238 Compute dependencies of the specified message/service file
239 @param f: message or service file to get dependencies for
240 @type f: str
241 @param stdout pipe: stdout pipe
242 @type stdout: file
243 @param stderr pipe: stderr pipe
244 @type stderr: file
245 @return: 'files': list of files that \a file depends on,
246 'deps': list of dependencies by type, 'spec': Msgs/Srvs
247 instance.
248 @rtype: dict
249 """
250 _, package = roslib.packages.get_dir_pkg(f)
251 spec = None
252 if f.endswith(roslib.msgs.EXT):
253 _, spec = roslib.msgs.load_from_file(f)
254 elif f.endswith(roslib.srvs.EXT):
255 _, spec = roslib.srvs.load_from_file(f)
256 else:
257 raise Exception("[%s] does not appear to be a message or service"%spec)
258 return get_dependencies(spec, package, stdout, stderr)
259
260 -def get_dependencies(spec, package, compute_files=True, stdout=sys.stdout, stderr=sys.stderr):
261 """
262 Compute dependencies of the specified Msgs/Srvs
263 @param spec: message or service instance
264 @type spec: L{roslib.msgs.MsgSpec}/L{roslib.srvs.SrvSpec}
265 @param package: package name
266 @type package: str
267 @param stdout: (optional) stdout pipe
268 @type stdout: file
269 @param stderr: (optional) stderr pipe
270 @type stderr: file
271 @param compute_files: (optional, default=True) compute file
272 dependencies of message ('files' key in return value)
273 @type compute_files: bool
274 @return: dict:
275 * 'files': list of files that \a file depends on
276 * 'deps': list of dependencies by type
277 * 'spec': Msgs/Srvs instance.
278 * 'uniquedeps': list of dependencies with duplicates removed,
279 * 'package': package that dependencies were generated relative to.
280 @rtype: dict
281 """
282
283
284
285
286
287
288 roslib.msgs._init()
289
290 deps = []
291 if isinstance(spec, roslib.msgs.MsgSpec):
292 _add_msgs_depends(spec, deps, package)
293 elif isinstance(spec, roslib.srvs.SrvSpec):
294 _add_msgs_depends(spec.request, deps, package)
295 _add_msgs_depends(spec.response, deps, package)
296 else:
297 raise Exception("[%s] does not appear to be a message or service"%spec)
298
299
300
301 if compute_files:
302 files = {}
303 for d in set(deps):
304 d_pkg, t = roslib.names.package_resource_name(d)
305 d_pkg = d_pkg or package
306 files[d] = roslib.msgs.msg_file(d_pkg, t)
307 else:
308 files = None
309
310
311 uniquedeps = []
312 for d in deps:
313 if not d in uniquedeps:
314 uniquedeps.append(d)
315
316 if compute_files:
317 return { 'files': files, 'deps': deps, 'spec': spec, 'package': package, 'uniquedeps': uniquedeps }
318 else:
319 return { 'deps': deps, 'spec': spec, 'package': package, 'uniquedeps': uniquedeps }
320