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
48 from sphinx.util.docutils import switch_source_input
54 app.add_directive("kernel-abi", KernelCmd)
57 , parallel_read_safe = True
58 , parallel_write_safe = True
61 class KernelCmd(Directive):
63 u"""KernelABI (``kernel-abi``) directive"""
65 required_arguments = 1
66 optional_arguments = 2
68 final_argument_whitespace = True
71 "debug" : directives.flag,
72 "rst" : directives.unchanged
77 doc = self.state.document
78 if not doc.settings.file_insertion_enabled:
79 raise self.warning("docutils: file insertion disabled")
81 env = doc.settings.env
82 cwd = path.dirname(doc.current_source)
83 cmd = "get_abi.pl rest --enable-lineno --dir "
84 cmd += self.arguments[0]
86 if 'rst' in self.options:
87 cmd += " --rst-source"
89 srctree = path.abspath(os.environ["srctree"])
93 # extend PATH with $(srctree)/scripts
94 path_env = os.pathsep.join([
95 srctree + os.sep + "scripts",
98 shell_env = os.environ.copy()
99 shell_env["PATH"] = path_env
100 shell_env["srctree"] = srctree
102 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
103 nodeList = self.nestedParse(lines, self.arguments[0])
106 def runCmd(self, cmd, **kwargs):
107 u"""Run command ``cmd`` and return its stdout as unicode."""
110 proc = subprocess.Popen(
112 , stdout = subprocess.PIPE
113 , stderr = subprocess.PIPE
116 out, err = proc.communicate()
118 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
120 if proc.returncode != 0:
122 u"command '%s' failed with return code %d"
123 % (cmd, proc.returncode)
125 except OSError as exc:
126 raise self.severe(u"problems with '%s' directive: %s."
127 % (self.name, ErrorString(exc)))
130 def nestedParse(self, lines, fname):
131 env = self.state.document.settings.env
133 node = nodes.section()
135 if "debug" in self.options:
136 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
137 for l in lines.split("\n"):
138 code_block += "\n " + l
139 lines = code_block + "\n\n"
141 line_regex = re.compile("^\.\. LINENO (\S+)\#([0-9]+)$")
146 for line in lines.split("\n"):
148 match = line_regex.search(line)
150 new_f = match.group(1)
152 # Sphinx parser is lazy: it stops parsing contents in the
153 # middle, if it is too big. So, handle it per input file
154 if new_f != f and content:
155 self.do_parse(content, node)
158 # Add the file to Sphinx build dependencies
159 env.note_dependency(os.path.abspath(f))
163 # sphinx counts lines from 0
164 ln = int(match.group(2)) - 1
166 content.append(line, f, ln)
168 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
171 self.do_parse(content, node)
175 def do_parse(self, content, node):
176 with switch_source_input(self.state, content):
177 self.state.nested_parse(content, 0, node, match_titles=1)