2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 # Copyright (C) 2005 Holger Hans Peter Freyther
8 # Permission is hereby granted, free of charge, to any person obtaining a copy
9 # of this software and associated documentation files (the "Software"), to deal
10 # in the Software without restriction, including without limitation the rights
11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 # copies of the Software, and to permit persons to whom the Software is
13 # furnished to do so, subject to the following conditions:
15 # The above copyright notice and this permission notice shall be included in all
16 # copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
24 # THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 import optparse, os, sys
31 sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
34 from string import split, join
40 Simple class to help to generate some sort of HTML files. It is
41 quite inferior solution compared to docbook, gtkdoc, doxygen but it
43 We've a global introduction site (index.html) and then one site for
44 the list of keys (alphabetical sorted) and one for the list of groups,
45 one site for each key with links to the relations and groups.
54 def replace(self, text, *pairs):
56 From pydoc... almost identical at least
60 text = join(split(text, a), b)
63 def escape(self, text):
65 Escape string to be conform HTML
67 return self.replace(text,
71 def createNavigator(self):
75 return """<table class="navigation" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2">
77 <td><a accesskey="g" href="index.html">Home</a></td>
78 <td><a accesskey="n" href="groups.html">Groups</a></td>
79 <td><a accesskey="u" href="keys.html">Keys</a></td>
83 def relatedKeys(self, item):
85 Create HTML to link to foreign keys
88 if len(item.related()) == 0:
91 txt = "<p><b>See also:</b><br>"
92 for it in item.related():
93 txt += """<a href="key%s.html">%s</a>, """ % (it, it)
97 def groups(self,item):
99 Create HTML to link to related groups
102 if len(item.groups()) == 0:
106 txt = "<p><b>Seel also:</b><br>"
107 for group in item.groups():
108 txt += """<a href="group%s.html">%s</a>, """ % (group,group)
113 def createKeySite(self,item):
115 Create a site for a key. It contains the header/navigator, a heading,
116 the description, links to related keys and to the groups.
119 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
120 <html><head><title>Key %s</title></head>
121 <link rel="stylesheet" href="style.css" type="text/css">
122 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
124 <h2><span class="refentrytitle">%s</span></h2>
126 <div class="refsynopsisdiv">
128 <pre class="synopsis">
133 <div class="refsynopsisdiv">
134 <h2>Related Keys</h2>
135 <pre class="synopsis">
140 <div class="refsynopsisdiv">
142 <pre class="synopsis">
149 """ % (item.name(), self.createNavigator(), item.name(),
150 self.escape(item.description()), self.relatedKeys(item), self.groups(item))
152 def createGroupsSite(self, doc):
154 Create the Group Overview site
158 sorted_groups = doc.groups()
160 for group in sorted_groups:
161 groups += """<a href="group%s.html">%s</a><br>""" % (group, group)
163 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
164 <html><head><title>Group overview</title></head>
165 <link rel="stylesheet" href="style.css" type="text/css">
166 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
168 <h2>Available Groups</h2>
171 """ % (self.createNavigator(), groups)
173 def createIndex(self):
175 Create the index file
178 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
179 <html><head><title>Bitbake Documentation</title></head>
180 <link rel="stylesheet" href="style.css" type="text/css">
181 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
183 <h2>Documentation Entrance</h2>
184 <a href="groups.html">All available groups</a><br>
185 <a href="keys.html">All available keys</a><br>
187 """ % self.createNavigator()
189 def createKeysSite(self, doc):
191 Create Overview of all avilable keys
194 sorted_keys = doc.doc_keys()
196 for key in sorted_keys:
197 keys += """<a href="key%s.html">%s</a><br>""" % (key, key)
199 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
200 <html><head><title>Key overview</title></head>
201 <link rel="stylesheet" href="style.css" type="text/css">
202 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
204 <h2>Available Keys</h2>
207 """ % (self.createNavigator(), keys)
209 def createGroupSite(self,gr, items):
211 Create a site for a group:
212 Group the name of the group, items contain the name of the keys
217 groups += """<a href="key%s.html">%s</a><br>""" % (group.name(), group.name())
219 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
220 <html><head><title>Group %s</title></head>
221 <link rel="stylesheet" href="style.css" type="text/css">
222 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
224 <div class="refsynopsisdiv">
225 <h2>Keys in Group %s</h2>
226 <pre class="synopsis">
231 """ % (gr, self.createNavigator(), gr, groups)
239 return """.synopsis, .classsynopsis
242 border: solid 1px #aaaaaa;
248 border: solid 1px #aaaaff;
256 .variablelist td:first-child
263 border: solid 1px #ffaaaa;
265 margin-bottom: 0.5em;
271 .navigation a:visited
288 div.gallery-float img
298 text-decoration: none;
302 text-decoration: underline;
309 class DocumentationItem:
311 A class to hold information about a configuration
312 item. It contains the key name, description, a list of related names,
313 and the group this item is contained in.
328 def description(self):
334 def setName(self, name):
337 def setDescription(self, desc):
340 def addGroup(self, group):
341 self._groups.append(group)
343 def addRelation(self,relation):
344 self._related.append(relation)
353 Holds the documentation... with mappings from key to items...
360 def insert_doc_item(self, item):
362 Insert the Doc Item into the internal list
366 self.__keys[item.name()] = item
368 for group in item.groups():
369 if not group in self.__groups:
370 self.__groups[group] = []
371 self.__groups[group].append(item)
374 def doc_item(self, key):
376 Return the DocumentationInstance describing the key
379 return self.__keys[key]
385 Return the documented KEYS (names)
387 return self.__keys.keys()
391 Return the names of available groups
393 return self.__groups.keys()
395 def group_content(self,group_name):
397 Return a list of keys/names that are in a specefic
398 group or the empty list
401 return self.__groups[group_name]
406 def parse_cmdline(args):
408 Parse the CMD line and return the result as a n-tuple
411 parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__,__version__))
412 usage = """%prog [options]
414 Create a set of html pages (documentation) for a bitbake.conf....
417 # Add the needed options
418 parser.add_option( "-c", "--config", help = "Use the specified configuration file as source",
419 action = "store", dest = "config", default = os.path.join("conf", "documentation.conf") )
421 parser.add_option( "-o", "--output", help = "Output directory for html files",
422 action = "store", dest = "output", default = "html/" )
424 parser.add_option( "-D", "--debug", help = "Increase the debug level",
425 action = "count", dest = "debug", default = 0 )
427 parser.add_option( "-v","--verbose", help = "output more chit-char to the terminal",
428 action = "store_true", dest = "verbose", default = False )
430 options, args = parser.parse_args( sys.argv )
433 bb.debug_level = options.debug
435 return options.config, options.output
442 (config_file,output_dir) = parse_cmdline( sys.argv )
444 # right to let us load the file now
446 documentation = bb.parse.handle( config_file, bb.data.init() )
448 bb.fatal( "Unable to open %s" % config_file )
449 except bb.parse.ParseError:
450 bb.fatal( "Unable to parse %s" % config_file )
453 # Assuming we've the file loaded now, we will initialize the 'tree'
454 doc = Documentation()
461 for key in bb.data.keys(documentation):
462 data = bb.data.getVarFlag(key, "doc", documentation)
466 # The Documentation now starts
467 doc_ins = DocumentationItem()
471 tokens = data.split(' ')
475 token = token.strip(',')
477 if not state == state_see and token == "@see":
480 elif not state == state_group and token == "@group":
484 if state == state_begin:
485 string += " %s" % token
486 elif state == state_see:
487 doc_ins.addRelation(token)
488 elif state == state_group:
489 doc_ins.addGroup(token)
491 # set the description
492 doc_ins.setDescription(string)
493 doc.insert_doc_item(doc_ins)
495 # let us create the HTML now
496 bb.mkdirhier(output_dir)
499 # Let us create the sites now. We do it in the following order
500 # Start with the index.html. It will point to sites explaining all
502 html_slave = HTMLFormatter()
504 f = file('style.css', 'w')
505 print >> f, html_slave.createCSS()
507 f = file('index.html', 'w')
508 print >> f, html_slave.createIndex()
510 f = file('groups.html', 'w')
511 print >> f, html_slave.createGroupsSite(doc)
513 f = file('keys.html', 'w')
514 print >> f, html_slave.createKeysSite(doc)
516 # now for each group create the site
517 for group in doc.groups():
518 f = file('group%s.html' % group, 'w')
519 print >> f, html_slave.createGroupSite(group, doc.group_content(group))
522 for key in doc.doc_keys():
523 f = file('key%s.html' % doc.doc_item(key).name(), 'w')
524 print >> f, html_slave.createKeySite(doc.doc_item(key))
527 if __name__ == "__main__":