diff options
author | Richard Purdie <richard@openedhand.com> | 2005-08-31 10:47:56 +0000 |
---|---|---|
committer | Richard Purdie <richard@openedhand.com> | 2005-08-31 10:47:56 +0000 |
commit | f54da734eb7b69e8e34de505bd89a13479e230e0 (patch) | |
tree | f796bea6f5683dfe3d591ca5390d12fd78e59c96 /bitbake/bin/bitdoc | |
parent | 4b46c1f6e891b1ddd5968536440b888661fade3e (diff) | |
download | poky-f54da734eb7b69e8e34de505bd89a13479e230e0.tar.gz |
Initial population
git-svn-id: https://svn.o-hand.com/repos/poky@2 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake/bin/bitdoc')
-rwxr-xr-x | bitbake/bin/bitdoc | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/bitbake/bin/bitdoc b/bitbake/bin/bitdoc new file mode 100755 index 0000000000..64d32945ba --- /dev/null +++ b/bitbake/bin/bitdoc | |||
@@ -0,0 +1,529 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # ex:ts=4:sw=4:sts=4:et | ||
3 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
4 | # | ||
5 | # Copyright (C) 2005 Holger Hans Peter Freyther | ||
6 | # | ||
7 | # | ||
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: | ||
14 | # | ||
15 | # The above copyright notice and this permission notice shall be included in all | ||
16 | # copies or substantial portions of the Software. | ||
17 | # | ||
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. | ||
25 | # | ||
26 | # | ||
27 | |||
28 | import optparse, os, sys | ||
29 | |||
30 | # bitbake | ||
31 | sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib')) | ||
32 | import bb | ||
33 | from bb import make | ||
34 | from string import split, join | ||
35 | |||
36 | __version__ = "0.0.2" | ||
37 | |||
38 | class HTMLFormatter: | ||
39 | """ | ||
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 | ||
42 | should work for now. | ||
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. | ||
46 | |||
47 | index.html | ||
48 | keys.html | ||
49 | groups.html | ||
50 | groupNAME.html | ||
51 | keyNAME.html | ||
52 | """ | ||
53 | |||
54 | def replace(self, text, *pairs): | ||
55 | """ | ||
56 | From pydoc... almost identical at least | ||
57 | """ | ||
58 | while pairs: | ||
59 | (a,b) = pairs[0] | ||
60 | text = join(split(text, a), b) | ||
61 | pairs = pairs[1:] | ||
62 | return text | ||
63 | def escape(self, text): | ||
64 | """ | ||
65 | Escape string to be conform HTML | ||
66 | """ | ||
67 | return self.replace(text, | ||
68 | ('&', '&'), | ||
69 | ('<', '<' ), | ||
70 | ('>', '>' ) ) | ||
71 | def createNavigator(self): | ||
72 | """ | ||
73 | Create the navgiator | ||
74 | """ | ||
75 | return """<table class="navigation" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"> | ||
76 | <tr valign="middle"> | ||
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> | ||
80 | </tr></table> | ||
81 | """ | ||
82 | |||
83 | def relatedKeys(self, item): | ||
84 | """ | ||
85 | Create HTML to link to foreign keys | ||
86 | """ | ||
87 | |||
88 | if len(item.related()) == 0: | ||
89 | return "" | ||
90 | |||
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) | ||
94 | |||
95 | return txt | ||
96 | |||
97 | def groups(self,item): | ||
98 | """ | ||
99 | Create HTML to link to related groups | ||
100 | """ | ||
101 | |||
102 | if len(item.groups()) == 0: | ||
103 | return "" | ||
104 | |||
105 | |||
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) | ||
109 | |||
110 | return txt | ||
111 | |||
112 | |||
113 | def createKeySite(self,item): | ||
114 | """ | ||
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. | ||
117 | """ | ||
118 | |||
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"> | ||
123 | %s | ||
124 | <h2><span class="refentrytitle">%s</span></h2> | ||
125 | |||
126 | <div class="refsynopsisdiv"> | ||
127 | <h2>Synopsis</h2> | ||
128 | <pre class="synopsis"> | ||
129 | %s | ||
130 | </pre> | ||
131 | </div> | ||
132 | |||
133 | <div class="refsynopsisdiv"> | ||
134 | <h2>Related Keys</h2> | ||
135 | <pre class="synopsis"> | ||
136 | %s | ||
137 | </pre> | ||
138 | </div> | ||
139 | |||
140 | <div class="refsynopsisdiv"> | ||
141 | <h2>Groups</h2> | ||
142 | <pre class="synopsis"> | ||
143 | %s | ||
144 | </pre> | ||
145 | </div> | ||
146 | |||
147 | |||
148 | </body> | ||
149 | """ % (item.name(), self.createNavigator(), item.name(), | ||
150 | self.escape(item.description()), self.relatedKeys(item), self.groups(item)) | ||
151 | |||
152 | def createGroupsSite(self, doc): | ||
153 | """ | ||
154 | Create the Group Overview site | ||
155 | """ | ||
156 | |||
157 | groups = "" | ||
158 | sorted_groups = doc.groups() | ||
159 | sorted_groups.sort() | ||
160 | for group in sorted_groups: | ||
161 | groups += """<a href="group%s.html">%s</a><br>""" % (group, group) | ||
162 | |||
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"> | ||
167 | %s | ||
168 | <h2>Available Groups</h2> | ||
169 | %s | ||
170 | </body> | ||
171 | """ % (self.createNavigator(), groups) | ||
172 | |||
173 | def createIndex(self): | ||
174 | """ | ||
175 | Create the index file | ||
176 | """ | ||
177 | |||
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"> | ||
182 | %s | ||
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> | ||
186 | </body> | ||
187 | """ % self.createNavigator() | ||
188 | |||
189 | def createKeysSite(self, doc): | ||
190 | """ | ||
191 | Create Overview of all avilable keys | ||
192 | """ | ||
193 | keys = "" | ||
194 | sorted_keys = doc.doc_keys() | ||
195 | sorted_keys.sort() | ||
196 | for key in sorted_keys: | ||
197 | keys += """<a href="key%s.html">%s</a><br>""" % (key, key) | ||
198 | |||
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"> | ||
203 | %s | ||
204 | <h2>Available Keys</h2> | ||
205 | %s | ||
206 | </body> | ||
207 | """ % (self.createNavigator(), keys) | ||
208 | |||
209 | def createGroupSite(self,gr, items): | ||
210 | """ | ||
211 | Create a site for a group: | ||
212 | Group the name of the group, items contain the name of the keys | ||
213 | inside this group | ||
214 | """ | ||
215 | groups = "" | ||
216 | for group in items: | ||
217 | groups += """<a href="key%s.html">%s</a><br>""" % (group.name(), group.name()) | ||
218 | |||
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"> | ||
223 | %s | ||
224 | <div class="refsynopsisdiv"> | ||
225 | <h2>Keys in Group %s</h2> | ||
226 | <pre class="synopsis"> | ||
227 | %s | ||
228 | </pre> | ||
229 | </div> | ||
230 | </body> | ||
231 | """ % (gr, self.createNavigator(), gr, groups) | ||
232 | |||
233 | |||
234 | |||
235 | def createCSS(self): | ||
236 | """ | ||
237 | Create the CSS file | ||
238 | """ | ||
239 | return """.synopsis, .classsynopsis | ||
240 | { | ||
241 | background: #eeeeee; | ||
242 | border: solid 1px #aaaaaa; | ||
243 | padding: 0.5em; | ||
244 | } | ||
245 | .programlisting | ||
246 | { | ||
247 | background: #eeeeff; | ||
248 | border: solid 1px #aaaaff; | ||
249 | padding: 0.5em; | ||
250 | } | ||
251 | .variablelist | ||
252 | { | ||
253 | padding: 4px; | ||
254 | margin-left: 3em; | ||
255 | } | ||
256 | .variablelist td:first-child | ||
257 | { | ||
258 | vertical-align: top; | ||
259 | } | ||
260 | table.navigation | ||
261 | { | ||
262 | background: #ffeeee; | ||
263 | border: solid 1px #ffaaaa; | ||
264 | margin-top: 0.5em; | ||
265 | margin-bottom: 0.5em; | ||
266 | } | ||
267 | .navigation a | ||
268 | { | ||
269 | color: #770000; | ||
270 | } | ||
271 | .navigation a:visited | ||
272 | { | ||
273 | color: #550000; | ||
274 | } | ||
275 | .navigation .title | ||
276 | { | ||
277 | font-size: 200%; | ||
278 | } | ||
279 | div.refnamediv | ||
280 | { | ||
281 | margin-top: 2em; | ||
282 | } | ||
283 | div.gallery-float | ||
284 | { | ||
285 | float: left; | ||
286 | padding: 10px; | ||
287 | } | ||
288 | div.gallery-float img | ||
289 | { | ||
290 | border-style: none; | ||
291 | } | ||
292 | div.gallery-spacer | ||
293 | { | ||
294 | clear: both; | ||
295 | } | ||
296 | a | ||
297 | { | ||
298 | text-decoration: none; | ||
299 | } | ||
300 | a:hover | ||
301 | { | ||
302 | text-decoration: underline; | ||
303 | color: #FF0000; | ||
304 | } | ||
305 | """ | ||
306 | |||
307 | |||
308 | |||
309 | class DocumentationItem: | ||
310 | """ | ||
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. | ||
314 | """ | ||
315 | |||
316 | def __init__(self): | ||
317 | self._groups = [] | ||
318 | self._related = [] | ||
319 | self._name = "" | ||
320 | self._desc = "" | ||
321 | |||
322 | def groups(self): | ||
323 | return self._groups | ||
324 | |||
325 | def name(self): | ||
326 | return self._name | ||
327 | |||
328 | def description(self): | ||
329 | return self._desc | ||
330 | |||
331 | def related(self): | ||
332 | return self._related | ||
333 | |||
334 | def setName(self, name): | ||
335 | self._name = name | ||
336 | |||
337 | def setDescription(self, desc): | ||
338 | self._desc = desc | ||
339 | |||
340 | def addGroup(self, group): | ||
341 | self._groups.append(group) | ||
342 | |||
343 | def addRelation(self,relation): | ||
344 | self._related.append(relation) | ||
345 | |||
346 | def sort(self): | ||
347 | self._related.sort() | ||
348 | self._groups.sort() | ||
349 | |||
350 | |||
351 | class Documentation: | ||
352 | """ | ||
353 | Holds the documentation... with mappings from key to items... | ||
354 | """ | ||
355 | |||
356 | def __init__(self): | ||
357 | self.__keys = {} | ||
358 | self.__groups = {} | ||
359 | |||
360 | def insert_doc_item(self, item): | ||
361 | """ | ||
362 | Insert the Doc Item into the internal list | ||
363 | of representation | ||
364 | """ | ||
365 | item.sort() | ||
366 | self.__keys[item.name()] = item | ||
367 | |||
368 | for group in item.groups(): | ||
369 | if not group in self.__groups: | ||
370 | self.__groups[group] = [] | ||
371 | self.__groups[group].append(item) | ||
372 | self.__groups[group].sort() | ||
373 | |||
374 | |||
375 | def doc_item(self, key): | ||
376 | """ | ||
377 | Return the DocumentationInstance describing the key | ||
378 | """ | ||
379 | try: | ||
380 | return self.__keys[key] | ||
381 | except KeyError: | ||
382 | return None | ||
383 | |||
384 | def doc_keys(self): | ||
385 | """ | ||
386 | Return the documented KEYS (names) | ||
387 | """ | ||
388 | return self.__keys.keys() | ||
389 | |||
390 | def groups(self): | ||
391 | """ | ||
392 | Return the names of available groups | ||
393 | """ | ||
394 | return self.__groups.keys() | ||
395 | |||
396 | def group_content(self,group_name): | ||
397 | """ | ||
398 | Return a list of keys/names that are in a specefic | ||
399 | group or the empty list | ||
400 | """ | ||
401 | try: | ||
402 | return self.__groups[group_name] | ||
403 | except KeyError: | ||
404 | return [] | ||
405 | |||
406 | |||
407 | def parse_cmdline(args): | ||
408 | """ | ||
409 | Parse the CMD line and return the result as a n-tuple | ||
410 | """ | ||
411 | |||
412 | parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__,__version__)) | ||
413 | usage = """%prog [options] | ||
414 | |||
415 | Create a set of html pages (documentation) for a bitbake.conf.... | ||
416 | """ | ||
417 | |||
418 | # Add the needed options | ||
419 | parser.add_option( "-c", "--config", help = "Use the specified configuration file as source", | ||
420 | action = "store", dest = "config", default = os.path.join("conf", "documentation.conf") ) | ||
421 | |||
422 | parser.add_option( "-o", "--output", help = "Output directory for html files", | ||
423 | action = "store", dest = "output", default = "html/" ) | ||
424 | |||
425 | parser.add_option( "-D", "--debug", help = "Increase the debug level", | ||
426 | action = "count", dest = "debug", default = 0 ) | ||
427 | |||
428 | parser.add_option( "-v","--verbose", help = "output more chit-char to the terminal", | ||
429 | action = "store_true", dest = "verbose", default = False ) | ||
430 | |||
431 | options, args = parser.parse_args( sys.argv ) | ||
432 | |||
433 | if options.debug: | ||
434 | bb.debug_level = options.debug | ||
435 | |||
436 | return options.config, options.output | ||
437 | |||
438 | def main(): | ||
439 | """ | ||
440 | The main Method | ||
441 | """ | ||
442 | |||
443 | (config_file,output_dir) = parse_cmdline( sys.argv ) | ||
444 | |||
445 | # right to let us load the file now | ||
446 | try: | ||
447 | documentation = bb.parse.handle( config_file, bb.data.init() ) | ||
448 | except IOError: | ||
449 | bb.fatal( "Unable to open %s" % config_file ) | ||
450 | except bb.parse.ParseError: | ||
451 | bb.fatal( "Unable to parse %s" % config_file ) | ||
452 | |||
453 | |||
454 | # Assuming we've the file loaded now, we will initialize the 'tree' | ||
455 | doc = Documentation() | ||
456 | |||
457 | # defined states | ||
458 | state_begin = 0 | ||
459 | state_see = 1 | ||
460 | state_group = 2 | ||
461 | |||
462 | for key in bb.data.keys(documentation): | ||
463 | data = bb.data.getVarFlag(key, "doc", documentation) | ||
464 | if not data: | ||
465 | continue | ||
466 | |||
467 | # The Documentation now starts | ||
468 | doc_ins = DocumentationItem() | ||
469 | doc_ins.setName(key) | ||
470 | |||
471 | |||
472 | tokens = data.split(' ') | ||
473 | state = state_begin | ||
474 | string= "" | ||
475 | for token in tokens: | ||
476 | token = token.strip(',') | ||
477 | |||
478 | if not state == state_see and token == "@see": | ||
479 | state = state_see | ||
480 | continue | ||
481 | elif not state == state_group and token == "@group": | ||
482 | state = state_group | ||
483 | continue | ||
484 | |||
485 | if state == state_begin: | ||
486 | string += " %s" % token | ||
487 | elif state == state_see: | ||
488 | doc_ins.addRelation(token) | ||
489 | elif state == state_group: | ||
490 | doc_ins.addGroup(token) | ||
491 | |||
492 | # set the description | ||
493 | doc_ins.setDescription(string) | ||
494 | doc.insert_doc_item(doc_ins) | ||
495 | |||
496 | # let us create the HTML now | ||
497 | bb.mkdirhier(output_dir) | ||
498 | os.chdir(output_dir) | ||
499 | |||
500 | # Let us create the sites now. We do it in the following order | ||
501 | # Start with the index.html. It will point to sites explaining all | ||
502 | # keys and groups | ||
503 | html_slave = HTMLFormatter() | ||
504 | |||
505 | f = file('style.css', 'w') | ||
506 | print >> f, html_slave.createCSS() | ||
507 | |||
508 | f = file('index.html', 'w') | ||
509 | print >> f, html_slave.createIndex() | ||
510 | |||
511 | f = file('groups.html', 'w') | ||
512 | print >> f, html_slave.createGroupsSite(doc) | ||
513 | |||
514 | f = file('keys.html', 'w') | ||
515 | print >> f, html_slave.createKeysSite(doc) | ||
516 | |||
517 | # now for each group create the site | ||
518 | for group in doc.groups(): | ||
519 | f = file('group%s.html' % group, 'w') | ||
520 | print >> f, html_slave.createGroupSite(group, doc.group_content(group)) | ||
521 | |||
522 | # now for the keys | ||
523 | for key in doc.doc_keys(): | ||
524 | f = file('key%s.html' % doc.doc_item(key).name(), 'w') | ||
525 | print >> f, html_slave.createKeySite(doc.doc_item(key)) | ||
526 | |||
527 | |||
528 | if __name__ == "__main__": | ||
529 | main() | ||