generate.py
Go to the documentation of this file.
1 #
2 # Copyright 2016 Rethink Robotics
3 #
4 # Copyright 2016 Chris Smith
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 from __future__ import print_function
18 
19 import sys
20 import os
21 import traceback
22 import re
23 from os.path import join as pjoin
24 
25 #import roslib.msgs
26 #import roslib.srvs
27 #import roslib.packages
28 #import roslib.gentools
29 from genmsg import SrvSpec, MsgSpec, MsgContext
30 from genmsg.msg_loader import load_srv_from_file, load_msg_by_type
31 import genmsg.gentools
32 from copy import deepcopy
33 
34 try:
35  from cStringIO import StringIO #Python 2.x
36 except ImportError:
37  from io import StringIO #Python 3.x
38 
39 ############################################################
40 # Built in types
41 ############################################################
42 
43 def is_fixnum(t):
44  return t in ['int8', 'uint8', 'int16', 'uint16']
45 
46 def is_integer(t):
47  return is_fixnum(t) or t in ['byte', 'char', 'int32', 'uint32', 'int64', 'uint64'] #t2 byte, char can be fixnum
48 
50  return t in ['int8', 'int16', 'int32', 'int64']
51 
53  return t in ['uint8', 'uint16', 'uint32', 'uint64']
54 
55 def is_bool(t):
56  return t == 'bool'
57 
58 def is_string(t):
59  return t == 'string'
60 
61 def is_float(t):
62  return t in ['float32', 'float64']
63 
64 def is_time(t):
65  return t in ['time', 'duration']
66 
68  if f.base_type == 'Header':
69  return ('std_msgs', 'Header')
70  else:
71  return f.base_type.split('/')
72 
74  if t in ['int8', 'byte', 'bool']:
75  return 'Int8Array'
76  elif t in ['uint8', 'char']:
77  return 'UInt8Array'
78  elif t == 'uint16':
79  return 'UInt16Array'
80  elif t == 'int16':
81  return 'Int16Array'
82  elif t == 'uint32':
83  return 'UInt32Array'
84  elif t == 'int32':
85  return 'Int32Array'
86  elif t == 'float32':
87  return 'Float32Array'
88  elif t == 'float64':
89  return 'Float64Array'
90  # else
91  return None
92 
93 
95  return is_fixnum(t) or is_float(t) or t in ['byte', 'char', 'bool', 'uint8', 'uint16','int8', 'int16', 'uint32', 'int32']
96 
98  """Returns the size in bytes of a builtin type if available. Else None"""
99  if t in ['int8', 'uint8', 'byte', 'bool', 'char']:
100  return 1
101  elif t in ['int16', 'uint16']:
102  return 2
103  elif t in ['int32', 'uint32', 'float32']:
104  return 4
105  elif t in ['int64', 'uint64', 'float64', 'time', 'duration']:
106  return 8
107  return None
108 
109 def get_default_value(field, current_message_package):
110  """Return the default value for a message data field"""
111  if field.is_array:
112  if not field.array_len:
113  return '[]'
114  else:
115  field_copy = deepcopy(field)
116  field_copy.is_array = False;
117  field_default = get_default_value(field_copy, current_message_package)
118  return 'new Array({}).fill({})'.format(field.array_len, field_default)
119  elif field.is_builtin:
120  if is_string(field.type):
121  return '\'\''
122  elif is_time(field.type):
123  return '{secs: 0, nsecs: 0}'
124  elif is_bool(field.type):
125  return 'false'
126  elif is_float(field.type):
127  return '0.0'
128  else:
129  return '0';
130  # else
131  (package, msg_type) = field.base_type.split('/')
132  if package == current_message_package:
133  return 'new {}()'.format(msg_type)
134  else:
135  return 'new {}.msg.{}()'.format(package, msg_type)
136 
137 def is_message_fixed_size(spec, search_path):
138  """Check if a particular message specification has a constant size in bytes"""
139  parsed_fields = spec.parsed_fields()
140  types = [f.base_type for f in parsed_fields]
141  variableLengthArrays = [f.is_array and not f.array_len for f in parsed_fields]
142  isBuiltin = [f.is_builtin for f in parsed_fields]
143  if 'string' in types:
144  return False
145  elif True in variableLengthArrays:
146  return False
147  elif False not in isBuiltin:
148  return True
149  else:
150  nonBuiltins = [f for f in parsed_fields if not f.is_builtin]
151  # print(nonBuiltins)
152  for idx, f in enumerate(nonBuiltins):
153  field_msg_context = MsgContext.create_default()
154  field_spec = genmsg.msg_loader.load_msg_by_type(field_msg_context, f.base_type, search_path)
155  if not is_message_fixed_size(field_spec, search_path):
156  return False
157  return True
158 
159 def get_message_fixed_size(spec, search_path):
160  """
161  Return the size of a message.
162  If the message does not have a fixed size, returns None
163  """
164  if not is_message_fixed_size(spec, search_path):
165  return None
166  # else
167  length = 0
168  for f in spec.parsed_fields():
169  if f.is_builtin:
170  type_size = get_type_size(f.base_type)
171  if type_size is None:
172  raise Exception('Field {} has a non-constant size'.format(f.base_type))
173  if not f.is_array:
174  length += type_size
175  elif not f.array_len:
176  raise Exception('Array field {} has a variable length'.format(f.base_type))
177  else:
178  length += (f.array_len * type_size)
179  else:
180  field_msg_context = MsgContext.create_default()
181  field_spec = genmsg.msg_loader.load_msg_by_type(field_msg_context, f.base_type, search_path)
182  field_size = get_message_fixed_size(field_spec, search_path)
183  if field_size is None:
184  raise Exception('Field {} has a non-constant size'.format(f.base_type))
185  length += field_size
186  return length
187 
188 ############################################################
189 # Indented writer
190 ############################################################
191 
193 
194  def __init__(self, s):
195  self.str = s
196  self.indentation = 0
197  self.block_indent = False
198 
199  def write(self, s, indent=True, newline=True):
200  if not indent:
201  newline = False
202  if self.block_indent:
203  self.block_indent = False
204  else:
205  if newline:
206  self.str.write('\n')
207  if indent:
208  for i in range(self.indentation):
209  self.str.write(' ')
210  self.str.write(s)
211 
212  def newline(self):
213  self.str.write('\n')
214 
215  def inc_indent(self, inc=2):
216  self.indentation += inc
217 
218  def dec_indent(self, dec=2):
219  self.indentation -= dec
220 
221  def reset_indent(self):
222  self.indentation = 0
223 
224  def block_next_indent(self):
225  self.block_indent = True
226 
227 class Indent():
228 
229  def __init__(self, w, inc=2, indent_first=True):
230  self.writer = w
231  self.inc = inc
232  self.indent_first = indent_first
233 
234  def __enter__(self):
235  self.writer.inc_indent(self.inc)
236  if not self.indent_first:
237  self.writer.block_next_indent()
238 
239  def __exit__(self, type, val, traceback):
240  self.writer.dec_indent(self.inc)
241 
243  cmake_path = os.environ['CMAKE_PREFIX_PATH']
244  paths = cmake_path.split(':')
245  for search_path in paths:
246  test_path = pjoin(search_path, path)
247  if os.path.exists(test_path):
248  return test_path
249  return None
250 
252  return find_path_from_cmake_path(pjoin('share/gennodejs/ros', package))
253 
254 def find_requires(spec):
255  found_packages = []
256  local_deps = []
257  for field in spec.parsed_fields():
258  if not field.is_builtin:
259  (field_type_package, msg_type) = field.base_type.split('/')
260  if field_type_package in found_packages:
261  continue
262  # else
263  if field_type_package == spec.package:
264  if msg_type not in local_deps:
265  local_deps.append(msg_type)
266  else:
267  found_packages.append(field_type_package)
268 
269  return found_packages, local_deps
270 
271 def write_begin(s, spec, is_service=False):
272  "Writes the beginning of the file: a comment saying it's auto-generated and the in-package form"
273 
274  s.write('// Auto-generated. Do not edit!\n\n', newline=False)
275  suffix = 'srv' if is_service else 'msg'
276  s.write('// (in-package %s.%s)\n\n'%(spec.package, suffix), newline=False)
277 
278 def write_requires(s, spec, previous_packages=None, prev_deps=None, isSrv=False):
279  "Writes out the require fields"
280  if previous_packages is None:
281  s.write('"use strict";')
282  s.newline()
283  s.write('const _serializer = _ros_msg_utils.Serialize;')
284  s.write('const _arraySerializer = _serializer.Array;');
285  s.write('const _deserializer = _ros_msg_utils.Deserialize;')
286  s.write('const _arrayDeserializer = _deserializer.Array;');
287  s.write('const _finder = _ros_msg_utils.Find;')
288  s.write('const _getByteLength = _ros_msg_utils.getByteLength;');
289  previous_packages = {}
290  if prev_deps is None:
291  prev_deps = []
292  # find other message packages and other messages in this packages
293  # that this message depends on
294  found_packages, local_deps = find_requires(spec)
295  # filter out previously found local deps
296  local_deps = [dep for dep in local_deps if dep not in prev_deps]
297 
298  # require mesages from this package
299  # messages from this package need to be requried separately
300  # so that we don't create a circular requires dependency
301  for dep in local_deps:
302  if isSrv:
303  s.write('let {} = require(\'../msg/{}.js\');'.format(dep, dep))
304  else:
305  s.write('let {} = require(\'./{}.js\');'.format(dep, dep))
306 
307  # filter out previously found packages
308  found_packages = {package for package in found_packages if package not in previous_packages}
309  for package in found_packages:
310  # TODO: finder is only relevant to node - we should support an option to
311  # create a flat message package directory. The downside is that it requires
312  # copying files between workspaces.
313  s.write('let {0} = _finder(\'{0}\');'.format(package))
314  s.newline()
315  s.write('//-----------------------------------------------------------')
316  s.newline()
317  return found_packages, local_deps
318 
319 def write_msg_constructor_field(s, spec, field):
320  s.write('if (initObj.hasOwnProperty(\'{}\')) {{'.format(field.name))
321  with Indent(s):
322  s.write('this.{} = initObj.{}'.format(field.name, field.name))
323  s.write('}')
324  s.write('else {')
325  with Indent(s):
326  s.write('this.{} = {};'.format(field.name, get_default_value(field, spec.package)))
327  s.write('}')
328 
329 def write_class(s, spec):
330  s.write('class {} {{'.format(spec.actual_name))
331  with Indent(s):
332  # TODO: add optional object argument
333  s.write('constructor(initObj={}) {')
334  with Indent(s):
335  s.write('if (initObj === null) {')
336  with Indent(s):
337  s.write('// initObj === null is a special case for deserialization where we don\'t initialize fields')
338  for field in spec.parsed_fields():
339  s.write('this.{} = null;'.format(field.name))
340  s.write('}')
341  s.write('else {')
342  with Indent(s):
343  for field in spec.parsed_fields():
344  write_msg_constructor_field(s, spec, field)
345  s.write('}')
346  s.write('}')
347  s.newline()
348 
350  (field_pkg, msg_type) = field.base_type.split('/')
351  if field_pkg == pkg:
352  return msg_type
353  # else
354  return '{}.msg.{}'.format(field_pkg, msg_type)
355 
356 def write_resolve(s, spec):
357  with Indent(s):
358  s.write('static Resolve(msg) {')
359  with Indent(s):
360  s.write('// deep-construct a valid message object instance of whatever was passed in');
361  s.write('if (typeof msg !== \'object\' || msg === null) {')
362  with Indent(s):
363  s.write('msg = {};')
364  s.write('}')
365  s.write('const resolved = new {}(null);'.format(spec.short_name))
366  for field in spec.parsed_fields():
367  if not field.is_builtin:
368  s.write('if (msg.{} !== undefined) {{'.format(field.name))
369  with Indent(s):
370  if field.is_array:
371  if field.array_len is None:
372  s.write('resolved.{} = new Array(msg.{}.length);'.format(field.name, field.name))
373  s.write('for (let i = 0; i < resolved.{}.length; ++i) {{'.format(field.name))
374  with Indent(s):
375  s.write('resolved.{}[i] = {}.Resolve(msg.{}[i]);'.format(field.name, get_message_path_from_field(field, spec.package), field.name))
376  s.write('}')
377  else:
378  s.write('resolved.{} = new Array({})'.format(field.name, field.array_len))
379  s.write('for (let i = 0; i < resolved.{}.length; ++i) {{'.format(field.name))
380  with Indent(s):
381  s.write('if (msg.{}.length > i) {{'.format(field.name))
382  with Indent(s):
383  s.write('resolved.{}[i] = {}.Resolve(msg.{}[i]);'.format(field.name, get_message_path_from_field(field, spec.package), field.name))
384  s.write('}')
385  s.write('else {')
386  with Indent(s):
387  s.write('resolved.{}[i] = new {}();'.format(field.name, get_message_path_from_field(field, spec.package)))
388  s.write('}')
389  s.write('}')
390  else:
391  s.write('resolved.{} = {}.Resolve(msg.{})'.format(field.name, get_message_path_from_field(field, spec.package), field.name))
392  s.write('}')
393  s.write('else {')
394  with Indent(s):
395  s.write('resolved.{} = {}'.format(field.name, get_default_value(field, spec.package)))
396  s.write('}')
397  else:
398  s.write('if (msg.{} !== undefined) {{'.format(field.name))
399  with Indent(s):
400  s.write('resolved.{} = msg.{};'.format(field.name, field.name))
401  s.write('}')
402  s.write('else {')
403  with Indent(s):
404  s.write('resolved.{} = {}'.format(field.name, get_default_value(field, spec.package)))
405  s.write('}')
406  s.newline()
407  s.write('return resolved;')
408  s.write('}')
409 
410 def write_end(s, spec):
411  s.write('};')
412  s.newline();
413  write_constants(s, spec)
414  s.write('module.exports = {};'.format(spec.actual_name))
415 
416 def write_serialize_base(s, rest):
417  s.write('bufferOffset = {};'.format(rest))
418 
420  #t2
421  s.write('// Serialize the length for message field [{}]'.format(name))
422  write_serialize_base(s, '_serializer.uint32(obj.{}.length, buffer, bufferOffset)'.format(name))
423 
425  s.write('// Check that the constant length array field [{}] has the right length'.format(field.name))
426  s.write('if (obj.{}.length !== {}) {{'.format(field.name, field.array_len))
427  with Indent(s):
428  s.write('throw new Error(\'Unable to serialize array field {} - length must be {}\')'.format(field.name, field.array_len))
429  s.write('}')
430 
431 # adds function to serialize builtin types (string, uint8, ...)
433  if (f.is_array):
434  write_serialize_base(s, '_arraySerializer.{}(obj.{}, buffer, bufferOffset, {})'.format(f.base_type, f.name, 'null' if f.array_len is None else f.array_len))
435  else:
436  write_serialize_base(s, '_serializer.{}(obj.{}, buffer, bufferOffset)'.format(f.base_type, f.name))
437 
438 # adds function to serlialize complex type (geometry_msgs/Pose)
439 def write_serialize_complex(s, f, thisPackage):
440  (package, msg_type) = f.base_type.split('/')
441  samePackage = package == thisPackage
442  if (f.is_array):
443  if f.array_len is None:
444  write_serialize_length(s, f.name)
445  s.write('obj.{}.forEach((val) => {{'.format(f.name))
446  with Indent(s):
447  if samePackage:
448  write_serialize_base(s, '{}.serialize(val, buffer, bufferOffset)'.format(msg_type))
449  else:
450  write_serialize_base(s, '{}.msg.{}.serialize(val, buffer, bufferOffset)'.format(package, msg_type))
451  s.write('});')
452  else:
453  if samePackage:
454  write_serialize_base(s, '{}.serialize(obj.{}, buffer, bufferOffset)'.format(msg_type, f.name))
455  else:
456  write_serialize_base(s, '{}.msg.{}.serialize(obj.{}, buffer, bufferOffset)'.format(package, msg_type, f.name))
457 
458 # writes serialization for a single field in the message
459 def write_serialize_field(s, f, package):
460  if f.is_array:
461  if f.array_len is not None:
463 
464  s.write('// Serialize message field [{}]'.format(f.name))
465  if f.is_builtin:
467  else:
468  write_serialize_complex(s, f, package)
469 
470 def write_serialize(s, spec):
471  """
472  Write the serialize method
473  """
474  with Indent(s):
475  s.write('static serialize(obj, buffer, bufferOffset) {')
476  with Indent(s):
477  s.write('// Serializes a message object of type {}'.format(spec.short_name))
478  for f in spec.parsed_fields():
479  write_serialize_field(s, f, spec.package)
480  s.write('return bufferOffset;')
481  s.write('}')
482  s.newline()
483 
484 # t2 can get rid of is_array
486  s.write('// Deserialize array length for message field [{}]'.format(name))
487  s.write('len = _deserializer.uint32(buffer, bufferOffset);')
488 
489 def write_deserialize_complex(s, f, thisPackage):
490  (package, msg_type) = f.base_type.split('/')
491  samePackage = package == thisPackage
492  if f.is_array:
493  if f.array_len is None:
494  write_deserialize_length(s, f.name)
495  else:
496  s.write('len = {};'.format(f.array_len))
497 
498  s.write('data.{} = new Array(len);'.format(f.name))
499  s.write('for (let i = 0; i < len; ++i) {')
500  with Indent(s):
501  if samePackage:
502  s.write('data.{}[i] = {}.deserialize(buffer, bufferOffset)'.format(f.name, msg_type));
503  else:
504  s.write('data.{}[i] = {}.msg.{}.deserialize(buffer, bufferOffset)'.format(f.name, package, msg_type));
505  s.write('}')
506  else:
507  if samePackage:
508  s.write('data.{} = {}.deserialize(buffer, bufferOffset);'.format(f.name, msg_type))
509  else:
510  s.write('data.{} = {}.msg.{}.deserialize(buffer, bufferOffset);'.format(f.name, package, msg_type))
511 
513  if f.is_array:
514  s.write('data.{} = _arrayDeserializer.{}(buffer, bufferOffset, {})'.format(f.name, f.base_type, 'null' if f.array_len is None else f.array_len));
515  else:
516  s.write('data.{} = _deserializer.{}(buffer, bufferOffset);'.format(f.name, f.base_type))
517 
518 
519 def write_deserialize_field(s, f, package):
520  s.write('// Deserialize message field [{}]'.format(f.name))
521  if f.is_builtin:
523  else:
524  write_deserialize_complex(s, f, package)
525 
526 
527 def write_deserialize(s, spec):
528  """
529  Write the deserialize method
530  """
531  with Indent(s):
532  s.write('static deserialize(buffer, bufferOffset=[0]) {')
533  with Indent(s):
534  s.write('//deserializes a message object of type {}'.format(spec.short_name))
535  s.write('let len;')
536  s.write('let data = new {}(null);'.format(spec.short_name))
537  for f in spec.parsed_fields():
538  write_deserialize_field(s, f, spec.package)
539 
540  s.write('return data;')
541  s.write('}')
542  s.newline()
543 
544 def write_get_message_size(s, spec, search_path):
545  """
546  Write a static method to determine the buffer size of a complete message
547  """
548 
549  with Indent(s):
550  s.write('static getMessageSize(object) {')
551  msg_size = get_message_fixed_size(spec, search_path)
552  if msg_size is not None:
553  with Indent(s):
554  s.write('return {};'.format(msg_size))
555  else:
556  def get_dynamic_field_length_line(field, query):
557  if field.is_builtin:
558  if not is_string(field.base_type):
559  raise Exception('Unexpected field {} with type {} has unknown length'.format(field.name, field.base_type))
560  # it's a string array!
561  return 'length += 4 + {}.length;'.format(query)
562  # else
563  (package, msg_type) = field.base_type.split('/')
564  samePackage = spec.package == package
565  if samePackage:
566  return 'length += {}.getMessageSize({});'.format(msg_type, query)
567  else:
568  return 'length += {}.msg.{}.getMessageSize({});'.format(package, msg_type, query)
569 
570  with Indent(s):
571  s.write('let length = 0;')
572  # certain fields will always have the same size
573  # calculate that here instead of dynamically every time
574  len_constant_length_fields = 0;
575  for f in spec.parsed_fields():
576  field_size = None
577  if f.is_builtin:
578  field_size = get_type_size(f.base_type)
579  else:
580  field_msg_context = MsgContext.create_default()
581  field_spec = genmsg.msg_loader.load_msg_by_type(field_msg_context, f.base_type, search_path)
582  field_size = get_message_fixed_size(field_spec, search_path)
583 
584  if f.is_array:
585  if f.array_len and field_size is not None:
586  len_constant_length_fields += (field_size * f.array_len)
587  continue
588  elif not f.array_len:
589  len_constant_length_fields += 4
590 
591  if field_size == 1:
592  s.write('length += object.{}.length;'.format(f.name))
593  elif field_size is not None:
594  s.write('length += {} * object.{}.length;'.format(field_size, f.name))
595  else:
596  if f.is_builtin:
597  if not is_string(f.base_type):
598  raise Exception('Unexpected field {} with type {} has unknown length'.format(f.name, f.base_type))
599  # it's a string array!
600  line_to_write = 'length += 4 + _getByteLength(val);'
601  else:
602  (package, msg_type) = f.base_type.split('/')
603  samePackage = spec.package == package
604  if samePackage:
605  line_to_write = 'length += {}.getMessageSize(val);'.format(msg_type,)
606  else:
607  line_to_write = 'length += {}.msg.{}.getMessageSize(val);'.format(package, msg_type)
608  s.write('object.{}.forEach((val) => {{'.format(f.name))
609  with Indent(s):
610  s.write(line_to_write)
611  s.write('});')
612  elif field_size is not None:
613  len_constant_length_fields += field_size
614  else:
615  # field size is dynamic!
616  if f.is_builtin:
617  if not is_string(f.base_type):
618  raise Exception('Unexpected field {} with type {} has unknown length'.format(f.name, f.base_type))
619  # it's a string array!
620  len_constant_length_fields += 4
621  line_to_write = 'length += _getByteLength(object.{});'.format(f.name)
622  else:
623  (package, msg_type) = f.base_type.split('/')
624  samePackage = spec.package == package
625  if samePackage:
626  line_to_write = 'length += {}.getMessageSize(object.{});'.format(msg_type, f.name)
627  else:
628  line_to_write = 'length += {}.msg.{}.getMessageSize(object.{});'.format(package, msg_type, f.name)
629  s.write(line_to_write)
630 
631  if len_constant_length_fields > 0:
632  s.write('return length + {};'.format(len_constant_length_fields))
633  else:
634  s.write('return length;')
635  s.write('}')
636  s.newline()
637 
638 def write_package_index(s, package_dir):
639  s.write('"use strict";')
640  s.newline()
641  s.write('module.exports = {')
642  msgExists = os.path.exists(pjoin(package_dir, 'msg/_index.js'))
643  srvExists = os.path.exists(pjoin(package_dir, 'srv/_index.js'))
644  with Indent(s):
645  if (msgExists):
646  s.write('msg: require(\'./msg/_index.js\'),')
647  if (srvExists):
648  s.write('srv: require(\'./srv/_index.js\')')
649  s.write('};')
650  s.newline()
651 
652 def write_msg_index(s, msgs, pkg, context):
653  "Writes an index for the messages"
654  s.write('"use strict";')
655  s.newline()
656 
657  for msg in msgs:
658  s.write('let {} = require(\'./{}.js\');'.format(msg, msg))
659  s.newline()
660  s.write('module.exports = {')
661  with Indent(s):
662  for msg in msgs:
663  s.write('{}: {},'.format(msg, msg))
664  s.write('};')
665  s.newline()
666 
667 def write_srv_index(s, srvs, pkg):
668  "Writes an index for the messages"
669  s.write('"use strict";')
670  s.newline()
671  for srv in srvs:
672  s.write('let {} = require(\'./{}.js\')'.format(srv, srv))
673  s.newline()
674  s.write('module.exports = {')
675  with Indent(s):
676  for srv in srvs:
677  s.write('{}: {},'.format(srv, srv))
678  s.write('};')
679  s.newline()
680 
681 def write_ros_datatype(s, spec):
682  with Indent(s):
683  s.write('static datatype() {')
684  with Indent(s):
685  s.write('// Returns string type for a %s object'%spec.component_type)
686  s.write('return \'{}\';'.format(spec.full_name))
687  s.write('}')
688  s.newline()
689 
690 def write_md5sum(s, msg_context, spec, parent=None):
691  md5sum = genmsg.compute_md5(msg_context, parent or spec)
692  with Indent(s):
693  s.write('static md5sum() {')
694  with Indent(s):
695  # t2 this should print 'service' instead of 'message' if it's a service request or response
696  s.write('//Returns md5sum for a message object')
697  s.write('return \'{}\';'.format(md5sum))
698  s.write('}')
699  s.newline()
700 
701 def write_message_definition(s, msg_context, spec):
702  with Indent(s):
703  s.write('static messageDefinition() {')
704  with Indent(s):
705  s.write('// Returns full string definition for message')
706  definition = genmsg.compute_full_text(msg_context, spec)
707  lines = definition.split('\n')
708  s.write('return `')
709  for line in lines:
710  s.write('{}'.format(line))
711  s.write('`;')
712  s.write('}')
713  s.newline()
714 
715 def write_constants(s, spec):
716  if spec.constants:
717  s.write('// Constants for message')
718  s.write('{}.Constants = {{'.format(spec.short_name))
719  with Indent(s):
720  for c in spec.constants:
721  if is_string(c.type):
722  s.write('{}: \'{}\','.format(c.name.upper(), c.val.replace("'", "\\'")))
723  elif is_bool(c.type):
724  s.write('{}: {},'.format(c.name.upper(), 'true' if c.val else 'false'))
725  else:
726  s.write('{}: {},'.format(c.name.upper(), c.val))
727  s.write('}')
728  s.newline()
729 
730 def write_srv_component(s, spec, context, parent, search_path):
731  spec.component_type='service'
732  write_class(s, spec)
733  write_serialize(s, spec)
734  write_deserialize(s, spec)
735  write_get_message_size(s, spec, search_path)
736  write_ros_datatype(s, spec)
737  write_md5sum(s, context, spec)
738  write_message_definition(s, context, spec)
739  write_resolve(s, spec)
740  s.write('};')
741  s.newline()
742  write_constants(s, spec)
743 
744 def write_srv_end(s, context, spec):
745  s.write('module.exports = {')
746  name = spec.short_name
747  with Indent(s):
748  s.write('Request: {}Request,'.format(name))
749  s.write('Response: {}Response,'.format(name))
750  md5sum = genmsg.compute_md5(context, spec)
751  s.write('md5sum() {{ return \'{}\'; }},'.format(md5sum))
752  s.write('datatype() {{ return \'{}\'; }}'.format(spec.full_name))
753  s.write('};')
754  s.newline()
755 
756 def generate_msg(pkg, files, out_dir, search_path):
757  """
758  Generate javascript code for all messages in a package
759  """
760  msg_context = MsgContext.create_default()
761  for f in files:
762  f = os.path.abspath(f)
763  infile = os.path.basename(f)
764  full_type = genmsg.gentools.compute_full_type_name(pkg, infile)
765  spec = genmsg.msg_loader.load_msg_from_file(msg_context, f, full_type)
766  generate_msg_from_spec(msg_context, spec, search_path, out_dir, pkg)
767 
768 def generate_srv(pkg, files, out_dir, search_path):
769  """
770  Generate javascript code for all services in a package
771  """
772  msg_context = MsgContext.create_default()
773  for f in files:
774  f = os.path.abspath(f)
775  infile = os.path.basename(f)
776  full_type = genmsg.gentools.compute_full_type_name(pkg, infile)
777  spec = genmsg.msg_loader.load_srv_from_file(msg_context, f, full_type)
778  generate_srv_from_spec(msg_context, spec, search_path, out_dir, pkg, f)
779 
780 def msg_list(pkg, search_path, ext):
781  dir_list = search_path[pkg]
782  files = []
783  for d in dir_list:
784  files.extend([f for f in os.listdir(d) if f.endswith(ext)])
785  return [f[:-len(ext)] for f in files]
786 
787 def generate_msg_from_spec(msg_context, spec, search_path, output_dir, package, msgs=None):
788  """
789  Generate a message
790 
791  @param msg_path: The path to the .msg file
792  @type msg_path: str
793  """
794  genmsg.msg_loader.load_depends(msg_context, spec, search_path)
795  spec.actual_name=spec.short_name
796  spec.component_type='message'
797  msgs = msg_list(package, search_path, '.msg')
798  for m in msgs:
799  genmsg.load_msg_by_type(msg_context, '%s/%s'%(package, m), search_path)
800 
801  ########################################
802  # 1. Write the .js file
803  ########################################
804 
805  io = StringIO()
806  s = IndentedWriter(io)
807  write_begin(s, spec)
808  write_requires(s, spec)
809  write_class(s, spec)
810  write_serialize(s, spec)
811  write_deserialize(s, spec)
812  write_get_message_size(s, spec, search_path)
813  write_ros_datatype(s, spec)
814  write_md5sum(s, msg_context, spec)
815  write_message_definition(s, msg_context, spec)
816  write_resolve(s, spec)
817  write_end(s, spec)
818 
819  if (not os.path.exists(output_dir)):
820  # if we're being run concurrently, the above test can report false but os.makedirs can still fail if
821  # another copy just created the directory
822  try:
823  os.makedirs(output_dir)
824  except OSError as e:
825  pass
826 
827  with open('%s/%s.js'%(output_dir, spec.short_name), 'w') as f:
828  f.write(io.getvalue() + "\n")
829  io.close()
830 
831  ########################################
832  # 3. Write the msg/_index.js file
833  # This is being rewritten once per msg
834  # file, which is inefficient
835  ########################################
836  io = StringIO()
837  s = IndentedWriter(io)
838  write_msg_index(s, msgs, package, msg_context)
839  with open('{}/_index.js'.format(output_dir), 'w') as f:
840  f.write(io.getvalue())
841  io.close()
842 
843  ########################################
844  # 3. Write the package _index.js file
845  # This is being rewritten once per msg
846  # file, which is inefficient
847  ########################################
848  io = StringIO()
849  s = IndentedWriter(io)
850  package_dir = os.path.dirname(output_dir)
851  write_package_index(s, package_dir)
852  with open('{}/_index.js'.format(package_dir), 'w') as f:
853  f.write(io.getvalue())
854  io.close()
855 
856 # t0 most of this could probably be refactored into being shared with messages
857 def generate_srv_from_spec(msg_context, spec, search_path, output_dir, package, path):
858  "Generate code from .srv file"
859  genmsg.msg_loader.load_depends(msg_context, spec, search_path)
860  ext = '.srv'
861  srv_path = os.path.dirname(path)
862  srvs = msg_list(package, {package: [srv_path]}, ext)
863  for srv in srvs:
864  load_srv_from_file(msg_context, '%s/%s%s'%(srv_path, srv, ext), '%s/%s'%(package, srv))
865 
866  ########################################
867  # 1. Write the .js file
868  ########################################
869 
870  io = StringIO()
871  s = IndentedWriter(io)
872  write_begin(s, spec, True)
873  found_packages,local_deps = write_requires(s, spec.request, None, None, True)
874  write_requires(s, spec.response, found_packages, local_deps, True)
875  spec.request.actual_name='%sRequest'%spec.short_name
876  spec.response.actual_name='%sResponse'%spec.short_name
877  write_srv_component(s, spec.request, msg_context, spec, search_path)
878  write_srv_component(s, spec.response, msg_context, spec, search_path)
879  write_srv_end(s, msg_context, spec)
880 
881  with open('%s/%s.js'%(output_dir, spec.short_name), 'w') as f:
882  f.write(io.getvalue())
883  io.close()
884 
885  ########################################
886  # 3. Write the msg/_index.js file
887  # This is being rewritten once per msg
888  # file, which is inefficient
889  ########################################
890  io = StringIO()
891  s = IndentedWriter(io)
892  write_srv_index(s, srvs, package)
893  with open('{}/_index.js'.format(output_dir), 'w') as f:
894  f.write(io.getvalue())
895  io.close()
896 
897  ########################################
898  # 3. Write the package _index.js file
899  # This is being rewritten once per msg
900  # file, which is inefficient
901  ########################################
902  io = StringIO()
903  s = IndentedWriter(io)
904  package_dir = os.path.dirname(output_dir)
905  write_package_index(s, package_dir)
906  with open('{}/_index.js'.format(package_dir), 'w') as f:
907  f.write(io.getvalue())
908  io.close()
def write_serialize(s, spec)
Definition: generate.py:470
def write_end(s, spec)
Definition: generate.py:410
def write_serialize_complex(s, f, thisPackage)
Definition: generate.py:439
def get_typed_array(t)
Definition: generate.py:73
def find_requires(spec)
Definition: generate.py:254
def write_deserialize_builtin(s, f)
Definition: generate.py:512
def write_deserialize_complex(s, f, thisPackage)
Definition: generate.py:489
def write(self, s, indent=True, newline=True)
Definition: generate.py:199
def get_message_path_from_field(field, pkg)
Definition: generate.py:349
def is_message_fixed_size(spec, search_path)
Definition: generate.py:137
def write_serialize_base(s, rest)
Definition: generate.py:416
def get_default_value(field, current_message_package)
Definition: generate.py:109
def find_path_for_package(package)
Definition: generate.py:251
def write_resolve(s, spec)
Definition: generate.py:356
def generate_msg_from_spec(msg_context, spec, search_path, output_dir, package, msgs=None)
Definition: generate.py:787
def write_package_index(s, package_dir)
Definition: generate.py:638
def is_fixnum(t)
Built in types.
Definition: generate.py:43
def write_srv_end(s, context, spec)
Definition: generate.py:744
def write_srv_component(s, spec, context, parent, search_path)
Definition: generate.py:730
def msg_list(pkg, search_path, ext)
Definition: generate.py:780
def find_path_from_cmake_path(path)
Definition: generate.py:242
def write_get_message_size(s, spec, search_path)
Definition: generate.py:544
def write_serialize_builtin(s, f)
Definition: generate.py:432
def get_type_size(t)
Definition: generate.py:97
def is_unsigned_int(t)
Definition: generate.py:52
def get_message_fixed_size(spec, search_path)
Definition: generate.py:159
def write_md5sum(s, msg_context, spec, parent=None)
Definition: generate.py:690
def write_constants(s, spec)
Definition: generate.py:715
def is_integer(t)
Definition: generate.py:46
def write_deserialize(s, spec)
Definition: generate.py:527
def write_serialize_length(s, name)
Definition: generate.py:419
def write_requires(s, spec, previous_packages=None, prev_deps=None, isSrv=False)
Definition: generate.py:278
def write_serialize_field(s, f, package)
Definition: generate.py:459
def parse_msg_type(f)
Definition: generate.py:67
def generate_srv_from_spec(msg_context, spec, search_path, output_dir, package, path)
Definition: generate.py:857
def write_ros_datatype(s, spec)
Definition: generate.py:681
def write_class(s, spec)
Definition: generate.py:329
def is_string(t)
Definition: generate.py:58
def write_msg_constructor_field(s, spec, field)
Definition: generate.py:319
def generate_srv(pkg, files, out_dir, search_path)
Definition: generate.py:768
def is_signed_int(t)
Definition: generate.py:49
def write_message_definition(s, msg_context, spec)
Definition: generate.py:701
def __init__(self, w, inc=2, indent_first=True)
Definition: generate.py:229
def write_deserialize_field(s, f, package)
Definition: generate.py:519
def write_deserialize_length(s, name)
Definition: generate.py:485
def generate_msg(pkg, files, out_dir, search_path)
Definition: generate.py:756
def write_msg_index(s, msgs, pkg, context)
Definition: generate.py:652
def write_serialize_length_check(s, field)
Definition: generate.py:424
def __exit__(self, type, val, traceback)
Definition: generate.py:239
def write_begin(s, spec, is_service=False)
Definition: generate.py:271
def write_srv_index(s, srvs, pkg)
Definition: generate.py:667
def has_typed_array(t)
Definition: generate.py:94


gennodejs
Author(s):
autogenerated on Mon Jan 27 2020 03:17:04