Merge from trunk
[plcapi.git] / doc / DocBook.py
1 #!/usr/bin/python
2 #
3 # Generates a DocBook section documenting all PLCAPI methods on
4 # stdout.
5 #
6 # Mark Huang <mlhuang@cs.princeton.edu>
7 # Copyright (C) 2006 The Trustees of Princeton University
8 #
9 # $Id$
10 #
11
12 import xml.dom.minidom
13 from xml.dom.minidom import Element, Text
14 import codecs
15
16 from PLC.Method import *
17 import DocBookLocal
18 import groups
19
20 # xml.dom.minidom.Text.writexml adds surrounding whitespace to textual
21 # data when pretty-printing. Override this behavior.
22 class TrimText(Text):
23     """text"""
24     def __init__(self, text = None):
25         self.data = unicode(text)
26
27     def writexml(self, writer, indent="", addindent="", newl=""):
28         Text.writexml(self, writer, "", "", "")
29
30 class TrimTextElement(Element):
31     """<tagName>text</tagName>"""
32     def __init__(self, tagName, text = None):
33         Element.__init__(self, tagName)
34         if text is not None:
35             self.appendChild(TrimText(text))
36
37     def writexml(self, writer, indent="", addindent="", newl=""):
38         writer.write(indent)
39         Element.writexml(self, writer, "", "", "")
40         writer.write(newl)
41
42 class simpleElement(TrimTextElement): pass
43
44 class paraElement(simpleElement):
45     """<para>text</para>"""
46     def __init__(self, text = None):
47         simpleElement.__init__(self, 'para', text)
48
49 class blockquoteElement(Element):
50     """<blockquote><para>text...</para><para>...text</para></blockquote>"""
51     def __init__(self, text = None):
52         Element.__init__(self, 'blockquote')
53         if text is not None:
54             # Split on blank lines
55             lines = [line.strip() for line in text.strip().split("\n")]
56             lines = "\n".join(lines)
57             paragraphs = lines.split("\n\n")
58
59             for paragraph in paragraphs:
60                 self.appendChild(paraElement(paragraph))
61
62 def param_type(param):
63     """Return the XML-RPC type of a parameter."""
64     if isinstance(param, Mixed) and len(param):
65         subtypes = [param_type(subparam) for subparam in param]
66         return " or ".join(subtypes)
67     elif isinstance(param, (list, tuple, set)) and len(param):
68         return "array of " + " or ".join([param_type(subparam) for subparam in param])
69     else:
70         return xmlrpc_type(python_type(param))
71
72 class paramElement(Element):
73     """An optionally named parameter."""
74     def __init__(self, name, param):
75         # <listitem>
76         Element.__init__(self, 'listitem')
77
78         description = Element('para')
79
80         if name:
81             description.appendChild(simpleElement('parameter', name))
82             description.appendChild(TrimText(": "))
83
84         description.appendChild(TrimText(param_type(param)))
85
86         if isinstance(param, (list, tuple, set)) and len(param) == 1:
87             param = param[0]
88
89         if isinstance(param, Parameter):
90             description.appendChild(TrimText(", " + param.doc))
91             param = param.type
92
93         self.appendChild(description)
94
95         if isinstance(param, dict):
96             itemizedlist = Element('itemizedlist')
97             self.appendChild(itemizedlist)
98             for name, subparam in param.iteritems():
99                 itemizedlist.appendChild(paramElement(name, subparam))
100
101         elif isinstance(param, (list, tuple, set)) and len(param):
102             itemizedlist = Element('itemizedlist')
103             self.appendChild(itemizedlist)
104             for subparam in param:
105                 itemizedlist.appendChild(paramElement(None, subparam))
106
107
108 def get_method_doc(func):
109
110     method = func.name
111
112     if func.status == "deprecated":
113         return
114
115     (min_args, max_args, defaults) = func.args()
116
117     section = Element('section')
118     section.setAttribute('id', func.name)
119     section.appendChild(simpleElement('title', func.name))
120
121     prototype = "%s (%s)" % (method, ", ".join(max_args))
122     para = paraElement('Prototype:')
123     para.appendChild(blockquoteElement(prototype))
124     section.appendChild(para)
125
126     para = paraElement('Description:')
127     para.appendChild(blockquoteElement(func.__doc__))
128     section.appendChild(para)
129
130     para = paraElement('Allowed Roles:')
131     para.appendChild(blockquoteElement(", ".join(func.roles)))
132     section.appendChild(para)
133
134     section.appendChild(paraElement('Parameters:'))
135     params = Element('itemizedlist')
136     if func.accepts:
137         for name, param, default in zip(max_args, func.accepts, defaults):
138             params.appendChild(paramElement(name, param))
139     else:
140         listitem = Element('listitem')
141         listitem.appendChild(paraElement('None'))
142         params.appendChild(listitem)
143     section.appendChild(params)
144
145     section.appendChild(paraElement('Returns:'))
146     returns = Element('itemizedlist')
147     returns.appendChild(paramElement(None, func.returns))
148     section.appendChild(returns)
149
150     #print section.toprettyxml(encoding = "UTF-8")
151     return section
152
153
154 def get_section(fields, field_list = None):
155     if not field_list:
156         field_list = fields.keys()
157         field_list.sort()
158
159     for field in field_list:
160         value = fields[field]
161         section = Element('section')
162         section.setAttribute('id', field.title())
163         section.appendChild(simpleElement('title', field.title()))
164         # if list of methods, append method docs
165         # else if dict, make a new section group
166         if isinstance(value, dict):
167             section.appendChild(get_section(value))
168         elif isinstance(value, list):
169             methods = DocBookLocal.get_func_list(value)
170             for method in methods:
171                 method_doc = get_method_doc(method)
172                 section.appendChild(method_doc)               
173
174     return section
175         
176 # write full list of methods to Methods.xml
177 #api_func_list = DocBookLocal.get_func_list()
178 #methods_xml = file('Methods.xml',  'w')
179 #for func in api_func_list:
180 #    section = get_method_doc(func)
181 #    if section:                
182 #        methods_xml.write(section)
183 #methods_xml.close()
184
185 # write methods grouped into interfaces
186 interfaces = ['Registry_Interface', 'Management_Interface', 'Slice_Interface']
187 for interface in interfaces:
188     interface_file = file(interface+'.xml', 'w')
189     interface_methods = groups.interfaces[interface]
190     section =  get_section(interface_methods, ['public', 'admin'])
191     if section:    
192         interface_file.write(section.toprettyxml(encoding = "UTF-8"))
193     interface_file.close()      
194         
195         
196
197         
198                 
199