summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorRadek Novacek <rnovacek@redhat.com>2013-03-18 09:52:42 +0100
committerRadek Novacek <rnovacek@redhat.com>2013-03-18 09:52:42 +0100
commitb5e14dcdb73d3b70131b9a602efd209488922a4e (patch)
tree0a863922e2987f881d25efd02ca481614f218cb6 /tools
parente34b7108248ee50c3effbd76bdb030aec69a8adb (diff)
downloadopenlmi-providers-b5e14dcdb73d3b70131b9a602efd209488922a4e.tar.gz
openlmi-providers-b5e14dcdb73d3b70131b9a602efd209488922a4e.tar.xz
openlmi-providers-b5e14dcdb73d3b70131b9a602efd209488922a4e.zip
tools: don't use CIMOM for generating documentation
class2rst.py and class2uml.py was altered to use konkretmof for parsing MOFs instead of calling CIMOM. This two modules was also renamed to openlmi-doc-class2* and will be installed to $prefix/bin.
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt3
-rwxr-xr-xtools/class2uml.py219
-rw-r--r--[-rwxr-xr-x]tools/openlmi-doc-class2rst (renamed from tools/class2rst.py)371
-rw-r--r--tools/openlmi-doc-class2uml143
4 files changed, 337 insertions, 399 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000..04d11b7
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,3 @@
+
+install(PROGRAMS openlmi-doc-class2rst openlmi-doc-class2uml DESTINATION bin)
+
diff --git a/tools/class2uml.py b/tools/class2uml.py
deleted file mode 100755
index e5e6ea4..0000000
--- a/tools/class2uml.py
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (C) 2012-2013 Red Hat, Inc. All rights reserved.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-# Authors: Jan Safranek <jsafrane@redhat.com>
-#
-
-import os;
-import pywbem;
-import optparse
-import re
-import cgi
-import sys
-
-class UmlExporter(object):
-
- def __init__(self, cliconn):
- self.classcache = {}
- self.cliconn = cliconn
- # original list of classes
- self.classes = set()
- self.file = sys.stdout
-
- def load_class(self, classname):
- if classname in self.classcache:
- return self.classcache[classname]
-
- c = self.cliconn.GetClass(classname)
- self.classcache[classname] = c
- return c
-
- def display_type(self, param):
- """
- Return displayable type of given parameter.
- It adds [] if it's array and class name of referenced classes.
- """
- if param.reference_class:
- ptype = param.reference_class
- else:
- ptype = param.type
- if param.is_array:
- ptype = ptype + "[]"
- return ptype
-
- def print_parameters(self, params):
- """
- Print table of method parametes.
- """
- if not params:
- print >>self.file, "None"
- return
-
- print >>self.file, "<table class=\"parameters\">"
- for p in params.values():
- direction = set()
- if p.qualifiers.has_key("Out"):
- direction.add("OUT")
- if p.qualifiers.has_key("In"):
- direction.add("IN")
- if not direction:
- direction.add("IN")
- direction = "/".join(sorted(direction))
-
- print >>self.file, "<tr>"
- print >>self.file, "<td>%s</td><td>%s</td><td><b>%s</b></td>" % (direction, self.display_type(p), p.name)
- print >>self.file, "<td><table class=\"qualifiers\">"
- self.print_qualifiers(p.qualifiers.values())
- print >>self.file, "</table></td>"
- print >>self.file, "</tr>"
- print >>self.file, "</table>"
-
- def print_qualifiers(self, qualifiers):
- """
- Print contenf of table of qualifiers.
- Only Deprecated, Description, Values and ValueMap are recognized.
- """
- deprecated = ""
- for q in sorted(qualifiers):
- if q.name == "Deprecated":
- deprecated = "<div class=\"deprecated\">DEPRECATED</div> "
- if q.name == "Description":
- print >>self.file, "<tr><td class=\"qualifiers\" colspan=\"2\">%s%s</td></tr>" % (deprecated, self.escape(q.value))
- if q.name == "Values":
- print >>self.file, "<tr><td class=\"qualifiers\"><b>Values</b></td> <td class=\"qualifiers\"><table><tr><td class=\"qualifiers\">%s</td></tr></table></td></tr>" % ("</td></tr><tr><td class=\"qualifiers\">".join(q.value))
- if q.name == "ValueMap":
- print >>self.file, "<tr><td class=\"qualifiers\"><b>ValueMap</b></td> <td class=\"qualifiers\"><table><tr><td class=\"qualifiers\">%s</td></tr></table></td></tr>" % ("</td></tr><tr><td class=\"qualifiers\">".join(q.value))
-
- def compare_properties(self, p1, p2):
- """
- Compare two properties if they should printed in Inherited properties.
- Only Name, Description and Implemented are checked.
- Returns False, if the property should be printed in Local.
- """
- if p1.name != p2.name:
- return False
- d1 = p1.qualifiers.get("Description", None)
- d2 = p2.qualifiers.get("Description", None)
- if d1.value != d2.value:
- return False
- i1 = p1.qualifiers.get("Implemented", None)
- i2 = p2.qualifiers.get("Implemented", None)
- if i1 and i1.value and not (i2 and i2.value):
- return False
- return True
-
- def print_class(self, c, display_local = True, box_only = False):
- """
- Print one class, inc. header.
- """
- parent = None
- if c.superclass:
- parent = self.load_class(c.superclass)
-
- if c.superclass:
- # draw arrow to parent
- print >>self.file, "%s -down-|> %s" % (c.classname, c.superclass)
-
- if box_only:
- self.file.write("class %s\n\n" % c.classname)
- return
-
- local_props = []
- for name in sorted(c.properties.keys()):
- if parent and parent.properties.has_key(name):
- if not self.compare_properties(c.properties[name], parent.properties[name]):
- # the property was overridden
- local_props.append(c.properties[name])
- else:
- local_props.append(c.properties[name])
-
- local_methods = []
- for name in sorted(c.methods.keys()):
- if parent and parent.methods.has_key(name):
- if not self.compare_properties(c.methods[name], parent.methods[name]):
- # the property was overridden
- local_methods.append(c.methods[name])
- else:
- local_methods.append(c.methods[name])
- self.file.write("class %s {\n" % c.classname)
-
- if display_local:
- for prop in local_props:
- self.file.write(" %s %s\n" % (self.display_type(prop), prop.name))
-
-
- if local_methods:
- for m in local_methods:
- self.file.write(" %s()\n" % (m.name))
-
- self.file.write("}\n")
- self.file.write("url of %s is [[%s.html]]\n" % (c.classname, c.classname))
-
- def add_class(self, classname):
- self.classes.add(classname)
-
- def export(self, shrink, noassoc = False):
- """
- Print all classes and their parents.
- """
- print >>self.file, "@startuml"
- while self.classes:
- c = self.classes.pop()
-
- cl = self.load_class(c)
- if noassoc and cl.qualifiers.get("Association", False):
- continue
-
- if shrink and shrink.match(c):
-
- self.print_class(cl, box_only = True)
- else:
- self.print_class(cl)
-
- print >>self.file, "@enduml"
-
-description = """
-Generate UML image for given classes. The tool connects to specified CIMOM
-and reads class definition from there. Each class specified on command line
-will be drawn as one box, containing locally defined or re-defined properties
-and methods. Inheritance will be shown as arrow between a parent class and a
-subclass.
-
-The generated file can be coverted to a picture by PlantUML tool.
-"""
-
-parser = optparse.OptionParser(usage="usage: %prog [options] classname [classname ...]", description=description)
-parser.add_option('-u', '--url', action='store', dest='addr', default='https://localhost:5989', help='URL of CIM server, default: https://localhost:5989')
-parser.add_option('-U', '--user', action='store', dest='user', default=None, help='CIM user name')
-parser.add_option('-s', '--shrink', action='store', dest='shrink', default=None, help='Regular expression pattern of CIM classes, which will be drawn only as boxes, without properties.')
-parser.add_option('-A', '--no-associations', action='store_true', dest='noassoc', default=False, help='Skip association classes.')
-parser.add_option('-P', '--password', action='store', dest='password', default=None, help='CIM password')
-(options, args) = parser.parse_args()
-
-sys.stdout.softspace=0
-
-shrink = None
-if options.shrink:
- shrink = re.compile(options.shrink)
-
-cliconn = pywbem.WBEMConnection(options.addr, (options.user, options.password))
-exporter = UmlExporter(cliconn)
-for c in args:
- exporter.add_class(c)
-exporter.export(shrink = shrink, noassoc = options.noassoc)
-
diff --git a/tools/class2rst.py b/tools/openlmi-doc-class2rst
index 12342f6..34d847d 100755..100644
--- a/tools/class2rst.py
+++ b/tools/openlmi-doc-class2rst
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright (C) 2012-2013 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -17,24 +17,24 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Authors: Jan Safranek <jsafrane@redhat.com>
+# Radek Novacek <rnovacek@redhat.com>
#
-import os;
-import pywbem;
+import os
+import konkretmof
import optparse
import re
import cgi
import sys
class HtmlExporter(object):
-
- def __init__(self, cliconn):
+
+ def __init__(self):
self.classcache = {}
- self.cliconn = cliconn
# original list of classes
self.classes = []
- # set of all classes to print, i.e. incl. all parents
- self.queue = set()
+ # list of all classes to print, i.e. incl. all parents
+ self.queue = []
self.file = None
def link(self, classname, attributename = ""):
@@ -42,23 +42,15 @@ class HtmlExporter(object):
link = classname + "-" + attributename
else:
link = classname
- link = link.replace("_","-")
+ link = str(link).replace("_","-")
return link
-
+
def print_escaped(self, string, prefix = ""):
# replace \n with prefixes
- lines = string.split("\\n")
+ lines = string.split("\n")
for line in lines:
print >>self.file, prefix + line
print >>self.file, ""
-
- def load_class(self, classname):
- if classname in self.classcache:
- return self.classcache[classname]
-
- c = self.cliconn.GetClass(classname)
- self.classcache[classname] = c
- return c
def source_class(self, c, param):
"""
@@ -67,21 +59,20 @@ class HtmlExporter(object):
"""
while True:
-
- if isinstance(param, pywbem.CIMMethod):
- if not c.methods.has_key(param.name):
+ if isinstance(param, konkretmof.MOF_Method_Decl):
+ if not c.methods().has_key(param.name):
break
else:
- if not c.properties.has_key(param.name):
+ if not c.properties().has_key(param.name):
break
- if not c.superclass:
+ if not c.super_class:
# we're at the top class
- return c.classname
-
+ return c.name
+
parent = c
- c = self.load_class(c.superclass)
- return parent.classname
+ c = c.super_class
+ return parent.name
def display_type(self, param):
"""
@@ -89,12 +80,17 @@ class HtmlExporter(object):
It adds [] if it's array and class name of referenced classes.
"""
url = False
- if param.reference_class:
- ptype = param.reference_class
+ if isinstance(param, konkretmof.MOF_Reference_Decl):
+ ptype = param.class_name
+ url = True
+ elif isinstance(param, konkretmof.MOF_Parameter) and (param.data_type == konkretmof.TOK_REF):
+ ptype = param.ref_name
+ self.add_class(param.ref_name)
url = True
else:
- ptype = param.type
- if param.is_array:
+ ptype = param.type_name()
+
+ if isinstance(param, (konkretmof.MOF_Property_Decl, konkretmof.MOF_Parameter)) and param.array_index != 0:
ptype = ptype + "[]"
if url:
ptype = ":ref:`%s <%s>`" % (ptype, self.link(ptype))
@@ -111,33 +107,34 @@ class HtmlExporter(object):
print >>self.file, "*None*"
return
- for p in params.values():
+ for p in params:
param_indent = " "*8
direction = set()
- if p.qualifiers.has_key("Out"):
+ if p.qualifiers.has_key("out"):
direction.add("*OUT*")
- if p.qualifiers.has_key("In"):
- if p.qualifiers["In"].value:
+ if p.qualifiers.has_key("in"):
+ if p.qualifiers.get("in").params.value():
direction.add("*IN*")
if not direction:
direction.add("*IN*")
direction = ", ".join(sorted(direction))
print >>self.file, param_indent + "%s %s **%s**" % (direction, self.display_type(p), p.name)
- self.print_qualifiers(p.qualifiers.values(), param_indent+ " "*4)
+ self.print_qualifiers(p.qualifiers, param_indent+ " "*4)
print >>self.file, param_indent
print >>self.file, function_indent
def print_prototype(self, method):
""" Print function prototype """
- self.file.write("``" + method.return_type + "`` ")
+ self.file.write("``" + method.type_name() + "`` ")
self.file.write("**" + method.name + "** (")
params = []
- for p in method.parameters.values():
- params.append((self.display_type(p) + " " + p.name))
+ if method.parameters:
+ for p in method.parameters:
+ params.append((self.display_type(p) + " " + p.name))
self.file.write(", ".join(params))
- self.file.write("\n")
-
+ self.file.write(")\n")
+
def print_table(self, col1, col2, indent):
"""
Print table with two columns.
@@ -161,151 +158,160 @@ class HtmlExporter(object):
values = None
maps = None
for q in sorted(qualifiers):
- if q.name == "Deprecated":
+ if not q:
+ continue
+ qname = q.name.lower()
+ if qname == "deprecated":
deprecated = "**Deprecated!** "
- if q.name == "Description":
+ if qname == "description":
if deprecated:
print >>self.file, indent + deprecated
- self.print_escaped(q.value, indent)
- if q.name == "Values":
- values = q.value
- if q.name == "ValueMap":
- maps = q.value
+ self.print_escaped(q.params.value(), indent)
+ if qname == "values":
+ values = []
+ for p in q.params:
+ values.append(p.value())
+ if qname == "valuemap":
+ maps = []
+ for p in q.params:
+ maps.append(p.value())
print >>self.file, indent
if maps and values:
self.print_table(maps, values, indent)
print >>self.file, indent
- def compare_properties(self, p1, p2):
- """
- Compare two properties if they should printed in Inherited properties.
- Only Name, Description and Implemented are checked.
- Returns False, if the property should be printed in Local.
- """
- if p1.name != p2.name:
- return False
- d1 = p1.qualifiers.get("Description", None)
- d2 = p2.qualifiers.get("Description", None)
- if d1.value != d2.value:
- return False
- i1 = p1.qualifiers.get("Implemented", None)
- i2 = p2.qualifiers.get("Implemented", None)
- if i1 and i1.value and not (i2 and i2.value):
- return False
- return True
-
- def print_keys(self, c):
+ def print_keys(self, class_hiearchy):
print >>self.file, "Key properties"
print >>self.file, "^^^^^^^^^^^^^^"
print >>self.file, ""
- for prop in c.properties.values():
- if prop.qualifiers.has_key('Key'):
- src = self.source_class(c, prop)
- link = self.link(src, prop.name)
- print >>self.file, "| :ref:`%s <%s>`" % (prop.name, link)
+ for cls in class_hiearchy:
+ for prop in cls.properties().values():
+ if prop.qualifiers.has_key('key'):
+ src = self.source_class(cls, prop)
+ link = self.link(src, prop.name)
+ print >>self.file, "| :ref:`%s <%s>`" % (prop.name, link)
print >>self.file, ""
def print_class(self, c):
"""
Print one class, inc. header.
"""
+ # We want to print following qualifiers for properties/methods
+ known_qualifiers = ("deprecated", "description", "values", "valuemap")
parent = None
- if c.superclass:
- parent = self.load_class(c.superclass)
- print >>self.file, "Subclass of :ref:`%s <%s>`" % (c.superclass, self.link(c.superclass))
+ class_hiearchy = [c]
+ cc = c
+ while cc.super_class:
+ cc = cc.super_class
+ class_hiearchy.append(cc)
+
+ if c.super_class:
+ parent = c.super_class
+ print >>self.file, "Subclass of :ref:`%s <%s>`" % (c.super_class_name, self.link(c.super_class_name))
print >>self.file, ""
- description = c.qualifiers.get("Description", None)
- if not description:
- description = parent.qualifiers.get("Description", None)
- if description:
- self.print_escaped(description.value, "")
+ for cls in class_hiearchy:
+ description = cls.qualifiers.get("description")
+ if description:
+ self.print_escaped(description.params.value(), "")
+ break
print >>self.file, ""
- self.print_keys(c)
-
- local_props = []
- inherited_props = []
- for name in sorted(c.properties.keys()):
- if parent and parent.properties.has_key(name):
- inherited_props.append(c.properties[name])
- if not self.compare_properties(c.properties[name], parent.properties[name]):
- # the property was overridden
- local_props.append(c.properties[name])
- else:
- local_props.append(c.properties[name])
-
- local_methods = []
- inherited_methods = []
- for name in sorted(c.methods.keys()):
- if parent and parent.methods.has_key(name):
- inherited_methods.append(c.methods[name])
- if not self.compare_properties(c.methods[name], parent.methods[name]):
- # the property was overridden
- local_methods.append(c.methods[name])
- else:
- local_methods.append(c.methods[name])
+ self.print_keys(class_hiearchy)
+
+ # Create dictionaries with properties and methods of given class and fill them
+ properties = {}
+ methods = {}
+ for cls in class_hiearchy:
+ for prop in cls.properties().values():
+ if prop.name not in properties.keys():
+ properties[prop.name] = prop
+ prop.cls = cls
+ prop.is_local = cls == c
+ prop.known_qualifiers = {}
+ for q in known_qualifiers:
+ prop.known_qualifiers[q] = prop.qualifiers.get(q)
+ else:
+ inherited_prop = properties[prop.name]
+ for q in known_qualifiers:
+ if not inherited_prop.known_qualifiers[q]:
+ inherited_prop.known_qualifiers[q] = prop.qualifiers.get(q)
+ for meth in cls.methods().values():
+ if meth.name not in methods.keys():
+ methods[meth.name] = meth
+ meth.cls = cls
+ meth.is_local = cls.name == c.name
+ meth.known_qualifiers = {}
+ for q in known_qualifiers:
+ meth.known_qualifiers[q] = meth.qualifiers.get(q)
+ else:
+ inherited_meth = methods[meth.name]
+ for q in known_qualifiers:
+ if not inherited_meth.known_qualifiers[q]:
+ inherited_meth.known_qualifiers[q] = meth.qualifiers.get(q)
print >>self.file, "Local properties"
print >>self.file, "^^^^^^^^^^^^^^^^"
print >>self.file, ""
- if local_props:
- for prop in local_props:
- prop_link = self.link(c.classname, prop.name)
+ present = False
+ for prop in properties.values():
+ if prop.is_local:
+ present = True
+ prop_link = self.link(c.name, prop.name)
print >>self.file, ".. _%s:" % (prop_link)
print >>self.file, ""
print >>self.file, "%s **%s**" % (self.display_type(prop), prop.name)
print >>self.file, ""
- self.print_qualifiers(prop.qualifiers.values(), " "*4)
- print >>self.file, ""
- else:
+ self.print_qualifiers(prop.known_qualifiers.values(), " "*4)
+ if not present:
print >>self.file, "*None*"
- print >>self.file, ""
+ print >>self.file, ""
print >>self.file, "Local methods"
print >>self.file, "^^^^^^^^^^^^^"
print >>self.file, ""
- if local_methods:
- for m in local_methods:
- link = self.link(c.classname, m.name)
+ present = False
+ for m in methods.values():
+ if m.is_local:
+ present = True
+ link = self.link(c.name, m.name)
print >>self.file, " .. _%s:" % (link)
print >>self.file, ""
self.print_prototype(m)
print >>self.file, ""
- self.print_qualifiers(m.qualifiers.values(), " "*4)
+ self.print_qualifiers(m.known_qualifiers.values(), " "*4)
print >>self.file, " **Parameters**"
print >>self.file, " "
self.print_parameters(m.parameters)
- print >>self.file, " "
- else:
+ if not present:
print >>self.file, "*None*"
- print >>self.file, ""
+ print >>self.file, ""
print >>self.file, "Inherited properties"
print >>self.file, "^^^^^^^^^^^^^^^^^^^^"
print >>self.file, ""
- if inherited_props:
- for p in inherited_props:
- src = self.source_class(c, p)
- link = self.link(src, p.name)
- print >>self.file, "| %s :ref:`%s <%s>`" % (self.display_type(p), p.name, link)
- print >>self.file, ""
- else:
+ present = False
+ for prop in properties.values():
+ if not prop.is_local:
+ present = True
+ link = self.link(prop.cls.name, prop.name)
+ print >>self.file, "| %s :ref:`%s <%s>`" % (self.display_type(prop), prop.name, link)
+ if not present:
print >>self.file, "*None*"
- print >>self.file, ""
+ print >>self.file, ""
print >>self.file, "Inherited methods"
print >>self.file, "^^^^^^^^^^^^^^^^^"
print >>self.file, ""
- if inherited_methods:
- for m in inherited_methods:
- src = self.source_class(c, m)
- link = self.link(src, m.name)
+ present = False
+ for m in methods.values():
+ if not m.is_local:
+ present = True
+ link = self.link(m.cls.name, m.name)
print >>self.file, "| :ref:`%s <%s>`" % (m.name, link)
- print >>self.file, ""
- else:
+ if not present:
print >>self.file, "*None*"
- print >>self.file, ""
+ print >>self.file, ""
def print_file(self, filename):
@@ -315,46 +321,44 @@ class HtmlExporter(object):
f.close()
def print_page(self, c, header, footer):
- print "exporting ", c.classname
- self.file = open(c.classname + ".rst", "w")
- print >>self.file, ".. _%s:" % self.link(c.classname)
+ print "exporting ", c.name
+ self.file = open(c.name + ".rst", "w")
+ print >>self.file, ".. _%s:" % self.link(c.name)
print >>self.file, ""
- print >>self.file, c.classname
- print >>self.file, "-"*len(c.classname)
+ print >>self.file, c.name
+ print >>self.file, "-"*len(c.name)
print >>self.file, ""
-# if header:
-# self.print_file(header)
+ if header:
+ self.print_file(header)
self.print_class(c)
-# if footer:
-# self.print_file(footer)
+ if footer:
+ self.print_file(footer)
self.file.close()
-
+
def add_class(self, classname):
+ if classname in self.classes:
+ return
+ c = konkretmof.MOF_Class_Decl.list.fget().find(classname)
+ if not c:
+ print 'No such class "%s"' % classname
+ return
self.classes.append(classname)
- print "adding", classname
- self.queue.add(classname)
- # add all parents
- c = self.load_class(classname)
- parentname = c.superclass
- while parentname:
- if parentname in self.queue:
- break
- print "adding", parentname
- self.queue.add(parentname)
- c = self.load_class(parentname)
- parentname = c.superclass
+ print "adding", c.name
+ self.queue.append(c)
+ if c.super_class:
+ self.add_class(c.super_class_name)
def export(self, header=None, footer=None):
"""
Print everything, i.e. index.rst + all classes + all their parents.
"""
# remove duplicate classes from the queue (and sort them)
- self.queue = sorted(self.queue)
+ self.queue.sort(key=lambda c:c.name)
self.print_tree_rst(header, footer)
self.print_index_rst(header, footer)
while self.queue:
c = self.queue.pop()
- self.print_page(self.load_class(c), header, footer)
+ self.print_page(c, header, footer)
def _do_print_tree(self, name, subtree, level):
nbsp=" |nbsp| "
@@ -378,24 +382,23 @@ class HtmlExporter(object):
# hash classname -> nr. of its parents
parents = {}
# initialize the hash
- for cname in self.queue:
- subclasses[cname] = {}
- parents[cname] = 0
+ for c in self.queue:
+ subclasses[c.name] = {}
+ parents[c.name] = 0
# fill the hash
- for cname in self.queue:
- c = self.load_class(cname)
- if c.superclass:
- subclasses[c.superclass][cname] = subclasses[cname]
- parents[cname] += 1
+ for c in self.queue:
+ if c.super_class:
+ subclasses[c.super_class_name][c.name] = subclasses[c.name]
+ parents[c.name] += 1
print >>self.file, ".. |nbsp| unicode:: 0xA0"
print >>self.file, " :trim:"
print >>self.file, ""
# print all top classes
- for cname in self.queue:
- if parents[cname] == 0:
- self._do_print_tree(cname, subclasses[cname], 0)
+ for c in self.queue:
+ if parents[c.name] == 0:
+ self._do_print_tree(c.name, subclasses[c.name], 0)
def print_index(self):
"""
@@ -406,8 +409,8 @@ class HtmlExporter(object):
print >>self.file, " :maxdepth: 1"
print >>self.file, ""
# print all top classes
- for cname in self.queue:
- print >>self.file, " " + cname
+ for c in self.queue:
+ print >>self.file, " " + c.name
def print_tree_rst(self, header, footer):
@@ -431,8 +434,7 @@ class HtmlExporter(object):
self.file.close()
description = """
-Generate RST documentation for given CIM classes. The tool connects to specified CIMOM
-and reads class definition from there. It generates separate RST file for each class
+Generate RST documentation from given MOF files. It generates separate RST file for each class
specified on command line and for all it's parents.
The tool also generates tree.rst with inheritance tree and index.rst with table of content.
@@ -444,17 +446,26 @@ Use Sphinx to generate html documentation from the RST files.
"""
parser = optparse.OptionParser(usage="usage: %prog [options] classname [classname ...]", description=description)
-parser.add_option('-u', '--url', action='store', dest='addr', default='https://localhost:5989', help='URL of CIM server, default: https://localhost:5989')
-parser.add_option('-U', '--user', action='store', dest='user', default=None, help='CIM user name')
-parser.add_option('-P', '--password', action='store', dest='password', default=None, help='CIM password')
+parser.add_option('-M', '--mof', action='append', dest='mof', default=[], help='MOF files to generate documentation from, can be used multiple times')
+parser.add_option('-S', '--schema', action='append', dest='schema', default=[], help='MOF files to scan for dependencies, can be used multiple times')
parser.add_option('-H', '--header', action='store', dest='header', default=None, help='File with HTML page header')
parser.add_option('-F', '--footer', action='store', dest='footer', default=None, help='File with HTML page footer')
(options, args) = parser.parse_args()
-cliconn = pywbem.WBEMConnection(options.addr, (options.user, options.password))
-exporter = HtmlExporter(cliconn)
-for c in args:
- exporter.add_class(c)
-exporter.export(options.header, options.footer)
+exporter = HtmlExporter()
+
+for mof in options.schema:
+ konkretmof.MOF_add_include_path(os.path.dirname(mof))
+ konkretmof.MOF_parse_file(mof)
+
+for mof in options.mof:
+ konkretmof.MOF_parse_file(mof)
+for cls in konkretmof.MOF_Class_Decl.list.fget():
+ if cls.file_name in options.mof:
+ exporter.add_class(cls.name)
+for cls in args:
+ exporter.add_class(cls)
+
+exporter.export(options.header, options.footer)
diff --git a/tools/openlmi-doc-class2uml b/tools/openlmi-doc-class2uml
new file mode 100644
index 0000000..840ecfd
--- /dev/null
+++ b/tools/openlmi-doc-class2uml
@@ -0,0 +1,143 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Authors: Jan Safranek <jsafrane@redhat.com>
+# Radek Novacek <rnovacek@redhat.com>
+#
+
+import os
+import konkretmof
+import optparse
+import re
+import cgi
+import sys
+
+class UmlExporter(object):
+
+ def __init__(self):
+ self.classcache = {}
+ # original list of classes
+ self.classes = set()
+ self.file = sys.stdout
+
+ def get_class(self, cls):
+ c = konkretmof.MOF_Class_Decl.list.fget().find(cls)
+ if c is None:
+ raise Exception("No such class: %s" % cls)
+ return c
+
+ def display_type(self, param):
+ """
+ Return displayable type of given parameter.
+ It adds [] if it's array and class name of referenced classes.
+ """
+ if isinstance(param, konkretmof.MOF_Reference_Decl):
+ ptype = param.class_name
+ elif isinstance(param, konkretmof.MOF_Parameter) and (param.data_type == konkretmof.TOK_REF):
+ ptype = param.ref_name
+ else:
+ ptype = param.type_name()
+
+ if isinstance(param, (konkretmof.MOF_Property_Decl, konkretmof.MOF_Parameter)) and param.array_index != 0:
+ ptype = ptype + "[]"
+ return ptype
+
+ def print_class(self, c, display_local = True, box_only = False):
+ """
+ Print one class, inc. header.
+ """
+ parent = None
+
+ if c.super_class:
+ # draw arrow to parent
+ print >>self.file, "%s -down-|> %s" % (c.name, c.super_class.name)
+
+ if box_only:
+ self.file.write("class %s\n\n" % c.name)
+ return
+
+ self.file.write("class %s {\n" % c.name)
+
+ if display_local:
+ for prop in sorted(c.properties().values(), key=lambda x: x.name):
+ self.file.write(" %s %s\n" % (self.display_type(prop), prop.name))
+
+
+ for m in sorted(c.methods().values(), key=lambda x: x.name):
+ self.file.write(" %s()\n" % (m.name))
+
+ self.file.write("}\n")
+ self.file.write("url of %s is [[%s.html]]\n" % (c.name, c.name))
+
+ def add_class(self, classname):
+ self.classes.add(classname)
+
+ def export(self, shrink, noassoc = False):
+ """
+ Print all classes and their parents.
+ """
+ print >>self.file, "@startuml"
+ while self.classes:
+ c = self.classes.pop()
+
+ cl = self.get_class(c)
+ if noassoc and cl.qualifiers.get("Association", False):
+ continue
+
+ if shrink and shrink.match(c):
+ self.print_class(cl, box_only = True)
+ else:
+ self.print_class(cl)
+
+ print >>self.file, "@enduml"
+
+description = """
+Generate UML image for given classes. Each class specified on command line
+will be drawn as one box, containing locally defined or re-defined properties
+and methods. Inheritance will be shown as arrow between a parent class and a
+subclass.
+
+The generated file can be coverted to a picture by PlantUML tool.
+"""
+
+parser = optparse.OptionParser(usage="usage: %prog [options] classname [classname ...]", description=description)
+parser.add_option('-M', '--mof', action='append', dest='mof', default=[], help='MOF files to generate documentation from, can be used multiple times')
+parser.add_option('-S', '--schema', action='append', dest='schema', default=[], help='MOF files to scan for dependencies, can be used multiple times')
+parser.add_option('-s', '--shrink', action='store', dest='shrink', default=None, help='Regular expression pattern of CIM classes, which will be drawn only as boxes, without properties.')
+parser.add_option('-A', '--no-associations', action='store_true', dest='noassoc', default=False, help='Skip association classes.')
+(options, args) = parser.parse_args()
+
+sys.stdout.softspace=0
+
+shrink = None
+if options.shrink:
+ shrink = re.compile(options.shrink)
+
+for mof in options.schema:
+ konkretmof.MOF_add_include_path(os.path.dirname(mof))
+ konkretmof.MOF_parse_file(mof)
+
+for mof in options.mof:
+ konkretmof.MOF_parse_file(mof)
+
+exporter = UmlExporter()
+
+for c in args:
+ exporter.add_class(c)
+
+exporter.export(shrink = shrink, noassoc = options.noassoc)