| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 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 <[email protected]>
|
| 14 | :license: GPL Version 2, June 1991 see Linux/COPYING for details.
|
| 15 |
|
| 16 | The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
|
| 17 | AbiParser class 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 |
|
| 35 | import os
|
| 36 | import re
|
| 37 | import sys
|
| 38 |
|
| 39 | from docutils import nodes, statemachine
|
| 40 | from docutils.statemachine import ViewList
|
| 41 | from docutils.parsers.rst import directives, Directive
|
| 42 | from sphinx.util.docutils import switch_source_input
|
| 43 | from sphinx.util import logging
|
| 44 |
|
| 45 | srctree = os.path.abspath(os.environ["srctree"])
|
| 46 | sys.path.insert(0, os.path.join(srctree, "tools/lib/python"))
|
| 47 |
|
| 48 | from abi.abi_parser import AbiParser
|
| 49 |
|
| 50 | __version__ = "1.0"
|
| 51 |
|
| 52 | logger = logging.getLogger('kernel_abi')
|
| 53 | path = os.path.join(srctree, "Documentation/ABI")
|
| 54 |
|
| 55 | _kernel_abi = None
|
| 56 |
|
| 57 | def get_kernel_abi():
|
| 58 | |
| 59 | Initialize kernel_abi global var, if not initialized yet.
|
| 60 |
|
| 61 | This is needed to avoid warnings during Sphinx module initialization.
|
| 62 |
|
| 63 | global _kernel_abi
|
| 64 |
|
| 65 | if not _kernel_abi:
|
| 66 | |
| 67 | _kernel_abi = AbiParser(path, logger=logger)
|
| 68 | _kernel_abi.parse_abi()
|
| 69 | _kernel_abi.check_issues()
|
| 70 |
|
| 71 | return _kernel_abi
|
| 72 |
|
| 73 | def setup(app):
|
| 74 |
|
| 75 | app.add_directive("kernel-abi", KernelCmd)
|
| 76 | return {
|
| 77 | "version": __version__,
|
| 78 | "parallel_read_safe": True,
|
| 79 | "parallel_write_safe": True
|
| 80 | }
|
| 81 |
|
| 82 |
|
| 83 | class KernelCmd(Directive):
|
| 84 |
|
| 85 |
|
| 86 | required_arguments = 1
|
| 87 | optional_arguments = 3
|
| 88 | has_content = False
|
| 89 | final_argument_whitespace = True
|
| 90 | parser = None
|
| 91 |
|
| 92 | option_spec = {
|
| 93 | "debug": directives.flag,
|
| 94 | "no-symbols": directives.flag,
|
| 95 | "no-files": directives.flag,
|
| 96 | }
|
| 97 |
|
| 98 | def run(self):
|
| 99 | kernel_abi = get_kernel_abi()
|
| 100 |
|
| 101 | doc = self.state.document
|
| 102 | if not doc.settings.file_insertion_enabled:
|
| 103 | raise self.warning("docutils: file insertion disabled")
|
| 104 |
|
| 105 | env = self.state.document.settings.env
|
| 106 | content = ViewList()
|
| 107 | node = nodes.section()
|
| 108 |
|
| 109 | abi_type = self.arguments[0]
|
| 110 |
|
| 111 | if "no-symbols" in self.options:
|
| 112 | show_symbols = False
|
| 113 | else:
|
| 114 | show_symbols = True
|
| 115 |
|
| 116 | if "no-files" in self.options:
|
| 117 | show_file = False
|
| 118 | else:
|
| 119 | show_file = True
|
| 120 |
|
| 121 | tab_width = self.options.get('tab-width',
|
| 122 | self.state.document.settings.tab_width)
|
| 123 |
|
| 124 | old_f = None
|
| 125 | n = 0
|
| 126 | n_sym = 0
|
| 127 | for msg, f, ln in kernel_abi.doc(show_file=show_file,
|
| 128 | show_symbols=show_symbols,
|
| 129 | filter_path=abi_type):
|
| 130 | n_sym += 1
|
| 131 | msg_list = statemachine.string2lines(msg, tab_width,
|
| 132 | convert_whitespace=True)
|
| 133 | if "debug" in self.options:
|
| 134 | lines = [
|
| 135 | "", "", ".. code-block:: rst",
|
| 136 | " :linenos:", ""
|
| 137 | ]
|
| 138 | for m in msg_list:
|
| 139 | lines.append(" " + m)
|
| 140 | else:
|
| 141 | lines = msg_list
|
| 142 |
|
| 143 | for line in lines:
|
| 144 | |
| 145 | content.append(line, f, ln - 1)
|
| 146 | n += 1
|
| 147 |
|
| 148 | if f != old_f:
|
| 149 | |
| 150 | fname = os.path.join(srctree, f)
|
| 151 | if os.path.isfile(fname):
|
| 152 | env.note_dependency(fname)
|
| 153 |
|
| 154 | old_f = f
|
| 155 |
|
| 156 | |
| 157 | |
| 158 | if content:
|
| 159 | self.do_parse(content, node)
|
| 160 | content = ViewList()
|
| 161 |
|
| 162 | if show_symbols and not show_file:
|
| 163 | logger.verbose("%s ABI: %i symbols (%i ReST lines)" % (abi_type, n_sym, n))
|
| 164 | elif not show_symbols and show_file:
|
| 165 | logger.verbose("%s ABI: %i files (%i ReST lines)" % (abi_type, n_sym, n))
|
| 166 | else:
|
| 167 | logger.verbose("%s ABI: %i data (%i ReST lines)" % (abi_type, n_sym, n))
|
| 168 |
|
| 169 | return node.children
|
| 170 |
|
| 171 | def do_parse(self, content, node):
|
| 172 | with switch_source_input(self.state, content):
|
| 173 | self.state.nested_parse(content, 0, node, match_titles=1)
|