root/masterdriverz/pkgcore-dev/build_docs.py @ masterdriverz%2540gmail.com-20080524202604-7jgff51ay1w7mwgx

Revision masterdriverz%2540gmail.com-20080524202604-7jgff51ay1w7mwgx, 8.8 kB (checked in by Charlie Shepherd <masterdriverz@…>, 6 months ago)

Kill trailing whitespace

  • Property executable set to True
Line 
1#!/usr/bin/env python
2
3
4"""Script for rebuilding our documentation."""
5
6
7import sys
8import os.path
9import optparse
10
11from docutils import nodes, core
12from docutils.parsers import rst
13import docutils.utils
14
15sys.path.append('man')
16import manpage
17
18from snakeoil import modules
19
20# (limited) support for trac wiki links.
21# This is copied and hacked up from rst.py in the trac source.
22
23def trac_get_reference(rawtext, link, text):
24    if not link.startswith('rst:'):
25        return None
26    target = link.split(':', 1)[1]
27    reference = nodes.reference(rawtext, text or target)
28    reference['refuri'] = target
29    return reference
30
31def trac(name, arguments, options, content, lineno,
32         content_offset, block_text, state, state_machine):
33    """Inserts a `reference` node into the document
34    for a given `TracLink`_, based on the content
35    of the arguments.
36
37    Usage::
38
39      .. trac:: target [text]
40
41    ``target`` may be any `TracLink`_, provided it doesn't
42    embed a space character (e.g. wiki:"..." notation won't work).
43
44    ``[text]`` is optional.  If not given, ``target`` is
45    used as the reference text.
46
47    .. _TracLink: http://trac.edgewall.org/wiki/TracLinks
48    """
49    link = arguments[0]
50    if len(arguments) == 2:
51        text = arguments[1]
52    else:
53        text = None
54    reference = trac_get_reference(block_text, link, text)
55    if reference:
56        p = nodes.paragraph()
57        p += reference
58        return p
59    # didn't find a match (invalid TracLink),
60    # report a warning
61    warning = state_machine.reporter.warning(
62            '%s is not a valid TracLink' % (arguments[0]),
63            nodes.literal_block(block_text, block_text),
64            line=lineno)
65    return [warning]
66
67def trac_role(name, rawtext, text, lineno, inliner, options={},
68              content=[]):
69    args  = text.split(" ",1)
70    link = args[0]
71    if len(args)==2:
72        text = args[1]
73    else:
74        text = None
75    reference = trac_get_reference(rawtext, link, text)
76    if reference:
77        return [reference], []
78    warning = nodes.warning(None, nodes.literal_block(text,
79        'WARNING: %s is not a valid TracLink' % rawtext))
80    return warning, []
81
82# 1 required arg, 1 optional arg, spaces allowed in last arg
83trac.arguments = (1, 1, True)
84trac.options = None
85trac.content = False
86rst.directives.register_directive('trac', trac)
87rst.roles.register_local_role('trac', trac_role)
88
89
90class HelpFormatter(optparse.HelpFormatter):
91
92    """Hack to "format" optparse help as a docutils tree.
93
94    Normally the methods return strings that are glued together. This
95    one builds a docutils tree as its "result" attribute and returns
96    empty strings.
97    """
98
99    def __init__(self, state):
100        optparse.HelpFormatter.__init__(
101            self, indent_increment=0, max_help_position=24, width=80,
102            short_first=0)
103        self.result = nodes.paragraph()
104        self.current = nodes.option_list()
105        self.result += self.current
106        self._state = state
107
108    def format_heading(self, heading):
109        section = nodes.section()
110        self.result += section
111        section += nodes.title(text=heading)
112        self.current = nodes.option_list()
113        section += self.current
114        return ''
115
116    def format_option(self, option):
117        item = nodes.option_list_item()
118        group = nodes.option_group()
119        item.append(group)
120        for opt_string in self.option_strings[option]:
121            opt_node = nodes.option()
122            opt_node.append(nodes.option_string(text=opt_string))
123            if option.takes_value():
124                metavar = option.metavar or option.dest
125                opt_node.append(nodes.option_argument(text=metavar))
126            group.append(opt_node)
127        if option.long_help:
128            desc = nodes.description()
129            par = nodes.paragraph()
130            helpnodes, messages = self._state.inline_text(option.long_help, 0)
131            par.extend(helpnodes)
132            # XXX I have no idea if this makes sense and triggering it
133            # without making rst2man explode is nontrivial.
134            par.extend(messages)
135            desc.append(par)
136            group.append(desc)
137        elif option.help:
138            desc = nodes.description()
139            par = nodes.paragraph(text=option.help)
140            desc.append(par)
141            group.append(desc)
142        self.current.append(item)
143        return ''
144
145    def format_option_strings(self, option):
146        return option._short_opts + option._long_opts
147
148def script_options(name, arguments, options, content, lineno,
149                   content_offset, block_text, state, state_machine):
150    assert len(arguments) == 1
151    assert not options, options
152    parserclass = modules.load_attribute(arguments[0])
153    if isinstance(parserclass, dict):
154        comp = nodes.compound()
155        base = arguments[0].split(".")[-2] # script location.
156        for command_name, bits in sorted(parserclass.iteritems()):
157            comp += nodes.title(text="%s %s" % (base, command_name))
158            comp += generate_script(bits[0], state)
159        return comp
160    return generate_script(parserclass, state)
161
162
163def generate_script(parserclass, state):
164    optionparser = parserclass()
165    formatter = HelpFormatter(state)
166    optionparser.format_help(formatter)
167    return formatter.result
168
169# 1 argument, no optional arguments, no spaces in the argument.
170script_options.arguments = (1, 0, False)
171# No options.
172script_options.options = None
173# No content used.
174script_options.content = False
175
176rst.directives.register_directive('pkgcore_script_options', script_options)
177
178
179def process_docs(directory, force, do_parent=False):
180    """Generate the table of contents and html files."""
181    print 'processing %s' % (directory,)
182    # Dirs first so we pick up their contents when generating ours.
183    for child in os.listdir(directory):
184        target = os.path.join(directory, child)
185        if os.path.isdir(target):
186            process_docs(target, force, True)
187    # Write the table of contents .rst file while processing files.
188    indexpath = os.path.join(directory, 'index.rst')
189    out = open(indexpath, 'w')
190    try:
191        out.write('===================\n')
192        out.write(' Table of contents\n')
193        out.write('===================\n')
194        out.write('\n')
195        if do_parent:
196            out.write('- `../ <../index.html>`_\n')
197        for entry in sorted(os.listdir(directory)):
198            original = os.path.join(directory, entry)
199            if entry == 'index.rst':
200                continue
201            if entry.lower().endswith('.rst'):
202                base = entry[:-4]
203                target = os.path.join(directory, base) + '.html'
204                out.write('- `%s <%s.html>`_\n' % (base, base))
205                # Check if we need to reprocess.
206                if force or not os.path.exists(target) or (
207                    os.path.getmtime(target) < os.path.getmtime(original)):
208                    print 'writing %s' % (target,)
209                    core.publish_file(source_path=original,
210                                      destination_path=target,
211                                      writer_name='html')
212                else:
213                    print 'up to date: %s' % (target,)
214            elif (os.path.isdir(original) and
215                  os.path.exists(os.path.join(original, 'index.rst'))):
216                out.write('- `%s/ <%s/index.html>`_\n' % (entry, entry))
217    finally:
218        out.close()
219    # And convert the index.
220    # (Guess we could keep its rst only in memory but who knows, someone
221    # might want to read it!)
222    core.publish_file(source_path=indexpath,
223                      destination_path=os.path.join(directory, 'index.html'),
224                      writer_name='html')
225
226
227def process_man(directory, force, debug):
228    """Generate manpages."""
229    print 'processing %s' % (directory,)
230    debug_loc = None
231    for entry in os.listdir(directory):
232        original = os.path.join(directory, entry)
233        if entry.lower().endswith('rst'):
234            base = entry[:-4]
235            target = os.path.join(directory, base)
236            if debug:
237                debug_loc = os.path.join(directory, base) + '.doctree'
238            if force or not os.path.exists(target) or (
239                os.path.getmtime(target) < os.path.getmtime(original)):
240                print 'writing %s' % (target,)
241                core.publish_file(source_path=original,
242                                  destination_path=target,
243                                  writer=manpage.Writer(debug_loc))
244            else:
245                print 'up to date: %s' % (target,)
246
247
248if __name__ == '__main__':
249    print 'checking documentation, use --force to force rebuild'
250    print
251    force = '--force' in sys.argv
252    debug = '--debug' in sys.argv
253    for directory in ['dev-notes', 'doc']:
254        process_docs(os.path.join(os.path.dirname(__file__), directory), force)
255    process_man(os.path.join(os.path.dirname(__file__), 'man'), force, debug)
Note: See TracBrowser for help on using the browser.