~ubuntu-branches/ubuntu/trusty/python-docutils/trusty

« back to all changes in this revision

Viewing changes to .pc/fix-buildhtml-progress.diff/tools/buildhtml.py

  • Committer: Package Import Robot
  • Author(s): Dmitry Shachnev
  • Date: 2013-02-24 13:00:16 UTC
  • mfrom: (11.1.8 experimental)
  • Revision ID: package-import@ubuntu.com-20130224130016-5my182zunop3uvij
Tags: 0.10-1ubuntu1
* Merge with Debian experimental, remaining changes:
  - Use dh_python2 instead of dh_pysupport.
  - debian/patches/disable_py33_failing_tests.diff: Disable the 5 tests
    which currently fail with Python 3.3, to fix FTBFS.
* debian/patches/support-aliases-in-references.diff: upstream patch to
  support embedded aliases within hyperlink references.
* debian/x-rst.xml: add mime file (for text/x-rst).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
# $Id: buildhtml.py 7464 2012-06-25 13:16:03Z milde $
 
4
# Author: David Goodger <goodger@python.org>
 
5
# Copyright: This module has been placed in the public domain.
 
6
 
 
7
"""
 
8
Generates .html from all the .txt files in a directory.
 
9
 
 
10
Ordinary .txt files are understood to be standalone reStructuredText.
 
11
Files named ``pep-*.txt`` are interpreted as reStructuredText PEPs.
 
12
"""
 
13
# Once PySource is here, build .html from .py as well.
 
14
 
 
15
__docformat__ = 'reStructuredText'
 
16
 
 
17
 
 
18
try:
 
19
    import locale
 
20
    locale.setlocale(locale.LC_ALL, '')
 
21
except:
 
22
    pass
 
23
 
 
24
import sys
 
25
import os
 
26
import os.path
 
27
import copy
 
28
from fnmatch import fnmatch
 
29
import docutils
 
30
from docutils import ApplicationError
 
31
from docutils import core, frontend, utils
 
32
from docutils.utils.error_reporting import ErrorOutput, ErrorString
 
33
from docutils.parsers import rst
 
34
from docutils.readers import standalone, pep
 
35
from docutils.writers import html4css1, pep_html
 
36
 
 
37
 
 
38
usage = '%prog [options] [<directory> ...]'
 
39
description = ('Generates .html from all the reStructuredText .txt files '
 
40
               '(including PEPs) in each <directory> '
 
41
               '(default is the current directory).')
 
42
 
 
43
 
 
44
class SettingsSpec(docutils.SettingsSpec):
 
45
 
 
46
    """
 
47
    Runtime settings & command-line options for the front end.
 
48
    """
 
49
 
 
50
    prune_default = ['.hg', '.bzr', '.git', '.svn', 'CVS']
 
51
 
 
52
    # Can't be included in OptionParser below because we don't want to
 
53
    # override the base class.
 
54
    settings_spec = (
 
55
        'Build-HTML Options',
 
56
        None,
 
57
        (('Recursively scan subdirectories for files to process.  This is '
 
58
          'the default.',
 
59
          ['--recurse'],
 
60
          {'action': 'store_true', 'default': 1,
 
61
           'validator': frontend.validate_boolean}),
 
62
         ('Do not scan subdirectories for files to process.',
 
63
          ['--local'], {'dest': 'recurse', 'action': 'store_false'}),
 
64
         ('Do not process files in <directory> (shell globbing patterns, '
 
65
          'separated by colons).  This option may be used '
 
66
          'more than once to specify multiple directories.  Default: "%s".'
 
67
          % ':'.join(prune_default),
 
68
          ['--prune'],
 
69
          {'metavar': '<directory>', 'action': 'append',
 
70
           'validator': frontend.validate_colon_separated_string_list,
 
71
           'default': prune_default,}),
 
72
         ('Recursively ignore files matching any of the given '
 
73
          'wildcard (shell globbing) patterns (separated by colons).',
 
74
          ['--ignore'],
 
75
          {'metavar': '<patterns>', 'action': 'append',
 
76
           'default': [],
 
77
           'validator': frontend.validate_colon_separated_string_list}),
 
78
         ('Work silently (no progress messages).  Independent of "--quiet".',
 
79
          ['--silent'],
 
80
          {'action': 'store_true', 'validator': frontend.validate_boolean}),
 
81
         ('Do not process files, show files that would be processed.',
 
82
          ['--dry-run'],
 
83
          {'action': 'store_true', 'validator': frontend.validate_boolean}),))
 
84
 
 
85
    relative_path_settings = ('prune',)
 
86
    config_section = 'buildhtml application'
 
87
    config_section_dependencies = ('applications',)
 
88
 
 
89
 
 
90
class OptionParser(frontend.OptionParser):
 
91
 
 
92
    """
 
93
    Command-line option processing for the ``buildhtml.py`` front end.
 
94
    """
 
95
 
 
96
    def check_values(self, values, args):
 
97
        frontend.OptionParser.check_values(self, values, args)
 
98
        values._source = None
 
99
        return values
 
100
 
 
101
    def check_args(self, args):
 
102
        source = destination = None
 
103
        if args:
 
104
            self.values._directories = args
 
105
        else:
 
106
            self.values._directories = [os.getcwd()]
 
107
        return source, destination
 
108
 
 
109
 
 
110
class Struct:
 
111
 
 
112
    """Stores data attributes for dotted-attribute access."""
 
113
 
 
114
    def __init__(self, **keywordargs):
 
115
        self.__dict__.update(keywordargs)
 
116
 
 
117
 
 
118
class Builder:
 
119
 
 
120
    def __init__(self):
 
121
        self.publishers = {
 
122
            '': Struct(components=(pep.Reader, rst.Parser, pep_html.Writer,
 
123
                                   SettingsSpec)),
 
124
            '.txt': Struct(components=(rst.Parser, standalone.Reader,
 
125
                                       html4css1.Writer, SettingsSpec),
 
126
                           reader_name='standalone',
 
127
                           writer_name='html'),
 
128
            'PEPs': Struct(components=(rst.Parser, pep.Reader,
 
129
                                       pep_html.Writer, SettingsSpec),
 
130
                           reader_name='pep',
 
131
                           writer_name='pep_html')}
 
132
        """Publisher-specific settings.  Key '' is for the front-end script
 
133
        itself.  ``self.publishers[''].components`` must contain a superset of
 
134
        all components used by individual publishers."""
 
135
 
 
136
        self.setup_publishers()
 
137
 
 
138
    def setup_publishers(self):
 
139
        """
 
140
        Manage configurations for individual publishers.
 
141
 
 
142
        Each publisher (combination of parser, reader, and writer) may have
 
143
        its own configuration defaults, which must be kept separate from those
 
144
        of the other publishers.  Setting defaults are combined with the
 
145
        config file settings and command-line options by
 
146
        `self.get_settings()`.
 
147
        """
 
148
        for name, publisher in self.publishers.items():
 
149
            option_parser = OptionParser(
 
150
                components=publisher.components, read_config_files=1,
 
151
                usage=usage, description=description)
 
152
            publisher.option_parser = option_parser
 
153
            publisher.setting_defaults = option_parser.get_default_values()
 
154
            frontend.make_paths_absolute(publisher.setting_defaults.__dict__,
 
155
                                         option_parser.relative_path_settings)
 
156
            publisher.config_settings = (
 
157
                option_parser.get_standard_config_settings())
 
158
        self.settings_spec = self.publishers[''].option_parser.parse_args(
 
159
            values=frontend.Values())   # no defaults; just the cmdline opts
 
160
        self.initial_settings = self.get_settings('')
 
161
 
 
162
    def get_settings(self, publisher_name, directory=None):
 
163
        """
 
164
        Return a settings object, from multiple sources.
 
165
 
 
166
        Copy the setting defaults, overlay the startup config file settings,
 
167
        then the local config file settings, then the command-line options.
 
168
        Assumes the current directory has been set.
 
169
        """
 
170
        publisher = self.publishers[publisher_name]
 
171
        settings = frontend.Values(publisher.setting_defaults.__dict__)
 
172
        settings.update(publisher.config_settings, publisher.option_parser)
 
173
        if directory:
 
174
            local_config = publisher.option_parser.get_config_file_settings(
 
175
                os.path.join(directory, 'docutils.conf'))
 
176
            frontend.make_paths_absolute(
 
177
                local_config, publisher.option_parser.relative_path_settings,
 
178
                directory)
 
179
            settings.update(local_config, publisher.option_parser)
 
180
        settings.update(self.settings_spec.__dict__, publisher.option_parser)
 
181
        return settings
 
182
 
 
183
    def run(self, directory=None, recurse=1):
 
184
        recurse = recurse and self.initial_settings.recurse
 
185
        if directory:
 
186
            self.directories = [directory]
 
187
        elif self.settings_spec._directories:
 
188
            self.directories = self.settings_spec._directories
 
189
        else:
 
190
            self.directories = [os.getcwd()]
 
191
        for directory in self.directories:
 
192
            for root, dirs, files in os.walk(directory):
 
193
                # os.walk by default this recurses down the tree,
 
194
                # influence by modifying dirs.
 
195
                if not recurse:
 
196
                    del dirs[:]
 
197
                self.visit(root, files, dirs)
 
198
 
 
199
    def visit(self, directory, names, subdirectories):
 
200
        settings = self.get_settings('', directory)
 
201
        errout = ErrorOutput(encoding=settings.error_encoding)
 
202
        if settings.prune and (os.path.abspath(directory) in settings.prune):
 
203
            errout.write('/// ...Skipping directory (pruned): %s\n' %
 
204
                         directory)
 
205
            sys.stderr.flush()
 
206
            del subdirectories[:]
 
207
            return
 
208
        if not self.initial_settings.silent:
 
209
            errout.write('/// Processing directory: %s' % directory)
 
210
            sys.stderr.flush()
 
211
        # settings.ignore grows many duplicate entries as we recurse
 
212
        # if we add patterns in config files or on the command line.
 
213
        for pattern in utils.uniq(settings.ignore):
 
214
            for i in range(len(names) - 1, -1, -1):
 
215
                if fnmatch(names[i], pattern):
 
216
                    # Modify in place!
 
217
                    del names[i]
 
218
        for name in names:
 
219
            if name.endswith('.txt'):
 
220
                self.process_txt(directory, name)
 
221
 
 
222
    def process_txt(self, directory, name):
 
223
        if name.startswith('pep-'):
 
224
            publisher = 'PEPs'
 
225
        else:
 
226
            publisher = '.txt'
 
227
        settings = self.get_settings(publisher, directory)
 
228
        errout = ErrorOutput(encoding=settings.error_encoding)
 
229
        pub_struct = self.publishers[publisher]
 
230
        settings._source = os.path.normpath(os.path.join(directory, name))
 
231
        settings._destination = settings._source[:-4]+'.html'
 
232
        if not self.initial_settings.silent:
 
233
            errout.write('    ::: Processing: %s\n' % name)
 
234
            sys.stderr.flush()
 
235
        try:
 
236
            if not settings.dry_run:
 
237
                core.publish_file(source_path=settings._source,
 
238
                              destination_path=settings._destination,
 
239
                              reader_name=pub_struct.reader_name,
 
240
                              parser_name='restructuredtext',
 
241
                              writer_name=pub_struct.writer_name,
 
242
                              settings=settings)
 
243
        except ApplicationError:
 
244
            error = sys.exc_info()[1] # get exception in Python <2.6 and 3.x
 
245
            errout.write('        %s\n' % ErrorString(error))
 
246
 
 
247
 
 
248
if __name__ == "__main__":
 
249
    Builder().run()