1 | #!/usr/bin/env python |
---|
2 | """ |
---|
3 | Functions for building sphinx docs. |
---|
4 | |
---|
5 | For more information on the invocation of sphinx see: |
---|
6 | http://sphinx-doc.org/invocation.html |
---|
7 | """ |
---|
8 | from __future__ import print_function |
---|
9 | |
---|
10 | import subprocess |
---|
11 | import os |
---|
12 | from os.path import join as joinpath, abspath, dirname, isdir, exists, relpath |
---|
13 | import sys |
---|
14 | import fnmatch |
---|
15 | import shutil |
---|
16 | import imp |
---|
17 | |
---|
18 | from glob import glob |
---|
19 | from distutils.dir_util import copy_tree |
---|
20 | from distutils.util import get_platform |
---|
21 | from distutils.spawn import find_executable |
---|
22 | |
---|
23 | from shutil import copy |
---|
24 | from os import listdir |
---|
25 | |
---|
26 | platform = '.%s-%s'%(get_platform(),sys.version[:3]) |
---|
27 | |
---|
28 | # sphinx paths |
---|
29 | SPHINX_ROOT = dirname(abspath(__file__)) |
---|
30 | SPHINX_BUILD = joinpath(SPHINX_ROOT, "build") |
---|
31 | SPHINX_SOURCE = joinpath(SPHINX_ROOT, "source-temp") |
---|
32 | SPHINX_PERSPECTIVES = joinpath(SPHINX_SOURCE, "user", "qtgui", "perspectives") |
---|
33 | |
---|
34 | # sasview paths |
---|
35 | SASVIEW_ROOT = joinpath(SPHINX_ROOT, '..', '..') |
---|
36 | SASVIEW_DOCS = joinpath(SPHINX_ROOT, "source") |
---|
37 | SASVIEW_BUILD = abspath(joinpath(SASVIEW_ROOT, "build", "lib"+platform)) |
---|
38 | SASVIEW_MEDIA_SOURCE = joinpath(SASVIEW_ROOT, "src", "sas") |
---|
39 | SASVIEW_DOC_TARGET = joinpath(SASVIEW_BUILD, "doc") |
---|
40 | SASVIEW_API_TARGET = joinpath(SPHINX_SOURCE, "dev", "sasview-api") |
---|
41 | |
---|
42 | # sasmodels paths |
---|
43 | SASMODELS_ROOT = joinpath(SASVIEW_ROOT, "..", "sasmodels") |
---|
44 | SASMODELS_DOCS = joinpath(SASMODELS_ROOT, "doc") |
---|
45 | SASMODELS_BUILD = joinpath(SASMODELS_ROOT, "build", "lib") |
---|
46 | SASMODELS_MODEL_SOURCE = joinpath(SASMODELS_DOCS, "model") |
---|
47 | SASMODELS_MODEL_TARGET = joinpath(SPHINX_SOURCE, "user", "models") |
---|
48 | #SASMODELS_API_SOURCE = joinpath(SASMODELS_DOCS, "api") |
---|
49 | SASMODELS_API_TARGET = joinpath(SPHINX_SOURCE, "dev", "sasmodels-api") |
---|
50 | SASMODELS_DEV_SOURCE = joinpath(SASMODELS_DOCS, "developer") |
---|
51 | SASMODELS_DEV_TARGET = joinpath(SPHINX_SOURCE, "dev", "sasmodels-dev") |
---|
52 | SASMODELS_GUIDE_SOURCE = joinpath(SASMODELS_DOCS, "guide") |
---|
53 | SASMODELS_GUIDE_TARGET = joinpath(SPHINX_PERSPECTIVES, "fitting") |
---|
54 | SASMODELS_GUIDE_EXCLUDE = [ |
---|
55 | "index.rst", "install.rst", "intro.rst", |
---|
56 | ] |
---|
57 | |
---|
58 | # bumps paths |
---|
59 | BUMPS_DOCS = joinpath(SASVIEW_ROOT, "..", "bumps", "doc") |
---|
60 | BUMPS_SOURCE = joinpath(BUMPS_DOCS, "guide") |
---|
61 | BUMPS_TARGET = joinpath(SPHINX_PERSPECTIVES, "fitting") |
---|
62 | |
---|
63 | run = imp.load_source('run', joinpath(SASVIEW_ROOT, 'run.py')) |
---|
64 | run.prepare() |
---|
65 | |
---|
66 | def inplace_change(filename, old_string, new_string): |
---|
67 | # Thanks to http://stackoverflow.com/questions/4128144/replace-string-within-file-contents |
---|
68 | s=open(filename).read() |
---|
69 | if old_string in s: |
---|
70 | print('Changing "{old_string}" to "{new_string}"'.format(**locals())) |
---|
71 | s=s.replace(old_string, new_string) |
---|
72 | f=open(filename, 'w') |
---|
73 | f.write(s) |
---|
74 | f.flush() |
---|
75 | f.close() |
---|
76 | else: |
---|
77 | print('No occurences of "{old_string}" found.'.format(**locals())) |
---|
78 | |
---|
79 | def _remove_dir(dir_path): |
---|
80 | """Removes the given directory.""" |
---|
81 | if isdir(dir_path): |
---|
82 | print("Removing \"%s\"... " % dir_path) |
---|
83 | shutil.rmtree(dir_path) |
---|
84 | |
---|
85 | def clean(): |
---|
86 | """ |
---|
87 | Clean the sphinx build directory. |
---|
88 | """ |
---|
89 | print("=== Cleaning Sphinx Build ===") |
---|
90 | _remove_dir(SASVIEW_DOC_TARGET) |
---|
91 | _remove_dir(SPHINX_BUILD) |
---|
92 | _remove_dir(SPHINX_SOURCE) |
---|
93 | |
---|
94 | def setup_source_temp(): |
---|
95 | """ |
---|
96 | Copy the source toctrees to new folder for assembling the sphinx-docs |
---|
97 | """ |
---|
98 | print("=== Copying Source toctrees ===") |
---|
99 | shutil.copytree(SASVIEW_DOCS, SPHINX_SOURCE) |
---|
100 | |
---|
101 | def retrieve_user_docs(): |
---|
102 | """ |
---|
103 | Copies across the contents of any media/ directories in src/, and puts them |
---|
104 | in an appropriately named directory of docs/sphinx-docs/source/. For |
---|
105 | example: |
---|
106 | |
---|
107 | sas/../[MODULE]/media/dir/A.rst |
---|
108 | sas/../[MODULE]/media/B.rst |
---|
109 | |
---|
110 | gets copied to a new location: |
---|
111 | |
---|
112 | docs/sphinx-docs/source/user/[MODULE]/dir/A.rst |
---|
113 | docs/sphinx-docs/source/user/[MODULE]/B.rst |
---|
114 | |
---|
115 | so that Sphinx may pick it up when generating the documentation. |
---|
116 | """ |
---|
117 | print("=== Retrieve User Docs ===") |
---|
118 | |
---|
119 | # Copy documentation files from sas/.../media to the sphinx directory |
---|
120 | for root, dirs, _ in os.walk(SASVIEW_MEDIA_SOURCE): |
---|
121 | if 'media' in dirs: |
---|
122 | source_dir = abspath(joinpath(root, "media")) |
---|
123 | relative = dirname(relpath(source_dir, SASVIEW_MEDIA_SOURCE)) |
---|
124 | dest_dir = joinpath(SPHINX_SOURCE, "user", relative) |
---|
125 | |
---|
126 | print("Found sasview docs folder at \"%s\"." % relative) |
---|
127 | copy_tree(source_dir, dest_dir) |
---|
128 | |
---|
129 | print("=== Sasmodels Docs ===") |
---|
130 | shutil.copy(joinpath(SASMODELS_DOCS, "rst_prolog"), SPHINX_SOURCE) |
---|
131 | copy_tree(SASMODELS_MODEL_SOURCE, SASMODELS_MODEL_TARGET) |
---|
132 | #copy_tree(SASMODELS_API_SOURCE, SASMODELS_API_TARGET) |
---|
133 | copy_tree(SASMODELS_DEV_SOURCE, SASMODELS_DEV_TARGET) |
---|
134 | copy_tree(SASMODELS_GUIDE_SOURCE, SASMODELS_GUIDE_TARGET) |
---|
135 | for filename in SASMODELS_GUIDE_EXCLUDE: |
---|
136 | os.unlink(joinpath(SASMODELS_GUIDE_TARGET, filename)) |
---|
137 | |
---|
138 | # Model category files reference the model as ../../model/name.rst. Since |
---|
139 | # we are rearranging the tree, we need to update each of these links. |
---|
140 | catdir = joinpath(SASMODELS_GUIDE_TARGET, "models") |
---|
141 | for filename in os.listdir(catdir): |
---|
142 | inplace_change(joinpath(catdir, filename), "../../model/", "/user/models/") |
---|
143 | |
---|
144 | |
---|
145 | def retrieve_bumps_docs(): |
---|
146 | """ |
---|
147 | Copies select files from the bumps documentation into fitting perspective |
---|
148 | """ |
---|
149 | if exists(BUMPS_SOURCE): |
---|
150 | print("=== Retrieve BUMPS Docs ===") |
---|
151 | filenames = [joinpath(BUMPS_SOURCE, "optimizer.rst")] |
---|
152 | filenames += glob(joinpath(BUMPS_SOURCE, "dream-*.png")) |
---|
153 | filenames += glob(joinpath(BUMPS_SOURCE, "fit-*.png")) |
---|
154 | for f in filenames: |
---|
155 | print("Copying file", f) |
---|
156 | shutil.copy(f, BUMPS_TARGET) |
---|
157 | else: |
---|
158 | print(""" |
---|
159 | ======= Error ======= |
---|
160 | missing directory %s |
---|
161 | The documentation will not include the optimizer selection section. |
---|
162 | Checkout the bumps source tree and rebuild the docs. |
---|
163 | """ % BUMPS_DOCS) |
---|
164 | |
---|
165 | def apidoc(): |
---|
166 | """ |
---|
167 | Runs sphinx-apidoc to generate .rst files from the docstrings in .py files |
---|
168 | in the SasView build directory. |
---|
169 | """ |
---|
170 | print("=== Generate API Rest Files ===") |
---|
171 | |
---|
172 | # Clean directory before generating a new version. |
---|
173 | #_remove_dir(SASVIEW_API_TARGET) |
---|
174 | |
---|
175 | subprocess.call(["sphinx-apidoc", |
---|
176 | "-o", SASVIEW_API_TARGET, # Output dir. |
---|
177 | "-d", "8", # Max depth of TOC. |
---|
178 | "-H", "SasView", # Package header |
---|
179 | SASVIEW_BUILD]) |
---|
180 | |
---|
181 | subprocess.call(["sphinx-apidoc", |
---|
182 | "-o", SASMODELS_API_TARGET, # Output dir. |
---|
183 | "-d", "8", # Max depth of TOC. |
---|
184 | "-H", "sasmodels", # Package header |
---|
185 | SASMODELS_BUILD, |
---|
186 | joinpath(SASMODELS_BUILD, "sasmodels", "models"), # exclude |
---|
187 | ]) |
---|
188 | |
---|
189 | def build_pdf(): |
---|
190 | """ |
---|
191 | Runs sphinx-build for pdf. Reads in all .rst files and spits out the final html. |
---|
192 | """ |
---|
193 | print("=== Build PDF Docs from ReST Files ===") |
---|
194 | subprocess.call(["sphinx-build", |
---|
195 | "-b", "latex", # Builder name. TODO: accept as arg to setup.py. |
---|
196 | "-d", joinpath(SPHINX_BUILD, "doctrees"), |
---|
197 | SPHINX_SOURCE, |
---|
198 | joinpath(SPHINX_BUILD, "latex")]) |
---|
199 | |
---|
200 | LATEXDIR = joinpath(SPHINX_BUILD, "latex") |
---|
201 | #TODO: Does it need to be done so many time? |
---|
202 | def pdflatex(): |
---|
203 | subprocess.call(["pdflatex", "SasView.tex"], cwd=LATEXDIR) |
---|
204 | pdflatex() |
---|
205 | pdflatex() |
---|
206 | pdflatex() |
---|
207 | subprocess.call(["makeindex", "-s", "python.ist", "SasView.idx"], cwd=LATEXDIR) |
---|
208 | pdflatex() |
---|
209 | pdflatex() |
---|
210 | |
---|
211 | print("=== Copy PDF to HTML Directory ===") |
---|
212 | source = joinpath(LATEXDIR, "SasView.pdf") |
---|
213 | target = joinpath(SASVIEW_DOC_TARGET, "SasView.pdf") |
---|
214 | shutil.copyfile(source, target) |
---|
215 | |
---|
216 | def build(): |
---|
217 | """ |
---|
218 | Runs sphinx-build. Reads in all .rst files and spits out the final html. |
---|
219 | """ |
---|
220 | print("=== Build HTML Docs from ReST Files ===") |
---|
221 | subprocess.call(["sphinx-build", |
---|
222 | "-b", "qthelp", # Builder name. TODO: accept as arg to setup.py. |
---|
223 | "-d", joinpath(SPHINX_BUILD, "doctrees"), |
---|
224 | SPHINX_SOURCE, |
---|
225 | joinpath(SPHINX_BUILD, "html")]) |
---|
226 | |
---|
227 | print("=== Copy HTML Docs to Build Directory ===") |
---|
228 | html = joinpath(SPHINX_BUILD, "html") |
---|
229 | copy_tree(html, SASVIEW_DOC_TARGET) |
---|
230 | |
---|
231 | def fetch_katex(version, destination="_static"): |
---|
232 | from zipfile import ZipFile |
---|
233 | import urllib2 |
---|
234 | url = "https://github.com/Khan/KaTeX/releases/download/%s/katex.zip" % version |
---|
235 | cache_path = "katex_%s.zip" % version |
---|
236 | if not exists(cache_path): |
---|
237 | try: |
---|
238 | fd_in = urllib2.urlopen(url) |
---|
239 | with open(cache_path, "wb") as fd_out: |
---|
240 | fd_out.write(fd_in.read()) |
---|
241 | finally: |
---|
242 | fd_in.close() |
---|
243 | with ZipFile(cache_path) as zip: |
---|
244 | zip.extractall(destination) |
---|
245 | |
---|
246 | def convert_katex(): |
---|
247 | print("=== Preprocess HTML, converting latex to html ===") |
---|
248 | subprocess.call(["node", "convertKaTex.js", SASVIEW_DOC_TARGET]) |
---|
249 | |
---|
250 | def convert_mathjax(): |
---|
251 | print("=== Preprocess HTML, converting latex to html ===") |
---|
252 | subprocess.call(["node", "convertMathJax.js", SASVIEW_DOC_TARGET]) |
---|
253 | |
---|
254 | def fetch_mathjax(): |
---|
255 | subprocess.call(["npm", "install", "mathjax-node-page"]) |
---|
256 | # TODO: copy fonts from node_modules/mathjax/fonts/HTML-CSS/Tex into static |
---|
257 | |
---|
258 | def rebuild(): |
---|
259 | clean() |
---|
260 | setup_source_temp() |
---|
261 | retrieve_user_docs() |
---|
262 | retrieve_bumps_docs() |
---|
263 | #fetch_katex(version=KATEX_VERSION, destination=KATEX_PARENT) |
---|
264 | #fetch_mathjax() |
---|
265 | apidoc() |
---|
266 | build() |
---|
267 | if find_executable('latex'): |
---|
268 | build_pdf() |
---|
269 | #convert_katex() |
---|
270 | #convert_mathjax() |
---|
271 | |
---|
272 | print("=== Done ===") |
---|
273 | |
---|
274 | if __name__ == "__main__": |
---|
275 | rebuild() |
---|