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
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 it's 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):
132 node = nodes.section()
134 if "debug" in self.options:
135 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
136 for l in lines.split("\n"):
137 code_block += "\n " + l
138 lines = code_block + "\n\n"
140 line_regex = re.compile("^#define LINENO (\S+)\#([0-9]+)$")
145 for line in lines.split("\n"):
147 match = line_regex.search(line)
149 new_f = match.group(1)
151 # Sphinx parser is lazy: it stops parsing contents in the
152 # middle, if it is too big. So, handle it per input file
153 if new_f != f and content:
154 self.do_parse(content, node)
159 # sphinx counts lines from 0
160 ln = int(match.group(2)) - 1
162 content.append(line, f, ln)
164 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
167 self.do_parse(content, node)
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)