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 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 = msg.split("\n") 109 if "debug" in self.options: 110 lines = [ 111 "", "", ".. code-block:: rst", 112 " :linenos:", "" 113 ] 114 for m in msg_list: 115 lines.append(" " + m) 116 else: 117 lines = msg_list 118 119 for line in lines: 120 # sphinx counts lines from 0 121 content.append(line, f, ln - 1) 122 n += 1 123 124 if f != old_f: 125 # Add the file to Sphinx build dependencies 126 env.note_dependency(os.path.abspath(f)) 127 128 old_f = f 129 130 # Sphinx doesn't like to parse big messages. So, let's 131 # add content symbol by symbol 132 if content: 133 self.do_parse(content, node) 134 content = ViewList() 135 136 self.logger.info("%s: parsed %i lines" % (fname, n)) 137 138 return node.children 139 140 def do_parse(self, content, node): 141 with switch_source_input(self.state, content): 142 self.state.nested_parse(content, 0, node, match_titles=1) 143