Implement Sphinx extension

This commit is contained in:
Adrian Vollmer 2022-10-05 17:11:12 +02:00
parent bf36d10bc7
commit 1924eb07a9
4 changed files with 70 additions and 25 deletions

View File

@ -41,8 +41,11 @@ Limitations
This approach is quite hacky, but it might work well enough for some purposes.
Some scripts may break as the execution flow is different than some scripts
expect.
* Some scripts may break as the execution flow is different than some scripts
expect. For example, HTML forms with `method="GET"` to local HTML files only
work if the receiving code uses URLSearchParams, as same-origin policies
forbid reading GET parameters otherwise.
* Opening links in a new tab won't work
Installation
@ -61,19 +64,11 @@ An entry point called `zundler` will appear in `~/.local/bin`.
Bundling Sphinx docs
--------------------
Providing a Sphinx extension does not make sense, because it would need to
add a new builder. Similar to the `latexpdf`
The Zundler package provides a Sphinx extension that adds an appropriate
builder. The builder is a thin wrapper around the HTML builder, which runs
`zundler` at the end. It can be used with `sphinx-build -b zundler` or, if
there is a suitable Makefile, with `make zundler`.
Suggested Makefile addition:
```make
.PHONY: zundler
latexpdf:
$(SPHINXBUILD) -b zundler $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo "Bundle asset into one self-contained HTML file..."
$(MAKE) -C $(BUILDDIR)/html
@echo "Zundler finished; the HTML file is in $(BUILDDIR)/zundler."
```
Demos
-----
@ -81,8 +76,6 @@ Demos
...
Copyright
---------

View File

@ -28,11 +28,14 @@ packages = find:
install_requires =
sphinx
bs4
lxml
importlib-metadata; python_version<"3.8"
[options.entry_points]
console_scripts =
zundler = zundler.__main__:main
sphinx.builders =
zundler = zundler.sphinxext
[mypy]
python_version = 3.8

View File

@ -9,7 +9,7 @@ It creates an HTML file that has three script tags:
virtual file tree instead of the file system
Also, two scripts are injected into all HTML files in the file tree. One as
the first child of <body>, one as the last. The first does some
the first child of <head>, one as the last child of <body>. The first does some
monkeypatching, the last sets up all magic.
Author: Adrian Vollmer
@ -162,11 +162,12 @@ def embed_html_resources(html, base_dir, before, after):
import bs4
soup = bs4.BeautifulSoup(html, 'lxml')
body = soup.find('body')
head = soup.find('head')
if body and before:
if head and before:
script = soup.new_tag("script")
script.string = before
body.insert(0, script)
head.insert(0, script)
if body and after:
script = soup.new_tag("script")

View File

@ -1,16 +1,64 @@
from sphinx.builders.html import StandaloneHTMLBuilder
import os
from pathlib import Path
MAKEFILE = """
"""
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.locale import get_translation
from sphinx.util import logging, progress_message
from sphinx.util.osutil import relpath
__ = get_translation(__name__, 'console')
logger = logging.getLogger(__name__)
class ZundlerBuilder(StandaloneHTMLBuilder):
def handle_finish(self) -> None:
super().handle_finish()
name = 'zundler'
epilog = ""
def __init__(self, app):
super().__init__(app)
self.epilog = (
'Your self-contained HTML file is now in %s.' %
relpath(self.app.original_outdir)
)
def finish(self):
super().finish()
from zundler.embed import embed_assets
input_path = os.path.join(
self.outdir,
self.config.root_doc + '.html',
)
output_path = os.path.join(
self.app.original_outdir,
self.config.root_doc + '.html',
)
with progress_message(__('embedding HTML assets')):
embed_assets(
input_path,
output_path=output_path,
)
def setup(app):
app.add_config_value('html_embed_assets', False, 'html')
# Fix the outdir. We want to build the files into $builddir/html first,
# then $builddir/$target second.
outdir = os.path.join(
os.path.dirname(app.outdir),
'html',
)
doctreedir = os.path.join(
os.path.dirname(app.outdir),
'doctree',
)
app.original_outdir = app.outdir
app.outdir = outdir
app.doctreedir = doctreedir
Path(app.outdir).mkdir(parents=True, exist_ok=True)
app.add_builder(ZundlerBuilder)