1 # -*- coding: utf-8; mode: python -*-
3 # SPDX-License-Identifier: GPL-2.0
9 Implementation of the ``kernel-abi`` reST-directive.
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.
16 The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
17 scripts/get_abi.pl script to parse the Kernel ABI files.
19 Overview of directive's argument and options.
23 .. kernel-abi:: <ABI directory location>
26 The argument ``<ABI directory location>`` is required. It contains the
27 location of the ABI files to be parsed.
30 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
31 what reST is generated.
44 from docutils import nodes, statemachine
45 from docutils.statemachine import ViewList
46 from docutils.parsers.rst import directives, Directive
47 from docutils.utils.error_reporting import ErrorString
50 # AutodocReporter is only good up to Sphinx 1.7
54 Use_SSI = sphinx.__version__[:3] >= '1.7'
56 from sphinx.util.docutils import switch_source_input
58 from sphinx.ext.autodoc import AutodocReporter
64 app.add_directive("kernel-abi", KernelCmd)
67 , parallel_read_safe = True
68 , parallel_write_safe = True
71 class KernelCmd(Directive):
73 u"""KernelABI (``kernel-abi``) directive"""
75 required_arguments = 1
76 optional_arguments = 2
78 final_argument_whitespace = True
81 "debug" : directives.flag,
82 "rst" : directives.unchanged
87 doc = self.state.document
88 if not doc.settings.file_insertion_enabled:
89 raise self.warning("docutils: file insertion disabled")
91 env = doc.settings.env
92 cwd = path.dirname(doc.current_source)
93 cmd = "get_abi.pl rest --enable-lineno --dir "
94 cmd += self.arguments[0]
96 if 'rst' in self.options:
97 cmd += " --rst-source"
99 srctree = path.abspath(os.environ["srctree"])
103 # extend PATH with $(srctree)/scripts
104 path_env = os.pathsep.join([
105 srctree + os.sep + "scripts",
108 shell_env = os.environ.copy()
109 shell_env["PATH"] = path_env
110 shell_env["srctree"] = srctree
112 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
113 nodeList = self.nestedParse(lines, self.arguments[0])
116 def runCmd(self, cmd, **kwargs):
117 u"""Run command ``cmd`` and return it's stdout as unicode."""
120 proc = subprocess.Popen(
122 , stdout = subprocess.PIPE
123 , stderr = subprocess.PIPE
126 out, err = proc.communicate()
128 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
130 if proc.returncode != 0:
132 u"command '%s' failed with return code %d"
133 % (cmd, proc.returncode)
135 except OSError as exc:
136 raise self.severe(u"problems with '%s' directive: %s."
137 % (self.name, ErrorString(exc)))
140 def nestedParse(self, lines, fname):
142 node = nodes.section()
144 if "debug" in self.options:
145 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
146 for l in lines.split("\n"):
147 code_block += "\n " + l
148 lines = code_block + "\n\n"
150 line_regex = re.compile("^#define LINENO (\S+)\#([0-9]+)$")
155 for line in lines.split("\n"):
157 match = line_regex.search(line)
159 new_f = match.group(1)
161 # Sphinx parser is lazy: it stops parsing contents in the
162 # middle, if it is too big. So, handle it per input file
163 if new_f != f and content:
164 self.do_parse(content, node)
169 # sphinx counts lines from 0
170 ln = int(match.group(2)) - 1
172 content.append(line, f, ln)
174 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
177 self.do_parse(content, node)
181 def do_parse(self, content, node):
183 with switch_source_input(self.state, content):
184 self.state.nested_parse(content, 0, node, match_titles=1)
186 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
188 self.state.memo.title_styles = []
189 self.state.memo.section_level = 0
190 self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
192 self.state.nested_parse(content, 0, node, match_titles=1)
194 self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf