2 # SPDX-License-Identifier: GPL-2.0
8 Implementation of the ``kernel-feat`` reST-directive.
10 :copyright: Copyright (C) 2016 Markus Heiser
11 :copyright: Copyright (C) 2016-2019 Mauro Carvalho Chehab
12 :maintained-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
13 :license: GPL Version 2, June 1991 see Linux/COPYING for details.
15 The ``kernel-feat`` (:py:class:`KernelFeat`) directive calls the
16 scripts/get_feat.pl script to parse the Kernel ABI files.
18 Overview of directive's argument and options.
22 .. kernel-feat:: <ABI directory location>
25 The argument ``<ABI directory location>`` is required. It contains the
26 location of the ABI files to be parsed.
29 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
30 what reST is generated.
42 from docutils import nodes, statemachine
43 from docutils.statemachine import ViewList
44 from docutils.parsers.rst import directives, Directive
45 from docutils.utils.error_reporting import ErrorString
46 from sphinx.util.docutils import switch_source_input
52 app.add_directive("kernel-feat", KernelFeat)
55 , parallel_read_safe = True
56 , parallel_write_safe = True
59 class KernelFeat(Directive):
61 u"""KernelFeat (``kernel-feat``) directive"""
63 required_arguments = 1
64 optional_arguments = 2
66 final_argument_whitespace = True
69 "debug" : directives.flag
72 def warn(self, message, **replace):
73 replace["fname"] = self.state.document.current_source
74 replace["line_no"] = replace.get("line_no", self.lineno)
75 message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
76 self.state.document.settings.env.app.warn(message, prefix="")
80 doc = self.state.document
81 if not doc.settings.file_insertion_enabled:
82 raise self.warning("docutils: file insertion disabled")
84 env = doc.settings.env
85 cwd = path.dirname(doc.current_source)
86 cmd = "get_feat.pl rest --enable-fname --dir "
87 cmd += self.arguments[0]
89 if len(self.arguments) > 1:
90 cmd += " --arch " + self.arguments[1]
92 srctree = path.abspath(os.environ["srctree"])
96 # extend PATH with $(srctree)/scripts
97 path_env = os.pathsep.join([
98 srctree + os.sep + "scripts",
101 shell_env = os.environ.copy()
102 shell_env["PATH"] = path_env
103 shell_env["srctree"] = srctree
105 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
107 line_regex = re.compile("^\.\. FILE (\S+)$")
111 for line in lines.split("\n"):
112 match = line_regex.search(line)
114 fname = match.group(1)
116 # Add the file to Sphinx build dependencies
117 env.note_dependency(os.path.abspath(fname))
119 out_lines += line + "\n"
121 nodeList = self.nestedParse(out_lines, fname)
124 def runCmd(self, cmd, **kwargs):
125 u"""Run command ``cmd`` and return its stdout as unicode."""
128 proc = subprocess.Popen(
130 , stdout = subprocess.PIPE
131 , stderr = subprocess.PIPE
134 out, err = proc.communicate()
136 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
138 if proc.returncode != 0:
140 u"command '%s' failed with return code %d"
141 % (cmd, proc.returncode)
143 except OSError as exc:
144 raise self.severe(u"problems with '%s' directive: %s."
145 % (self.name, ErrorString(exc)))
148 def nestedParse(self, lines, fname):
150 node = nodes.section()
152 if "debug" in self.options:
153 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
154 for l in lines.split("\n"):
155 code_block += "\n " + l
156 lines = code_block + "\n\n"
158 for c, l in enumerate(lines.split("\n")):
159 content.append(l, fname, c)
161 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
163 with switch_source_input(self.state, content):
164 self.state.nested_parse(content, 0, node, match_titles=1)