forked from mirrors/gecko-dev
Previously, we uploaded the main Firefox tree docs to /. In reality, there are multiple Sphinx projects in the repo. In addition, it is sometimes desirable to access docs for an older version of Firefox. In this commit, we add support for specifying the S3 key prefix for uploads. Then we change the upload code to upload to multiple locations: * <project>/latest (always) * <project>/<version> (if a version is defined in the Sphinx config) * / (for the main Sphinx docs project) For the Firefox docs, ``version`` corresponds to a sanitized value from ``milestone.txt``. Currently, it resolves to ``57.0``. While we're here, we add support for declaring an alternate project name in the Sphinx conf.py file. If ``moz_project_name`` is defined, we use that as the project name. For Firefox, we set it to ``main``. This means our paths (local and uploaded) are now ``main`` instead of ``Mozilla_Source_Tree_Docs``. That's much more pleasant. MozReview-Commit-ID: 8Gl6l2m6uU4 --HG-- extra : rebase_source : e56885092c12eb8cc76e5e7300f938be566e3e5a extra : intermediate-source : 8509af1e135177a93460270b27f263c10a62d996 extra : source : 71b4f32caf209fe9dffc340c0b8ccb51ac79c7de
169 lines
5.8 KiB
Python
169 lines
5.8 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, # You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
from __future__ import absolute_import, print_function, unicode_literals
|
|
|
|
import os
|
|
import sys
|
|
|
|
from mach.decorators import (
|
|
Command,
|
|
CommandArgument,
|
|
CommandProvider,
|
|
)
|
|
|
|
import mozhttpd
|
|
|
|
from mozbuild.base import MachCommandBase
|
|
|
|
|
|
@CommandProvider
|
|
class Documentation(MachCommandBase):
|
|
"""Helps manage in-tree documentation."""
|
|
|
|
@Command('doc', category='devenv',
|
|
description='Generate and display documentation from the tree.')
|
|
@CommandArgument('what', nargs='*', metavar='DIRECTORY [, DIRECTORY]',
|
|
help='Path(s) to documentation to build and display.')
|
|
@CommandArgument('--format', default='html',
|
|
help='Documentation format to write.')
|
|
@CommandArgument('--outdir', default=None, metavar='DESTINATION',
|
|
help='Where to write output.')
|
|
@CommandArgument('--archive', action='store_true',
|
|
help='Write a gzipped tarball of generated docs')
|
|
@CommandArgument('--no-open', dest='auto_open', default=True,
|
|
action='store_false',
|
|
help="Don't automatically open HTML docs in a browser.")
|
|
@CommandArgument('--http', const=':6666', metavar='ADDRESS', nargs='?',
|
|
help='Serve documentation on an HTTP server, '
|
|
'e.g. ":6666".')
|
|
@CommandArgument('--upload', action='store_true',
|
|
help='Upload generated files to S3')
|
|
def build_docs(self, what=None, format=None, outdir=None, auto_open=True,
|
|
http=None, archive=False, upload=False):
|
|
self._activate_virtualenv()
|
|
self.virtualenv_manager.install_pip_package('sphinx_rtd_theme==0.1.6')
|
|
|
|
import sphinx
|
|
import webbrowser
|
|
import moztreedocs
|
|
|
|
if not outdir:
|
|
outdir = os.path.join(self.topobjdir, 'docs')
|
|
if not what:
|
|
what = [os.path.join(self.topsrcdir, 'tools')]
|
|
|
|
format_outdir = os.path.join(outdir, format)
|
|
|
|
generated = []
|
|
failed = []
|
|
for path in what:
|
|
path = os.path.normpath(os.path.abspath(path))
|
|
docdir = self._find_doc_dir(path)
|
|
|
|
if not docdir:
|
|
failed.append((path, 'could not find docs at this location'))
|
|
continue
|
|
|
|
props = self._project_properties(docdir)
|
|
savedir = os.path.join(format_outdir, props['project'])
|
|
|
|
args = [
|
|
'sphinx',
|
|
'-b', format,
|
|
docdir,
|
|
savedir,
|
|
]
|
|
result = sphinx.build_main(args)
|
|
if result != 0:
|
|
failed.append((path, 'sphinx return code %d' % result))
|
|
else:
|
|
generated.append(savedir)
|
|
|
|
if archive:
|
|
archive_path = os.path.join(outdir,
|
|
'%s.tar.gz' % props['project'])
|
|
moztreedocs.create_tarball(archive_path, savedir)
|
|
print('Archived to %s' % archive_path)
|
|
|
|
if upload:
|
|
self._s3_upload(savedir, props['project'], props['version'])
|
|
|
|
index_path = os.path.join(savedir, 'index.html')
|
|
if not http and auto_open and os.path.isfile(index_path):
|
|
webbrowser.open(index_path)
|
|
|
|
if generated:
|
|
print('\nGenerated documentation:\n%s\n' % '\n'.join(generated))
|
|
|
|
if failed:
|
|
failed = ['%s: %s' % (f[0], f[1]) for f in failed]
|
|
return die('failed to generate documentation:\n%s' % '\n'.join(failed))
|
|
|
|
if http is not None:
|
|
host, port = http.split(':', 1)
|
|
addr = (host, int(port))
|
|
if len(addr) != 2:
|
|
return die('invalid address: %s' % http)
|
|
|
|
httpd = mozhttpd.MozHttpd(host=addr[0], port=addr[1],
|
|
docroot=format_outdir)
|
|
print('listening on %s:%d' % addr)
|
|
httpd.start(block=True)
|
|
|
|
def _project_properties(self, path):
|
|
import imp
|
|
path = os.path.join(path, 'conf.py')
|
|
with open(path, 'r') as fh:
|
|
conf = imp.load_module('doc_conf', fh, path,
|
|
('.py', 'r', imp.PY_SOURCE))
|
|
|
|
# Prefer the Mozilla project name, falling back to Sphinx's
|
|
# default variable if it isn't defined.
|
|
project = getattr(conf, 'moz_project_name', None)
|
|
if not project:
|
|
project = conf.project.replace(' ', '_')
|
|
|
|
return {
|
|
'project': project,
|
|
'version': getattr(conf, 'version', None)
|
|
}
|
|
|
|
def _find_doc_dir(self, path):
|
|
search_dirs = ('doc', 'docs')
|
|
for d in search_dirs:
|
|
p = os.path.join(path, d)
|
|
if os.path.isfile(os.path.join(p, 'conf.py')):
|
|
return p
|
|
|
|
def _s3_upload(self, root, project, version=None):
|
|
self.virtualenv_manager.install_pip_package('boto3==1.4.4')
|
|
|
|
from moztreedocs import distribution_files
|
|
from moztreedocs.upload import s3_upload
|
|
|
|
# Files are uploaded to multiple locations:
|
|
#
|
|
# <project>/latest
|
|
# <project>/<version>
|
|
#
|
|
# This allows multiple projects and versions to be stored in the
|
|
# S3 bucket.
|
|
|
|
files = list(distribution_files(root))
|
|
|
|
s3_upload(files, key_prefix='%s/latest' % project)
|
|
if version:
|
|
s3_upload(files, key_prefix='%s/%s' % (project, version))
|
|
|
|
# Until we redirect / to main/latest, upload the main docs
|
|
# to the root.
|
|
if project == 'main':
|
|
s3_upload(files)
|
|
|
|
|
|
def die(msg, exit_code=1):
|
|
msg = '%s: %s' % (sys.argv[0], msg)
|
|
print(msg, file=sys.stderr)
|
|
return exit_code
|