forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sphinx_base.py
146 lines (133 loc) · 5.05 KB
/
sphinx_base.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import argparse
from http.server import SimpleHTTPRequestHandler
import os
from os import listdir, symlink, mkdir
from os.path import abspath, dirname, isabs, isdir, isfile, join
from shutil import rmtree
from socketserver import TCPServer
from subprocess import check_call
import sys
import tempfile
import webbrowser
from rules_python.python.runfiles import runfiles
def _die(s):
print(s, file=sys.stderr)
exit(1)
def gen_main(input_dir, strict, src_func=None):
"""Main entry point for generation.
Args:
input_dir: Directory which contains initial input files.
strict: Determines if Sphinx warnings should be interpreted as errors.
src_func: (optional) Callable of form `f(src_dir)` which will introduce
additional source files to `src_dir`.
"""
sphinx_build = runfiles.Create().Rlocation("sphinx/sphinx-build")
assert isfile(sphinx_build), "Please execute via 'bazel run'"
parser = argparse.ArgumentParser()
parser.add_argument(
"--out_dir", type=str, required=True,
help="Output directory. Does not have to exist beforehand.")
parser.add_argument(
"--debug", action="store_true",
help="If enabled, leaves intermediate files that are otherwise "
"deleted.")
args = parser.parse_args()
out_dir = args.out_dir
if out_dir == "<test>":
out_dir = join(os.environ["TEST_TMPDIR"], "doc")
if not isabs(out_dir):
_die("--out_dir must be absolute path: {}".format(out_dir))
# Use default temp directory, handling both `bazel run` and `bazel test`.
tmp_dir = tempfile.mkdtemp(dir=os.environ.get("TEST_TMPDIR"))
doctree_dir = join(tmp_dir, "doctrees")
src_dir = join(tmp_dir, "src")
# Symlink inputs to src dir (so that we can also generate doc modules).
mkdir(src_dir)
for f in listdir(input_dir):
src_f = join(src_dir, f)
symlink(join(input_dir, f), src_f)
# Optionally generate additional input files as source.
if src_func:
src_func(src_dir)
print("Generating documentation...")
if strict:
# Turn warnings into errors; else be quiet.
warning_args = ["-W", "-N", "-q"]
else:
warning_args = [
"-N", "-Q", # Be very quiet.
"-T", # Traceback (for plugin)
]
os.environ["LANG"] = "en_US.UTF-8"
check_call(
[
sphinx_build,
"-b", "html", # HTML output.
"-a", "-E", # Don't use caching.
"-d", doctree_dir
] + warning_args + [
src_dir, # Source dir.
out_dir,
]
)
if not args.debug:
rmtree(tmp_dir)
else:
print("DEBUG: Temporary files: {}".format(tmp_dir))
class _Handler(SimpleHTTPRequestHandler):
# An HTTP handler without logging.
def log_request(*_):
pass
def _str2bool(value):
# From: https://stackoverflow.com/a/19233287/7829525
return value.lower() in ("yes", "y", "true", "t", "1")
def preview_main(gen_script, default_port):
"""Main entrypoint for previewing documentation.
Args:
gen_script: Generation script, required to generate docs.
default_port: Default port for local HTTP server.
"""
sphinx_build = runfiles.Create().Rlocation("sphinx/sphinx-build")
assert isfile(sphinx_build), "Please execute via 'bazel run'"
parser = argparse.ArgumentParser()
parser.register('type', 'bool', _str2bool)
parser.add_argument(
"--browser", type='bool', default=True, metavar='BOOL',
help="Open browser. Disable this if you are frequently recompiling.")
parser.add_argument(
"--port", type=int, default=default_port, metavar='PORT',
help="Port for serving doc pages with a HTTP server.")
args = parser.parse_args()
# Choose an arbitrary location for generating documentation.
out_dir = abspath("sphinx-tmp")
if isdir(out_dir):
rmtree(out_dir)
# Generate.
check_call([sys.executable, gen_script, "--out_dir", out_dir])
print("Sphinx preview docs are available at:")
file_url = "file://{}".format(join(out_dir, "index.html"))
browser_url = file_url
print()
print(" {}".format(file_url))
# Serve the current directory for local browsing. Required for MacOS.
# N.B. We serve the preview via a HTTP server because it is necessary for
# certain browsers (Safari on MacOS, possibly Chrome) due to local file
# restrictions.
os.chdir(out_dir)
sockaddr = ("127.0.0.1", args.port)
TCPServer.allow_reuse_address = True
httpd = TCPServer(sockaddr, _Handler)
http_url = "http://{}:{}/index.html".format(*sockaddr)
print()
print(" {}".format(http_url))
# Default to using HTTP serving only on MacOS; on Ubuntu, it can spit
# out errors and exceptions about broken pipes, 404 files, etc.
if sys.platform == "darwin":
browser_url = http_url
# Try the default browser.
if args.browser:
webbrowser.open(browser_url)
# Wait for server.
print()
print("Serving and waiting ... use Ctrl-C to exit.")
httpd.serve_forever()