asterisk/build_tools/get_documentation.py

173 lines
5.7 KiB
Python

#! /usr/bin/env python
# vin: sw=3 et:
'''
Copyright (C) 2012, Digium, Inc.
Matt Jordan <mjordan@digium.com>
This program is free software, distributed under the terms of
the GNU General Public License Version 2.
'''
import sys
import xml.dom.minidom
def get_manager_event_method_type(candidate_string):
if "ast_manager_event_multichan" in candidate_string:
return "multichan"
elif "ast_manager_event" in candidate_string:
return "ast_manager_event"
elif "manager_event" in candidate_string:
return "manager_event"
return ""
def parse_manager_event_instance(xml_fragment):
''' Parse the information for a manager event
Keyword Arguments:
xml_fragment The XML fragment comment
Returns:
A well-formed XML fragment containing the comments passed in, as well as
information obtained from the manager_event macro calls
'''
def __node_contains_parameter(node, parameter):
''' Return whether or not a node contains a given parameter name '''
return any([n for n in node.getElementsByTagName("parameter")
if __node_contains_attribute(n, parameter)])
def __node_contains_attribute(node, attribute_name):
''' Return whether or not a node contains a given attribute name '''
return any([attr for attr in node.attributes.items()
if attr[1] == attribute_name])
candidate_lines = []
type = ""
# Read the manager_event method call, which should occur after
# the documentation block
for line in sys.stdin:
if len(line):
candidate_lines.append(line)
if ");" in line:
break
candidate_string = ''.join(candidate_lines)
type = get_manager_event_method_type(candidate_string)
if not type:
# Unknown, return what we have
return ''.join(xml_fragment)
# strip off the macro name
first_paren = candidate_string.index("(", 0)
last_paren = candidate_string.rindex(");")
candidate_string = candidate_string[first_paren + 1:last_paren]
# split into parameter tokens
func_parameter_tokens = candidate_string.split(',')
if type == "manager_event" or type == "multichan":
class_level = func_parameter_tokens[0].strip()
event_type = func_parameter_tokens[1].strip()
else:
class_level = func_parameter_tokens[1].strip()
event_type = func_parameter_tokens[2].strip()
if type == "manager_event":
event_parameters = func_parameter_tokens[2].strip()
elif type == "ast_manager_event":
event_parameters = func_parameter_tokens[3].strip()
else:
event_parameters = func_parameter_tokens[4].strip()
parameter_tokens = event_parameters.replace("\"", "").split('\\r\\n')
# Build the top level XML element information. Note that we temporarily
# add the xi namespace in case any includes are used
node_text = '<managerEvent language=\"%s\" name=\"%s\" xmlns:xi=\"%s\">'
xml_fragment.insert(0, node_text % ('en_US',
event_type.strip().replace("\"", ""),
'http://www.w3.org/2001/XInclude'))
xml_fragment[1] = "<managerEventInstance class=\"%s\">" % (class_level)
xml_fragment.insert(len(xml_fragment), "</managerEvent>")
# Turn the XML into a DOM to manage the rest of the node manipulations
dom = xml.dom.minidom.parseString(''.join(xml_fragment))
# Get the syntax node if we have one; otherwise make one
instance = dom.getElementsByTagName("managerEventInstance")[0]
syntax = instance.getElementsByTagName("syntax")
if not syntax:
syntax = dom.createElement("syntax")
instance.appendChild(syntax)
# Move any existing parameter nodes over
for node in instance.getElementsByTagName("parameter"):
syntax.appendChild(node.cloneNode(True))
instance.removeChild(node)
else:
syntax = syntax[0]
# Add parameters found in the method invocation that were not previously
# documented
for parameter in parameter_tokens:
if not len(parameter):
continue
index = parameter.find(':')
if index < 0:
index = len(parameter)
parameter = (parameter[:index].strip().replace("\"", ""))
if ('%s' not in parameter and
not __node_contains_parameter(syntax, parameter)):
e = dom.createElement("parameter")
e.setAttribute('name', parameter)
syntax.appendChild(e)
return dom.toxml().replace("<?xml version=\"1.0\" ?>", "").replace(
'xmlns:xi="http://www.w3.org/2001/XInclude"', '')
def main(argv=None):
if argv is None:
argv = sys.argv
in_doc = False
xml_fragment = []
xml = []
line_number = 0
for line in sys.stdin:
# Note: multiple places may have to read a line, so iterating over
# readlines isn't possible. Break when a null line is returned
line_number += 1
if not line:
break
line = line.strip()
if ("/*** DOCUMENTATION" in line):
in_doc = True
elif ("***/" in line and in_doc):
# Depending on what we're processing, determine if we need to do
# any additional work
in_doc = False
if not xml_fragment:
# Nothing read, move along
continue
if "<managerEventInstance>" in xml_fragment[0]:
xml.append(parse_manager_event_instance(xml_fragment))
else:
xml.append(''.join(xml_fragment))
xml_fragment = []
elif (in_doc):
xml_fragment.append("%s\n" % line)
sys.stdout.write(''.join(xml))
return 0
if __name__ == "__main__":
sys.exit(main() or 0)