blob: ae1999efd8854468470604393985a7b8c5105222 [file] [log] [blame]
Khen Nursimulud7688092016-11-17 00:08:57 -05001#!/usr/bin/env python
2#
3# Copyright 2016 the original author or authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
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
18"""protoc plugin to convert a protobuf schema to a yang schema
19
20 - basic support for message, fields. enumeration, service, method
21
22 - yang semantic rules needs to be implemented
23
24 - to run this plugin :
25
26 $ python -m grpc.tools.protoc -I.
27 --plugin=protoc-gen-custom=./proto2yang.py --custom_out=. <proto file>.proto
28
Khen Nursimulu95b919d2016-11-18 16:20:20 -050029 - the above will produce a ietf-<proto file>.yang file formatted for yang
Khen Nursimulud7688092016-11-17 00:08:57 -050030
31 - two examples of proto that can be used in the same directory are
32 yang.proto and addressbook.proto
33
34"""
35
36import sys
37
38from jinja2 import Template
39from google.protobuf.compiler import plugin_pb2 as plugin
40from descriptor_parser import DescriptorParser
41
42from google.protobuf.descriptor import FieldDescriptor
43
44template_yang = Template("""
Khen Nursimulu95b919d2016-11-18 16:20:20 -050045module ietf-{{ module.name }} {
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -050046
47 {% macro set_module_prefix(type) %}
48 {% for t in module.data_types %}
49 {% if t.type == type %}
50 {% if t.module != module.name %} {{ t.module }}:{{ type }};
51 {% else %} {{ type }};
52 {% endif %}
53 {% set found=True %}
54 {% endif %}
55 {% if loop.last %}
56 {% if not found %} {{ type }}; {% endif %}
57 {% endif %}
58 {% endfor %}
59 {% endmacro %}
60
61 namespace "urn:opencord:params:xml:ns:voltha:ietf-{{ module.name }}";
62 prefix {{ module.name }};
63
64 {% for imp in module.imports %}
65 import ietf-{{ imp.name }} { prefix {{ imp.name }} ; }
66 {% endfor %}
Khen Nursimulud7688092016-11-17 00:08:57 -050067
Khen Nursimulu95b919d2016-11-18 16:20:20 -050068 organization "CORD";
69 contact
70 " Any name";
71
72 description
73 "{{ module.description }}";
74
75 revision "2016-11-15" {
Khen Nursimulud7688092016-11-17 00:08:57 -050076 description "Initial revision.";
Khen Nursimulu95b919d2016-11-18 16:20:20 -050077 reference "reference";
Khen Nursimulud7688092016-11-17 00:08:57 -050078 }
Khen Nursimulubd24f552016-11-18 11:31:15 -050079
80 {% for enum in module.enums %}
Khen Nursimulubd24f552016-11-18 11:31:15 -050081 typedef {{ enum.name }} {
82 type enumeration {
83 {% for v in enum.value %}
Khen Nursimulubd24f552016-11-18 11:31:15 -050084 enum {{ v.name }} {
85 description "{{ v.description }}";
86 }
Khen Nursimulubd24f552016-11-18 11:31:15 -050087 {% endfor %}
88 }
Khen Nursimulu95b919d2016-11-18 16:20:20 -050089 description
90 "{{ enum.description }}";
Khen Nursimulubd24f552016-11-18 11:31:15 -050091 }
92 {% endfor %}
93
Khen Nursimulud7688092016-11-17 00:08:57 -050094 {% for message in module.messages recursive %}
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -050095 {% if message.name in module.referred_messages %}
Khen Nursimulud7688092016-11-17 00:08:57 -050096 grouping {{ message.name }} {
Khen Nursimulubd24f552016-11-18 11:31:15 -050097 {% else %}
98 container {{ message.name }} {
99 {% endif %}
Khen Nursimulu95b919d2016-11-18 16:20:20 -0500100 description
101 "{{ message.description }}";
Khen Nursimulud7688092016-11-17 00:08:57 -0500102 {% for field in message.fields %}
103 {% if field.type_ref %}
Khen Nursimulubd24f552016-11-18 11:31:15 -0500104 {% for dict_item in module.referred_messages_with_keys %}
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500105 {% if dict_item.name == field.type %}
106 {% if not field.repeated %}
107 container {{ field.name }} {
108 {% else %}
Khen Nursimulubd24f552016-11-18 11:31:15 -0500109 list {{ field.name }} {
110 key "{{ dict_item.key }}";
111 {% if not field.repeated %}
112 max-elements 1;
113 {% endif %}
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500114 {% endif %}
115 uses {{ set_module_prefix(field.type) }}
Khen Nursimulu95b919d2016-11-18 16:20:20 -0500116 description
117 "{{ field.description }}";
Khen Nursimulubd24f552016-11-18 11:31:15 -0500118 }
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500119 {% endif %}
Khen Nursimulubd24f552016-11-18 11:31:15 -0500120 {% endfor %}
121 {% elif field.repeated %}
122 list {{ field.name }} {
123 key "{{ field.name }}";
124 leaf {{ field.name }} {
125 {% if field.type == "decimal64" %}
126 type {{ field.type }} {
127 fraction-digits 5;
128 }
129 {% else %}
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500130 type {{ set_module_prefix(field.type) }}
Khen Nursimulubd24f552016-11-18 11:31:15 -0500131 {% endif %}
Khen Nursimulubd24f552016-11-18 11:31:15 -0500132 description
Khen Nursimulu95b919d2016-11-18 16:20:20 -0500133 "{{ field.description }}";
Khen Nursimulubd24f552016-11-18 11:31:15 -0500134 }
Khen Nursimulu95b919d2016-11-18 16:20:20 -0500135 description
136 "{{ field.description }}";
Khen Nursimulubd24f552016-11-18 11:31:15 -0500137 }
Khen Nursimulud7688092016-11-17 00:08:57 -0500138 {% else %}
139 leaf {{ field.name }} {
140 {% if field.type == "decimal64" %}
141 type {{ field.type }} {
142 fraction-digits 5;
143 }
144 {% else %}
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500145 type {{ set_module_prefix(field.type) }}
Khen Nursimulud7688092016-11-17 00:08:57 -0500146 {% endif %}
Khen Nursimulud7688092016-11-17 00:08:57 -0500147 description
Khen Nursimulu95b919d2016-11-18 16:20:20 -0500148 "{{ field.description }}";
Khen Nursimulud7688092016-11-17 00:08:57 -0500149 }
150 {% endif %}
Khen Nursimulubd24f552016-11-18 11:31:15 -0500151
Khen Nursimulud7688092016-11-17 00:08:57 -0500152 {% endfor %}
153 {% for enum_type in message.enums %}
Khen Nursimulud7688092016-11-17 00:08:57 -0500154 typedef {{ enum_type.name }} {
155 type enumeration {
156 {% for v in enum_type.value %}
Khen Nursimulud7688092016-11-17 00:08:57 -0500157 enum {{ v.name }} {
158 description "{{ v.description }}";
159 }
Khen Nursimulud7688092016-11-17 00:08:57 -0500160 {% endfor %}
161 }
Khen Nursimulu95b919d2016-11-18 16:20:20 -0500162 description
163 "{{ enum_type.description }}";
Khen Nursimulud7688092016-11-17 00:08:57 -0500164 }
Khen Nursimulubd24f552016-11-18 11:31:15 -0500165
Khen Nursimulud7688092016-11-17 00:08:57 -0500166 {% endfor %}
167 {% if message.messages %}
168 {{ loop (message.messages)|indent(4, false) }}
169 {% endif %}
170 }
Khen Nursimulud7688092016-11-17 00:08:57 -0500171
Khen Nursimulubd24f552016-11-18 11:31:15 -0500172 {% endfor %}
Khen Nursimulud7688092016-11-17 00:08:57 -0500173 {% for service in module.services %}
174 {% if service.description %}
175 /* {{ service.description }}" */
176 {% endif %}
Khen Nursimulud7688092016-11-17 00:08:57 -0500177 {% for method in service.methods %}
Khen Nursimulud7688092016-11-17 00:08:57 -0500178 rpc {{ service.service }}-{{ method.method }} {
Khen Nursimulu95b919d2016-11-18 16:20:20 -0500179 description
180 "{{ method.description }}";
Khen Nursimulud7688092016-11-17 00:08:57 -0500181 {% if method.input %}
182 input {
183 {% if method.input_ref %}
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500184 uses {{ set_module_prefix(method.input) }}
Khen Nursimulud7688092016-11-17 00:08:57 -0500185 {% else %}
186 leaf {{ method.input }} {
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500187 type {{ set_module_prefix(method.input) }}
Khen Nursimulud7688092016-11-17 00:08:57 -0500188 }
189 {% endif %}
190 }
191 {% endif %}
192 {% if method.output %}
193 output {
194 {% if method.output_ref %}
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500195 uses {{ set_module_prefix(method.output) }}
Khen Nursimulud7688092016-11-17 00:08:57 -0500196 {% else %}
197 leaf {{ method.output }} {
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500198 type {{ set_module_prefix(method.output) }}
Khen Nursimulud7688092016-11-17 00:08:57 -0500199 }
200 {% endif %}
201 }
202 {% endif %}
203 }
Khen Nursimulubd24f552016-11-18 11:31:15 -0500204
Khen Nursimulud7688092016-11-17 00:08:57 -0500205 {% endfor %}
Khen Nursimulubd24f552016-11-18 11:31:15 -0500206
Khen Nursimulud7688092016-11-17 00:08:57 -0500207 {% endfor %}
208}
209""", trim_blocks=True, lstrip_blocks=True)
210
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500211# def traverse_dependencies(descriptor):
212# dependencies = []
213# proto_imports = descriptor.get('dependency', [])
214# for proto_import in proto_imports:
215# # If the import file has a directory path to it remove it as it is not
216# # allowed in Yang. The proto extension should be removed as well
217# dependencies.append (
218# {
219# 'name' : proto_import.split('/')[-1][:-len('.proto')]
220# }
221# )
222# return dependencies
223
Khen Nursimulud7688092016-11-17 00:08:57 -0500224
Khen Nursimulubd24f552016-11-18 11:31:15 -0500225def traverse_messages(message_types, prefix, referenced_messages):
Khen Nursimulud7688092016-11-17 00:08:57 -0500226 messages = []
227 for message_type in message_types:
228 assert message_type['_type'] == 'google.protobuf.DescriptorProto'
Khen Nursimulubd24f552016-11-18 11:31:15 -0500229
230 # full_name = prefix + '-' + message_type['name']
231 full_name = message_type['name']
232
Khen Nursimulud7688092016-11-17 00:08:57 -0500233 # parse the fields
Khen Nursimulubd24f552016-11-18 11:31:15 -0500234 fields = traverse_fields(message_type.get('field', []), full_name,
235 referenced_messages)
Khen Nursimulud7688092016-11-17 00:08:57 -0500236
237 # parse the enums
Khen Nursimulubd24f552016-11-18 11:31:15 -0500238 enums = traverse_enums(message_type.get('enum_type', []), full_name)
Khen Nursimulud7688092016-11-17 00:08:57 -0500239
240 # parse nested messages
241 nested = message_type.get('nested_type', [])
Khen Nursimulubd24f552016-11-18 11:31:15 -0500242 nested_messages = traverse_messages(nested, full_name,
243 referenced_messages)
Khen Nursimulud7688092016-11-17 00:08:57 -0500244 messages.append(
245 {
Khen Nursimulubd24f552016-11-18 11:31:15 -0500246 'name': full_name,
Khen Nursimulud7688092016-11-17 00:08:57 -0500247 'fields': fields,
248 'enums': enums,
249 # 'extensions': extensions,
250 'messages': nested_messages,
Khen Nursimulubd24f552016-11-18 11:31:15 -0500251 'description': remove_unsupported_characters(
252 message_type.get('_description', '')),
Khen Nursimulud7688092016-11-17 00:08:57 -0500253 # 'extension_ranges': extension_ranges,
254 # 'oneof': oneof
255 }
256 )
257 return messages
258
259
Khen Nursimulubd24f552016-11-18 11:31:15 -0500260def traverse_fields(fields_desc, prefix, referenced_messages):
Khen Nursimulud7688092016-11-17 00:08:57 -0500261 fields = []
262 for field in fields_desc:
263 assert field['_type'] == 'google.protobuf.FieldDescriptorProto'
Khen Nursimulubd24f552016-11-18 11:31:15 -0500264 yang_base_type = is_base_type(field['type'])
265 _type = get_yang_type(field)
266 if not yang_base_type:
267 referenced_messages.append(_type)
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500268 # add to referred messages also if it is an enumeration type
269 if is_enumeration(field['type']):
270 referenced_messages.append(_type)
Khen Nursimulubd24f552016-11-18 11:31:15 -0500271
Khen Nursimulud7688092016-11-17 00:08:57 -0500272 fields.append(
273 {
Khen Nursimulubd24f552016-11-18 11:31:15 -0500274 # 'name': prefix + '-' + field.get('name', ''),
Khen Nursimulud7688092016-11-17 00:08:57 -0500275 'name': field.get('name', ''),
276 'label': field.get('label', ''),
Khen Nursimulubd24f552016-11-18 11:31:15 -0500277 'repeated': field['label'] == FieldDescriptor.LABEL_REPEATED,
Khen Nursimulud7688092016-11-17 00:08:57 -0500278 'number': field.get('number', ''),
279 'options': field.get('options', ''),
280 'type_name': field.get('type_name', ''),
Khen Nursimulubd24f552016-11-18 11:31:15 -0500281 'type': _type,
282 'type_ref': not yang_base_type,
Khen Nursimulud7688092016-11-17 00:08:57 -0500283 'description': remove_unsupported_characters(field.get(
284 '_description', ''))
285 }
286 )
287 return fields
288
289
Khen Nursimulubd24f552016-11-18 11:31:15 -0500290def traverse_enums(enums_desc, prefix):
Khen Nursimulud7688092016-11-17 00:08:57 -0500291 enums = []
292 for enum in enums_desc:
293 assert enum['_type'] == 'google.protobuf.EnumDescriptorProto'
Khen Nursimulubd24f552016-11-18 11:31:15 -0500294 # full_name = prefix + '-' + enum.get('name', '')
295 full_name = enum.get('name', '')
Khen Nursimulud7688092016-11-17 00:08:57 -0500296 enums.append(
297 {
Khen Nursimulubd24f552016-11-18 11:31:15 -0500298 'name': full_name,
Khen Nursimulud7688092016-11-17 00:08:57 -0500299 'value': enum.get('value', ''),
Khen Nursimulubd24f552016-11-18 11:31:15 -0500300 'description': remove_unsupported_characters(enum.get(
301 '_description', ''))
Khen Nursimulud7688092016-11-17 00:08:57 -0500302 }
303 )
304 return enums
305
306
Khen Nursimulubd24f552016-11-18 11:31:15 -0500307def traverse_services(service_desc, referenced_messages):
Khen Nursimulud7688092016-11-17 00:08:57 -0500308 services = []
309 for service in service_desc:
310 methods = []
311 for method in service.get('method', []):
312 assert method['_type'] == 'google.protobuf.MethodDescriptorProto'
Khen Nursimulubd24f552016-11-18 11:31:15 -0500313
Khen Nursimulud7688092016-11-17 00:08:57 -0500314 input_name = method.get('input_type')
315 input_ref = False
316 if not is_base_type(input_name):
Khen Nursimulubd24f552016-11-18 11:31:15 -0500317 input_name = remove_first_character_if_match(input_name, '.')
318 # input_name = input_name.replace(".", "-")
Khen Nursimulud7688092016-11-17 00:08:57 -0500319 input_name = input_name.split('.')[-1]
Khen Nursimulubd24f552016-11-18 11:31:15 -0500320 referenced_messages.append(input_name)
Khen Nursimulud7688092016-11-17 00:08:57 -0500321 input_ref = True
Khen Nursimulubd24f552016-11-18 11:31:15 -0500322
Khen Nursimulud7688092016-11-17 00:08:57 -0500323 output_name = method.get('output_type')
324 output_ref = False
325 if not is_base_type(output_name):
Khen Nursimulubd24f552016-11-18 11:31:15 -0500326 output_name = remove_first_character_if_match(output_name, '.')
327 # output_name = output_name.replace(".", "-")
Khen Nursimulud7688092016-11-17 00:08:57 -0500328 output_name = output_name.split('.')[-1]
Khen Nursimulubd24f552016-11-18 11:31:15 -0500329 referenced_messages.append(output_name)
Khen Nursimulud7688092016-11-17 00:08:57 -0500330 output_ref = True
Khen Nursimulubd24f552016-11-18 11:31:15 -0500331
Khen Nursimulud7688092016-11-17 00:08:57 -0500332 methods.append(
333 {
334 'method': method.get('name', ''),
335 'input': input_name,
336 'input_ref': input_ref,
337 'output': output_name,
338 'output_ref': output_ref,
Khen Nursimulubd24f552016-11-18 11:31:15 -0500339 'description': remove_unsupported_characters(method.get(
340 '_description', '')),
Khen Nursimulud7688092016-11-17 00:08:57 -0500341 'server_streaming': method.get('server_streaming',
342 False) == True
343 }
344 )
345 services.append(
346 {
347 'service': service.get('name', ''),
348 'methods': methods,
Khen Nursimulubd24f552016-11-18 11:31:15 -0500349 'description': remove_unsupported_characters(service.get(
350 '_description', '')),
Khen Nursimulud7688092016-11-17 00:08:57 -0500351 }
352 )
353 return services
354
355
Khen Nursimulubd24f552016-11-18 11:31:15 -0500356def rchop(thestring, ending):
Khen Nursimulud7688092016-11-17 00:08:57 -0500357 if thestring.endswith(ending):
358 return thestring[:-len(ending)]
359 return thestring
360
361
Khen Nursimulubd24f552016-11-18 11:31:15 -0500362def traverse_desc(descriptor):
363 referenced_messages = []
364 name = rchop(descriptor.get('name', ''), '.proto')
Khen Nursimulud7688092016-11-17 00:08:57 -0500365 package = descriptor.get('package', '')
366 description = descriptor.get('_description', '')
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500367 # imports=traverse_dependencies(descriptor)
Khen Nursimulubd24f552016-11-18 11:31:15 -0500368 messages = traverse_messages(descriptor.get('message_type', []),
369 package, referenced_messages)
370 enums = traverse_enums(descriptor.get('enum_type', []), package)
371 services = traverse_services(descriptor.get('service', []),
372 referenced_messages)
Khen Nursimulud7688092016-11-17 00:08:57 -0500373 # extensions = _traverse_extensions(descriptors)
374 # options = _traverse_options(descriptors)
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500375 # set_messages_keys(messages)
376 # unique_referred_messages_with_keys = []
377 # for message_name in list(set(referenced_messages)):
378 # unique_referred_messages_with_keys.append(
379 # {
380 # 'name': message_name,
381 # 'key': get_message_key(message_name, messages)
382 # }
383 # )
384
385 # Get a list of type definitions (messages, enums) defined in this
386 # descriptor
387 defined_types = [m['name'].split('/')[-1] for m in messages] + \
388 [e['name'].split('/')[-1] for e in enums]
Khen Nursimulud7688092016-11-17 00:08:57 -0500389
390 data = {
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500391 'name': name.split('/')[-1],
Khen Nursimulud7688092016-11-17 00:08:57 -0500392 'package': package,
Khen Nursimulubd24f552016-11-18 11:31:15 -0500393 'description': description,
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500394 # 'imports' : imports,
Khen Nursimulud7688092016-11-17 00:08:57 -0500395 'messages': messages,
396 'enums': enums,
397 'services': services,
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500398 'defined_types' : defined_types,
Khen Nursimulubd24f552016-11-18 11:31:15 -0500399 'referenced_messages': list(set(referenced_messages)),
400 # TODO: simplify for easier jinja2 template use
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500401 # 'referred_messages_with_keys': unique_referred_messages_with_keys,
Khen Nursimulud7688092016-11-17 00:08:57 -0500402 # 'extensions': extensions,
403 # 'options': options
404 }
Khen Nursimulud7688092016-11-17 00:08:57 -0500405 return data
406
407
Khen Nursimulubd24f552016-11-18 11:31:15 -0500408def set_messages_keys(messages):
409 for message in messages:
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500410 message['key'] = _get_message_key(message, messages)
Khen Nursimulubd24f552016-11-18 11:31:15 -0500411 if message['messages']:
412 set_messages_keys(message['messages'])
413
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500414def _get_message_key(message, messages):
Khen Nursimulubd24f552016-11-18 11:31:15 -0500415 # assume key is first yang base type field
416 for field in message['fields']:
417 if not field['type_ref']:
418 return field['name']
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500419 else:
420 # if the field name is a message then loop for the key in that
421 # message
422 ref_message = _get_message(field['type'], messages)
423 if ref_message:
424 return _get_message_key(ref_message, messages)
425
Khen Nursimulubd24f552016-11-18 11:31:15 -0500426 # no key yet - search nested messaged
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500427 for m in message['messages']:
428 key = _get_message_key(m, messages)
429 if key is not None:
430 return key
Khen Nursimulubd24f552016-11-18 11:31:15 -0500431 else:
432 return None
433
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500434def _get_message(name, messages):
435 for m in messages:
436 if m['name'] == name:
437 return m
438 return None
Khen Nursimulubd24f552016-11-18 11:31:15 -0500439
440def get_message_key(message_name, messages):
441 for message in messages:
442 if message_name == message['name']:
443 return message['key']
444 if message['messages']:
445 return get_message_key(message_name, message['messages'])
446 return None
447
448
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500449def update_module_imports(module):
450 used_imports = set()
451 for ref_msg in module['referenced_messages']:
452 for type_dict in module['data_types']:
453 if ref_msg == type_dict['type']:
454 if module['name'] != type_dict['module']:
455 used_imports.add(type_dict['module'])
456 break
457 module['imports'] = [{'name' : i} for i in used_imports]
458
459
Khen Nursimulud7688092016-11-17 00:08:57 -0500460def generate_code(request, response):
461 assert isinstance(request, plugin.CodeGeneratorRequest)
462
463 parser = DescriptorParser()
464
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500465 # First process the proto file with the imports
466 all_defined_types = []
467 all_proto_data = []
468 all_referred_messages = []
469 all_messages = []
Khen Nursimulud7688092016-11-17 00:08:57 -0500470 for proto_file in request.proto_file:
471 native_data = parser.parse_file_descriptor(proto_file,
472 type_tag_name='_type',
473 fold_comments=True)
474
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500475 # Consolidate the defined types across imports
Khen Nursimulubd24f552016-11-18 11:31:15 -0500476 yang_data = traverse_desc(native_data)
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500477 for type in yang_data['defined_types']:
478 all_defined_types.append(
479 {
480 'type' : type,
481 'module' : yang_data['name']
482 }
483 )
Khen Nursimulud7688092016-11-17 00:08:57 -0500484
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500485 all_proto_data.append(
486 {
487 'file_name': '{}-{}'.format('ietf', proto_file.name.split(
488 '/')[-1].replace('.proto','.yang')),
489 'module': yang_data
490 }
491 )
492
493 # Consolidate referred messages across imports
494 all_referred_messages = all_referred_messages + yang_data['referenced_messages']
495
496 # consolidate all messages
497 all_messages = all_messages + yang_data['messages']
498
499 # Set the message keys - required for List definitions (repeated label)
500 set_messages_keys(all_messages)
501 unique_referred_messages_with_keys = []
502 for m in all_messages:
503 unique_referred_messages_with_keys.append(
504 {
505 'name': m['name'],
506 'key': m['key']
507 }
508 )
509
510 # Create the files
511 for proto_data in all_proto_data:
Khen Nursimulud7688092016-11-17 00:08:57 -0500512 f = response.file.add()
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500513 f.name = proto_data['file_name']
514 proto_data['module']['data_types'] = all_defined_types
515 proto_data['module']['referred_messages'] = all_referred_messages
516 proto_data['module']['referred_messages_with_keys'] = unique_referred_messages_with_keys
517 update_module_imports(proto_data['module'])
518 f.content = template_yang.render(module=proto_data['module'])
Khen Nursimulud7688092016-11-17 00:08:57 -0500519
Khen Nursimulubd24f552016-11-18 11:31:15 -0500520
Khen Nursimulud7688092016-11-17 00:08:57 -0500521def get_yang_type(field):
522 type = field['type']
523 if type in YANG_TYPE_MAP.keys():
524 _type, _ = YANG_TYPE_MAP[type]
525 if _type in ['enumeration', 'message', 'group']:
526 return field['type_name'].split('.')[-1]
Khen Nursimulubd24f552016-11-18 11:31:15 -0500527 # return remove_first_character_if_match(field['type_name'],
528 # '.').replace('.', '-')
Khen Nursimulud7688092016-11-17 00:08:57 -0500529 else:
530 return _type
531 else:
532 return type
533
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500534def is_enumeration(type):
535 if type in YANG_TYPE_MAP.keys():
536 _type, _ = YANG_TYPE_MAP[type]
537 return _type in ['enumeration']
538 return False
Khen Nursimulubd24f552016-11-18 11:31:15 -0500539
Khen Nursimulud7688092016-11-17 00:08:57 -0500540def is_base_type(type):
541 # check numeric value of the type first
542 if type in YANG_TYPE_MAP.keys():
543 _type, _ = YANG_TYPE_MAP[type]
544 return _type not in ['message', 'group']
545 else:
546 # proto name of the type
Khen Nursimulubd24f552016-11-18 11:31:15 -0500547 result = [_format for (_, _format) in YANG_TYPE_MAP.values() if
Khen Nursimuluaaac7ee2016-12-11 22:03:52 -0500548 _format == type and _format not in ['message',
549 'group']]
Khen Nursimulud7688092016-11-17 00:08:57 -0500550 return len(result) > 0
551
Khen Nursimulubd24f552016-11-18 11:31:15 -0500552
Khen Nursimulud7688092016-11-17 00:08:57 -0500553def remove_unsupported_characters(text):
Khen Nursimulubd24f552016-11-18 11:31:15 -0500554 unsupported_characters = ["{", "}", "[", "]", "\"", "\\", "*", "/"]
555 return ''.join([i if i not in unsupported_characters else ' ' for i in
556 text])
557
558
559def remove_first_character_if_match(str, char):
560 if str.startswith(char):
561 return str[1:]
562 return str
563
Khen Nursimulud7688092016-11-17 00:08:57 -0500564
565YANG_TYPE_MAP = {
566 FieldDescriptor.TYPE_BOOL: ('boolean', 'boolean'),
567 FieldDescriptor.TYPE_BYTES: ('binary', 'byte'),
568 FieldDescriptor.TYPE_DOUBLE: ('decimal64', 'double'),
569 FieldDescriptor.TYPE_ENUM: ('enumeration', 'enum'),
570 FieldDescriptor.TYPE_FIXED32: ('int32', 'int64'),
571 FieldDescriptor.TYPE_FIXED64: ('int64', 'uint64'),
572 FieldDescriptor.TYPE_FLOAT: ('decimal64', 'float'),
573 FieldDescriptor.TYPE_INT32: ('int32', 'int32'),
574 FieldDescriptor.TYPE_INT64: ('int64', 'int64'),
575 FieldDescriptor.TYPE_SFIXED32: ('int32', 'int32'),
576 FieldDescriptor.TYPE_SFIXED64: ('int64', 'int64'),
577 FieldDescriptor.TYPE_STRING: ('string', 'string'),
578 FieldDescriptor.TYPE_SINT32: ('int32', 'int32'),
579 FieldDescriptor.TYPE_SINT64: ('int64', 'int64'),
580 FieldDescriptor.TYPE_UINT32: ('uint32', 'int64'),
581 FieldDescriptor.TYPE_UINT64: ('uint64', 'uint64'),
582 FieldDescriptor.TYPE_MESSAGE: ('message', 'message'),
583 FieldDescriptor.TYPE_GROUP: ('group', 'group')
584}
585
586if __name__ == '__main__':
587 # Read request message from stdin
588 data = sys.stdin.read()
589
590 # Parse request
591 request = plugin.CodeGeneratorRequest()
592 request.ParseFromString(data)
593
594 # Create response
595 response = plugin.CodeGeneratorResponse()
596
597 # Generate code
598 generate_code(request, response)
599
600 # Serialise response message
601 output = response.SerializeToString()
602
603 # Write to stdout
604 sys.stdout.write(output)
Khen Nursimulubd24f552016-11-18 11:31:15 -0500605 # print is_base_type(9)