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 52 53def setup(app): 54 55 app.add_directive("kernel-abi", KernelCmd) 56 return { 57 "version": __version__, 58 "parallel_read_safe": True, 59 "parallel_write_safe": True 60 } 61 62 63class KernelCmd(Directive): 64 u"""KernelABI (``kernel-abi``) directive""" 65 66 required_arguments = 1 67 optional_arguments = 2 68 has_content = False 69 final_argument_whitespace = True 70 logger = logging.getLogger('kernel_abi') 71 parser = None 72 73 option_spec = { 74 "debug": directives.flag, 75 } 76 77 def run(self): 78 doc = self.state.document 79 if not doc.settings.file_insertion_enabled: 80 raise self.warning("docutils: file insertion disabled") 81 82 path = os.path.join(srctree, "Documentation", self.arguments[0]) 83 self.parser = AbiParser(path, logger=self.logger) 84 self.parser.parse_abi() 85 self.parser.check_issues() 86 87 node = self.nested_parse(None, self.arguments[0]) 88 return node 89 90 def nested_parse(self, data, fname): 91 env = self.state.document.settings.env 92 content = ViewList() 93 node = nodes.section() 94 95 if data is not None: 96 # Handles the .rst file 97 for line in data.split("\n"): 98 content.append(line, fname, 0) 99 100 self.do_parse(content, node) 101 102 else: 103 # Handles the ABI parser content, symbol by symbol 104 105 old_f = fname 106 n = 0 107 for msg, f, ln in self.parser.doc(): 108 msg_list = statemachine.string2lines(msg, tab_width, 109 convert_whitespace=True) 110 if "debug" in self.options: 111 lines = [ 112 "", "", ".. code-block:: rst", 113 " :linenos:", "" 114 ] 115 for m in msg_list: 116 lines.append(" " + m) 117 else: 118 lines = msg_list 119 120 for line in lines: 121 # sphinx counts lines from 0 122 content.append(line, f, ln - 1) 123 n += 1 124 125 if f != old_f: 126 # Add the file to Sphinx build dependencies 127 env.note_dependency(os.path.abspath(f)) 128 129 old_f = f 130 131 # Sphinx doesn't like to parse big messages. So, let's 132 # add content symbol by symbol 133 if content: 134 self.do_parse(content, node) 135 content = ViewList() 136 137 self.logger.info("%s: parsed %i lines" % (fname, n)) 138 139 return node.children 140 141 def do_parse(self, content, node): 142 with switch_source_input(self.state, content): 143 self.state.nested_parse(content, 0, node, match_titles=1) 144