1# SPDX-License-Identifier: GPL-2.0 2# Copyright 2025 Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 3 4""" 5Sphinx extension for processing YAML files 6""" 7 8import os 9import re 10import sys 11 12from pprint import pformat 13 14from docutils import statemachine 15from docutils.parsers.rst import Parser as RSTParser 16from docutils.parsers.rst import states 17from docutils.statemachine import ViewList 18 19from sphinx.util import logging 20from sphinx.parsers import Parser 21 22srctree = os.path.abspath(os.environ["srctree"]) 23sys.path.insert(0, os.path.join(srctree, "tools/net/ynl/pyynl/lib")) 24 25from doc_generator import YnlDocGenerator # pylint: disable=C0413 26 27logger = logging.getLogger(__name__) 28 29class YamlParser(Parser): 30 """ 31 Kernel parser for YAML files. 32 33 This is a simple sphinx.Parser to handle yaml files inside the 34 Kernel tree that will be part of the built documentation. 35 36 The actual parser function is not contained here: the code was 37 written in a way that parsing yaml for different subsystems 38 can be done from a single dispatcher. 39 40 All it takes to have parse YAML patches is to have an import line: 41 42 from some_parser_code import NewYamlGenerator 43 44 To this module. Then add an instance of the parser with: 45 46 new_parser = NewYamlGenerator() 47 48 and add a logic inside parse() to handle it based on the path, 49 like this: 50 51 if "/foo" in fname: 52 msg = self.new_parser.parse_yaml_file(fname) 53 """ 54 55 supported = ('yaml', ) 56 57 netlink_parser = YnlDocGenerator() 58 59 re_lineno = re.compile(r"\.\. LINENO ([0-9]+)$") 60 61 tab_width = 8 62 63 def rst_parse(self, inputstring, document, msg): 64 """ 65 Receives a ReST content that was previously converted by the 66 YAML parser, adding it to the document tree. 67 """ 68 69 self.setup_parse(inputstring, document) 70 71 result = ViewList() 72 73 self.statemachine = states.RSTStateMachine(state_classes=states.state_classes, 74 initial_state='Body', 75 debug=document.reporter.debug_flag) 76 77 try: 78 # Parse message with RSTParser 79 lineoffset = 0; 80 81 lines = statemachine.string2lines(msg, self.tab_width, 82 convert_whitespace=True) 83 84 for line in lines: 85 match = self.re_lineno.match(line) 86 if match: 87 lineoffset = int(match.group(1)) 88 continue 89 90 result.append(line, document.current_source, lineoffset) 91 92 self.statemachine.run(result, document) 93 94 except Exception as e: 95 document.reporter.error("YAML parsing error: %s" % pformat(e)) 96 97 self.finish_parse() 98 99 # Overrides docutils.parsers.Parser. See sphinx.parsers.RSTParser 100 def parse(self, inputstring, document): 101 """Check if a YAML is meant to be parsed.""" 102 103 fname = document.current_source 104 105 # Handle netlink yaml specs 106 if "/netlink/specs/" in fname: 107 msg = self.netlink_parser.parse_yaml_file(fname) 108 self.rst_parse(inputstring, document, msg) 109 110 # All other yaml files are ignored 111 112def setup(app): 113 """Setup function for the Sphinx extension.""" 114 115 # Add YAML parser 116 app.add_source_parser(YamlParser) 117 app.add_source_suffix('.yaml', 'yaml') 118 119 return { 120 'version': '1.0', 121 'parallel_read_safe': True, 122 'parallel_write_safe': True, 123 } 124