diff options
author | Adrian Dudau <adrian.dudau@enea.com> | 2013-12-12 13:38:32 +0100 |
---|---|---|
committer | Adrian Dudau <adrian.dudau@enea.com> | 2013-12-12 13:50:20 +0100 |
commit | e2e6f6fe07049f33cb6348780fa975162752e421 (patch) | |
tree | b1813295411235d1297a0ed642b1346b24fdfb12 /bitbake/bin/bitdoc | |
download | poky-e2e6f6fe07049f33cb6348780fa975162752e421.tar.gz |
initial commit of Enea Linux 3.1
Migrated from the internal git server on the dora-enea branch
Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
Diffstat (limited to 'bitbake/bin/bitdoc')
-rwxr-xr-x | bitbake/bin/bitdoc | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/bitbake/bin/bitdoc b/bitbake/bin/bitdoc new file mode 100755 index 0000000000..576d88b574 --- /dev/null +++ b/bitbake/bin/bitdoc | |||
@@ -0,0 +1,531 @@ | |||
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 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License version 2 as | ||
9 | # published by the Free Software Foundation. | ||
10 | # | ||
11 | # This program is distributed in the hope that it will be useful, | ||
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | # GNU General Public License for more details. | ||
15 | # | ||
16 | # You should have received a copy of the GNU General Public License along | ||
17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | |||
20 | import optparse, os, sys | ||
21 | |||
22 | # bitbake | ||
23 | sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__), 'lib')) | ||
24 | import bb | ||
25 | import bb.parse | ||
26 | from string import split, join | ||
27 | |||
28 | __version__ = "0.0.2" | ||
29 | |||
30 | class HTMLFormatter: | ||
31 | """ | ||
32 | Simple class to help to generate some sort of HTML files. It is | ||
33 | quite inferior solution compared to docbook, gtkdoc, doxygen but it | ||
34 | should work for now. | ||
35 | We've a global introduction site (index.html) and then one site for | ||
36 | the list of keys (alphabetical sorted) and one for the list of groups, | ||
37 | one site for each key with links to the relations and groups. | ||
38 | |||
39 | index.html | ||
40 | all_keys.html | ||
41 | all_groups.html | ||
42 | groupNAME.html | ||
43 | keyNAME.html | ||
44 | """ | ||
45 | |||
46 | def replace(self, text, *pairs): | ||
47 | """ | ||
48 | From pydoc... almost identical at least | ||
49 | """ | ||
50 | while pairs: | ||
51 | (a, b) = pairs[0] | ||
52 | text = join(split(text, a), b) | ||
53 | pairs = pairs[1:] | ||
54 | return text | ||
55 | def escape(self, text): | ||
56 | """ | ||
57 | Escape string to be conform HTML | ||
58 | """ | ||
59 | return self.replace(text, | ||
60 | ('&', '&'), | ||
61 | ('<', '<' ), | ||
62 | ('>', '>' ) ) | ||
63 | def createNavigator(self): | ||
64 | """ | ||
65 | Create the navgiator | ||
66 | """ | ||
67 | return """<table class="navigation" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"> | ||
68 | <tr valign="middle"> | ||
69 | <td><a accesskey="g" href="index.html">Home</a></td> | ||
70 | <td><a accesskey="n" href="all_groups.html">Groups</a></td> | ||
71 | <td><a accesskey="u" href="all_keys.html">Keys</a></td> | ||
72 | </tr></table> | ||
73 | """ | ||
74 | |||
75 | def relatedKeys(self, item): | ||
76 | """ | ||
77 | Create HTML to link to foreign keys | ||
78 | """ | ||
79 | |||
80 | if len(item.related()) == 0: | ||
81 | return "" | ||
82 | |||
83 | txt = "<p><b>See also:</b><br>" | ||
84 | txts = [] | ||
85 | for it in item.related(): | ||
86 | txts.append("""<a href="key%(it)s.html">%(it)s</a>""" % vars() ) | ||
87 | |||
88 | return txt + ",".join(txts) | ||
89 | |||
90 | def groups(self, item): | ||
91 | """ | ||
92 | Create HTML to link to related groups | ||
93 | """ | ||
94 | |||
95 | if len(item.groups()) == 0: | ||
96 | return "" | ||
97 | |||
98 | |||
99 | txt = "<p><b>See also:</b><br>" | ||
100 | txts = [] | ||
101 | for group in item.groups(): | ||
102 | txts.append( """<a href="group%s.html">%s</a> """ % (group, group) ) | ||
103 | |||
104 | return txt + ",".join(txts) | ||
105 | |||
106 | |||
107 | def createKeySite(self, item): | ||
108 | """ | ||
109 | Create a site for a key. It contains the header/navigator, a heading, | ||
110 | the description, links to related keys and to the groups. | ||
111 | """ | ||
112 | |||
113 | return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | ||
114 | <html><head><title>Key %s</title></head> | ||
115 | <link rel="stylesheet" href="style.css" type="text/css"> | ||
116 | <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> | ||
117 | %s | ||
118 | <h2><span class="refentrytitle">%s</span></h2> | ||
119 | |||
120 | <div class="refsynopsisdiv"> | ||
121 | <h2>Synopsis</h2> | ||
122 | <p> | ||
123 | %s | ||
124 | </p> | ||
125 | </div> | ||
126 | |||
127 | <div class="refsynopsisdiv"> | ||
128 | <h2>Related Keys</h2> | ||
129 | <p> | ||
130 | %s | ||
131 | </p> | ||
132 | </div> | ||
133 | |||
134 | <div class="refsynopsisdiv"> | ||
135 | <h2>Groups</h2> | ||
136 | <p> | ||
137 | %s | ||
138 | </p> | ||
139 | </div> | ||
140 | |||
141 | |||
142 | </body> | ||
143 | """ % (item.name(), self.createNavigator(), item.name(), | ||
144 | self.escape(item.description()), self.relatedKeys(item), self.groups(item)) | ||
145 | |||
146 | def createGroupsSite(self, doc): | ||
147 | """ | ||
148 | Create the Group Overview site | ||
149 | """ | ||
150 | |||
151 | groups = "" | ||
152 | sorted_groups = sorted(doc.groups()) | ||
153 | for group in sorted_groups: | ||
154 | groups += """<a href="group%s.html">%s</a><br>""" % (group, group) | ||
155 | |||
156 | return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | ||
157 | <html><head><title>Group overview</title></head> | ||
158 | <link rel="stylesheet" href="style.css" type="text/css"> | ||
159 | <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> | ||
160 | %s | ||
161 | <h2>Available Groups</h2> | ||
162 | %s | ||
163 | </body> | ||
164 | """ % (self.createNavigator(), groups) | ||
165 | |||
166 | def createIndex(self): | ||
167 | """ | ||
168 | Create the index file | ||
169 | """ | ||
170 | |||
171 | return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | ||
172 | <html><head><title>Bitbake Documentation</title></head> | ||
173 | <link rel="stylesheet" href="style.css" type="text/css"> | ||
174 | <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> | ||
175 | %s | ||
176 | <h2>Documentation Entrance</h2> | ||
177 | <a href="all_groups.html">All available groups</a><br> | ||
178 | <a href="all_keys.html">All available keys</a><br> | ||
179 | </body> | ||
180 | """ % self.createNavigator() | ||
181 | |||
182 | def createKeysSite(self, doc): | ||
183 | """ | ||
184 | Create Overview of all avilable keys | ||
185 | """ | ||
186 | keys = "" | ||
187 | sorted_keys = sorted(doc.doc_keys()) | ||
188 | for key in sorted_keys: | ||
189 | keys += """<a href="key%s.html">%s</a><br>""" % (key, key) | ||
190 | |||
191 | return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | ||
192 | <html><head><title>Key overview</title></head> | ||
193 | <link rel="stylesheet" href="style.css" type="text/css"> | ||
194 | <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> | ||
195 | %s | ||
196 | <h2>Available Keys</h2> | ||
197 | %s | ||
198 | </body> | ||
199 | """ % (self.createNavigator(), keys) | ||
200 | |||
201 | def createGroupSite(self, gr, items, _description = None): | ||
202 | """ | ||
203 | Create a site for a group: | ||
204 | Group the name of the group, items contain the name of the keys | ||
205 | inside this group | ||
206 | """ | ||
207 | groups = "" | ||
208 | description = "" | ||
209 | |||
210 | # create a section with the group descriptions | ||
211 | if _description: | ||
212 | description += "<h2 Description of Grozp %s</h2>" % gr | ||
213 | description += _description | ||
214 | |||
215 | items.sort(lambda x, y:cmp(x.name(), y.name())) | ||
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 | %s | ||
225 | <div class="refsynopsisdiv"> | ||
226 | <h2>Keys in Group %s</h2> | ||
227 | <pre class="synopsis"> | ||
228 | %s | ||
229 | </pre> | ||
230 | </div> | ||
231 | </body> | ||
232 | """ % (gr, self.createNavigator(), description, gr, groups) | ||
233 | |||
234 | |||
235 | |||
236 | def createCSS(self): | ||
237 | """ | ||
238 | Create the CSS file | ||
239 | """ | ||
240 | return """.synopsis, .classsynopsis | ||
241 | { | ||
242 | background: #eeeeee; | ||
243 | border: solid 1px #aaaaaa; | ||
244 | padding: 0.5em; | ||
245 | } | ||
246 | .programlisting | ||
247 | { | ||
248 | background: #eeeeff; | ||
249 | border: solid 1px #aaaaff; | ||
250 | padding: 0.5em; | ||
251 | } | ||
252 | .variablelist | ||
253 | { | ||
254 | padding: 4px; | ||
255 | margin-left: 3em; | ||
256 | } | ||
257 | .variablelist td:first-child | ||
258 | { | ||
259 | vertical-align: top; | ||
260 | } | ||
261 | table.navigation | ||
262 | { | ||
263 | background: #ffeeee; | ||
264 | border: solid 1px #ffaaaa; | ||
265 | margin-top: 0.5em; | ||
266 | margin-bottom: 0.5em; | ||
267 | } | ||
268 | .navigation a | ||
269 | { | ||
270 | color: #770000; | ||
271 | } | ||
272 | .navigation a:visited | ||
273 | { | ||
274 | color: #550000; | ||
275 | } | ||
276 | .navigation .title | ||
277 | { | ||
278 | font-size: 200%; | ||
279 | } | ||
280 | div.refnamediv | ||
281 | { | ||
282 | margin-top: 2em; | ||
283 | } | ||
284 | div.gallery-float | ||
285 | { | ||
286 | float: left; | ||
287 | padding: 10px; | ||
288 | } | ||
289 | div.gallery-float img | ||
290 | { | ||
291 | border-style: none; | ||
292 | } | ||
293 | div.gallery-spacer | ||
294 | { | ||
295 | clear: both; | ||
296 | } | ||
297 | a | ||
298 | { | ||
299 | text-decoration: none; | ||
300 | } | ||
301 | a:hover | ||
302 | { | ||
303 | text-decoration: underline; | ||
304 | color: #FF0000; | ||
305 | } | ||
306 | """ | ||
307 | |||
308 | |||
309 | |||
310 | class DocumentationItem: | ||
311 | """ | ||
312 | A class to hold information about a configuration | ||
313 | item. It contains the key name, description, a list of related names, | ||
314 | and the group this item is contained in. | ||
315 | """ | ||
316 | |||
317 | def __init__(self): | ||
318 | self._groups = [] | ||
319 | self._related = [] | ||
320 | self._name = "" | ||
321 | self._desc = "" | ||
322 | |||
323 | def groups(self): | ||
324 | return self._groups | ||
325 | |||
326 | def name(self): | ||
327 | return self._name | ||
328 | |||
329 | def description(self): | ||
330 | return self._desc | ||
331 | |||
332 | def related(self): | ||
333 | return self._related | ||
334 | |||
335 | def setName(self, name): | ||
336 | self._name = name | ||
337 | |||
338 | def setDescription(self, desc): | ||
339 | self._desc = desc | ||
340 | |||
341 | def addGroup(self, group): | ||
342 | self._groups.append(group) | ||
343 | |||
344 | def addRelation(self, relation): | ||
345 | self._related.append(relation) | ||
346 | |||
347 | def sort(self): | ||
348 | self._related.sort() | ||
349 | self._groups.sort() | ||
350 | |||
351 | |||
352 | class Documentation: | ||
353 | """ | ||
354 | Holds the documentation... with mappings from key to items... | ||
355 | """ | ||
356 | |||
357 | def __init__(self): | ||
358 | self.__keys = {} | ||
359 | self.__groups = {} | ||
360 | |||
361 | def insert_doc_item(self, item): | ||
362 | """ | ||
363 | Insert the Doc Item into the internal list | ||
364 | of representation | ||
365 | """ | ||
366 | item.sort() | ||
367 | self.__keys[item.name()] = item | ||
368 | |||
369 | for group in item.groups(): | ||
370 | if not group in self.__groups: | ||
371 | self.__groups[group] = [] | ||
372 | self.__groups[group].append(item) | ||
373 | self.__groups[group].sort() | ||
374 | |||
375 | |||
376 | def doc_item(self, key): | ||
377 | """ | ||
378 | Return the DocumentationInstance describing the key | ||
379 | """ | ||
380 | try: | ||
381 | return self.__keys[key] | ||
382 | except KeyError: | ||
383 | return None | ||
384 | |||
385 | def doc_keys(self): | ||
386 | """ | ||
387 | Return the documented KEYS (names) | ||
388 | """ | ||
389 | return self.__keys.keys() | ||
390 | |||
391 | def groups(self): | ||
392 | """ | ||
393 | Return the names of available groups | ||
394 | """ | ||
395 | return self.__groups.keys() | ||
396 | |||
397 | def group_content(self, group_name): | ||
398 | """ | ||
399 | Return a list of keys/names that are in a specefic | ||
400 | group or the empty list | ||
401 | """ | ||
402 | try: | ||
403 | return self.__groups[group_name] | ||
404 | except KeyError: | ||
405 | return [] | ||
406 | |||
407 | |||
408 | def parse_cmdline(args): | ||
409 | """ | ||
410 | Parse the CMD line and return the result as a n-tuple | ||
411 | """ | ||
412 | |||
413 | parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__, __version__)) | ||
414 | usage = """%prog [options] | ||
415 | |||
416 | Create a set of html pages (documentation) for a bitbake.conf.... | ||
417 | """ | ||
418 | |||
419 | # Add the needed options | ||
420 | parser.add_option( "-c", "--config", help = "Use the specified configuration file as source", | ||
421 | action = "store", dest = "config", default = os.path.join("conf", "documentation.conf") ) | ||
422 | |||
423 | parser.add_option( "-o", "--output", help = "Output directory for html files", | ||
424 | action = "store", dest = "output", default = "html/" ) | ||
425 | |||
426 | parser.add_option( "-D", "--debug", help = "Increase the debug level", | ||
427 | action = "count", dest = "debug", default = 0 ) | ||
428 | |||
429 | parser.add_option( "-v", "--verbose", help = "output more chit-char to the terminal", | ||
430 | action = "store_true", dest = "verbose", default = False ) | ||
431 | |||
432 | options, args = parser.parse_args( sys.argv ) | ||
433 | |||
434 | bb.msg.init_msgconfig(options.verbose, 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 | if isinstance(documentation, dict): | ||
454 | documentation = documentation[""] | ||
455 | |||
456 | # Assuming we've the file loaded now, we will initialize the 'tree' | ||
457 | doc = Documentation() | ||
458 | |||
459 | # defined states | ||
460 | state_begin = 0 | ||
461 | state_see = 1 | ||
462 | state_group = 2 | ||
463 | |||
464 | for key in bb.data.keys(documentation): | ||
465 | data = documentation.getVarFlag(key, "doc") | ||
466 | if not data: | ||
467 | continue | ||
468 | |||
469 | # The Documentation now starts | ||
470 | doc_ins = DocumentationItem() | ||
471 | doc_ins.setName(key) | ||
472 | |||
473 | |||
474 | tokens = data.split(' ') | ||
475 | state = state_begin | ||
476 | string= "" | ||
477 | for token in tokens: | ||
478 | token = token.strip(',') | ||
479 | |||
480 | if not state == state_see and token == "@see": | ||
481 | state = state_see | ||
482 | continue | ||
483 | elif not state == state_group and token == "@group": | ||
484 | state = state_group | ||
485 | continue | ||
486 | |||
487 | if state == state_begin: | ||
488 | string += " %s" % token | ||
489 | elif state == state_see: | ||
490 | doc_ins.addRelation(token) | ||
491 | elif state == state_group: | ||
492 | doc_ins.addGroup(token) | ||
493 | |||
494 | # set the description | ||
495 | doc_ins.setDescription(string) | ||
496 | doc.insert_doc_item(doc_ins) | ||
497 | |||
498 | # let us create the HTML now | ||
499 | bb.utils.mkdirhier(output_dir) | ||
500 | os.chdir(output_dir) | ||
501 | |||
502 | # Let us create the sites now. We do it in the following order | ||
503 | # Start with the index.html. It will point to sites explaining all | ||
504 | # keys and groups | ||
505 | html_slave = HTMLFormatter() | ||
506 | |||
507 | f = file('style.css', 'w') | ||
508 | print >> f, html_slave.createCSS() | ||
509 | |||
510 | f = file('index.html', 'w') | ||
511 | print >> f, html_slave.createIndex() | ||
512 | |||
513 | f = file('all_groups.html', 'w') | ||
514 | print >> f, html_slave.createGroupsSite(doc) | ||
515 | |||
516 | f = file('all_keys.html', 'w') | ||
517 | print >> f, html_slave.createKeysSite(doc) | ||
518 | |||
519 | # now for each group create the site | ||
520 | for group in doc.groups(): | ||
521 | f = file('group%s.html' % group, 'w') | ||
522 | print >> f, html_slave.createGroupSite(group, doc.group_content(group)) | ||
523 | |||
524 | # now for the keys | ||
525 | for key in doc.doc_keys(): | ||
526 | f = file('key%s.html' % doc.doc_item(key).name(), 'w') | ||
527 | print >> f, html_slave.createKeySite(doc.doc_item(key)) | ||
528 | |||
529 | |||
530 | if __name__ == "__main__": | ||
531 | main() | ||