mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-03 16:15:27 +00:00
Add Sphinx extension to help with ARM maintenance and cross-linking
The extension provides a "Sphinx domain factory". Each new Sphinx domain defines a namespace for configuration statements so named.conf and rndc.conf do not clash. Currently the Sphinx domains are instantiated twice and resuling domains are named "namedconf" and "rndcconf". This commit adds a single new directive: .. statement:: max-cache-size It is namespaced like this: .. namedconf:statement:: max-cache-size This directive generates a new anchor for configuration statement and it can be referenced like :any:`max-cache-size` (if the identifier is unique), or more specific :namedconf:ref:`max-cache-size`. It is based on Sphinx "tutorial" extension "recipe". Beware, some details in Sphinx docs are not up-to-date, it's better to read Sphinx and docutil sources.
This commit is contained in:
@@ -61,6 +61,9 @@ EXTRA_DIST = \
|
|||||||
troubleshooting.inc.rst \
|
troubleshooting.inc.rst \
|
||||||
tsig.inc.rst \
|
tsig.inc.rst \
|
||||||
zones.inc.rst \
|
zones.inc.rst \
|
||||||
|
_ext/iscconf.py \
|
||||||
|
_ext/namedconf.py \
|
||||||
|
_ext/rndcconf.py \
|
||||||
_static/custom.css \
|
_static/custom.css \
|
||||||
../dnssec-guide \
|
../dnssec-guide \
|
||||||
../misc/acl.grammar.rst \
|
../misc/acl.grammar.rst \
|
||||||
|
176
doc/arm/_ext/iscconf.py
Normal file
176
doc/arm/_ext/iscconf.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
############################################################################
|
||||||
|
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
#
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
#
|
||||||
|
# See the COPYRIGHT file distributed with this work for additional
|
||||||
|
# information regarding copyright ownership.
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sphinx domains for ISC configuration files.
|
||||||
|
|
||||||
|
Use setup() to install new Sphinx domains for ISC configuration files.
|
||||||
|
|
||||||
|
This extension is based on combination of two Sphinx extension tutorials:
|
||||||
|
https://www.sphinx-doc.org/en/master/development/tutorials/todo.html
|
||||||
|
https://www.sphinx-doc.org/en/master/development/tutorials/recipe.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sphinx import addnodes
|
||||||
|
from sphinx.directives import ObjectDescription
|
||||||
|
from sphinx.domains import Domain
|
||||||
|
from sphinx.roles import XRefRole
|
||||||
|
from sphinx.util.nodes import make_refnode
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=too-many-statements
|
||||||
|
def domain_factory(domainname, domainlabel):
|
||||||
|
"""
|
||||||
|
Return parametrized Sphinx domain object.
|
||||||
|
@param domainname Name used when referencing domain in .rst: e.g. namedconf
|
||||||
|
@param confname Humand-readable name for texts, e.g. named.conf
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ISCConfDomain(Domain):
|
||||||
|
"""
|
||||||
|
Custom Sphinx domain for ISC config.
|
||||||
|
Provides .. statement:: directive to define config statement.
|
||||||
|
:ref:`statementname` works as usual.
|
||||||
|
|
||||||
|
See https://www.sphinx-doc.org/en/master/extdev/domainapi.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
class StatementDirective(ObjectDescription):
|
||||||
|
"""
|
||||||
|
A custom directive that describes a statement,
|
||||||
|
e.g. max-cache-size.
|
||||||
|
"""
|
||||||
|
|
||||||
|
has_content = True
|
||||||
|
required_arguments = 1
|
||||||
|
option_spec = {}
|
||||||
|
|
||||||
|
def handle_signature(self, sig, signode):
|
||||||
|
signode += addnodes.desc_name(text=sig)
|
||||||
|
return sig
|
||||||
|
|
||||||
|
def add_target_and_index(self, _name_cls, sig, signode):
|
||||||
|
signode["ids"].append(domainname + "-statement-" + sig)
|
||||||
|
|
||||||
|
iscconf = self.env.get_domain(domainname)
|
||||||
|
iscconf.add_statement(sig)
|
||||||
|
|
||||||
|
name = domainname
|
||||||
|
label = domainlabel
|
||||||
|
|
||||||
|
directives = {
|
||||||
|
"statement": StatementDirective,
|
||||||
|
}
|
||||||
|
|
||||||
|
roles = {"ref": XRefRole(warn_dangling=True)}
|
||||||
|
initial_data = {
|
||||||
|
"statements": [], # object list for Sphinx API
|
||||||
|
}
|
||||||
|
|
||||||
|
indices = {} # no custom indicies
|
||||||
|
|
||||||
|
def get_objects(self):
|
||||||
|
"""Sphinx API: iterable of object descriptions"""
|
||||||
|
for obj in self.data["statements"]:
|
||||||
|
yield obj
|
||||||
|
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
|
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
|
||||||
|
"""
|
||||||
|
Sphinx API:
|
||||||
|
Resolve the pending_xref *node* with the given typ and target.
|
||||||
|
"""
|
||||||
|
match = [
|
||||||
|
(docname, anchor)
|
||||||
|
for name, sig, typ, docname, anchor, _prio in self.get_objects()
|
||||||
|
if sig == target
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(match) == 0:
|
||||||
|
return None
|
||||||
|
todocname = match[0][0]
|
||||||
|
targ = match[0][1]
|
||||||
|
|
||||||
|
refnode = make_refnode(
|
||||||
|
builder, fromdocname, todocname, targ, contnode, targ
|
||||||
|
)
|
||||||
|
return refnode
|
||||||
|
|
||||||
|
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
|
||||||
|
"""
|
||||||
|
Sphinx API:
|
||||||
|
Raising NotImplementedError uses fall-back bassed on resolve_xref.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def add_statement(self, signature):
|
||||||
|
"""
|
||||||
|
Add a new statement to the domain data structures.
|
||||||
|
No visible effect.
|
||||||
|
"""
|
||||||
|
name = "{}.{}.{}".format(domainname, "statement", signature)
|
||||||
|
anchor = "{}-statement-{}".format(domainname, signature)
|
||||||
|
|
||||||
|
# Sphinx API: name, dispname, type, docname, anchor, priority
|
||||||
|
self.data["statements"].append(
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
signature,
|
||||||
|
domainlabel + " statement",
|
||||||
|
self.env.docname,
|
||||||
|
anchor,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def clear_doc(self, docname):
|
||||||
|
"""
|
||||||
|
Sphinx API: like env-purge-doc event, but in a domain.
|
||||||
|
|
||||||
|
Remove traces of a document in the domain-specific inventories.
|
||||||
|
"""
|
||||||
|
self.data["statements"] = list(
|
||||||
|
obj for obj in self.data["statements"] if obj[3] != docname
|
||||||
|
)
|
||||||
|
|
||||||
|
def merge_domaindata(self, docnames, otherdata):
|
||||||
|
"""Sphinx API: Merge in data regarding *docnames* from a different
|
||||||
|
domaindata inventory (coming from a subprocess in parallel builds).
|
||||||
|
|
||||||
|
@param otherdata is self.data equivalent from another process
|
||||||
|
|
||||||
|
Beware: As of Sphinx 4.5.0, this is called multiple times in a row
|
||||||
|
with the same data and has to guard against duplicites. It seems
|
||||||
|
that all existing domains in Sphinx distribution have todo like
|
||||||
|
"deal with duplicates" but do nothing about them, so we just follow
|
||||||
|
the suite."""
|
||||||
|
self.data["statements"] = list(
|
||||||
|
set(self.data["statements"] + otherdata["statements"])
|
||||||
|
)
|
||||||
|
|
||||||
|
return ISCConfDomain
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app, domainname, confname):
|
||||||
|
"""
|
||||||
|
Install new parametrized Sphinx domain.
|
||||||
|
"""
|
||||||
|
|
||||||
|
Conf = domain_factory(domainname, confname)
|
||||||
|
app.add_domain(Conf)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"version": "0.1",
|
||||||
|
"parallel_read_safe": True,
|
||||||
|
"parallel_write_safe": True,
|
||||||
|
}
|
22
doc/arm/_ext/namedconf.py
Normal file
22
doc/arm/_ext/namedconf.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
############################################################################
|
||||||
|
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
#
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
#
|
||||||
|
# See the COPYRIGHT file distributed with this work for additional
|
||||||
|
# information regarding copyright ownership.
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sphinx domain "namedconf". See iscconf.py for details.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import iscconf
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
return iscconf.setup(app, "namedconf", "named.conf")
|
22
doc/arm/_ext/rndcconf.py
Normal file
22
doc/arm/_ext/rndcconf.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
############################################################################
|
||||||
|
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
#
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
#
|
||||||
|
# See the COPYRIGHT file distributed with this work for additional
|
||||||
|
# information regarding copyright ownership.
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sphinx domain "rndcconf". See iscconf.py for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import iscconf
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
return iscconf.setup(app, "rndcconf", "rndc.conf")
|
@@ -13,7 +13,9 @@
|
|||||||
|
|
||||||
# flake8: noqa: E501
|
# flake8: noqa: E501
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
@@ -99,12 +101,9 @@ def setup(app):
|
|||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, make it absolute.
|
||||||
#
|
#
|
||||||
# import os
|
sys.path.append(str(Path(__file__).resolve().parent / "_ext"))
|
||||||
# import sys
|
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
@@ -135,7 +134,7 @@ release = version
|
|||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = []
|
extensions = ["namedconf", "rndcconf"]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ["_templates"]
|
templates_path = ["_templates"]
|
||||||
|
Reference in New Issue
Block a user