summaryrefslogtreecommitdiffstats
path: root/tools/docs/mach_commands.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/docs/mach_commands.py')
-rw-r--r--tools/docs/mach_commands.py117
1 files changed, 117 insertions, 0 deletions
diff --git a/tools/docs/mach_commands.py b/tools/docs/mach_commands.py
new file mode 100644
index 000000000..825e5ec38
--- /dev/null
+++ b/tools/docs/mach_commands.py
@@ -0,0 +1,117 @@
+# 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('--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".')
+ def build_docs(self, what=None, format=None, outdir=None, auto_open=True, http=None):
+ self._activate_virtualenv()
+ self.virtualenv_manager.install_pip_package('sphinx_rtd_theme==0.1.6')
+
+ import sphinx
+ import webbrowser
+
+ if not outdir:
+ outdir = os.path.join(self.topobjdir, 'docs')
+ if not what:
+ what = [os.path.join(self.topsrcdir, 'tools')]
+ 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
+
+ # find project name to use as a namespace within `outdir`
+ project = self._find_project_name(docdir)
+ savedir = os.path.join(outdir, 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)
+
+ 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=outdir)
+ print('listening on %s:%d' % addr)
+ httpd.start(block=True)
+
+ def _find_project_name(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))
+
+ return conf.project.replace(' ', '_')
+
+ 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 die(msg, exit_code=1):
+ msg = '%s: %s' % (sys.argv[0], msg)
+ print(msg, file=sys.stderr)
+ return exit_code