|
@@ -0,0 +1,510 @@
|
|
|
+#!/usr/bin/env python
|
|
|
+# ex:ts=4:sw=4:sts=4:et
|
|
|
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
|
+#
|
|
|
+# Copyright (C) 2005 Holger Hans Peter Freyther
|
|
|
+#
|
|
|
+#
|
|
|
+# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
+# of this software and associated documentation files (the "Software"), to deal
|
|
|
+# in the Software without restriction, including without limitation the rights
|
|
|
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
+# copies of the Software, and to permit persons to whom the Software is
|
|
|
+# furnished to do so, subject to the following conditions:
|
|
|
+#
|
|
|
+# The above copyright notice and this permission notice shall be included in all
|
|
|
+# copies or substantial portions of the Software.
|
|
|
+#
|
|
|
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
|
+# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
|
+# THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
+#
|
|
|
+#
|
|
|
+
|
|
|
+import optparse, os, sys
|
|
|
+
|
|
|
+# bitbake
|
|
|
+sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
|
|
+import bb
|
|
|
+from bb import make
|
|
|
+from string import split, join
|
|
|
+
|
|
|
+__version__ = "0.0.2"
|
|
|
+
|
|
|
+class HTMLFormatter:
|
|
|
+ """
|
|
|
+ Simple class to help to generate some sort of HTML files. It is
|
|
|
+ quite inferior solution compared to docbook, gtkdoc, doxygen but it
|
|
|
+ should work for now.
|
|
|
+ We've a global introduction site (index.html) and then one site for
|
|
|
+ the list of keys (alphabetical sorted) and one for the list of groups,
|
|
|
+ one site for each key with links to the relations and groups.
|
|
|
+
|
|
|
+ index.html
|
|
|
+ keys.html
|
|
|
+ groups.html
|
|
|
+ groupNAME.html
|
|
|
+ keyNAME.html
|
|
|
+ """
|
|
|
+
|
|
|
+ def replace(self, text, *pairs):
|
|
|
+ """
|
|
|
+ From pydoc... almost identical at least
|
|
|
+ """
|
|
|
+ while pairs:
|
|
|
+ (a,b) = pairs[0]
|
|
|
+ text = join(split(text, a), b)
|
|
|
+ pairs = pairs[1:]
|
|
|
+ return text
|
|
|
+ def escape(self, text):
|
|
|
+ """
|
|
|
+ Escape string to be conform HTML
|
|
|
+ """
|
|
|
+ return self.replace(text,
|
|
|
+ ('&', '&'),
|
|
|
+ ('<', '<' ),
|
|
|
+ ('>', '>' ) )
|
|
|
+ def createNavigator(self):
|
|
|
+ """
|
|
|
+ Create the navgiator
|
|
|
+ """
|
|
|
+ return """<table class="navigation" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2">
|
|
|
+<tr valign="middle">
|
|
|
+<td><a accesskey="g" href="index.html">Home</a></td>
|
|
|
+<td><a accesskey="n" href="groups.html">Groups</a></td>
|
|
|
+<td><a accesskey="u" href="keys.html">Keys</a></td>
|
|
|
+</tr></table>
|
|
|
+"""
|
|
|
+
|
|
|
+ def relatedKeys(self, item):
|
|
|
+ """
|
|
|
+ Create HTML to link to foreign keys
|
|
|
+ """
|
|
|
+ txt = "<p><b>See also:</b><br>"
|
|
|
+ for it in item.related():
|
|
|
+ txt += """<a href="key%s.html">%s</a>, """ % (it, it)
|
|
|
+
|
|
|
+ return txt
|
|
|
+
|
|
|
+ def groups(self,item):
|
|
|
+ """
|
|
|
+ Create HTML to link to related groups
|
|
|
+ """
|
|
|
+ txt = "<p><b>Seel also:</b><br>"
|
|
|
+ for group in item.groups():
|
|
|
+ txt += """<a href="group%s.html">%s</a>, """ % (group,group)
|
|
|
+
|
|
|
+ return txt
|
|
|
+
|
|
|
+
|
|
|
+ def createKeySite(self,item):
|
|
|
+ """
|
|
|
+ Create a site for a key. It contains the header/navigator, a heading,
|
|
|
+ the description, links to related keys and to the groups.
|
|
|
+ """
|
|
|
+
|
|
|
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
+<html><head><title>Key %s</title></head>
|
|
|
+<link rel="stylesheet" href="style.css" type="text/css">
|
|
|
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
|
+%s
|
|
|
+<h2><span class="refentrytitle">%s</span></h2>
|
|
|
+
|
|
|
+<div class="refsynopsisdiv">
|
|
|
+<h2>Synopsis</h2>
|
|
|
+<pre class="synopsis">
|
|
|
+%s
|
|
|
+</pre>
|
|
|
+</div>
|
|
|
+
|
|
|
+<div class="refsynopsisdiv">
|
|
|
+<h2>Related Keys</h2>
|
|
|
+<pre class="synopsis">
|
|
|
+%s
|
|
|
+</pre>
|
|
|
+</div>
|
|
|
+
|
|
|
+<div class="refsynopsisdiv">
|
|
|
+<h2>Groups</h2>
|
|
|
+<pre class="synopsis">
|
|
|
+%s
|
|
|
+</pre>
|
|
|
+</div>
|
|
|
+
|
|
|
+
|
|
|
+</body>
|
|
|
+""" % (item.name(), self.createNavigator(), item.name(),
|
|
|
+ self.escape(item.description()), self.relatedKeys(item), self.groups(item))
|
|
|
+
|
|
|
+ def createGroupsSite(self, doc):
|
|
|
+ """
|
|
|
+ Create the Group Overview site
|
|
|
+ """
|
|
|
+
|
|
|
+ groups = ""
|
|
|
+ for group in doc.groups():
|
|
|
+ groups += """<a href="group%s.html">%s</a><br>""" % (group, group)
|
|
|
+
|
|
|
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
+<html><head><title>Group overview</title></head>
|
|
|
+<link rel="stylesheet" href="style.css" type="text/css">
|
|
|
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
|
+%s
|
|
|
+<h2>Available Groups</h2>
|
|
|
+%s
|
|
|
+</body>
|
|
|
+""" % (self.createNavigator(), groups)
|
|
|
+
|
|
|
+ def createIndex(self):
|
|
|
+ """
|
|
|
+ Create the index file
|
|
|
+ """
|
|
|
+
|
|
|
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
+<html><head><title>Bitbake Documentation</title></head>
|
|
|
+<link rel="stylesheet" href="style.css" type="text/css">
|
|
|
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
|
+%s
|
|
|
+<h2>Documentation Entrance</h2>
|
|
|
+<a href="groups.html">All available groups</a><br>
|
|
|
+<a href="keys.html">All available keys</a><br>
|
|
|
+</body>
|
|
|
+""" % self.createNavigator()
|
|
|
+
|
|
|
+ def createKeysSite(self, doc):
|
|
|
+ """
|
|
|
+ Create Overview of all avilable keys
|
|
|
+ """
|
|
|
+ keys = ""
|
|
|
+ for key in doc.doc_keys():
|
|
|
+ keys += """<a href="key%s.html">%s</a><br>""" % (key, key)
|
|
|
+
|
|
|
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
+<html><head><title>Key overview</title></head>
|
|
|
+<link rel="stylesheet" href="style.css" type="text/css">
|
|
|
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
|
+%s
|
|
|
+<h2>Available Keys</h2>
|
|
|
+%s
|
|
|
+</body>
|
|
|
+""" % (self.createNavigator(), keys)
|
|
|
+
|
|
|
+ def createGroupSite(self,gr, items):
|
|
|
+ """
|
|
|
+ Create a site for a group:
|
|
|
+ Group the name of the group, items contain the name of the keys
|
|
|
+ inside this group
|
|
|
+ """
|
|
|
+ groups = ""
|
|
|
+ for group in items:
|
|
|
+ groups += """<a href="group%s.html">%s</a><br>""" % (group.name(), group.name())
|
|
|
+
|
|
|
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
+<html><head><title>Group %s</title></head>
|
|
|
+<link rel="stylesheet" href="style.css" type="text/css">
|
|
|
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
|
+%s
|
|
|
+<div class="refsynopsisdiv">
|
|
|
+<h2>Keys in Group %s</h2>
|
|
|
+<pre class="synopsis">
|
|
|
+%s
|
|
|
+</pre>
|
|
|
+</div>
|
|
|
+</body>
|
|
|
+""" % (gr, self.createNavigator(), gr, groups)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ def createCSS(self):
|
|
|
+ """
|
|
|
+ Create the CSS file
|
|
|
+ """
|
|
|
+ return """.synopsis, .classsynopsis
|
|
|
+{
|
|
|
+ background: #eeeeee;
|
|
|
+ border: solid 1px #aaaaaa;
|
|
|
+ padding: 0.5em;
|
|
|
+}
|
|
|
+.programlisting
|
|
|
+{
|
|
|
+ background: #eeeeff;
|
|
|
+ border: solid 1px #aaaaff;
|
|
|
+ padding: 0.5em;
|
|
|
+}
|
|
|
+.variablelist
|
|
|
+{
|
|
|
+ padding: 4px;
|
|
|
+ margin-left: 3em;
|
|
|
+}
|
|
|
+.variablelist td:first-child
|
|
|
+{
|
|
|
+ vertical-align: top;
|
|
|
+}
|
|
|
+table.navigation
|
|
|
+{
|
|
|
+ background: #ffeeee;
|
|
|
+ border: solid 1px #ffaaaa;
|
|
|
+ margin-top: 0.5em;
|
|
|
+ margin-bottom: 0.5em;
|
|
|
+}
|
|
|
+.navigation a
|
|
|
+{
|
|
|
+ color: #770000;
|
|
|
+}
|
|
|
+.navigation a:visited
|
|
|
+{
|
|
|
+ color: #550000;
|
|
|
+}
|
|
|
+.navigation .title
|
|
|
+{
|
|
|
+ font-size: 200%;
|
|
|
+}
|
|
|
+div.refnamediv
|
|
|
+{
|
|
|
+ margin-top: 2em;
|
|
|
+}
|
|
|
+div.gallery-float
|
|
|
+{
|
|
|
+ float: left;
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+div.gallery-float img
|
|
|
+{
|
|
|
+ border-style: none;
|
|
|
+}
|
|
|
+div.gallery-spacer
|
|
|
+{
|
|
|
+ clear: both;
|
|
|
+}
|
|
|
+a
|
|
|
+{
|
|
|
+ text-decoration: none;
|
|
|
+}
|
|
|
+a:hover
|
|
|
+{
|
|
|
+ text-decoration: underline;
|
|
|
+ color: #FF0000;
|
|
|
+}
|
|
|
+"""
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+class DocumentationItem:
|
|
|
+ """
|
|
|
+ A class to hold information about a configuration
|
|
|
+ item. It contains the key name, description, a list of related names,
|
|
|
+ and the group this item is contained in.
|
|
|
+ """
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ self._groups = []
|
|
|
+ self._related = []
|
|
|
+ self._name = ""
|
|
|
+ self._desc = ""
|
|
|
+
|
|
|
+ def groups(self):
|
|
|
+ return self._groups
|
|
|
+
|
|
|
+ def name(self):
|
|
|
+ return self._name
|
|
|
+
|
|
|
+ def description(self):
|
|
|
+ return self._desc
|
|
|
+
|
|
|
+ def related(self):
|
|
|
+ return self._related
|
|
|
+
|
|
|
+ def setName(self, name):
|
|
|
+ self._name = name
|
|
|
+
|
|
|
+ def setDescription(self, desc):
|
|
|
+ self._desc = desc
|
|
|
+
|
|
|
+ def addGroup(self, group):
|
|
|
+ self._groups.append(group)
|
|
|
+
|
|
|
+ def addRelation(self,relation):
|
|
|
+ self._related.append(relation)
|
|
|
+
|
|
|
+
|
|
|
+class Documentation:
|
|
|
+ """
|
|
|
+ Holds the documentation... with mappings from key to items...
|
|
|
+ """
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ self.__keys = {}
|
|
|
+ self.__groups = {}
|
|
|
+
|
|
|
+ def insert_doc_item(self, item):
|
|
|
+ """
|
|
|
+ Insert the Doc Item into the internal list
|
|
|
+ of representation
|
|
|
+ """
|
|
|
+ self.__keys[item.name()] = item
|
|
|
+
|
|
|
+ for group in item.groups():
|
|
|
+ if not group in self.__groups:
|
|
|
+ self.__groups[group] = []
|
|
|
+ self.__groups[group].append(item)
|
|
|
+
|
|
|
+
|
|
|
+ def doc_item(self, key):
|
|
|
+ """
|
|
|
+ Return the DocumentationInstance describing the key
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ return self.__keys[key]
|
|
|
+ except KeyError:
|
|
|
+ return None
|
|
|
+
|
|
|
+ def doc_keys(self):
|
|
|
+ """
|
|
|
+ Return the documented KEYS (names)
|
|
|
+ """
|
|
|
+ return self.__keys.keys()
|
|
|
+
|
|
|
+ def groups(self):
|
|
|
+ """
|
|
|
+ Return the names of available groups
|
|
|
+ """
|
|
|
+ return self.__groups.keys()
|
|
|
+
|
|
|
+ def group_content(self,group_name):
|
|
|
+ """
|
|
|
+ Return a list of keys/names that are in a specefic
|
|
|
+ group or the empty list
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ return self.__groups[group_name]
|
|
|
+ except KeyError:
|
|
|
+ return []
|
|
|
+
|
|
|
+
|
|
|
+def parse_cmdline(args):
|
|
|
+ """
|
|
|
+ Parse the CMD line and return the result as a n-tuple
|
|
|
+ """
|
|
|
+
|
|
|
+ parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__,__version__))
|
|
|
+ usage = """%prog [options]
|
|
|
+
|
|
|
+Create a set of html pages (documentation) for a bitbake.conf....
|
|
|
+"""
|
|
|
+
|
|
|
+ # Add the needed options
|
|
|
+ parser.add_option( "-c", "--config", help = "Use the specified configuration file as source",
|
|
|
+ action = "store", dest = "config", default = os.path.join("conf", "documentation.conf") )
|
|
|
+
|
|
|
+ parser.add_option( "-o", "--output", help = "Output directory for html files",
|
|
|
+ action = "store", dest = "output", default = "html/" )
|
|
|
+
|
|
|
+ parser.add_option( "-D", "--debug", help = "Increase the debug level",
|
|
|
+ action = "count", dest = "debug", default = 0 )
|
|
|
+
|
|
|
+ parser.add_option( "-v","--verbose", help = "output more chit-char to the terminal",
|
|
|
+ action = "store_true", dest = "verbose", default = False )
|
|
|
+
|
|
|
+ options, args = parser.parse_args( sys.argv )
|
|
|
+
|
|
|
+ if options.debug:
|
|
|
+ bb.debug_level = options.debug
|
|
|
+
|
|
|
+ return options.config, options.output
|
|
|
+
|
|
|
+def main():
|
|
|
+ """
|
|
|
+ The main Method
|
|
|
+ """
|
|
|
+
|
|
|
+ (config_file,output_dir) = parse_cmdline( sys.argv )
|
|
|
+
|
|
|
+ # right to let us load the file now
|
|
|
+ try:
|
|
|
+ documentation = bb.parse.handle( config_file, bb.data.init() )
|
|
|
+ except IOError:
|
|
|
+ bb.fatal( "Unable to open %s" % config_file )
|
|
|
+ except bb.parse.ParseError:
|
|
|
+ bb.fatal( "Unable to parse %s" % config_file )
|
|
|
+
|
|
|
+
|
|
|
+ # Assuming we've the file loaded now, we will initialize the 'tree'
|
|
|
+ doc = Documentation()
|
|
|
+
|
|
|
+ # defined states
|
|
|
+ state_begin = 0
|
|
|
+ state_see = 1
|
|
|
+ state_group = 2
|
|
|
+
|
|
|
+ for key in bb.data.keys(documentation):
|
|
|
+ data = bb.data.getVarFlag(key, "doc", documentation)
|
|
|
+ if not data:
|
|
|
+ continue
|
|
|
+
|
|
|
+ # The Documentation now starts
|
|
|
+ doc_ins = DocumentationItem()
|
|
|
+ doc_ins.setName(key)
|
|
|
+
|
|
|
+
|
|
|
+ tokens = data.split(' ')
|
|
|
+ state = state_begin
|
|
|
+ string= ""
|
|
|
+ for token in tokens:
|
|
|
+ token = token.strip(',')
|
|
|
+
|
|
|
+ if not state == state_see and token == "@see":
|
|
|
+ state = state_see
|
|
|
+ continue
|
|
|
+ elif not state == state_group and token == "@group":
|
|
|
+ state = state_group
|
|
|
+ continue
|
|
|
+
|
|
|
+ if state == state_begin:
|
|
|
+ string += " %s" % token
|
|
|
+ elif state == state_see:
|
|
|
+ doc_ins.addRelation(token)
|
|
|
+ elif state == state_group:
|
|
|
+ doc_ins.addGroup(token)
|
|
|
+
|
|
|
+ # set the description
|
|
|
+ doc_ins.setDescription(string)
|
|
|
+ doc.insert_doc_item(doc_ins)
|
|
|
+
|
|
|
+ # let us create the HTML now...
|
|
|
+ bb.mkdirhier(output_dir)
|
|
|
+ os.chdir(output_dir)
|
|
|
+
|
|
|
+ # Let us create the sites now. We do it in the following order
|
|
|
+ # Start with the index.html. It will point to sites explaining all
|
|
|
+ # keys and groups
|
|
|
+ html_slave = HTMLFormatter()
|
|
|
+
|
|
|
+ f = file('style.css', 'w')
|
|
|
+ print >> f, html_slave.createCSS()
|
|
|
+
|
|
|
+ f = file('index.html', 'w')
|
|
|
+ print >> f, html_slave.createIndex()
|
|
|
+
|
|
|
+ f = file('groups.html', 'w')
|
|
|
+ print >> f, html_slave.createGroupsSite(doc)
|
|
|
+
|
|
|
+ f = file('keys.html', 'w')
|
|
|
+ print >> f, html_slave.createKeysSite(doc)
|
|
|
+
|
|
|
+ # now for each group create the site
|
|
|
+ for group in doc.groups():
|
|
|
+ f = file('group%s.html' % group, 'w')
|
|
|
+ print >> f, html_slave.createGroupSite(group, doc.group_content(group))
|
|
|
+
|
|
|
+ # now for the keys
|
|
|
+ for key in doc.doc_keys():
|
|
|
+ f = file('key%s.html' % doc.doc_item(key).name(), 'w')
|
|
|
+ print >> f, html_slave.createKeySite(doc.doc_item(key))
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ main()
|