# -*- 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 pathlib import shutil import sys sys.path.append(os.path.abspath("./_ext")) from docutils import nodes, utils from docutils.parsers.rst.roles import set_classes # -- Project information ----------------------------------------------------- project = u'VyOS' copyright = u'2026, VyOS maintainers and contributors' author = u'VyOS maintainers and contributors' # The short X.Y version (rolling — next major; bumped at branch cut) version = u'rolling' # The full version, including alpha/beta/rc tags. The `rolling` branch # is the rolling tip and serves at /en/rolling/ on RTD; the literal # below is exposed in the page footer ("v: rolling (current)") and is # interpolated into _templates/llms.txt.j2 ("This documentation covers # {{ release }}."). Pin this to a value that names what the rolling # docs actually serve, not a stale LTS codename. The "(current)" suffix # is release-channel terminology for the current rolling release; it is # unrelated to the former branch name. release = u'rolling (current)' # -- 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.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.graphviz', 'notfound.extension', 'autosectionlabel', 'myst_parser', 'sphinx_design', 'vyos', 'sphinx_llms_txt', 'sphinx_sitemap', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # autosectionlabel autosectionlabel_prefix_document = True # The suffix(es) of source filenames. source_suffix = ['.md'] myst_enable_extensions = ["colon_fence", "deflist", "fieldlist", "substitution"] myst_fence_as_directive = ["cfgcmd", "opcmd", "cmdincludemd"] # 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" # https://docs.readthedocs.io/en/stable/guides/manage-translations-sphinx.html#create-translatable-files locale_dirs = ['_locale/'] gettext_compact = True gettext_uuid = False # 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 = [ u'_build', 'Thumbs.db', '.DS_Store', '_include/vyos-1x', '_rst_legacy', ] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True # -- 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 = "sphinx_rtd_theme" # 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 = {} # 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'] html_extra_path = ['_html_extra'] html_baseurl = 'https://docs.vyos.io/en/rolling/' _rtd_version_type = os.environ.get('READTHEDOCS_VERSION_TYPE', '') _github_version = ( os.environ.get('READTHEDOCS_GIT_COMMIT_HASH', 'rolling') if _rtd_version_type == 'external' else os.environ.get('READTHEDOCS_GIT_IDENTIFIER', 'rolling') ) html_context = { 'display_github': True, 'github_user': 'vyos', 'github_repo': 'vyos-documentation', 'github_version': _github_version, 'conf_py_path': '/docs/', 'gtm_id': os.environ.get('GTM_ID', ''), 'cookiebot_id': os.environ.get('COOKIEBOT_ID', ''), } # sphinx-sitemap: baseurl already includes /en/rolling/, so skip lang+version sitemap_url_scheme = '{link}' # sphinx-llms-txt: disable the package's auto-generated index llms.txt. # The curated llms.txt is rendered at build time from # _templates/llms.txt.j2 by the _write_llms_txt() build-finished hook # below; llms-full.txt is still auto-generated by sphinx-llms-txt. llms_txt_file = False # 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 = {} # The name of an image file (relative to this directory) to place at the top # of the sidebar. html_logo = '_static/images/vyos-logo.webp' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = '_static/images/vyos-logo-icon.png' # The "title" for HTML documentation generated with Sphinx's own templates. # This is appended to the `` tag of individual pages, and used # in the navigation bar as the "topmost" element. html_title = f'{project} rolling release (current)' # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'VyOSdoc' # -- Options fo_r 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', 'preamble': r'''\def\changemargin#1#2{\list{}{\rightmargin#2\leftmargin#1}\item[]} \let\endchangemargin=\endlist''', 'classoptions': ',openany,oneside' } # 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, 'VyOS.tex', u'VyOS Documentation', u'VyOS maintainers and contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. latex_logo = '_static/images/vyos-logo.png' # -- 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, 'vyos', u'VyOS 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, 'VyOS', u'VyOS Documentation', author, 'VyOS', 'One line description of project.', 'Miscellaneous'), ] def _prefer_webp(app): """Prepend WebP to supported image types for HTML builders.""" if app.builder.name in ('html', 'dirhtml', 'readthedocs'): types = app.builder.supported_image_types if 'image/webp' not in types: app.builder.supported_image_types = ['image/webp'] + types def _write_llms_txt(app, exception): # Skip dirhtml: production publishes via the `html` / `readthedocs` # builders only. The `.md` links in the curated template do # actually resolve under `dirhtml` (`_copy_md_sources` puts `.md` # files at their source-relative paths regardless of builder), but # we still don't render llms.txt for builds we don't ship — local # `make dirhtml` is a developer convenience, not a publish target. if exception is not None or app.builder.name not in ( 'html', 'readthedocs'): return if not app.config.html_baseurl: # Fail loudly rather than rendering /quick-start.md etc. as a # silently-broken root-relative URL — every supported branch # sets html_baseurl, so a missing value is a regression. raise RuntimeError( 'html_baseurl must be set to render llms.txt') from pathlib import Path from jinja2 import Environment, FileSystemLoader, StrictUndefined tpl_dir = Path(app.srcdir) / '_templates' out_path = Path(app.outdir) / 'llms.txt' baseurl = app.config.html_baseurl.rstrip('/') + '/' # FileSystemLoader + get_template (rather than from_string) makes # Jinja tracebacks reference the real template filename and line # number — useful when StrictUndefined trips on a typo in # llms.txt.j2. StrictUndefined: missing template variables raise # rather than silently render as empty strings, so a typo in # llms.txt.j2 fails the build instead of shipping a half-blank # llms.txt. env = Environment( loader=FileSystemLoader(str(tpl_dir)), undefined=StrictUndefined, keep_trailing_newline=True, # Plain-text template (not HTML), so HTML autoescape is not # appropriate. Setting autoescape=False explicitly to silence # bandit/ruff S701 and document the intent. autoescape=False, ) template = env.get_template('llms.txt.j2') rendered = template.render( baseurl=baseurl, release=app.config.release, ) out_path.write_text(rendered, encoding='utf-8') def _copy_md_sources(app, exception): """Copy .md source files verbatim into the HTML output tree.""" if exception is not None: return src = pathlib.Path(app.srcdir) out = pathlib.Path(app.outdir) for path in src.rglob("*.md"): dest = out / path.relative_to(src) dest.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(path, dest) def setup(app): app.connect('builder-inited', _prefer_webp) app.connect('build-finished', _copy_md_sources) app.connect('build-finished', _write_llms_txt)