[9bf64f6] | 1 | #!/usr/bin/env python |
---|
[35bf493] | 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 | """ |
---|
[01f1e17] | 8 | from __future__ import print_function |
---|
| 9 | |
---|
[35bf493] | 10 | import subprocess |
---|
| 11 | import os |
---|
[3bd677b] | 12 | from os.path import join as joinpath, abspath, dirname, isdir, exists, relpath |
---|
[35bf493] | 13 | import sys |
---|
| 14 | import fnmatch |
---|
| 15 | import shutil |
---|
[296f290] | 16 | import imp |
---|
[35bf493] | 17 | |
---|
[21bba86] | 18 | from glob import glob |
---|
[35bf493] | 19 | from distutils.dir_util import copy_tree |
---|
| 20 | from distutils.util import get_platform |
---|
[1573220] | 21 | from distutils.spawn import find_executable |
---|
| 22 | |
---|
[d2143ab] | 23 | from shutil import copy |
---|
[b7a2ebfd] | 24 | from os import listdir |
---|
[35bf493] | 25 | |
---|
[90d9cd3] | 26 | platform = '.%s-%s'%(get_platform(),sys.version[:3]) |
---|
[35bf493] | 27 | |
---|
[3bd677b] | 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", "sasgui", "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')) |
---|
[296f290] | 64 | run.prepare() |
---|
| 65 | |
---|
[bb0c836] | 66 | def inplace_change(filename, old_string, new_string): |
---|
| 67 | # Thanks to http://stackoverflow.com/questions/4128144/replace-string-within-file-contents |
---|
[90d9cd3] | 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())) |
---|
[bb0c836] | 78 | |
---|
[35bf493] | 79 | def _remove_dir(dir_path): |
---|
| 80 | """Removes the given directory.""" |
---|
[3bd677b] | 81 | if isdir(dir_path): |
---|
[21bba86] | 82 | print("Removing \"%s\"... " % dir_path) |
---|
[35bf493] | 83 | shutil.rmtree(dir_path) |
---|
| 84 | |
---|
| 85 | def clean(): |
---|
| 86 | """ |
---|
| 87 | Clean the sphinx build directory. |
---|
| 88 | """ |
---|
[f4d571b] | 89 | print("=== Cleaning Sphinx Build ===") |
---|
[3bd677b] | 90 | _remove_dir(SASVIEW_DOC_TARGET) |
---|
[35bf493] | 91 | _remove_dir(SPHINX_BUILD) |
---|
[5dd7499] | 92 | _remove_dir(SPHINX_SOURCE) |
---|
[35bf493] | 93 | |
---|
[5dd7499] | 94 | def setup_source_temp(): |
---|
| 95 | """ |
---|
| 96 | Copy the source toctrees to new folder for assembling the sphinx-docs |
---|
| 97 | """ |
---|
[f4d571b] | 98 | print("=== Copying Source toctrees ===") |
---|
[3bd677b] | 99 | shutil.copytree(SASVIEW_DOCS, SPHINX_SOURCE) |
---|
[354524d] | 100 | |
---|
[35bf493] | 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 | """ |
---|
[f4d571b] | 117 | print("=== Retrieve User Docs ===") |
---|
[35bf493] | 118 | |
---|
[3bd677b] | 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 | |
---|
[6a9c0e5a] | 144 | |
---|
[c22c5e3] | 145 | def retrieve_bumps_docs(): |
---|
| 146 | """ |
---|
| 147 | Copies select files from the bumps documentation into fitting perspective |
---|
| 148 | """ |
---|
[3bd677b] | 149 | if exists(BUMPS_SOURCE): |
---|
[f4d571b] | 150 | print("=== Retrieve BUMPS Docs ===") |
---|
[3bd677b] | 151 | filenames = [joinpath(BUMPS_SOURCE, "optimizer.rst")] |
---|
| 152 | filenames += glob(joinpath(BUMPS_SOURCE, "dream-*.png")) |
---|
| 153 | filenames += glob(joinpath(BUMPS_SOURCE, "fit-*.png")) |
---|
[c22c5e3] | 154 | for f in filenames: |
---|
[f4d571b] | 155 | print("Copying file", f) |
---|
[c22c5e3] | 156 | shutil.copy(f, BUMPS_TARGET) |
---|
| 157 | else: |
---|
[f4d571b] | 158 | print(""" |
---|
[01f1e17] | 159 | ======= Error ======= |
---|
| 160 | missing directory %s |
---|
[c22c5e3] | 161 | The documentation will not include the optimizer selection section. |
---|
| 162 | Checkout the bumps source tree and rebuild the docs. |
---|
[f4d571b] | 163 | """ % BUMPS_DOCS) |
---|
[c22c5e3] | 164 | |
---|
[35bf493] | 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 | """ |
---|
[f4d571b] | 170 | print("=== Generate API Rest Files ===") |
---|
[35bf493] | 171 | |
---|
| 172 | # Clean directory before generating a new version. |
---|
[3bd677b] | 173 | #_remove_dir(SASVIEW_API_TARGET) |
---|
[35bf493] | 174 | |
---|
| 175 | subprocess.call(["sphinx-apidoc", |
---|
[3bd677b] | 176 | "-o", SASVIEW_API_TARGET, # Output dir. |
---|
[35bf493] | 177 | "-d", "8", # Max depth of TOC. |
---|
[3bd677b] | 178 | "-H", "SasView", # Package header |
---|
[35bf493] | 179 | SASVIEW_BUILD]) |
---|
| 180 | |
---|
[3bd677b] | 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 | |
---|
[3194371] | 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. |
---|
[3bd677b] | 196 | "-d", joinpath(SPHINX_BUILD, "doctrees"), |
---|
[3194371] | 197 | SPHINX_SOURCE, |
---|
[3bd677b] | 198 | joinpath(SPHINX_BUILD, "latex")]) |
---|
[3194371] | 199 | |
---|
[3bd677b] | 200 | LATEXDIR = joinpath(SPHINX_BUILD, "latex") |
---|
[1573220] | 201 | #TODO: Does it need to be done so many time? |
---|
[3194371] | 202 | def pdflatex(): |
---|
[6e546f8] | 203 | subprocess.call(["pdflatex", "SasView.tex"], cwd=LATEXDIR) |
---|
[3194371] | 204 | pdflatex() |
---|
| 205 | pdflatex() |
---|
| 206 | pdflatex() |
---|
[6e546f8] | 207 | subprocess.call(["makeindex", "-s", "python.ist", "SasView.idx"], cwd=LATEXDIR) |
---|
[3194371] | 208 | pdflatex() |
---|
| 209 | pdflatex() |
---|
| 210 | |
---|
| 211 | print("=== Copy PDF to HTML Directory ===") |
---|
[3bd677b] | 212 | source = joinpath(LATEXDIR, "SasView.pdf") |
---|
| 213 | target = joinpath(SASVIEW_DOC_TARGET, "SasView.pdf") |
---|
[3194371] | 214 | shutil.copyfile(source, target) |
---|
| 215 | |
---|
[35bf493] | 216 | def build(): |
---|
| 217 | """ |
---|
| 218 | Runs sphinx-build. Reads in all .rst files and spits out the final html. |
---|
| 219 | """ |
---|
[3194371] | 220 | print("=== Build HTML Docs from ReST Files ===") |
---|
[35bf493] | 221 | subprocess.call(["sphinx-build", |
---|
[e90988c] | 222 | "-b", "qthelp", # Builder name. TODO: accept as arg to setup.py. |
---|
[3bd677b] | 223 | "-d", joinpath(SPHINX_BUILD, "doctrees"), |
---|
[35bf493] | 224 | SPHINX_SOURCE, |
---|
[3bd677b] | 225 | joinpath(SPHINX_BUILD, "html")]) |
---|
[35bf493] | 226 | |
---|
[f4d571b] | 227 | print("=== Copy HTML Docs to Build Directory ===") |
---|
[3bd677b] | 228 | html = joinpath(SPHINX_BUILD, "html") |
---|
| 229 | copy_tree(html, SASVIEW_DOC_TARGET) |
---|
[35bf493] | 230 | |
---|
[f4771596] | 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 |
---|
[3bd677b] | 236 | if not exists(cache_path): |
---|
[f4771596] | 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 | |
---|
[3194371] | 246 | def convert_katex(): |
---|
| 247 | print("=== Preprocess HTML, converting latex to html ===") |
---|
[3bd677b] | 248 | subprocess.call(["node", "convertKaTex.js", SASVIEW_DOC_TARGET]) |
---|
[3194371] | 249 | |
---|
[f4771596] | 250 | def convert_mathjax(): |
---|
| 251 | print("=== Preprocess HTML, converting latex to html ===") |
---|
[3bd677b] | 252 | subprocess.call(["node", "convertMathJax.js", SASVIEW_DOC_TARGET]) |
---|
[f4771596] | 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 | |
---|
[c2ee2b1] | 258 | def rebuild(): |
---|
[35bf493] | 259 | clean() |
---|
[5dd7499] | 260 | setup_source_temp() |
---|
[35bf493] | 261 | retrieve_user_docs() |
---|
[c22c5e3] | 262 | retrieve_bumps_docs() |
---|
[f4771596] | 263 | #fetch_katex(version=KATEX_VERSION, destination=KATEX_PARENT) |
---|
| 264 | #fetch_mathjax() |
---|
[35bf493] | 265 | apidoc() |
---|
| 266 | build() |
---|
[3d37fe9] | 267 | if find_executable('latex'): |
---|
[df72475] | 268 | build_pdf() |
---|
[3194371] | 269 | #convert_katex() |
---|
[f4771596] | 270 | #convert_mathjax() |
---|
[c2ee2b1] | 271 | |
---|
[f4d571b] | 272 | print("=== Done ===") |
---|
[c2ee2b1] | 273 | |
---|
| 274 | if __name__ == "__main__": |
---|
[9bf64f6] | 275 | rebuild() |
---|