Speed up doc builds with spack list --format=html (#6945)

- Generating the HTML from for >2300 packages from RST in Sphinx seems to
  take forever.

- Add an option to `spack list` to generate straight HTML instead.

- This reduces the doc build time to about a minute (from 5 minutes on a mac laptop).
This commit is contained in:
Todd Gamblin 2018-01-16 00:12:11 -08:00 committed by GitHub
parent 1fb38c9e04
commit 50ca4979e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 141 additions and 18 deletions

View File

@ -1,4 +1,4 @@
package_list.rst package_list.html
command_index.rst command_index.rst
spack*.rst spack*.rst
llnl*.rst llnl*.rst

View File

@ -83,7 +83,7 @@ help:
@echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean: clean:
-rm -f package_list.rst command_index.rst -rm -f command_index.rst
-rm -rf $(BUILDDIR)/* $(APIDOC_FILES) -rm -rf $(BUILDDIR)/* $(APIDOC_FILES)
html: html:

View File

@ -68,9 +68,10 @@
# #
# Generate package list using spack command # Generate package list using spack command
# #
with open('package_list.rst', 'w') as plist_file: with open('package_list.html', 'w') as plist_file:
subprocess.Popen( subprocess.Popen(
[spack_root + '/bin/spack', 'list', '--format=rst'], stdout=plist_file) [spack_root + '/bin/spack', 'list', '--format=html'],
stdout=plist_file)
# #
# Find all the `cmd-spack-*` references and add them to a command index # Find all the `cmd-spack-*` references and add them to a command index

View File

@ -0,0 +1,12 @@
.. _package-list:
============
Package List
============
This is a list of things you can install using Spack. It is
automatically generated based on the packages in the latest Spack
release.
.. raw:: html
:file: package_list.html

View File

@ -23,12 +23,14 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
from __future__ import print_function from __future__ import print_function
from __future__ import division
import argparse import argparse
import cgi import cgi
import fnmatch import fnmatch
import re import re
import sys import sys
import math
from six import StringIO from six import StringIO
@ -113,23 +115,35 @@ def name_only(pkgs):
colify(pkgs, indent=indent) colify(pkgs, indent=indent)
@formatter def github_url(pkg):
def rst(pkgs):
"""Print out information on all packages in restructured text."""
def github_url(pkg):
"""Link to a package file on github.""" """Link to a package file on github."""
url = 'https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/{0}/package.py' url = 'https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/{0}/package.py'
return url.format(pkg.name) return url.format(pkg.name)
def rst_table(elts):
def rst_table(elts):
"""Print out a RST-style table.""" """Print out a RST-style table."""
cols = StringIO() cols = StringIO()
ncol, widths = colify(elts, output=cols, tty=True) ncol, widths = colify(elts, output=cols, tty=True)
header = ' '.join('=' * (w - 1) for w in widths) header = ' '.join('=' * (w - 1) for w in widths)
return '%s\n%s%s' % (header, cols.getvalue(), header) return '%s\n%s%s' % (header, cols.getvalue(), header)
pkg_names = pkgs
def rows_for_ncols(elts, ncols):
"""Print out rows in a table with ncols of elts laid out vertically."""
clen = int(math.ceil(len(elts) / ncols))
for r in range(clen):
row = []
for c in range(ncols):
i = c * clen + r
row.append(elts[i] if i < len(elts) else None)
yield row
@formatter
def rst(pkg_names):
"""Print out information on all packages in restructured text."""
pkgs = [spack.repo.get(name) for name in pkg_names] pkgs = [spack.repo.get(name) for name in pkg_names]
print('.. _package-list:') print('.. _package-list:')
@ -183,6 +197,102 @@ def rst_table(elts):
print() print()
@formatter
def html(pkg_names):
"""Print out information on all packages in Sphinx HTML.
This is intended to be inlined directly into Sphinx documentation.
We write HTML instead of RST for speed; generating RST from *all*
packages causes the Sphinx build to take forever. Including this as
raw HTML is much faster.
"""
# Read in all packages
pkgs = [spack.repo.get(name) for name in pkg_names]
# Start at 2 because the title of the page from Sphinx is id1.
span_id = 2
# HTML header with an increasing id span
def head(n, span_id, title, anchor=None):
if anchor is None:
anchor = title
print(('<span id="id%d"></span>'
'<h1>%s<a class="headerlink" href="#%s" '
'title="Permalink to this headline">&para;</a>'
'</h1>') % (span_id, title, anchor))
# Start with the number of packages, skipping the title and intro
# blurb, which we maintain in the RST file.
print('<p>')
print('Spack currently has %d mainline packages:' % len(pkgs))
print('</p>')
# Table of links to all packages
print('<table border="1" class="docutils">')
print('<tbody valign="top">')
for i, row in enumerate(rows_for_ncols(pkg_names, 3)):
print('<tr class="row-odd">' if i % 2 == 0 else
'<tr class="row-even">')
for name in row:
print('<td>')
print('<a class="reference internal" href="#%s">%s</a></td>'
% (name, name))
print('</td>')
print('</tr>')
print('</tbody>')
print('</table>')
print('<hr class="docutils"/>')
# Output some text for each package.
for pkg in pkgs:
print('<div class="section" id="%s">' % pkg.name)
head(2, span_id, pkg.name)
span_id += 1
print('<dl class="docutils">')
print('<dt>Homepage:</dt>')
print('<dd><ul class="first last simple">')
print(('<li>'
'<a class="reference external" href="%s">%s</a>'
'</li>') % (pkg.homepage, cgi.escape(pkg.homepage)))
print('</ul></dd>')
print('<dt>Spack package:</dt>')
print('<dd><ul class="first last simple">')
print(('<li>'
'<a class="reference external" href="%s">%s/package.py</a>'
'</li>') % (github_url(pkg), pkg.name))
print('</ul></dd>')
if pkg.versions:
print('<dt>Versions:</dt>')
print('<dd>')
print(', '.join(str(v) for v in reversed(sorted(pkg.versions))))
print('</dd>')
for deptype in spack.all_deptypes:
deps = pkg.dependencies_of_type(deptype)
if deps:
print('<dt>%s Dependencies:</dt>' % deptype.capitalize())
print('<dd>')
print(', '.join(
d if d not in pkg_names else
'<a class="reference internal" href="#%s">%s</a>' % (d, d)
for d in deps))
print('</dd>')
print('<dt>Description:</dt>')
print('<dd>')
print(cgi.escape(pkg.format_doc(indent=2)))
print('</dd>')
print('</dl>')
print('<hr class="docutils"/>')
print('</div>')
def list(parser, args): def list(parser, args):
# Retrieve the names of all the packages # Retrieve the names of all the packages
pkgs = set(spack.repo.all_package_names()) pkgs = set(spack.repo.all_package_names())