srcanamdw/codescanner/pyinstaller/doc/source/tools/buildrecursive.py
changeset 1 22878952f6e2
equal deleted inserted replaced
0:509e4801c378 1:22878952f6e2
       
     1 #!/usr/bin/env python
       
     2 
       
     3 # Author: David Goodger
       
     4 # Contact: goodger@users.sourceforge.net
       
     5 # Revision: $Revision: 1.1 $
       
     6 # Date: $Date: 2009/02/05 23:03:30 $
       
     7 # Copyright: This module has been placed in the public domain.
       
     8 
       
     9 # Addapted by William Caban to look for .rst by default instead of .txt
       
    10 # added docutils availability
       
    11 
       
    12 """
       
    13 Generates .html from all the .rst files in a directory.
       
    14 
       
    15 Ordinary .rst files are understood to be standalone reStructuredText.
       
    16 Files named ``pep-*.rst`` are interpreted as reStructuredText PEPs.
       
    17 """
       
    18 # Once PySource is here, build .html from .py as well.
       
    19 
       
    20 __docformat__ = 'reStructuredText'
       
    21 
       
    22 
       
    23 try:
       
    24     import locale
       
    25     locale.setlocale(locale.LC_ALL, '')
       
    26 except:
       
    27     pass
       
    28 
       
    29 import sys
       
    30 import os
       
    31 import os.path
       
    32 import copy
       
    33 try:
       
    34 	import docutils
       
    35 	from docutils import ApplicationError
       
    36 	from docutils import core, frontend
       
    37 	from docutils.parsers import rst
       
    38 	from docutils.readers import standalone, pep
       
    39 	from docutils.writers import html4css1, pep_html
       
    40 except:
       
    41 	print "################################################################"
       
    42 	print "# You need 'docutils' installed to execute this program.       #"
       
    43 	print "# 'docutils' is available from http://docutils.sourceforge.net #"
       
    44 	print "################################################################"
       
    45 	sys.exit(1)
       
    46 
       
    47 
       
    48 usage = '%prog [options] [<directory> ...]'
       
    49 description = ('Generates .html from all the reStructuredText .rst files '
       
    50                '(including PEPs) in each <directory> '
       
    51                '(default is the current directory).')
       
    52 
       
    53 
       
    54 class SettingsSpec(docutils.SettingsSpec):
       
    55 
       
    56     """
       
    57     Runtime settings & command-line options for the front end.
       
    58     """
       
    59 
       
    60     # Can't be included in OptionParser below because we don't want to
       
    61     # override the base class.
       
    62     settings_spec = (
       
    63         'Build-HTML Options',
       
    64         None,
       
    65         (('Recursively scan subdirectories for files to process.  This is '
       
    66           'the default.',
       
    67           ['--recurse'],
       
    68           {'action': 'store_true', 'default': 1,
       
    69            'validator': frontend.validate_boolean}),
       
    70          ('Generate output files in the specified directory.  The default is '
       
    71           'to put them in the same directory of the input files.',
       
    72           ['--outpath'], {'metavar': '<directory>', 'type': 'string'}),
       
    73          ('Do not scan subdirectories for files to process.',
       
    74           ['--local'], {'dest': 'recurse', 'action': 'store_false'}),
       
    75          ('Do not process files in <directory>.  This option may be used '
       
    76           'more than once to specify multiple directories.',
       
    77           ['--prune'],
       
    78           {'metavar': '<directory>', 'action': 'append',
       
    79            'validator': frontend.validate_colon_separated_string_list}),
       
    80          ('Work silently (no progress messages).  Independent of "--quiet".',
       
    81           ['--silent'],
       
    82           {'action': 'store_true', 'validator': frontend.validate_boolean}),))
       
    83 
       
    84     relative_path_settings = ('prune',)
       
    85     config_section = 'buildhtml application'
       
    86     config_section_dependencies = ('applications',)
       
    87 
       
    88 
       
    89 class OptionParser(frontend.OptionParser):
       
    90 
       
    91     """
       
    92     Command-line option processing for the ``buildhtml.py`` front end.
       
    93     """
       
    94 
       
    95     def check_values(self, values, args):
       
    96         frontend.OptionParser.check_values(self, values, args)
       
    97         values._source = None
       
    98         return values
       
    99 
       
   100     def check_args(self, args):
       
   101         source = destination = None
       
   102         if args:
       
   103             self.values._directories = args
       
   104         else:
       
   105             self.values._directories = [os.getcwd()]
       
   106         return source, destination
       
   107 
       
   108 
       
   109 class Struct:
       
   110 
       
   111     """Stores data attributes for dotted-attribute access."""
       
   112 
       
   113     def __init__(self, **keywordargs):
       
   114         self.__dict__.update(keywordargs)
       
   115 
       
   116 
       
   117 class Builder:
       
   118 
       
   119     def __init__(self):
       
   120         self.publishers = {
       
   121             '': Struct(components=(pep.Reader, rst.Parser, pep_html.Writer,
       
   122                                    SettingsSpec)),
       
   123             '.rst': Struct(components=(rst.Parser, standalone.Reader,
       
   124                                        html4css1.Writer, SettingsSpec),
       
   125                            reader_name='standalone',
       
   126                            writer_name='html'),
       
   127             'PEPs': Struct(components=(rst.Parser, pep.Reader,
       
   128                                        pep_html.Writer, SettingsSpec),
       
   129                            reader_name='pep',
       
   130                            writer_name='pep_html')}
       
   131         """Publisher-specific settings.  Key '' is for the front-end script
       
   132         itself.  ``self.publishers[''].components`` must contain a superset of
       
   133         all components used by individual publishers."""
       
   134 
       
   135         self.setup_publishers()
       
   136 
       
   137     def setup_publishers(self):
       
   138         """
       
   139         Manage configurations for individual publishers.
       
   140 
       
   141         Each publisher (combination of parser, reader, and writer) may have
       
   142         its own configuration defaults, which must be kept separate from those
       
   143         of the other publishers.  Setting defaults are combined with the
       
   144         config file settings and command-line options by
       
   145         `self.get_settings()`.
       
   146         """
       
   147         for name, publisher in self.publishers.items():
       
   148             option_parser = OptionParser(
       
   149                 components=publisher.components, read_config_files=1,
       
   150                 usage=usage, description=description)
       
   151             publisher.option_parser = option_parser
       
   152             publisher.setting_defaults = option_parser.get_default_values()
       
   153             frontend.make_paths_absolute(publisher.setting_defaults.__dict__,
       
   154                                          option_parser.relative_path_settings)
       
   155             publisher.config_settings = (
       
   156                 option_parser.get_standard_config_settings())
       
   157         self.settings_spec = self.publishers[''].option_parser.parse_args(
       
   158             values=frontend.Values())   # no defaults; just the cmdline opts
       
   159         self.initial_settings = self.get_settings('')
       
   160 
       
   161     def get_settings(self, publisher_name, directory=None):
       
   162         """
       
   163         Return a settings object, from multiple sources.
       
   164 
       
   165         Copy the setting defaults, overlay the startup config file settings,
       
   166         then the local config file settings, then the command-line options.
       
   167         Assumes the current directory has been set.
       
   168         """
       
   169         publisher = self.publishers[publisher_name]
       
   170         settings = frontend.Values(publisher.setting_defaults.__dict__)
       
   171         settings.update(publisher.config_settings, publisher.option_parser)
       
   172         if directory:
       
   173             local_config = publisher.option_parser.get_config_file_settings(
       
   174                 os.path.join(directory, 'docutils.conf'))
       
   175             frontend.make_paths_absolute(
       
   176                 local_config, publisher.option_parser.relative_path_settings,
       
   177                 directory)
       
   178             settings.update(local_config, publisher.option_parser)
       
   179         settings.update(self.settings_spec.__dict__, publisher.option_parser)
       
   180         return settings
       
   181 
       
   182     def run(self, directory=None, recurse=1):
       
   183         recurse = recurse and self.initial_settings.recurse
       
   184         if directory:
       
   185             self.directories = [directory]
       
   186         elif self.settings_spec._directories:
       
   187             self.directories = self.settings_spec._directories
       
   188         else:
       
   189             self.directories = [os.getcwd()]
       
   190         for directory in self.directories:
       
   191             os.path.walk(directory, self.visit, recurse)
       
   192 
       
   193     def visit(self, recurse, directory, names):
       
   194         settings = self.get_settings('', directory)
       
   195         if settings.prune and (os.path.abspath(directory) in settings.prune):
       
   196             print >>sys.stderr, '/// ...Skipping directory (pruned):', directory
       
   197             sys.stderr.flush()
       
   198             names[:] = []
       
   199             return
       
   200         if not self.initial_settings.silent:
       
   201             print >>sys.stderr, '/// Processing directory:', directory
       
   202             sys.stderr.flush()
       
   203         prune = 0
       
   204         for name in names:
       
   205             if name.endswith('.rst'):
       
   206                 prune = self.process_rst(directory, name)
       
   207                 if prune:
       
   208                     break
       
   209         if not recurse:
       
   210             del names[:]
       
   211 
       
   212     def process_rst(self, directory, name):
       
   213         if name.startswith('pep-'):
       
   214             publisher = 'PEPs'
       
   215         else:
       
   216             publisher = '.rst'
       
   217         settings = self.get_settings(publisher, directory)
       
   218         pub_struct = self.publishers[publisher]
       
   219         if settings.prune and (directory in settings.prune):
       
   220             return 1
       
   221         settings._source = os.path.normpath(os.path.join(directory, name))
       
   222         settings._destination = settings._source[:-4]+'.html'
       
   223         if settings.outpath:
       
   224             # FIXME: we should probably try and recreate the exising structure here,
       
   225             # but that's more work than we need right now.
       
   226             settings._destination = os.path.join(settings.outpath, os.path.basename(settings._destination))
       
   227         if not self.initial_settings.silent:
       
   228             print >>sys.stderr, '    ::: Processing:', name
       
   229             sys.stderr.flush()
       
   230         try:
       
   231             core.publish_file(source_path=settings._source,
       
   232                               destination_path=settings._destination,
       
   233                               reader_name=pub_struct.reader_name,
       
   234                               parser_name='restructuredtext',
       
   235                               writer_name=pub_struct.writer_name,
       
   236                               settings=settings)
       
   237         except ApplicationError, error:
       
   238             print >>sys.stderr, ('        Error (%s): %s'
       
   239                                  % (error.__class__.__name__, error))
       
   240 
       
   241 
       
   242 if __name__ == "__main__":
       
   243     Builder().run()