From 6364d23f356612379caeeb488342f72dde0f30c7 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Mon, 19 Oct 2026 08:44:55 -0600 Subject: [PATCH] Add a local documentation server [skip appveyor] For a long time, it's been a pain to view the generated API docs, as the links don't work right. This change lets you start a tiny http server during development, a similar concept to what has long been available for the scons-website project. Use "scons serve-docs" and "scons stop-docs" to start/stop the server. It will tell you the links to go to, assuming they already exist, so the usage model is Build docs -> start server -> view. This change was AI-assisted. Signed-off-by: Mats Wichmann --- CHANGES.txt | 6 ++++++ RELEASE.txt | 10 ++++++++++ SConstruct | 28 +++++++++++++++++++++++++++ doc/SConscript | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index b113b9852..8f96639c7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -128,6 +128,12 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - User Guide improvements: * Removed the out-of-date table of option names for SetOption and GetOption and instead point to the maintained tables in Appendix D. + - Add serve-docs and stop-docs aliases to the local doc build: they start + and stop a small detached HTTP server for the built documentation in + build/doc. This is needed to view the Sphinx API docs, whose search + index and cross-page links only work when served over HTTP. You have + to ask for these explicitly. Serves on 8000; add PORT=8888 on cmdline + to select a non-default port. From Zhaoqi Xu: - ParseDepends() now treats Windows drive-letter colons as part of the diff --git a/RELEASE.txt b/RELEASE.txt index bc87be0e4..b0e5004b2 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -136,18 +136,28 @@ DOCUMENTATION since the information does not exclusively apply to the emitter argument to Builder(). The Builder Objects "emitter" argument section still has some wording, plus a link to the new section. + - Fix four documentation examples that were not valid Python: a stray parenthesis in the Command() example, an unterminated string in the MSVC_VERSION example, a missing comma that joined the two X_RPM_EXTRADEFS strings into one, and the user guide's Progress() callable, which lacked a colon and a "global count". + - Improve the wording for the Help() function (manpage and User Guide) + - Corrected the lists of construction variables the cc, hpcc and sgiar tools are documented to set. - Fix typo in X_RPM_EXCLUSIVEARCH manpage entry. - Further tweak the wording for JAVAVERSION in manpage and User Guide +- Add serve-docs and stop-docs aliases to the local doc build: they start + and stop a small detached HTTP server for the built documentation in + build/doc. This is needed to view the Sphinx API docs, whose search + index and cross-page links only work when served over HTTP. You have + to ask for these explicitly. Serves on 8000; add PORT=8888 on cmdline + to select a non-default port. + DEVELOPMENT ----------- diff --git a/SConstruct b/SConstruct index 7272a1620..9036932f3 100644 --- a/SConstruct +++ b/SConstruct @@ -140,6 +140,34 @@ for alias, help_text in aliases: ) Help(tw.fill(help_text) + '\n') +Help(""" +The following aliases serve the built documentation over a local HTTP +connection, and stop that server again. The Sphinx API docs need this: +their search index and the relative links between pages do not work +with file:// URLs, and a browser will not load the search index at all: + +""") + +serve_docs_help = ( + "Serve the documentation build directory (build/doc) over HTTP at " + "http://127.0.0.1:8000/, so it can be browsed in a web browser. " + "Build the docs first, e.g. with 'scons doc'. Set PORT= to " + "listen on a different port." +) + +doc_aliases = [ + ('serve-docs', serve_docs_help), + ('stop-docs', "Stop the documentation server started by serve-docs."), +] + +for alias, help_text in doc_aliases: + tw = textwrap.TextWrapper( + width=78, + initial_indent=indent_fmt % alias, + subsequent_indent=indent_fmt % '' + ' ', + ) + Help(tw.fill(help_text) + '\n') + Help(""" The following command-line variables can be set: diff --git a/doc/SConscript b/doc/SConscript index 0391b1341..71dec57ba 100644 --- a/doc/SConscript +++ b/doc/SConscript @@ -696,6 +696,57 @@ else: tar_list.append(htmldir) Alias('apidoc', html_files) +# +# --- Local web server for browsing the built documentation --- +# +# The docs build drops static files into build/doc, which is good enough +# for the user guide and the man pages, but the Sphinx API docs are really +# meant to be fetched over HTTP: the search index, the module pages and +# the relative links between them are all built around living at a URL, +# and a browser won't load the search index from a file:// URL at all. +# +# So provide a small standalone web server for the doc build directory, +# with aliases to start and stop it. The server is detached from the +# build: scons exits as soon as it has started it, and the server keeps +# running until "scons stop-docs" is used. +# +# The aliases deliberately don't force a doc build: they serve whatever +# is already in the build directory, so viewing freshly built docs is +# instant, and environments with only part of the toolchain (or none of +# it) can still serve an existing doc build. Just run the desired doc +# build first, e.g. "scons doc" or "scons apidoc". +# +# Neither alias is part of any default target, they only act when +# explicitly requested. The server listens on port 8000 by default, use +# e.g. "scons serve-docs PORT=8123" for a different one. +# +doc_port = ARGUMENTS.get('PORT', '8000') +doc_url = f'http://127.0.0.1:{doc_port}' +doc_pidfile = os.path.join(command_line.build_dir, 'doc-serve.pid') +doc_logfile = os.path.join(command_line.build_dir, 'doc-serve.log') + +doc_serve_action = f"""\ +@if [ -f {doc_pidfile} ]; then kill `cat {doc_pidfile}` 2>/dev/null; sleep 1; fi +@if [ ! -d {build}/HTML ]; then echo "doc: no HTML documentation built in {build} (run 'scons doc' first?)"; exit 1; fi +@nohup $PYTHON -m http.server {doc_port} --bind 127.0.0.1 --directory {build} > {doc_logfile} 2>&1 < /dev/null & echo $$! > {doc_pidfile} +@sleep 1 +@if ! kill -0 `cat {doc_pidfile}` 2>/dev/null; then rm -f {doc_pidfile}; echo "doc: web server did not start, see {doc_logfile}"; exit 1; fi +@echo "doc: serving {build} at {doc_url}/" +@if [ -f {build}/HTML/scons-api/index.html ]; then echo "doc: API docs: {doc_url}/HTML/scons-api/"; fi +@if [ -f {build}/HTML/scons-user/index.html ]; then echo "doc: user guide: {doc_url}/HTML/scons-user/"; fi +@echo "doc: stop with: scons stop-docs" +""" + +doc_serve = env.Alias('serve-docs', action=doc_serve_action) +env.AlwaysBuild(doc_serve) + +doc_stop_action = f"""\ +@if [ -f {doc_pidfile} ]; then kill `cat {doc_pidfile}` 2>/dev/null; rm -f {doc_pidfile}; echo "doc: stopped the documentation server"; else echo "doc: no documentation server is running"; fi +""" + +doc_stop = env.Alias('stop-docs', action=doc_stop_action) +env.AlwaysBuild(doc_stop) + # # Now actually create the tar file of the documentation, # for easy distribution to the web site.