blob: 2fee04f1dedd885aad9876cb47f50e801acef6c5 [file] [log] [blame]
Heinrich Schuchardtc8e0f202020-12-31 23:16:46 +01001# coding=utf-8
2# SPDX-License-Identifier: GPL-2.0
3#
4u"""
5 kernel-feat
6 ~~~~~~~~~~~
7
8 Implementation of the ``kernel-feat`` reST-directive.
9
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.
14
15 The ``kernel-feat`` (:py:class:`KernelFeat`) directive calls the
16 scripts/get_feat.pl script to parse the Kernel ABI files.
17
18 Overview of directive's argument and options.
19
20 .. code-block:: rst
21
22 .. kernel-feat:: <ABI directory location>
23 :debug:
24
25 The argument ``<ABI directory location>`` is required. It contains the
26 location of the ABI files to be parsed.
27
28 ``debug``
29 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
30 what reST is generated.
31
32"""
33
34import codecs
35import os
36import subprocess
37import sys
38
39from os import path
40
41from docutils import nodes, statemachine
42from docutils.statemachine import ViewList
43from docutils.parsers.rst import directives, Directive
44from docutils.utils.error_reporting import ErrorString
45
46#
47# AutodocReporter is only good up to Sphinx 1.7
48#
49import sphinx
50
51Use_SSI = sphinx.__version__[:3] >= '1.7'
52if Use_SSI:
53 from sphinx.util.docutils import switch_source_input
54else:
55 from sphinx.ext.autodoc import AutodocReporter
56
57__version__ = '1.0'
58
59def setup(app):
60
61 app.add_directive("kernel-feat", KernelFeat)
62 return dict(
63 version = __version__
64 , parallel_read_safe = True
65 , parallel_write_safe = True
66 )
67
68class KernelFeat(Directive):
69
70 u"""KernelFeat (``kernel-feat``) directive"""
71
72 required_arguments = 1
73 optional_arguments = 2
74 has_content = False
75 final_argument_whitespace = True
76
77 option_spec = {
78 "debug" : directives.flag
79 }
80
81 def warn(self, message, **replace):
82 replace["fname"] = self.state.document.current_source
83 replace["line_no"] = replace.get("line_no", self.lineno)
84 message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
85 self.state.document.settings.env.app.warn(message, prefix="")
86
87 def run(self):
88
89 doc = self.state.document
90 if not doc.settings.file_insertion_enabled:
91 raise self.warning("docutils: file insertion disabled")
92
93 env = doc.settings.env
94 cwd = path.dirname(doc.current_source)
95 cmd = "get_feat.pl rest --dir "
96 cmd += self.arguments[0]
97
98 if len(self.arguments) > 1:
99 cmd += " --arch " + self.arguments[1]
100
101 srctree = path.abspath(os.environ["srctree"])
102
103 fname = cmd
104
105 # extend PATH with $(srctree)/scripts
106 path_env = os.pathsep.join([
107 srctree + os.sep + "scripts",
108 os.environ["PATH"]
109 ])
110 shell_env = os.environ.copy()
111 shell_env["PATH"] = path_env
112 shell_env["srctree"] = srctree
113
114 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
115 nodeList = self.nestedParse(lines, fname)
116 return nodeList
117
118 def runCmd(self, cmd, **kwargs):
119 u"""Run command ``cmd`` and return it's stdout as unicode."""
120
121 try:
122 proc = subprocess.Popen(
123 cmd
124 , stdout = subprocess.PIPE
125 , stderr = subprocess.PIPE
126 , **kwargs
127 )
128 out, err = proc.communicate()
129
130 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
131
132 if proc.returncode != 0:
133 raise self.severe(
134 u"command '%s' failed with return code %d"
135 % (cmd, proc.returncode)
136 )
137 except OSError as exc:
138 raise self.severe(u"problems with '%s' directive: %s."
139 % (self.name, ErrorString(exc)))
140 return out
141
142 def nestedParse(self, lines, fname):
143 content = ViewList()
144 node = nodes.section()
145
146 if "debug" in self.options:
147 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
148 for l in lines.split("\n"):
149 code_block += "\n " + l
150 lines = code_block + "\n\n"
151
152 for c, l in enumerate(lines.split("\n")):
153 content.append(l, fname, c)
154
155 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
156
157 if Use_SSI:
158 with switch_source_input(self.state, content):
159 self.state.nested_parse(content, 0, node, match_titles=1)
160 else:
161 self.state.memo.title_styles = []
162 self.state.memo.section_level = 0
163 self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
164 try:
165 self.state.nested_parse(content, 0, node, match_titles=1)
166 finally:
167 self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf
168
169 return node.children