doc: add ability to disambiguate clicmds

Multiple daemons have the same CLI commands defined, but the current
directive used to document CLI commands only takes the command
definition string. Since CLI command objects can be cross-referenced
using the :clicmd: directive, and are placed in the index, each object
needs to be unique.

To accomplish this, add a custom directive. This directive extends the
directive class used by sphinx's add_object_type to add a :daemon:
option. By specifying this option where needed, the object name becomes
"(<daemon>) <definition>", disambiguating it.

Signed-off-by: Quentin Young <qlyoung@qlyoung.net>
This commit is contained in:
Quentin Young 2023-09-28 20:11:31 -04:00
parent 5f41bb29ab
commit dc00f2dc1d

View File

@ -18,6 +18,8 @@ import re
import pygments import pygments
import sphinx import sphinx
from sphinx.highlighting import lexers from sphinx.highlighting import lexers
from sphinx.domains.std import GenericObject
from docutils.parsers.rst import directives
# 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
@ -373,13 +375,49 @@ def vparse(s):
return a[:3] return a[:3]
# custom extensions here class ClicmdDirective(GenericObject):
"""
Directive for documenting CLI commands.
The xref string, if no option is provided, will be the verbatim command
string. If the :daemon: option is provided, then it's
"(<daemon>) <command string>)".
Options:
:daemon: - specify the daemon this command belongs to. Useful for
disambiguating multiple definitions of the same command.
"""
has_content = True
required_arguments = 1
optional_arguments = 0
option_spec = {
**GenericObject.option_spec,
"daemon": directives.unchanged,
}
def handle_signature(self, sig, signode):
name = super().handle_signature(sig, signode)
daemon = self.options["daemon"] if "daemon" in self.options else ""
prefix = f"({daemon}) " if daemon else ""
return prefix + name
def run(self):
daemon = self.options["daemon"] if "daemon" in self.options else ""
if daemon:
self.indextemplate = f"pair: ({daemon}) %s; configuration command"
else:
self.indextemplate = f"pair: %s; configuration command"
nodes = super().run()
return nodes
def setup(app): def setup(app):
# object type for FRR CLI commands, can be extended to document parent CLI app.add_object_type("clicmd", "clicmd", objname="CLI command")
# node later on # Override the directive that was just created for us
app.add_object_type( app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True)
"clicmd", "clicmd", indextemplate="pair: %s; configuration command"
)
# I dont care how stupid this is # I dont care how stupid this is
if "add_js_file" in dir(app): if "add_js_file" in dir(app):