#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Expedite documentation builds.
.. module:: make
:synopsis: Expedite documentation builds.
We attempt to automate documentation builds with this module.
Still need to add an option to recursively move the html files out of the
currently git-ignored directory `_build/html/` into this directory.
Update the options you can give to the parser:
#) remove python path
#) Add open in browser as an option
#) Fix the output for the `commands` argument when this is run with :data:`sys.argv` == 0
"""
import argparse
import logging
import os
import shutil
import subprocess
import sys
import webbrowser
from pyutil.__about__ import __version__
DOC_PATH = os.path.dirname(os.path.abspath(__file__))
BUILD_PATH = os.path.join(DOC_PATH, '_build')
LOGGER = logging.getLogger(name=__name__)
[docs]def _parse_arguments(cmds=None):
"""Parse user arguments.
Parameters
----------
cmd : str
Arguments provided by the user.
Returns
-------
user_args : :class:`argparse.NameSpace`
Argumemts as they've been interpreted by :mod:`argparse`.
See Also
--------
:mod:`docutils.core`
Shows a few good methods on how to programatically publish docs.
"""
cmds = [method for method in dir(DocBuilder) if not method.startswith('_')]
parser = argparse.ArgumentParser(description="Pyutil doc builder.",
epilog="Commands: {}".format(
','.join(cmds)))
parser.add_argument('builder',
nargs='?',
default='html',
metavar='builder: (html or latex)',
help='command to run: {}'.format(', '.join(cmds)))
parser.add_argument('-j',
'--num-jobs',
metavar='num-jobs',
dest='jobs',
type=int,
default=os.cpu_count(),
help='Number of parallel jobs used by `sphinx-build`.')
parser.add_argument('-s',
'--single',
metavar='FILENAME',
type=str,
default=None,
help=('filename of section or method name to build.'))
parser.add_argument('-p',
'--python-path',
type=str,
default=os.path.dirname(DOC_PATH),
help='path')
parser.add_argument('-l',
'--log',
default=sys.stdout,
type=argparse.FileType('w'),
help='File to write logging messages to.')
parser.add_argument('-ll',
'--log-level',
dest='log_level',
default='INFO',
help='Log level. Defaults to INFO. Implies logging.')
parser.add_argument(
'-V',
'--verbose',
default=False,
help='Enable verbose logging and increase level to `debug`.')
parser.add_argument('--version', action='version', version=__version__)
user_args = parser.parse_args()
if len(sys.argv[1:]) == 0:
parser.print_help()
sys.exit()
# from ipdb import set_trace
# set_trace()
return user_args
[docs]class DocBuilder:
"""Class to wrap the different commands of this script.
All public methods of this class can be called as parameters of the
script.
Attributes
-----------
builder : str
The filetype :command:`make` invokes :command:`sphinx-build` to create.
"""
def __init__(self, num_jobs=1, verbosity=0, warnings_are_errors=False):
self.num_jobs = num_jobs
self.verbosity = verbosity
self.warnings_are_errors = warnings_are_errors
[docs] def sphinx_build(self, kind='html'):
"""Build docs.
Parameters
----------
kind : {'html', 'latex'}
Kind of docs to build.
Examples
--------
>>> DocBuilder(num_jobs=4).sphinx_build('html')
"""
if kind not in ('html', 'latex'):
raise ValueError('kind must be html or latex, '
'not {}'.format(kind))
cmd = ['sphinx-build', '-b', kind, '-c', '.']
if self.num_jobs:
cmd += ['-j', str(self.num_jobs)]
if self.warnings_are_errors:
cmd += ['-W', '--keep-going']
if self.verbosity:
cmd.append('-{}'.format('v' * self.verbosity))
cmd += [
'-d',
os.path.join(BUILD_PATH, 'doctrees'), DOC_PATH,
os.path.join(BUILD_PATH, kind)
]
return subprocess.call(cmd)
[docs] def _open_browser(self, single_doc_html):
"""Open a browser tab showing the single doc html option."""
url = os.path.join('file://', DOC_PATH, 'build', 'html',
single_doc_html)
webbrowser.open(url, new=2)
[docs]def termux_hack():
"""Android permissions don't allow viewing files in app specific files."""
try:
shutil.copytree(
'_build/html/',
'/data/data/com.termux/files/home/storage/downloads/html')
except FileExistsError:
shutil.rmtree(
'/data/data/com.termux/files/home/storage/downloads/html')
shutil.copytree(
'_build/html/',
'/data/data/com.termux/files/home/storage/downloads/html')
except FileNotFoundError:
logging.error("The build directory currently doesn't exist. Exiting.")
[docs]def main():
"""Set everything up."""
args = _parse_arguments()
try:
log_level = args.log_level.upper()
except AttributeError:
logging.basicConfig(level=logging.WARNING)
else:
logging.basicConfig(level=log_level)
jobs = args.jobs # there's a default for the argument so no need for try/ excepts
try:
verbosity = args.verbosity
except AttributeError:
verbosity = None
builder = args.builder
DocBuilder(num_jobs=jobs, verbosity=verbosity).sphinx_build(kind=builder)
if os.environ.get('ANDROID_ROOT'):
termux_hack()
if __name__ == "__main__":
main()