Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1# -*- coding: utf-8; mode: python -*-
2# coding=utf-8
3# SPDX-License-Identifier: GPL-2.0
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 <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 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
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, "tools/lib/python"))
47
48from abi.abi_parser import AbiParser
49
50__version__ = "1.0"
51
52logger = logging.getLogger('kernel_abi')
53path = os.path.join(srctree, "Documentation/ABI")
54
55_kernel_abi = None
56
57def 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 # Parse ABI symbols only once
67 _kernel_abi = AbiParser(path, logger=logger)
68 _kernel_abi.parse_abi()
69 _kernel_abi.check_issues()
70
71 return _kernel_abi
72
73def 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
83class KernelCmd(Directive):
84 """KernelABI (``kernel-abi``) directive"""
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 # sphinx counts lines from 0
145 content.append(line, f, ln - 1)
146 n += 1
147
148 if f != old_f:
149 # Add the file to Sphinx build dependencies if the file exists
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 # Sphinx doesn't like to parse big messages. So, let's
157 # add content symbol by symbol
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)