[asterisk-commits] mjordan: branch mjordan/manager-events r368091 - in /team/mjordan/manager-eve...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu May 31 16:40:42 CDT 2012


Author: mjordan
Date: Thu May 31 16:40:37 2012
New Revision: 368091

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=368091
Log:
Add infrastructure for documentation of manager events

Although the post_process_documentation.py script is a tad on the broken
side currently, this actually will parse out information from manager
events (app_dial) and put it all in the appropriate XML file.

TODO:
1. Finish up the post_process_documentation.py script
2. Update the DTD for validation
3. Place documentation blobs in front of the 1000 or so manager events
4. Steal underpants
5. ...
6. Profit

Added:
    team/mjordan/manager-events/
      - copied from r367982, trunk/
    team/mjordan/manager-events/build_tools/get_documentation.py   (with props)
    team/mjordan/manager-events/build_tools/post_process_documentation.py   (with props)
    team/mjordan/manager-events/configure.ac
      - copied, changed from r366351, trunk/configure.ac
Modified:
    team/mjordan/manager-events/Makefile
    team/mjordan/manager-events/apps/app_dial.c
    team/mjordan/manager-events/configure
    team/mjordan/manager-events/makeopts.in

Modified: team/mjordan/manager-events/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/manager-events/Makefile?view=diff&rev=368091&r1=367982&r2=368091
==============================================================================
--- team/mjordan/manager-events/Makefile (original)
+++ team/mjordan/manager-events/Makefile Thu May 31 16:40:37 2012
@@ -96,6 +96,7 @@
 export WGET_EXTRA_ARGS
 export LDCONFIG
 export LDCONFIG_FLAGS
+export PYTHON
 
 # even though we could use '-include makeopts' here, use a wildcard
 # lookup anyway, so that make won't try to build makeopts if it doesn't
@@ -314,12 +315,28 @@
 	@echo " +               $(mK) install               +"
 	@echo " +-------------------------------------------+"
 
+full: _cleantest_all_full
+	@echo " +--------- Asterisk Build Complete ---------+"
+	@echo " + Asterisk has successfully been built, and +"
+	@echo " + can be installed by running:              +"
+	@echo " +                                           +"
+	@echo " +               $(mK) install               +"
+	@echo " +-------------------------------------------+"
+
+
 # For parallel builds, we must call cleantest *before* running the
 # other dependencies on _all.
 _cleantest_all: cleantest
 	@$(MAKE) _all
 
+# For parallel builds, we must call cleantest *before* running the
+# other dependencies on _all.
+_cleantest_all_full: cleantest
+	@$(MAKE) _all_full
+
 _all: makeopts $(SUBDIRS) doc/core-en_US.xml $(ADDL_TARGETS)
+
+_all_full: makeopts $(SUBDIRS) doc/core-full-en_US.xml $(ADDL_TARGETS)
 
 makeopts: configure
 	@echo "****"
@@ -463,6 +480,34 @@
 	done
 	@echo
 	@echo "</docs>" >> $@
+
+doc/core-full-en_US.xml: $(foreach dir,$(MOD_SUBDIRS),$(shell $(GREP) -l "language=\"en_US\"" $(dir)/*.c $(dir)/*.cc 2>/dev/null))
+	@printf "Building Documentation For: "
+	@echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@
+	@echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@
+	@echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@
+	@for x in $(MOD_SUBDIRS); do \
+		printf "$$x " ; \
+		for i in $$x/*.c; do \
+			$(PYTHON) build_tools/get_documentation.py < $$i >> $@ ; \
+		done ; \
+	done
+	@echo
+	@echo "</docs>" >> $@
+	$(PYTHON) build_tools/post_process_documentation.py -i $@ -o "doc/core-en_US.xml"
+
+validate-docs-full: doc/core-full-en_US.xml
+ifeq ($(XMLSTARLET)$(XMLLINT),::)
+	@echo "--------------------------------------------------------------------------"
+	@echo "--- Please install xmllint or xmlstarlet to validate the documentation ---"
+	@echo "--------------------------------------------------------------------------"
+else
+  ifneq ($(XMLLINT),:)
+	$(XMLLINT) --dtdvalid doc/appdocsxml.dtd --noout $<
+  else
+	$(XMLSTARLET) val -d doc/appdocsxml.dtd $<
+  endif
+endif
 
 validate-docs: doc/core-en_US.xml
 ifeq ($(XMLSTARLET)$(XMLLINT),::)

Modified: team/mjordan/manager-events/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/manager-events/apps/app_dial.c?view=diff&rev=368091&r1=367982&r2=368091
==============================================================================
--- team/mjordan/manager-events/apps/app_dial.c (original)
+++ team/mjordan/manager-events/apps/app_dial.c Thu May 31 16:40:37 2012
@@ -823,6 +823,16 @@
 static void senddialevent(struct ast_channel *src, struct ast_channel *dst, const char *dialstring)
 {
 	struct ast_channel *chans[] = { src, dst };
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<reason>Called when a dial event is started.</reason>
+			<syntax>
+				<parameter name="SubEvent">
+					<para>The sub event</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
 	ast_manager_event_multichan(EVENT_FLAG_CALL, "Dial", 2, chans,
 		"SubEvent: Begin\r\n"
 		"Channel: %s\r\n"
@@ -845,6 +855,11 @@
 
 static void senddialendevent(struct ast_channel *src, const char *dialstatus)
 {
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<reason>Called when a dial event is ended.</reason>
+		</managerEventInstance>
+	***/
 	ast_manager_event(src, EVENT_FLAG_CALL, "Dial",
 		"SubEvent: End\r\n"
 		"Channel: %s\r\n"

Added: team/mjordan/manager-events/build_tools/get_documentation.py
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/manager-events/build_tools/get_documentation.py?view=auto&rev=368091
==============================================================================
--- team/mjordan/manager-events/build_tools/get_documentation.py (added)
+++ team/mjordan/manager-events/build_tools/get_documentation.py Thu May 31 16:40:37 2012
@@ -1,0 +1,145 @@
+#! /usr/bin/env python
+# vin: sw=3 et:
+'''
+Copyright (C) 2012, Digium, Inc.
+Matt Jordan <mjordan at digium.com>
+
+This program is free software, distributed under the terms of
+the GNU General Public License Version 2.
+'''
+
+import sys
+import os
+import xml.dom.minidom
+
+from xml.dom.minidom import Element
+
+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
+    '''
+
+    candidate_lines = []
+    type = ""
+
+    # Read the manager_event method call, which should occur after
+    # the documentation block
+    while (True):
+        line = sys.stdin.readline()
+        line = line.strip()
+        candidate_lines.append(line)
+        if ");" in line:
+            break;
+
+    candidate_string = ''.join(candidate_lines)
+    if "ast_manager_event_multichan" in candidate_string:
+        type = "multichan"
+    elif "ast_manager_event" in candidate_string:
+        type = "ast_manager_event"
+    elif "manager_event" in candidate_string:
+        type = "manager_event"
+    else:
+        # Unknown, return what we have
+        return ''.join(xml_fragment)
+
+    # strip off the macro name
+    candidate_string = candidate_string[candidate_string.index("(",0) + 1:candidate_string.rindex(");")]
+    # 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
+    xml_fragment.insert(0, "<managerEvent name=\"%s\">" % event_type.strip().replace("\"",""))
+    xml_fragment[1] = "<managerEventInstance class=\"%s\">" % (class_level)
+    xml_fragment.insert(len(xml_fragment), "</managerEvent>")
+
+    dom = xml.dom.minidom.parseString(''.join(xml_fragment))
+
+    instance = dom.getElementsByTagName("managerEventInstance")[0]
+    syntax = instance.getElementsByTagName("syntax")
+    if not syntax:
+        syntax = dom.createElement("syntax")
+        instance.appendChild(syntax)
+    else:
+        syntax = syntax[0]
+
+    # Add parameters found in the method invocation that were not previously
+    # documented
+    for parameter in parameter_tokens:
+        if not parameter:
+            continue
+        parameter = (parameter.strip().replace("\"",""))[:parameter.index(":")]
+        if not any([node for node in syntax.getElementsByTagName("parameter") if
+                any([attr for attr in node.attributes.items() if attr[1] == parameter])]):
+            e = dom.createElement("parameter")
+            e.setAttribute('name', parameter)
+            syntax.appendChild(e)
+
+    return dom.toprettyxml().replace("<?xml version=\"1.0\" ?>", "")
+
+def main(argv=None):
+
+    if argv is None:
+        argv = sys.argv
+
+    in_doc = False
+    xml_fragment = []
+    xml = []
+    line_number = 0
+
+    while(True):
+        # Note: multiple places may have to read a line, so iterating over
+        # readlines isn't possible.  Break when a null line is returned
+        line = sys.stdin.readline()
+        line_number += 1
+        if not line:
+            break
+
+        line = line.strip()
+        if ("/*** DOCUMENTATION" in line):
+            in_doc = True
+        elif ("***/" in line and in_doc == True):
+            # 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
+            try:
+                if "<managerEventInstance>" in xml_fragment[0]:
+                    xml.append(parse_manager_event_instance(xml_fragment))
+                else:
+                    xml.append(''.join(xml_fragment))
+                xml_fragment = []
+            except:
+                print "Failed to parse XML near line: %d" % line_number
+                return 1
+        elif (in_doc == True):
+            xml_fragment.append("%s\n" % line)
+
+    sys.stdout.write(''.join(xml))
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main() or 0)

Propchange: team/mjordan/manager-events/build_tools/get_documentation.py
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mjordan/manager-events/build_tools/get_documentation.py
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mjordan/manager-events/build_tools/get_documentation.py
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/mjordan/manager-events/build_tools/post_process_documentation.py
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/manager-events/build_tools/post_process_documentation.py?view=auto&rev=368091
==============================================================================
--- team/mjordan/manager-events/build_tools/post_process_documentation.py (added)
+++ team/mjordan/manager-events/build_tools/post_process_documentation.py Thu May 31 16:40:37 2012
@@ -1,0 +1,85 @@
+#! /usr/bin/env python
+# vin: sw=3 et:
+'''
+Copyright (C) 2012, Digium, Inc.
+Matt Jordan <mjordan at digium.com>
+
+This program is free software, distributed under the terms of
+the GNU General Public License Version 2.
+'''
+
+import sys
+import os
+import xml.dom.minidom
+
+from xml.dom.minidom import Element, parse
+
+def merge_parameter_information(managerEvent):
+    instances = managerEvent.getElementsByTagName("managerEventInstance")
+    merged = []
+    for instance in instances:
+        others = [i for i in instances if i != instance]
+        parameters = instance.getElementsByTagName("parameter")
+        for parameter in parameters:
+            if parameter not in merged:
+                # Once we process a parameter, we don't need to do it again for any other
+                # managerEventInstances
+                merged.append(parameter)
+                # Compare the parameter to every other managerEventInstance's set of parameters
+                for other in others:
+                    other_parameters = other.getElementsByTagName("parameter")
+                    match = [p for p in other_parameters if p.getAttribute('name') == parameter.getAttribute('name')]
+                    if (match):
+                        # See who has the better documentation and use it, 
+                        if (parameter.hasChildNodes()):
+                            match[0].parentNode.replaceChild(parameter.cloneNode(True), match[0])
+                        elif (match[0].hasChildNodes()):
+                            parameter.parentNode.replaceChild(match[0].cloneNode(True), parameter)
+
+def collapse_event_pair(managerEventOne, managerEventTwo):
+    # Move all children of managerEventTwo to managerEventOne
+    for node in managerEventTwo.childNodes:
+        managerEventOne.appendChild(node.cloneNode(True))
+
+    return managerEventOne
+
+def collapse_manager_events(rootNode, managerEvents):
+
+    events = {}
+    for managerEvent in managerEvents:
+        rootNode.removeChild(managerEvent)
+        attr = managerEvent.getAttribute('name')
+        if attr in events:
+            # match, collapse the two managerEvents
+            events[attr] = collapse_event_pair(events[attr], managerEvent)
+        else:
+            events[attr] = managerEvent
+
+    # Combine parameter information and re-add the manager Events
+    for k, event in events.items():
+        merge_parameter_information(event)
+        rootNode.appendChild(event)
+    return
+
+def main(argv=None):
+
+    if argv is None:
+        argv = sys.argv
+
+    
+
+    dom = parse(inputFile)
+
+    datasource = open("doc/core-en_US.xml", 'w')
+    docs = dom.getElementsByTagName("docs")[0]
+    managerEvents = dom.getElementsByTagName("managerEvent")
+    if (managerEvents):
+        collapse_manager_events(docs, managerEvents)
+
+    dom.writexml(datasource)
+    datasource.close()
+
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main() or 0)

Propchange: team/mjordan/manager-events/build_tools/post_process_documentation.py
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mjordan/manager-events/build_tools/post_process_documentation.py
------------------------------------------------------------------------------
    svn:executable = *

Propchange: team/mjordan/manager-events/build_tools/post_process_documentation.py
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mjordan/manager-events/build_tools/post_process_documentation.py
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: team/mjordan/manager-events/configure.ac (from r366351, trunk/configure.ac)
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/manager-events/configure.ac?view=diff&rev=368091&p1=trunk/configure.ac&r1=366351&p2=team/mjordan/manager-events/configure.ac&r2=368091
==============================================================================
--- trunk/configure.ac (original)
+++ team/mjordan/manager-events/configure.ac Thu May 31 16:40:37 2012
@@ -247,6 +247,7 @@
 AC_PATH_PROG([CMP], [cmp], :)
 AC_PATH_PROG([FLEX], [flex], :)
 AC_PATH_PROG([GREP], [grep], :)
+AC_PATH_PROG([PYTHON], [python], :)
 AC_PATH_PROG([FIND], [find], :)
 AC_PATH_PROG([COMPRESS], [compress], :)
 AC_PATH_PROG([BASENAME], [basename], :)

Modified: team/mjordan/manager-events/makeopts.in
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/manager-events/makeopts.in?view=diff&rev=368091&r1=367982&r2=368091
==============================================================================
--- team/mjordan/manager-events/makeopts.in (original)
+++ team/mjordan/manager-events/makeopts.in Thu May 31 16:40:37 2012
@@ -12,6 +12,7 @@
 BISON=@BISON@
 FLEX=@FLEX@
 GREP=@GREP@
+PYTHON=@PYTHON@
 MAKE=@GNU_MAKE@
 AR=@AR@
 RANLIB=@RANLIB@




More information about the asterisk-commits mailing list