3 # Author: David Goodger
4 # Contact: goodger@users.sourceforge.net
7 # Copyright: This module has been placed in the public domain.
10 Generates .html from all the .txt files in a directory.
12 Ordinary .txt files are understood to be standalone reStructuredText.
13 Files named ``pep-*.txt`` are interpreted as reStructuredText PEPs.
15 # Once PySource is here, build .html from .py as well.
17 __docformat__
= 'reStructuredText'
22 locale
.setlocale(locale
.LC_ALL
, '')
31 from docutils
import ApplicationError
32 from docutils
import core
, frontend
33 from docutils
.parsers
import rst
34 from docutils
.readers
import standalone
, pep
35 from docutils
.writers
import html4css1
, pep_html
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).')
44 class SettingsSpec(docutils
.SettingsSpec
):
47 Runtime settings & command-line options for the front end.
50 # Can't be included in OptionParser below because we don't want to
51 # override the base class.
55 (('Recursively scan subdirectories for files to process. This is '
58 {'action': 'store_true', 'default': 1,
59 'validator': frontend
.validate_boolean
}),
60 ('Do not scan subdirectories for files to process.',
61 ['--local'], {'dest': 'recurse', 'action': 'store_false'}),
62 ('Do not process files in <directory>. This option may be used '
63 'more than once to specify multiple directories.',
65 {'metavar': '<directory>', 'action': 'append',
66 'validator': frontend
.validate_colon_separated_string_list
}),
67 ('Work silently (no progress messages). Independent of "--quiet".',
69 {'action': 'store_true', 'validator': frontend
.validate_boolean
}),))
71 relative_path_settings
= ('prune',)
72 config_section
= 'buildhtml application'
73 config_section_dependencies
= ('applications',)
76 class OptionParser(frontend
.OptionParser
):
79 Command-line option processing for the ``buildhtml.py`` front end.
82 def check_values(self
, values
, args
):
83 frontend
.OptionParser
.check_values(self
, values
, args
)
87 def check_args(self
, args
):
88 source
= destination
= None
90 self
.values
._directories
= args
92 self
.values
._directories
= [os
.getcwd()]
93 return source
, destination
98 """Stores data attributes for dotted-attribute access."""
100 def __init__(self
, **keywordargs
):
101 self
.__dict
__.update(keywordargs
)
108 '': Struct(components
=(pep
.Reader
, rst
.Parser
, pep_html
.Writer
,
110 '.txt': Struct(components
=(rst
.Parser
, standalone
.Reader
,
111 html4css1
.Writer
, SettingsSpec
),
112 reader_name
='standalone',
114 'PEPs': Struct(components
=(rst
.Parser
, pep
.Reader
,
115 pep_html
.Writer
, SettingsSpec
),
117 writer_name
='pep_html')}
118 """Publisher-specific settings. Key '' is for the front-end script
119 itself. ``self.publishers[''].components`` must contain a superset of
120 all components used by individual publishers."""
122 self
.setup_publishers()
124 def setup_publishers(self
):
126 Manage configurations for individual publishers.
128 Each publisher (combination of parser, reader, and writer) may have
129 its own configuration defaults, which must be kept separate from those
130 of the other publishers. Setting defaults are combined with the
131 config file settings and command-line options by
132 `self.get_settings()`.
134 for name
, publisher
in self
.publishers
.items():
135 option_parser
= OptionParser(
136 components
=publisher
.components
, read_config_files
=1,
137 usage
=usage
, description
=description
)
138 publisher
.option_parser
= option_parser
139 publisher
.setting_defaults
= option_parser
.get_default_values()
140 frontend
.make_paths_absolute(publisher
.setting_defaults
.__dict
__,
141 option_parser
.relative_path_settings
)
142 publisher
.config_settings
= (
143 option_parser
.get_standard_config_settings())
144 self
.settings_spec
= self
.publishers
[''].option_parser
.parse_args(
145 values
=frontend
.Values()) # no defaults; just the cmdline opts
146 self
.initial_settings
= self
.get_settings('')
148 def get_settings(self
, publisher_name
, directory
=None):
150 Return a settings object, from multiple sources.
152 Copy the setting defaults, overlay the startup config file settings,
153 then the local config file settings, then the command-line options.
154 Assumes the current directory has been set.
156 publisher
= self
.publishers
[publisher_name
]
157 settings
= frontend
.Values(publisher
.setting_defaults
.__dict
__)
158 settings
.update(publisher
.config_settings
, publisher
.option_parser
)
160 local_config
= publisher
.option_parser
.get_config_file_settings(
161 os
.path
.join(directory
, 'docutils.conf'))
162 frontend
.make_paths_absolute(
163 local_config
, publisher
.option_parser
.relative_path_settings
,
165 settings
.update(local_config
, publisher
.option_parser
)
166 settings
.update(self
.settings_spec
.__dict
__, publisher
.option_parser
)
169 def run(self
, directory
=None, recurse
=1):
170 recurse
= recurse
and self
.initial_settings
.recurse
172 self
.directories
= [directory
]
173 elif self
.settings_spec
._directories
:
174 self
.directories
= self
.settings_spec
._directories
176 self
.directories
= [os
.getcwd()]
177 for directory
in self
.directories
:
178 os
.path
.walk(directory
, self
.visit
, recurse
)
180 def visit(self
, recurse
, directory
, names
):
181 settings
= self
.get_settings('', directory
)
182 if settings
.prune
and (os
.path
.abspath(directory
) in settings
.prune
):
183 print >>sys
.stderr
, '/// ...Skipping directory (pruned):', directory
187 if not self
.initial_settings
.silent
:
188 print >>sys
.stderr
, '/// Processing directory:', directory
192 if name
.endswith('.txt'):
193 prune
= self
.process_txt(directory
, name
)
199 def process_txt(self
, directory
, name
):
200 if name
.startswith('pep-'):
204 settings
= self
.get_settings(publisher
, directory
)
205 pub_struct
= self
.publishers
[publisher
]
206 if settings
.prune
and (directory
in settings
.prune
):
208 settings
._source
= os
.path
.normpath(os
.path
.join(directory
, name
))
209 settings
._destination
= settings
._source
[:-4]+'.html'
210 if not self
.initial_settings
.silent
:
211 print >>sys
.stderr
, ' ::: Processing:', name
214 core
.publish_file(source_path
=settings
._source
,
215 destination_path
=settings
._destination
,
216 reader_name
=pub_struct
.reader_name
,
217 parser_name
='restructuredtext',
218 writer_name
=pub_struct
.writer_name
,
220 except ApplicationError
, error
:
221 print >>sys
.stderr
, (' Error (%s): %s'
222 % (error
.__class
__.__name
__, error
))
225 if __name__
== "__main__":