зеркало из https://github.com/microsoft/CCF.git
494 строки
15 KiB
Python
494 строки
15 KiB
Python
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
# Licensed under the Apache 2.0 License.
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Configuration file for the Sphinx documentation builder.
|
|
#
|
|
# This file does only contain a selection of the most common options. For a
|
|
# full list see the documentation:
|
|
# http://www.sphinx-doc.org/en/master/config
|
|
|
|
# -- Path setup --------------------------------------------------------------
|
|
|
|
# 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
|
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
#
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import pathlib
|
|
import re
|
|
|
|
from docutils import nodes
|
|
|
|
# To import generate_config_rst
|
|
sys.path.insert(0, os.path.abspath("."))
|
|
|
|
import generate_config_rst
|
|
|
|
|
|
# -- Project information -----------------------------------------------------
|
|
|
|
project = "CCF"
|
|
copyright = "2024, Microsoft"
|
|
author = "Microsoft"
|
|
|
|
# The short X.Y version
|
|
version = ""
|
|
# The full version, including alpha/beta/rc tags
|
|
release = ""
|
|
|
|
|
|
# -- General configuration ---------------------------------------------------
|
|
|
|
# If your documentation needs a minimal Sphinx version, state it here.
|
|
#
|
|
# needs_sphinx = '1.0'
|
|
|
|
# Add any Sphinx extension module names here, as strings. They can be
|
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
# ones.
|
|
extensions = [
|
|
"sphinx.ext.todo",
|
|
"sphinx.ext.mathjax",
|
|
"sphinx.ext.ifconfig",
|
|
"sphinx.ext.viewcode",
|
|
"breathe",
|
|
"sphinxcontrib.mermaid",
|
|
"sphinx.ext.autosectionlabel",
|
|
"sphinx.ext.githubpages",
|
|
"sphinx_multiversion",
|
|
"sphinx_copybutton",
|
|
"sphinx.ext.autodoc",
|
|
"sphinxcontrib.openapi",
|
|
"sphinx_panels",
|
|
"sphinx.ext.extlinks",
|
|
"sphinx_inline_tabs",
|
|
]
|
|
|
|
autosectionlabel_prefix_document = True
|
|
|
|
# Add any paths that contain templates here, relative to this directory.
|
|
templates_path = ["_templates"]
|
|
|
|
# The suffix(es) of source filenames.
|
|
# You can specify multiple suffix as a list of string:
|
|
#
|
|
# source_suffix = ['.rst', '.md']
|
|
source_suffix = ".rst"
|
|
|
|
# The master toctree document.
|
|
master_doc = "index"
|
|
|
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
# for a list of supported languages.
|
|
#
|
|
# This is also used if you do content translation via gettext catalogs.
|
|
# Usually you set "language" from the command line for these cases.
|
|
language = "en"
|
|
|
|
# List of patterns, relative to source directory, that match files and
|
|
# directories to ignore when looking for source files.
|
|
# This pattern also affects html_static_path and html_extra_path .
|
|
exclude_patterns = []
|
|
|
|
# The name of the Pygments (syntax highlighting) style to use.
|
|
pygments_style = "default"
|
|
pygments_dark_style = "zenburn"
|
|
|
|
# Ignore main index file that has clickable images, JS/Doxygen output,
|
|
# github anchors https://github.com/sphinx-doc/sphinx/issues/9016), and nghttp2
|
|
# (which is now HTTP2-only)
|
|
linkcheck_exclude_documents = [r"^index$"]
|
|
linkcheck_ignore = [
|
|
r"https://github.com/.*#",
|
|
r"../js/ccf-app.*",
|
|
r"../doxygen/index.html",
|
|
r"https://nghttp2.org/.*",
|
|
r"https://www.w3.org/Protocols/rfc2616/.*",
|
|
]
|
|
|
|
|
|
# -- Options for HTML output -------------------------------------------------
|
|
|
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
# a list of builtin themes.
|
|
#
|
|
html_theme = "furo"
|
|
|
|
# Theme options are theme-specific and customize the look and feel of a theme
|
|
# further. For a list of options available for each theme, see the
|
|
# documentation.
|
|
#
|
|
html_theme_options = {
|
|
"light_logo": "ccf.svg",
|
|
"dark_logo": "ccf.svg",
|
|
}
|
|
|
|
# Add any paths that contain custom static files (such as style sheets) here,
|
|
# relative to this directory. They are copied after the builtin static files,
|
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
html_static_path = ["_static"]
|
|
|
|
# Custom sidebar templates, must be a dictionary that maps document names
|
|
# to template names.
|
|
#
|
|
# The default sidebars (for documents that don't match any pattern) are
|
|
# defined by theme itself. Builtin themes are using these templates by
|
|
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
|
# 'searchbox.html']``.
|
|
#
|
|
html_sidebars = {}
|
|
|
|
html_css_files = [
|
|
"css/custom.css",
|
|
]
|
|
|
|
html_js_files = ["https://kit.fontawesome.com/c75a35380d.js"]
|
|
|
|
html_extra_path = []
|
|
|
|
# -- Options for HTMLHelp output ---------------------------------------------
|
|
|
|
# Output file base name for HTML help builder.
|
|
htmlhelp_basename = "CCFdoc"
|
|
|
|
|
|
# -- Options for LaTeX output ------------------------------------------------
|
|
|
|
latex_elements = {
|
|
# The paper size ('letterpaper' or 'a4paper').
|
|
#
|
|
# 'papersize': 'letterpaper',
|
|
# The font size ('10pt', '11pt' or '12pt').
|
|
#
|
|
# 'pointsize': '10pt',
|
|
# Additional stuff for the LaTeX preamble.
|
|
#
|
|
# 'preamble': '',
|
|
# Latex figure (float) alignment
|
|
#
|
|
# 'figure_align': 'htbp',
|
|
}
|
|
|
|
# Grouping the document tree into LaTeX files. List of tuples
|
|
# (source start file, target name, title,
|
|
# author, documentclass [howto, manual, or own class]).
|
|
latex_documents = [
|
|
(master_doc, "CCF.tex", "CCF Documentation", "Microsoft", "manual")
|
|
]
|
|
|
|
|
|
# -- Options for manual page output ------------------------------------------
|
|
|
|
# One entry per manual page. List of tuples
|
|
# (source start file, name, description, authors, manual section).
|
|
man_pages = [(master_doc, "ccf", "CCF Documentation", [author], 1)]
|
|
|
|
|
|
# -- Options for Texinfo output ----------------------------------------------
|
|
|
|
# Grouping the document tree into Texinfo files. List of tuples
|
|
# (source start file, target name, title, author,
|
|
# dir menu entry, description, category)
|
|
texinfo_documents = [
|
|
(
|
|
master_doc,
|
|
"CCF",
|
|
"CCF Documentation",
|
|
author,
|
|
"CCF",
|
|
"One line description of project.",
|
|
"Miscellaneous",
|
|
)
|
|
]
|
|
|
|
|
|
# -- Extension configuration -------------------------------------------------
|
|
|
|
# -- Options for todo extension ----------------------------------------------
|
|
|
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
|
todo_include_todos = True
|
|
|
|
# -- Breathe configuration
|
|
|
|
# Setup the breathe extension
|
|
breathe_projects = {"CCF": "../doxygen/xml"}
|
|
breathe_default_project = "CCF"
|
|
|
|
# Set up multiversion extension
|
|
|
|
smv_tag_whitelist = None
|
|
smv_branch_whitelist = r"^(main)|(release\/([4-9]|\d\d\d*)\.x)$"
|
|
smv_remote_whitelist = None
|
|
smv_outputdir_format = "{ref.name}"
|
|
|
|
assert re.match(smv_branch_whitelist, "main")
|
|
assert not re.match(smv_branch_whitelist, "release/1.x")
|
|
assert not re.match(smv_branch_whitelist, "release/2.x")
|
|
assert re.match(smv_branch_whitelist, "release/100.x")
|
|
assert not re.match(smv_branch_whitelist, "release/1.x_feature")
|
|
|
|
# Intercept command line arguments passed by sphinx-multiversion to retrieve doc version.
|
|
# This is a little hacky with sphinx-multiversion 0.2.4 and the `SPHINX_MULTIVERSION_NAME`
|
|
# envvar should be used for further versions (release pending).
|
|
docs_version = None
|
|
for arg in sys.argv:
|
|
if "smv_current_version=" in arg:
|
|
docs_version = arg.split("=")[1]
|
|
break
|
|
|
|
# If that didn't work, try extracting it from env vars inserted by Azure pipelines. This
|
|
# is used by single-build jobs and Link checks targeting release branches.
|
|
if docs_version is None:
|
|
if os.environ.get("BUILD_REASON") == "PullRequest":
|
|
docs_version = os.environ["SYSTEM_PULLREQUEST_TARGETBRANCH"]
|
|
|
|
# If we still have no docs_version, assume we're on main
|
|
if docs_version is None:
|
|
docs_version = "main"
|
|
|
|
# :ccf_repo: directive can be used to create a versioned link to GitHub repo
|
|
extlinks = {
|
|
"ccf_repo": (
|
|
f"https://github.com/microsoft/CCF/tree/{docs_version}/%s",
|
|
"%s",
|
|
)
|
|
}
|
|
|
|
# Theme options
|
|
|
|
html_logo = "_static/ccf.svg"
|
|
html_favicon = "_static/favicon.ico"
|
|
|
|
html_context = {
|
|
"github_user": "Microsoft",
|
|
"github_repo": "CCF",
|
|
"github_version": "main",
|
|
"doc_path": "doc/",
|
|
}
|
|
|
|
# Configuration for sphinxcontrib-httpdomain, without which the following error happens
|
|
# ERROR: HTTP status code must be an integer (e.g. `200`) or start with an integer (e.g. `200 OK`);
|
|
# <#text: 'default'> is invalid
|
|
http_strict_mode = False
|
|
|
|
# Python autodoc options
|
|
autodoc_default_options = {
|
|
"member-order": "bysource",
|
|
}
|
|
|
|
# sphinxcontrib.spelling options
|
|
spelling_show_suggestions = True
|
|
spelling_lang = "en_UK"
|
|
tokenizer_lang = "en_UK"
|
|
spelling_word_list_filename = ["spelling_wordlist.txt"]
|
|
|
|
# sphinxcontrib-mermaid options
|
|
mermaid_init_js = """mermaid.initialize({startOnLoad:true});
|
|
|
|
// Remove height from all mermaid diagrams
|
|
window.addEventListener(
|
|
'load',
|
|
function() {
|
|
let nodes = document.querySelectorAll('.mermaid');
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
const element = nodes[i];
|
|
const svg = element.firstChild;
|
|
svg.removeAttribute('height');
|
|
}
|
|
},
|
|
false
|
|
);"""
|
|
|
|
|
|
def typedoc_role(
|
|
name: str, rawtext: str, text: str, lineno, inliner, options={}, content=[]
|
|
):
|
|
"""
|
|
Supported syntaxes:
|
|
:typedoc:package:`ccf-app`
|
|
:typedoc:module:`ccf-app/global`
|
|
:typedoc:function:`ccf-app/crypto#wrapKey`
|
|
:typedoc:interface:`ccf-app/endpoints/Body`
|
|
:typedoc:class:`ccf-app/kv/TypedKvMap`
|
|
:typedoc:classmethod:`ccf-app/kv/TypedKvMap#delete`
|
|
:typedoc:interfacemethod:`ccf-app/endpoints/Body#json`
|
|
:typedoc:interface:`Body <ccf-app/endpoints/Body>`
|
|
"""
|
|
# check for custom label
|
|
if "<" in text:
|
|
label, text = text.split(" <")
|
|
text = text[:-1]
|
|
else:
|
|
label = text
|
|
|
|
# extract hash if any, has to be appended after .html later on
|
|
text_without_hash, *hash_name = text.split("#")
|
|
url_hash = f"#{hash_name[0].lower()}" if hash_name else ""
|
|
|
|
# translate role kind into typedoc subfolder
|
|
# and add '()' for functions/methods
|
|
kind_name = name.replace("typedoc:", "")
|
|
is_kind_package = False
|
|
if kind_name == "package":
|
|
is_kind_package = True
|
|
elif kind_name in ["module", "interface"]:
|
|
kind_name += "s"
|
|
elif kind_name == "class":
|
|
kind_name += "es"
|
|
elif kind_name == "function":
|
|
kind_name = "modules"
|
|
label += "()"
|
|
elif kind_name == "classmethod":
|
|
kind_name = "classes"
|
|
label += "()"
|
|
elif kind_name == "interfacemethod":
|
|
kind_name = "interfaces"
|
|
label += "()"
|
|
else:
|
|
raise ValueError(f"unknown typedoc kind: {kind_name}")
|
|
|
|
# build typedoc url relative to doc root
|
|
pkg_name, *element_path = text_without_hash.split("/")
|
|
typedoc_path = f"js/{pkg_name}"
|
|
if not is_kind_package:
|
|
element_path = ".".join(element_path)
|
|
typedoc_path += f"/{kind_name}/{element_path}.html{url_hash}"
|
|
|
|
# construct final url relative to current page
|
|
source = inliner.document.attributes["source"]
|
|
rel_source = source.split("/doc/", 1)[1]
|
|
levels = rel_source.count("/")
|
|
refuri = "../" * levels + typedoc_path
|
|
|
|
# build docutils node
|
|
text_node = nodes.literal(label, label, classes=["xref"])
|
|
ref_node = nodes.reference("", "", refuri=refuri)
|
|
ref_node += text_node
|
|
|
|
return [ref_node], []
|
|
|
|
|
|
def config_property_role(
|
|
name: str, rawtext: str, text: str, lineno, inliner, options={}, content=[]
|
|
):
|
|
try:
|
|
prefix, val = text.rsplit(".", 1)
|
|
prefix = prefix + "."
|
|
except ValueError:
|
|
prefix, val = None, text
|
|
|
|
children = [
|
|
nodes.strong(
|
|
val,
|
|
val,
|
|
ids=[text],
|
|
),
|
|
nodes.reference("#", "#", refid=text, classes=["headerlink"]),
|
|
]
|
|
if prefix:
|
|
children.insert(
|
|
0,
|
|
nodes.emphasis(
|
|
prefix,
|
|
prefix,
|
|
),
|
|
)
|
|
|
|
line = nodes.line(
|
|
"",
|
|
"",
|
|
*children,
|
|
classes=["configproperty"],
|
|
)
|
|
|
|
return [line], []
|
|
|
|
|
|
def config_inited(app, config):
|
|
# anything that needs to access app.config goes here
|
|
|
|
doc_dir = pathlib.Path(app.srcdir)
|
|
outdir = pathlib.Path(app.outdir)
|
|
|
|
js_pkg_dir = doc_dir / ".." / "js" / "ccf-app"
|
|
js_docs_dir = outdir / "js" / "ccf-app"
|
|
if js_pkg_dir.exists():
|
|
# make versions.json from sphinx-multiversion available
|
|
if app.config.smv_metadata_path:
|
|
os.environ["SMV_METADATA_PATH"] = app.config.smv_metadata_path
|
|
os.environ["SMV_CURRENT_VERSION"] = app.config.smv_current_version
|
|
subprocess.run(
|
|
["sed", "-i", "s/\^4.2.3/4.2.4/g", "package.json"],
|
|
cwd=js_pkg_dir,
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
["sed", "-i", 's/"\^14\.14\.35"/"14\.17\.27"/g', "package.json"],
|
|
cwd=js_pkg_dir,
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
["npm", "install", "--save-exact", "colors@1.4.0"],
|
|
cwd=js_pkg_dir,
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
["npm", "install", "--no-package-lock", "--no-audit", "--no-fund"],
|
|
cwd=js_pkg_dir,
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
["npm", "run", "docs", "--", "--out", str(js_docs_dir)],
|
|
cwd=js_pkg_dir,
|
|
check=True,
|
|
)
|
|
# allow to link to typedoc pages
|
|
for kind in [
|
|
"package",
|
|
"module",
|
|
"interface",
|
|
"class",
|
|
"function",
|
|
"interfacemethod",
|
|
"classmethod",
|
|
]:
|
|
app.add_role(f"typedoc:{kind}", typedoc_role)
|
|
|
|
|
|
def setup(app):
|
|
if not os.environ.get("SKIP_JS"):
|
|
app.connect("config-inited", config_inited)
|
|
|
|
app.add_role("configproperty", config_property_role)
|
|
doc_dir = pathlib.Path(app.srcdir) # CCF/doc/
|
|
root_dir = pathlib.Path(os.path.abspath(doc_dir / "..")) # CCF/
|
|
out_dir = pathlib.Path(app.outdir) # CCF/build/html
|
|
|
|
# import ccf python package to generate docs for this version
|
|
python_path = os.path.abspath(doc_dir / "../python")
|
|
sys.path.insert(0, python_path)
|
|
|
|
# doxygen
|
|
breathe_projects["CCF"] = str(doc_dir / breathe_projects["CCF"])
|
|
if not os.environ.get("SKIP_DOXYGEN"):
|
|
subprocess.run(["doxygen"], cwd=root_dir, check=True)
|
|
doxygen_html_src = root_dir / "doxygen/html"
|
|
if doxygen_html_src.exists() and doxygen_html_src.is_dir():
|
|
doxygen_html_dest = str(out_dir / "doxygen")
|
|
subprocess.run(
|
|
["cp", "-r", str(doxygen_html_src), doxygen_html_dest], check=True
|
|
)
|
|
|
|
# configuration generator
|
|
input_file_path = doc_dir / "host_config_schema/cchost_config.json"
|
|
output_file_path = doc_dir / "operations/generated_config.rst"
|
|
|
|
if os.path.exists(input_file_path):
|
|
generate_config_rst.generate_configuration_docs(
|
|
input_file_path, output_file_path
|
|
)
|