protoc-gen-json.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #!/opt/esp/python_env/idf4.4_py3.8_env/bin/python
  2. import os
  3. import logging
  4. import json
  5. from pathlib import Path
  6. from typing import Dict, List
  7. from google.protobuf.compiler import plugin_pb2 as plugin
  8. from google.protobuf.descriptor_pb2 import FileDescriptorProto, DescriptorProto, FieldDescriptorProto,FieldOptions
  9. from google.protobuf.descriptor import FieldDescriptor, Descriptor, FileDescriptor
  10. from ProtoElement import ProtoElement
  11. from ProtocParser import ProtocParser
  12. logger = logging.getLogger(__name__)
  13. logging.basicConfig(
  14. level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
  15. )
  16. class JsonParser(ProtocParser) :
  17. def start_message(self,message:ProtoElement) :
  18. super().start_message(message)
  19. def end_message(self,message:ProtoElement):
  20. super().end_message(message)
  21. jsonmessage = message.render()
  22. respfile = self.response.file.add()
  23. respfile.name = f'{message.fullname}_pb2.json'
  24. logger.info(f"Creating new template json file: {respfile.name}")
  25. respfile.content = json.dumps(jsonmessage, indent=2) + "\r\n"
  26. def start_file(self,file:FileDescriptor) :
  27. super().start_file(file)
  28. self.jsonmessages = {}
  29. def end_file(self,file:ProtoElement) :
  30. super().end_file(file)
  31. def get_name(self)->str:
  32. return 'protoc_plugin_json'
  33. def add_comment_if_exists(element, comment_type: str, path: str) -> dict:
  34. comment = getattr(element, f"{comment_type}_comment", "").strip()
  35. return {f"__{comment_type}_{path}": comment} if comment else {}
  36. def repeated_render(self,element:ProtoElement,obj:any):
  37. return [obj] if element.repeated else obj
  38. def render(self,element: ProtoElement) -> Dict:
  39. result = {}
  40. if len(element.childs)>0:
  41. oneof = getattr(element.descriptor,'containing_oneof',None)
  42. if oneof:
  43. result[f'__one_of_{element.name}'] = f'Choose only one structure for {oneof.full_name}'
  44. for child in element.childs:
  45. child_result = child.render()
  46. if len(child.childs) > 0:
  47. result[child.name] = child_result
  48. elif isinstance(child_result, dict):
  49. result.update(child_result)
  50. else:
  51. result.update({
  52. **({f'__comments_{element.name}': element.leading_comment} if element.leading_comment.strip() else {}),
  53. **({f'__values_{element.name}': element.enum_values_str} if element.is_enum else {}),
  54. element.name: element._default_value,
  55. **({f'__comments2_{element.name}': element.trailing_comment} if element.trailing_comment.strip() else {})
  56. })
  57. optnames = ['init_from_mac', 'const_prefix','read_only','default_value']
  58. if len(element.options)>0:
  59. logger.debug(f'{element.name} has options')
  60. for optname in [optname for optname in optnames if optname in element.options]:
  61. logger.debug(f"{element.name} [{optname} = {element.options[optname]}]")
  62. return self.repeated_render(element,result)
  63. if __name__ == '__main__':
  64. data = ProtocParser.get_data()
  65. logger.info(f"Generating blank json file(s)")
  66. protocParser:JsonParser = JsonParser(data)
  67. protocParser.process()
  68. logger.debug('Done generating JSON file(s)')