始终重新生成包含特定指令的 Sphinx 文档

Always regenerate Sphinx documents containing a specific directive

Sphinx 通常会增量构建文档,这意味着只会重新生成已更改的文件。我想知道是否有办法告诉 Sphinx 始终重新生成某些文件,这些文件可能没有直接更改但受到其他文件更改的影响。更具体:有没有办法告诉 Sphinx 总是重新生成包含特定指令的文件?我正在处理的文档依赖于在指令的帮助下经常从其他页面收集和重新格式化信息的可能性。干净 (make clean && make [html]) and/or 完整 (sphinx-build -a) 构建比增量构建花费的时间要长得多。此外,手动跟踪包含该指令的文件可能很复杂。该文档由 10 多位作者编写,他们在编写 Sphinx 文档方面经验有限。

但即使在不太复杂的情况下,您也可能会遇到这种情况 'issue': 例如 sphinx.ext.todo 包含一个名为 todolist 的指令,它从整个文档中收集待办事项。如果我创建一个包含文档中所有待办事项的文件(基本上是一个仅包含 todolist 指令的空文档),则在我进行干净构建或更改文件之前,该列表不会更新。

如果您想自己测试:使用 sphinx-quickstart 创建文档并坚持使用默认值,

除外
'> todo: write "todo" entries that can be shown or hidden on build (y/n) [n]: y'

source 中添加一个名为 todos.rst 的文件并从 index.rst.

中引用该文件

index.rst的内容:

Welcome to sphinx-todo's documentation!
=======================================

.. toctree::
   :maxdepth: 2

   todos


.. todo::
 I have to do this


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

todos.rst的内容:

.. _`todos`:

List of ToDos
=============

.. todolist::

假设您使用 html 输出,您会注意到当您将待办事项添加到 index.htmltodos.html 不会改变。

tl;dr:如果可能的话,我如何将包含特定指令(例如 todolist)的文件包含到 Sphinx 的 incremental 构建中而不需要手动跟踪它们吗?

默认情况下,Sphinx 只会更新新文件或更改文件的输出。这被埋在 sphinx-build -a.

sphinx-build 命令选项的文档末尾:

You can also give one or more filenames on the command line after the source and build directories. Sphinx will then try to build only these output files (and their dependencies).

您可以直接或通过您的 makefile 调用 sphinx-build,具体取决于您的 Sphinx 版本附带的 makefile(您也可以自定义 makefile)。

仅作记录:我对几个解决方案进行了基准测试。

我在 conf.py 中创建了一个名为 touch_files 的函数。它在文件中搜索字符串 - 如果找到 - 接触文件以触发重建:

def touch_files(*args):
    # recursively search the 'source' directory
    for root, dirnames, filenames in os.walk('.'):
        # check all rst files
        for filename in fnmatch.filter(filenames, '*.rst'):
            cur = os.path.join(root, filename)
            f = open(cur)
            # access content directly from disk
            s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
            if any(s.find(d) != -1 for d in args):
                # if a string pattern has been found alter the edit 
                # time of the file
                os.utime(cur, None)
            f.close()

# actually call the function
touch_files('.. todolist::')

touch_files 可以使用可变数量的参数调用,并在找到其中一个参数时编辑文件。我试图用正则表达式优化函数,但这并没有取得多大成就。用mmap直接从磁盘读取文件内容好像影响不大。

这是 78 个文件的结果,其中 36 个包含两个指令之一。

Command                                 Time     Comment
time make html                          2.3 s    No changes
time sh -c 'make clean && make html'   13.3 s
time make htmlfull                      9.4 s    sphinx-build -a    
time make html                          8.4 s    with 'touch_files'
'touch_files'                           0.2 s    tested with testit

结果:每个命令只被调用了几次('touch_files'除外),因此缺乏统计可靠性。 Sphinx 需要大约 2.3 秒来检查文档是否有更改,而无需执行任何操作。干净的构建需要 13.3 秒,这比 sphinx-build -a 的构建要长得多。如果我们只重建 78 个文件中的 36 个,构建过程会稍微快一些,尽管我怀疑这里能否找到显着差异。 'touch_files' 的开销相当低。与编辑时间戳相比,查找字符串的成本非常低。

结论:正如指出的那样,使用sphinx-build -a似乎是最合理的方法。至少对于我的用例。如果不包含相关指令的文件导致构建时间过长 touch_files 可能会有用。