/
githubmirror
/
salt
Обзор
Документация
Войти
/
githubmirror
/
salt
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
doc/conf.py
588 строк
19 KB
Daniel A. Wozniak
Merge branch '3007.x' into merge/3007.x/3008.x/25-06-08
10 июн 2026, 01:06
10 июн 2026, 01:06
d96c6ed
Код
Авторство
О чём код?
# pylint: disable=C0103,W0622 """ Sphinx documentation for Salt """ import os import sys import urllib.parse # Sphinx crashes parsing docstring URLs like ``http://hostname[:port]`` because # urllib.parse.urlsplit raises ValueError("Invalid IPv6 URL") on the bracketed # host placeholder. Return a dummy SplitResult for that one case so the build # can proceed. _original_urlsplit = urllib.parse.urlsplit def _safe_urlsplit(url, scheme="", allow_fragments=True): try: return _original_urlsplit(url, scheme, allow_fragments) except ValueError as exc: if "Invalid IPv6 URL" in str(exc): return urllib.parse.SplitResult(scheme, "", url, "", "") raise urllib.parse.urlsplit = _safe_urlsplit import pathlib import re import shutil import textwrap import time import types from sphinx.directives.other import TocTree from sphinx.util import logging log = logging.getLogger(__name__) # -- Add paths to PYTHONPATH --------------------------------------------------- try: docs_basepath = os.path.abspath(os.path.dirname(__file__)) except NameError: # sphinx-intl and six execute some code which will raise this NameError # assume we're in the doc/ directory docs_basepath = os.path.abspath(os.path.dirname(".")) addtl_paths = ( os.pardir, # salt itself (for autodoc) "_ext", # custom Sphinx extensions ) for addtl_path in addtl_paths: path = os.path.abspath(os.path.join(docs_basepath, addtl_path)) sys.path.insert(0, path) # We're now able to import salt import salt.version # isort:skip formulas_dir = os.path.join(os.pardir, docs_basepath, "formulas") # ----- Intersphinx Settings ------------------------------------------------> intersphinx_mapping = { "python": ( "https://docs.python.org/3", ( "/usr/share/doc/python{}.{}/html/objects.inv".format( sys.version_info[0], sys.version_info[1] ), "/usr/share/doc/python/html/objects.inv", None, ), ) } # <---- Intersphinx Settings ------------------------------------------------- # -- General Configuration ----------------------------------------------------- # Set a var if we're building docs for the live site or not on_saltstack = "SALT_ON_SALTSTACK" in os.environ project = "Salt" # This is the default branch on GitHub for the Salt project repo_primary_branch = "master" if "LATEST_RELEASE" not in os.environ: salt_version = salt.version.__saltstack_version__ else: salt_version = salt.version.SaltStackVersion.parse(os.environ["LATEST_RELEASE"]) major_version = str(salt_version.major) latest_release = ".".join([str(x) for x in salt_version.info]) previous_release = os.environ.get( "PREVIOUS_RELEASE", "previous_release" ) # latest release from previous branch (3002.5) previous_release_dir = os.environ.get( "PREVIOUS_RELEASE_DIR", "previous_release_dir" ) # path on web server for previous branch (3002.5) next_release = "" # next release next_release_dir = "" # path on web server for next release branch # Sphinx variable # https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-version version = latest_release today = "" copyright = "" if on_saltstack: today = "Generated on {} at {}.".format( time.strftime("%B %d, %Y"), time.strftime("%X %Z") ) copyright = time.strftime("%Y") # < --- START do not merge these settings to other branches START ---> # build_type = os.environ.get( "BUILD_TYPE", repo_primary_branch ) # latest, previous, master, next # < --- END do not merge these settings to other branches END ---> # # Set google custom search engine if build_type == repo_primary_branch: release = latest_release search_cx = "011515552685726825874:v1had6i279q" # master # search_cx = '011515552685726825874:x17j5zl74g8' # develop elif build_type == "next": release = next_release search_cx = "011515552685726825874:ht0p8miksrm" # latest elif build_type == "previous": release = previous_release if release.startswith("3006"): search_cx = "2e4374de8af93a7b1" # 3006 elif release.startswith("3005"): search_cx = "57b1006b37edd9e79" # 3005 elif release.startswith("3004"): search_cx = "23cd7068705804111" # 3004 elif release.startswith("3003"): search_cx = "a70a1a73eef62aecd" # 3003 elif release.startswith("3002"): search_cx = "5026f4f2af0bdbe2d" # 3002 elif release.startswith("3001"): search_cx = "f0e4f298fa32b8a5e" # 3001 elif release.startswith("3000"): search_cx = "011515552685726825874:3skhaozjtyn" # 3000 elif release.startswith("2019.2"): search_cx = "011515552685726825874:huvjhlpptnm" # 2019.2 elif release.startswith("2018.3"): search_cx = "011515552685726825874:vadptdpvyyu" # 2018.3 elif release.startswith("2017.7"): search_cx = "011515552685726825874:w-hxmnbcpou" # 2017.7 elif release.startswith("2016.11"): search_cx = "011515552685726825874:dlsj745pvhq" # 2016.11 else: search_cx = "011515552685726825874:ht0p8miksrm" # latest else: # latest or something else release = latest_release search_cx = "011515552685726825874:ht0p8miksrm" # latest needs_sphinx = "1.3" spelling_lang = "en_US" spelling_show_suggestions = True language = "en" locale_dirs = [ "_locale", ] master_doc = "contents" templates_path = ["_templates"] exclude_patterns = [ "_build", "_incl/*", "ref/cli/_includes/*.rst", # Stand-alone design notes; not linked from the doc toctree (see e.g. # ``topics/proposals/async-batch.md``). "topics/proposals/*.md", ] extensions = [ "saltdomain", # Must come early "sphinx.ext.autodoc", "sphinx.ext.napoleon", "sphinx.ext.autosummary", "sphinx.ext.extlinks", "sphinx.ext.imgconverter", "sphinx.ext.intersphinx", "sphinxcontrib.httpdomain", "saltrepo", "myst_parser", #'saltautodoc', # Must be AFTER autodoc ] # Only enable spell-checking if enchant library is available # This is optional for package builds but useful during development try: import enchant extensions.append("sphinxcontrib.spelling") except ImportError: log.info("Spell-checking disabled: enchant library not available") # Vault policy lexer is only needed for HTML builds (syntax highlighting) # Man pages don't use syntax highlighting, so we only add it for non-man builds # Check if we're building man pages by looking for 'man' builder in sys.argv building_man_only = any( sys.argv[i] == "-b" and i + 1 < len(sys.argv) and sys.argv[i + 1] == "man" for i in range(len(sys.argv)) ) if not building_man_only: extensions.append("vaultpolicylexer") modindex_common_prefix = ["salt."] autosummary_generate = True autosummary_generate_overwrite = False # Smart dependency handling for documentation builds # For man pages (lightweight CLI docs), we auto-mock missing dependencies # For full HTML docs, we fail with helpful errors about what's missing autodoc_mock_imports = [] # External dependencies that Salt imports at module level # These need to be available for full HTML docs (autodoc) but can be mocked for man pages _SALT_DEPENDENCIES = [ "distro", "jinja2", "looseversion", "msgpack", "packaging", "yaml", ] # backports is optional - it doesn't exist in Python 3.13+ and may not be installed # Always mock it to avoid warnings autodoc_mock_imports.append("backports") _missing_deps = [] for dep in _SALT_DEPENDENCIES: try: __import__(dep) except ImportError: _missing_deps.append(dep) # Always mock missing dependencies to allow build to proceed autodoc_mock_imports.append(dep) if _missing_deps: if building_man_only: # For man pages, this is expected - they don't need Salt modules log.info( "Building man pages with mocked dependencies: %s (this is normal for man pages)", ", ".join(_missing_deps), ) else: # For HTML/full builds, warn that docs may be incomplete log.warning( "\n" "=" * 70 + "\n" "WARNING: Missing dependencies for full documentation build:\n" " %s\n\n" "Autodoc will use mocked modules. Documentation will be generated but\n" "may be incomplete or show incorrect type hints.\n\n" "For complete documentation, install with:\n" " pip install %s\n" + "=" * 70, ", ".join(_missing_deps), " ".join(_missing_deps), ) # strip git rev as there won't necessarily be a release based on it stripped_release = re.sub(r"-\d+-g[0-9a-f]+$", "", release) # Define a substitution for linking to the latest release tarball rst_prolog = """\ .. |current_release_doc| replace:: :doc:`/topics/releases/{release}` .. |saltrepo| replace:: https://github.com/saltstack/salt .. _`salt-users`: https://groups.google.com/forum/#!forum/salt-users .. _`salt-announce`: https://groups.google.com/forum/#!forum/salt-announce .. _`salt-packagers`: https://groups.google.com/forum/#!forum/salt-packagers .. _`salt-discord`: https://discord.com/invite/J7b7EscrAs """.format( release=stripped_release ) # A shortcut for linking to tickets on the GitHub issue tracker extlinks = { "blob": ( "https://github.com/saltstack/salt/blob/%s/%%s" % repo_primary_branch, "%s", ), "issue": ("https://github.com/saltstack/salt/issues/%s", "issue %s"), "pull": ("https://github.com/saltstack/salt/pull/%s", "PR %s"), "formula_url": ("https://github.com/saltstack-formulas/%s", "url %s"), } myst_gfm_only = True # ----- Localization --------------------------------------------------------> locale_dirs = ["locale/"] gettext_compact = False # <---- Localization --------------------------------------------------------- ### HTML options # set 'HTML_THEME=saltstack' to use previous theme html_theme = os.environ.get("HTML_THEME", "pydata_sphinx_theme") html_theme_path = ["_themes"] html_title = "" html_short_title = "Salt" html_static_path = ["_static"] html_logo = None # specified in the theme layout.html html_favicon = "favicon.ico" smartquotes = False # Use Google customized search or use Sphinx built-in JavaScript search if on_saltstack: html_search_template = "googlesearch.html" else: html_search_template = "searchbox.html" html_additional_pages = { "404": "404.html", } html_default_sidebars = [ html_search_template, "version.html", "localtoc.html", "relations.html", "sourcelink.html", "saltstack.html", ] if html_theme == "pydata_sphinx_theme": html_theme_options = { "logo": { "image_light": "https://gitlab.com/saltstack/open/salt-branding-guide/-/raw/master/logos/SaltProject_altlogo_teal.png", "image_dark": "https://gitlab.com/saltstack/open/salt-branding-guide/-/raw/master/logos/SaltProject_altlogo_teal.png", }, "navbar_start": ["navbar-logo"], "navbar_center": [ "navbar-nav", "header-links", ], # navbar-nav provides structure, header-links provides logic "navbar_end": ["version-switcher", "theme-switcher", "navbar-icon-links"], "show_nav_level": 4, "navigation_depth": 4, "collapse_navigation": False, "shorten_urls": False, # Disable to avoid crashes on malformed URLs "check_switcher": False, # Disable to avoid warnings about local json file "switcher": { "json_url": "https://docs.saltproject.io/en/latest/_static/versions.json", # Match an entry in versions.json by BUILD_TYPE: the published # /en/latest/ build is "latest"; dev/master is "master"; release # branches publish to /en/<major>/ (e.g. /en/3006/) and match the # major version derived from `release`. "version_match": ( "master" if build_type == repo_primary_branch or build_type == "next" else "latest" if build_type == "latest" else release.split(".", 1)[0] ), }, } html_sidebars = {"**": ["globaltoc.html", "sidebar-ethical-ads"]} elif html_theme == "furo": pass else: html_sidebars = { "ref/**/all/salt.*": [ html_search_template, "version.html", "modules-sidebar.html", "localtoc.html", "relations.html", "sourcelink.html", "saltstack.html", ], "ref/formula/all/*": [], } html_context = { "on_saltstack": on_saltstack, "html_default_sidebars": html_default_sidebars, "github_base": "https://github.com/saltstack/salt", "github_issues": "https://github.com/saltstack/salt/issues", "github_downloads": "https://github.com/saltstack/salt/downloads", "latest_release": latest_release, "previous_release": previous_release, "previous_release_dir": previous_release_dir, "next_release": next_release, "next_release_dir": next_release_dir, "search_cx": search_cx, "build_type": build_type, "today": today, "copyright": copyright, "repo_primary_branch": repo_primary_branch, } html_use_index = True html_last_updated_fmt = "%b %d, %Y" html_show_sourcelink = False html_show_sphinx = True html_show_copyright = True ### Latex options latex_documents = [ ("contents", "Salt.tex", "Salt Documentation", "VMware, Inc.", "manual"), ] latex_logo = "_static/salt-logo.png" latex_elements = { "inputenc": "", # use XeTeX instead of the inputenc LaTeX package. "utf8extra": "", "preamble": r""" \usepackage{fontspec} \setsansfont{Linux Biolinum O} \setromanfont{Linux Libertine O} \setmonofont{Source Code Pro} """, } ### Linux Biolinum, Linux Libertine: http://www.linuxlibertine.org/ ### Source Code Pro: https://github.com/adobe-fonts/source-code-pro/releases ### Linkcheck options linkcheck_ignore = [ r"http://127.0.0.1", r"http://salt:\d+", r"http://local:\d+", r"https://console.aws.amazon.com", r"http://192.168.33.10", r"http://domain:\d+", r"http://123.456.789.012:\d+", r"http://localhost", r"https://groups.google.com/forum/#!forum/salt-users", r"https://www.elastic.co/logstash/docs/latest/inputs/udp", r"https://www.elastic.co/logstash/docs/latest/inputs/zeromq", r"http://www.youtube.com/saltstack", r"https://raven.readthedocs.io", r"https://getsentry.com", r"https://salt-cloud.readthedocs.io", r"https://salt.readthedocs.io", r"http://www.pip-installer.org/", r"https://github.com/watching", r"dash-feed://", r"https://github.com/saltstack/salt/", r"https://bootstrap.saltproject.io", r"https://raw.githubusercontent.com/saltstack/salt-bootstrap/stable/bootstrap-salt.sh", r"media.readthedocs.org/dash/salt/latest/salt.xml", r"https://portal.aws.amazon.com/gp/aws/securityCredentials", r"dash-feed://https%3A//media.readthedocs.org/dash/salt/latest/salt.xml", r"(?i)dns:.*", r"TCP:4506", r"https?://", r"https://cloud.github.com/downloads/saltstack/.*", r"https://INFOBLOX/.*", r"https://SOMESERVERIP:.*", r"https://community.saltstack.com/.*", # GitHub Users r"https://github.com/[^/]$", # GitHub Salt Forks r"https://github.com/[^/]/salt$", r"tag:key=value", r"jdbc:mysql:.*", r"http:post", ] linkcheck_exclude_documents = [ r"topics/releases/(2015|2016)\..*\.rst", r"topics/releases/saltapi/0\.8\.0.*", ] linkcheck_timeout = 10 linkcheck_anchors = False ### Manpage options # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). authors = [ "Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file", ] man_pages = [ ("ref/cli/salt", "salt", "salt", authors, 1), ("ref/cli/salt-master", "salt-master", "salt-master Documentation", authors, 1), ("ref/cli/salt-minion", "salt-minion", "salt-minion Documentation", authors, 1), ("ref/cli/salt-key", "salt-key", "salt-key Documentation", authors, 1), ("ref/cli/salt-cp", "salt-cp", "salt-cp Documentation", authors, 1), ("ref/cli/salt-call", "salt-call", "salt-call Documentation", authors, 1), ("ref/cli/salt-proxy", "salt-proxy", "salt-proxy Documentation", authors, 1), ("ref/cli/salt-syndic", "salt-syndic", "salt-syndic Documentation", authors, 1), ("ref/cli/salt-run", "salt-run", "salt-run Documentation", authors, 1), ("ref/cli/salt-ssh", "salt-ssh", "salt-ssh Documentation", authors, 1), ("ref/cli/salt-cloud", "salt-cloud", "Salt Cloud Command", authors, 1), ("ref/cli/salt-api", "salt-api", "salt-api Command", authors, 1), ("ref/cli/spm", "spm", "Salt Package Manager Command", authors, 1), ] def skip_mod_init_member(app, what, name, obj, skip, options): # pylint: disable=too-many-arguments,unused-argument if name.startswith("_"): return True if isinstance(obj, types.FunctionType) and obj.__name__ == "mod_init": return True return False def _normalize_version(args): _, path = args return ".".join([x.zfill(4) for x in (path.split("/")[-1].split("."))]) class ReleasesTree(TocTree): option_spec = dict(TocTree.option_spec) def run(self): rst = super().run() entries = rst[0][0]["entries"][:] entries.sort(key=_normalize_version, reverse=True) rst[0][0]["entries"][:] = entries return rst def copy_release_templates_pre(app): app._copied_release_files = [] docs_path = pathlib.Path(docs_basepath) release_files_dir = docs_path / "topics" / "releases" release_template_files_dir = release_files_dir / "templates" for fpath in release_template_files_dir.iterdir(): dest = release_files_dir / fpath.name.replace(".template", "") if dest.exists(): continue log.info( "Copying '%s' -> '%s' just for this build ...", fpath.relative_to(docs_path), dest.relative_to(docs_path), ) app._copied_release_files.append(dest) shutil.copyfile(fpath, dest) def copy_release_templates_post(app, exception): docs_path = pathlib.Path(docs_basepath) for fpath in app._copied_release_files: log.info( "The release file '%s' was copied for the build, but its not in " "version control system. Deleting.", fpath.relative_to(docs_path), ) fpath.unlink() def extract_module_deprecations(app, what, name, obj, options, lines): """ Add a warning to the modules being deprecated into extensions. """ # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#event-autodoc-process-docstring if what != "module": # We're only interested in module deprecations return try: deprecated_info = obj.__deprecated__ except AttributeError: # The module is not deprecated return _version, _extension, _url = deprecated_info msg = textwrap.dedent( f""" .. warning:: This module will be removed from Salt in version {_version} in favor of the `{_extension} Salt Extension <{_url}>`_. """ ) # Modify the docstring lines in-place lines[:] = msg.splitlines() + lines def setup(app): app.add_directive("releasestree", ReleasesTree) app.connect("autodoc-skip-member", skip_mod_init_member) app.connect("builder-inited", copy_release_templates_pre) app.connect("build-finished", copy_release_templates_post) app.connect("autodoc-process-docstring", extract_module_deprecations)