get_documentation.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #! /usr/bin/env python
  2. # vin: sw=3 et:
  3. '''
  4. Copyright (C) 2012, Digium, Inc.
  5. Matt Jordan <mjordan@digium.com>
  6. This program is free software, distributed under the terms of
  7. the GNU General Public License Version 2.
  8. '''
  9. import sys
  10. import os
  11. import xml.dom.minidom
  12. from xml.dom.minidom import Element
  13. def get_manager_event_method_type(candidate_string):
  14. if "ast_manager_event_multichan" in candidate_string:
  15. return "multichan"
  16. elif "ast_manager_event" in candidate_string:
  17. return "ast_manager_event"
  18. elif "manager_event" in candidate_string:
  19. return "manager_event"
  20. return ""
  21. def parse_manager_event_instance(xml_fragment):
  22. ''' Parse the information for a manager event
  23. Keyword Arguments:
  24. xml_fragment The XML fragment comment
  25. Returns:
  26. A well-formed XML fragment containing the comments passed in, as well as
  27. information obtained from the manager_event macro calls
  28. '''
  29. def __node_contains_parameter(node, parameter):
  30. ''' Return whether or not a node contains a given parameter name '''
  31. return any([n for n in node.getElementsByTagName("parameter")
  32. if __node_contains_attribute(n, parameter)])
  33. def __node_contains_attribute(node, attribute_name):
  34. ''' Return whether or not a node contains a given attribute name '''
  35. return any([attr for attr in node.attributes.items()
  36. if attr[1] == attribute_name])
  37. candidate_lines = []
  38. type = ""
  39. # Read the manager_event method call, which should occur after
  40. # the documentation block
  41. for line in sys.stdin:
  42. if len(line):
  43. candidate_lines.append(line)
  44. if ");" in line:
  45. break
  46. candidate_string = ''.join(candidate_lines)
  47. type = get_manager_event_method_type(candidate_string)
  48. if not type:
  49. # Unknown, return what we have
  50. return ''.join(xml_fragment)
  51. # strip off the macro name
  52. first_paren = candidate_string.index("(", 0)
  53. last_paren = candidate_string.rindex(");")
  54. candidate_string = candidate_string[first_paren + 1:last_paren]
  55. # split into parameter tokens
  56. func_parameter_tokens = candidate_string.split(',')
  57. if type == "manager_event" or type == "multichan":
  58. class_level = func_parameter_tokens[0].strip()
  59. event_type = func_parameter_tokens[1].strip()
  60. else:
  61. class_level = func_parameter_tokens[1].strip()
  62. event_type = func_parameter_tokens[2].strip()
  63. if type == "manager_event":
  64. event_parameters = func_parameter_tokens[2].strip()
  65. elif type == "ast_manager_event":
  66. event_parameters = func_parameter_tokens[3].strip()
  67. else:
  68. event_parameters = func_parameter_tokens[4].strip()
  69. parameter_tokens = event_parameters.replace("\"", "").split('\\r\\n')
  70. # Build the top level XML element information. Note that we temporarily
  71. # add the xi namespace in case any includes are used
  72. node_text = '<managerEvent language=\"%s\" name=\"%s\" xmlns:xi=\"%s\">'
  73. xml_fragment.insert(0, node_text % ('en_US',
  74. event_type.strip().replace("\"", ""),
  75. 'http://www.w3.org/2001/XInclude'))
  76. xml_fragment[1] = "<managerEventInstance class=\"%s\">" % (class_level)
  77. xml_fragment.insert(len(xml_fragment), "</managerEvent>")
  78. # Turn the XML into a DOM to manage the rest of the node manipulations
  79. dom = xml.dom.minidom.parseString(''.join(xml_fragment))
  80. # Get the syntax node if we have one; otherwise make one
  81. instance = dom.getElementsByTagName("managerEventInstance")[0]
  82. syntax = instance.getElementsByTagName("syntax")
  83. if not syntax:
  84. syntax = dom.createElement("syntax")
  85. instance.appendChild(syntax)
  86. # Move any existing parameter nodes over
  87. for node in instance.getElementsByTagName("parameter"):
  88. syntax.appendChild(node.cloneNode(True))
  89. instance.removeChild(node)
  90. else:
  91. syntax = syntax[0]
  92. # Add parameters found in the method invocation that were not previously
  93. # documented
  94. for parameter in parameter_tokens:
  95. if not len(parameter):
  96. continue
  97. index = parameter.find(':')
  98. if index < 0:
  99. index = len(parameter)
  100. parameter = (parameter[:index].strip().replace("\"", ""))
  101. if ('%s' not in parameter and
  102. not __node_contains_parameter(syntax, parameter)):
  103. e = dom.createElement("parameter")
  104. e.setAttribute('name', parameter)
  105. syntax.appendChild(e)
  106. return dom.toxml().replace("<?xml version=\"1.0\" ?>", "").replace(
  107. 'xmlns:xi="http://www.w3.org/2001/XInclude"', '')
  108. def main(argv=None):
  109. if argv is None:
  110. argv = sys.argv
  111. in_doc = False
  112. xml_fragment = []
  113. xml = []
  114. line_number = 0
  115. for line in sys.stdin:
  116. # Note: multiple places may have to read a line, so iterating over
  117. # readlines isn't possible. Break when a null line is returned
  118. line_number += 1
  119. if not line:
  120. break
  121. line = line.strip()
  122. if ("/*** DOCUMENTATION" in line):
  123. in_doc = True
  124. elif ("***/" in line and in_doc):
  125. # Depending on what we're processing, determine if we need to do
  126. # any additional work
  127. in_doc = False
  128. if not xml_fragment:
  129. # Nothing read, move along
  130. continue
  131. if "<managerEventInstance>" in xml_fragment[0]:
  132. xml.append(parse_manager_event_instance(xml_fragment))
  133. else:
  134. xml.append(''.join(xml_fragment))
  135. xml_fragment = []
  136. elif (in_doc):
  137. xml_fragment.append("%s\n" % line)
  138. sys.stdout.write(''.join(xml))
  139. return 0
  140. if __name__ == "__main__":
  141. sys.exit(main() or 0)