1# -*- coding: utf-8; mode: python -*- 2# coding=utf-8 3# SPDX-License-Identifier: GPL-2.0 4# 5u""" 6 kernel-abi 7 ~~~~~~~~~~ 8 9 Implementation of the ``kernel-abi`` reST-directive. 10 11 :copyright: Copyright (C) 2016 Markus Heiser 12 :copyright: Copyright (C) 2016-2020 Mauro Carvalho Chehab 13 :maintained-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 14 :license: GPL Version 2, June 1991 see Linux/COPYING for details. 15 16 The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the 17 scripts/get_abi.py script to parse the Kernel ABI files. 18 19 Overview of directive's argument and options. 20 21 .. code-block:: rst 22 23 .. kernel-abi:: <ABI directory location> 24 :debug: 25 26 The argument ``<ABI directory location>`` is required. It contains the 27 location of the ABI files to be parsed. 28 29 ``debug`` 30 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see 31 what reST is generated. 32 33""" 34 35import os 36import re 37import sys 38 39from docutils import nodes, statemachine 40from docutils.statemachine import ViewList 41from docutils.parsers.rst import directives, Directive 42from sphinx.util.docutils import switch_source_input 43from sphinx.util import logging 44 45srctree = os.path.abspath(os.environ["srctree"]) 46sys.path.insert(0, os.path.join(srctree, "scripts/lib/abi")) 47 48from abi_parser import AbiParser 49 50__version__ = "1.0" 51 52logger = logging.getLogger('kernel_abi') 53path = os.path.join(srctree, "Documentation/ABI") 54 55# Parse ABI symbols only once 56kernel_abi = AbiParser(path, logger=logger) 57kernel_abi.parse_abi() 58kernel_abi.check_issues() 59 60def setup(app): 61 62 app.add_directive("kernel-abi", KernelCmd) 63 return { 64 "version": __version__, 65 "parallel_read_safe": True, 66 "parallel_write_safe": True 67 } 68 69 70class KernelCmd(Directive): 71 u"""KernelABI (``kernel-abi``) directive""" 72 73 required_arguments = 1 74 optional_arguments = 3 75 has_content = False 76 final_argument_whitespace = True 77 parser = None 78 79 option_spec = { 80 "debug": directives.flag, 81 "no-symbols": directives.flag, 82 "no-files": directives.flag, 83 } 84 85 def run(self): 86 doc = self.state.document 87 if not doc.settings.file_insertion_enabled: 88 raise self.warning("docutils: file insertion disabled") 89 90 env = self.state.document.settings.env 91 content = ViewList() 92 node = nodes.section() 93 94 abi_type = self.arguments[0] 95 96 if "no-symbols" in self.options: 97 show_symbols = False 98 else: 99 show_symbols = True 100 101 if "no-files" in self.options: 102 show_file = False 103 else: 104 show_file = True 105 106 tab_width = self.options.get('tab-width', 107 self.state.document.settings.tab_width) 108 109 old_f = None 110 n = 0 111 n_sym = 0 112 for msg, f, ln in kernel_abi.doc(show_file=show_file, 113 show_symbols=show_symbols, 114 filter_path=abi_type): 115 n_sym += 1 116 msg_list = statemachine.string2lines(msg, tab_width, 117 convert_whitespace=True) 118 if "debug" in self.options: 119 lines = [ 120 "", "", ".. code-block:: rst", 121 " :linenos:", "" 122 ] 123 for m in msg_list: 124 lines.append(" " + m) 125 else: 126 lines = msg_list 127 128 for line in lines: 129 # sphinx counts lines from 0 130 content.append(line, f, ln - 1) 131 n += 1 132 133 if f != old_f: 134 # Add the file to Sphinx build dependencies 135 env.note_dependency(os.path.abspath(f)) 136 137 old_f = f 138 139 # Sphinx doesn't like to parse big messages. So, let's 140 # add content symbol by symbol 141 if content: 142 self.do_parse(content, node) 143 content = ViewList() 144 145 if show_symbols and not show_file: 146 logger.verbose("%s ABI: %i symbols (%i ReST lines)" % (abi_type, n_sym, n)) 147 elif not show_symbols and show_file: 148 logger.verbose("%s ABI: %i files (%i ReST lines)" % (abi_type, n_sym, n)) 149 else: 150 logger.verbose("%s ABI: %i data (%i ReST lines)" % (abi_type, n_sym, n)) 151 152 return node.children 153 154 def do_parse(self, content, node): 155 with switch_source_input(self.state, content): 156 self.state.nested_parse(content, 0, node, match_titles=1) 157