second try
[vsorcdistro/.git] / ryu / .eggs / pbr-5.3.1-py2.7.egg / pbr / builddoc.py
1 # Copyright 2011 OpenStack Foundation
2 # Copyright 2012-2013 Hewlett-Packard Development Company, L.P.
3 # All Rights Reserved.
4 #
5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
6 #    not use this file except in compliance with the License. You may obtain
7 #    a copy of the License at
8 #
9 #         http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #    Unless required by applicable law or agreed to in writing, software
12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 #    License for the specific language governing permissions and limitations
15 #    under the License.
16
17 from distutils import log
18 import fnmatch
19 import os
20 import sys
21
22 try:
23     import cStringIO
24 except ImportError:
25     import io as cStringIO
26
27 try:
28     import sphinx
29     # NOTE(dhellmann): Newer versions of Sphinx have moved the apidoc
30     # module into sphinx.ext and the API is slightly different (the
31     # function expects sys.argv[1:] instead of sys.argv[:]. So, figure
32     # out where we can import it from and set a flag so we can invoke
33     # it properly. See this change in sphinx for details:
34     # https://github.com/sphinx-doc/sphinx/commit/87630c8ae8bff8c0e23187676e6343d8903003a6
35     try:
36         from sphinx.ext import apidoc
37         apidoc_use_padding = False
38     except ImportError:
39         from sphinx import apidoc
40         apidoc_use_padding = True
41     from sphinx import application
42     from sphinx import setup_command
43 except Exception as e:
44     # NOTE(dhellmann): During the installation of docutils, setuptools
45     # tries to import pbr code to find the egg_info.writer hooks. That
46     # imports this module, which imports sphinx, which imports
47     # docutils, which is being installed. Because docutils uses 2to3
48     # to convert its code during installation under python 3, the
49     # import fails, but it fails with an error other than ImportError
50     # (today it's a NameError on StandardError, an exception base
51     # class). Convert the exception type here so it can be caught in
52     # packaging.py where we try to determine if we can import and use
53     # sphinx by importing this module.  See bug #1403510 for details.
54     raise ImportError(str(e))
55 from pbr import git
56 from pbr import options
57 from pbr import version
58
59
60 _deprecated_options = ['autodoc_tree_index_modules', 'autodoc_index_modules',
61                        'autodoc_tree_excludes', 'autodoc_exclude_modules']
62 _deprecated_envs = ['AUTODOC_TREE_INDEX_MODULES', 'AUTODOC_INDEX_MODULES']
63 _rst_template = """%(heading)s
64 %(underline)s
65
66 .. automodule:: %(module)s
67   :members:
68   :undoc-members:
69   :show-inheritance:
70 """
71
72
73 def _find_modules(arg, dirname, files):
74     for filename in files:
75         if filename.endswith('.py') and filename != '__init__.py':
76             arg["%s.%s" % (dirname.replace('/', '.'),
77                            filename[:-3])] = True
78
79
80 class LocalBuildDoc(setup_command.BuildDoc):
81
82     builders = ['html']
83     command_name = 'build_sphinx'
84     sphinx_initialized = False
85
86     def _get_source_dir(self):
87         option_dict = self.distribution.get_option_dict('build_sphinx')
88         pbr_option_dict = self.distribution.get_option_dict('pbr')
89         _, api_doc_dir = pbr_option_dict.get('api_doc_dir', (None, 'api'))
90         if 'source_dir' in option_dict:
91             source_dir = os.path.join(option_dict['source_dir'][1],
92                                       api_doc_dir)
93         else:
94             source_dir = 'doc/source/' + api_doc_dir
95         if not os.path.exists(source_dir):
96             os.makedirs(source_dir)
97         return source_dir
98
99     def generate_autoindex(self, excluded_modules=None):
100         log.info("[pbr] Autodocumenting from %s"
101                  % os.path.abspath(os.curdir))
102         modules = {}
103         source_dir = self._get_source_dir()
104         for pkg in self.distribution.packages:
105             if '.' not in pkg:
106                 for dirpath, dirnames, files in os.walk(pkg):
107                     _find_modules(modules, dirpath, files)
108
109         def include(module):
110             return not any(fnmatch.fnmatch(module, pat)
111                            for pat in excluded_modules)
112
113         module_list = sorted(mod for mod in modules.keys() if include(mod))
114         autoindex_filename = os.path.join(source_dir, 'autoindex.rst')
115         with open(autoindex_filename, 'w') as autoindex:
116             autoindex.write(""".. toctree::
117    :maxdepth: 1
118
119 """)
120             for module in module_list:
121                 output_filename = os.path.join(source_dir,
122                                                "%s.rst" % module)
123                 heading = "The :mod:`%s` Module" % module
124                 underline = "=" * len(heading)
125                 values = dict(module=module, heading=heading,
126                               underline=underline)
127
128                 log.info("[pbr] Generating %s"
129                          % output_filename)
130                 with open(output_filename, 'w') as output_file:
131                     output_file.write(_rst_template % values)
132                 autoindex.write("   %s.rst\n" % module)
133
134     def _sphinx_tree(self):
135             source_dir = self._get_source_dir()
136             cmd = ['-H', 'Modules', '-o', source_dir, '.']
137             if apidoc_use_padding:
138                 cmd.insert(0, 'apidoc')
139             apidoc.main(cmd + self.autodoc_tree_excludes)
140
141     def _sphinx_run(self):
142         if not self.verbose:
143             status_stream = cStringIO.StringIO()
144         else:
145             status_stream = sys.stdout
146         confoverrides = {}
147         if self.project:
148             confoverrides['project'] = self.project
149         if self.version:
150             confoverrides['version'] = self.version
151         if self.release:
152             confoverrides['release'] = self.release
153         if self.today:
154             confoverrides['today'] = self.today
155         if self.sphinx_initialized:
156             confoverrides['suppress_warnings'] = [
157                 'app.add_directive', 'app.add_role',
158                 'app.add_generic_role', 'app.add_node',
159                 'image.nonlocal_uri',
160             ]
161         app = application.Sphinx(
162             self.source_dir, self.config_dir,
163             self.builder_target_dir, self.doctree_dir,
164             self.builder, confoverrides, status_stream,
165             freshenv=self.fresh_env, warningiserror=self.warning_is_error)
166         self.sphinx_initialized = True
167
168         try:
169             app.build(force_all=self.all_files)
170         except Exception as err:
171             from docutils import utils
172             if isinstance(err, utils.SystemMessage):
173                 sys.stder.write('reST markup error:\n')
174                 sys.stderr.write(err.args[0].encode('ascii',
175                                                     'backslashreplace'))
176                 sys.stderr.write('\n')
177             else:
178                 raise
179
180         if self.link_index:
181             src = app.config.master_doc + app.builder.out_suffix
182             dst = app.builder.get_outfilename('index')
183             os.symlink(src, dst)
184
185     def run(self):
186         option_dict = self.distribution.get_option_dict('pbr')
187
188         # TODO(stephenfin): Remove this (and the entire file) when 5.0 is
189         # released
190         warn_opts = set(option_dict.keys()).intersection(_deprecated_options)
191         warn_env = list(filter(lambda x: os.getenv(x), _deprecated_envs))
192         if warn_opts or warn_env:
193             msg = ('The autodoc and autodoc_tree features are deprecated in '
194                    '4.2 and will be removed in a future release. You should '
195                    'use the sphinxcontrib-apidoc Sphinx extension instead. '
196                    'Refer to the pbr documentation for more information.')
197             if warn_opts:
198                 msg += ' Deprecated options: %s' % list(warn_opts)
199             if warn_env:
200                 msg += ' Deprecated environment variables: %s' % warn_env
201
202             log.warn(msg)
203
204         if git._git_is_installed():
205             git.write_git_changelog(option_dict=option_dict)
206             git.generate_authors(option_dict=option_dict)
207         tree_index = options.get_boolean_option(option_dict,
208                                                 'autodoc_tree_index_modules',
209                                                 'AUTODOC_TREE_INDEX_MODULES')
210         auto_index = options.get_boolean_option(option_dict,
211                                                 'autodoc_index_modules',
212                                                 'AUTODOC_INDEX_MODULES')
213         if not os.getenv('SPHINX_DEBUG'):
214             # NOTE(afazekas): These options can be used together,
215             # but they do a very similar thing in a different way
216             if tree_index:
217                 self._sphinx_tree()
218             if auto_index:
219                 self.generate_autoindex(
220                     set(option_dict.get(
221                         "autodoc_exclude_modules",
222                         [None, ""])[1].split()))
223
224         self.finalize_options()
225
226         is_multibuilder_sphinx = version.SemanticVersion.from_pip_string(
227             sphinx.__version__) >= version.SemanticVersion(1, 6)
228
229         # TODO(stephenfin): Remove support for Sphinx < 1.6 in 4.0
230         if not is_multibuilder_sphinx:
231             log.warn('[pbr] Support for Sphinx < 1.6 will be dropped in '
232                      'pbr 4.0. Upgrade to Sphinx 1.6+')
233
234         # TODO(stephenfin): Remove this at the next MAJOR version bump
235         if self.builders != ['html']:
236             log.warn("[pbr] Sphinx 1.6 added native support for "
237                      "specifying multiple builders in the "
238                      "'[sphinx_build] builder' configuration option, "
239                      "found in 'setup.cfg'. As a result, the "
240                      "'[sphinx_build] builders' option has been "
241                      "deprecated and will be removed in pbr 4.0. Migrate "
242                      "to the 'builder' configuration option.")
243             if is_multibuilder_sphinx:
244                 self.builder = self.builders
245
246         if is_multibuilder_sphinx:
247             # Sphinx >= 1.6
248             return setup_command.BuildDoc.run(self)
249
250         # Sphinx < 1.6
251         for builder in self.builders:
252             self.builder = builder
253             self.finalize_options()
254             self._sphinx_run()
255
256     def initialize_options(self):
257         # Not a new style class, super keyword does not work.
258         setup_command.BuildDoc.initialize_options(self)
259
260         # NOTE(dstanek): exclude setup.py from the autodoc tree index
261         # builds because all projects will have an issue with it
262         self.autodoc_tree_excludes = ['setup.py']
263
264     def finalize_options(self):
265         from pbr import util
266
267         # Not a new style class, super keyword does not work.
268         setup_command.BuildDoc.finalize_options(self)
269
270         # Handle builder option from command line - override cfg
271         option_dict = self.distribution.get_option_dict('build_sphinx')
272         if 'command line' in option_dict.get('builder', [[]])[0]:
273             self.builders = option_dict['builder'][1]
274         # Allow builders to be configurable - as a comma separated list.
275         if not isinstance(self.builders, list) and self.builders:
276             self.builders = self.builders.split(',')
277
278         self.project = self.distribution.get_name()
279         self.version = self.distribution.get_version()
280         self.release = self.distribution.get_version()
281
282         # NOTE(dstanek): check for autodoc tree exclusion overrides
283         # in the setup.cfg
284         opt = 'autodoc_tree_excludes'
285         option_dict = self.distribution.get_option_dict('pbr')
286         if opt in option_dict:
287             self.autodoc_tree_excludes = util.split_multiline(
288                 option_dict[opt][1])
289
290         # handle Sphinx < 1.5.0
291         if not hasattr(self, 'warning_is_error'):
292             self.warning_is_error = False