blob: 8138d69a6987ad43f42fe0f0a13fcb483c592f89 [file] [log] [blame]
Mauro Carvalho Chehabb9721222020-11-30 16:36:33 +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
Jonathan Corbetf546ff02021-02-01 16:26:25 -070045from sphinx.util.docutils import switch_source_input
Mauro Carvalho Chehabb9721222020-11-30 16:36:33 +010046
47__version__ = '1.0'
48
49def setup(app):
50
51 app.add_directive("kernel-feat", KernelFeat)
52 return dict(
53 version = __version__
54 , parallel_read_safe = True
55 , parallel_write_safe = True
56 )
57
58class KernelFeat(Directive):
59
60 u"""KernelFeat (``kernel-feat``) directive"""
61
62 required_arguments = 1
63 optional_arguments = 2
64 has_content = False
65 final_argument_whitespace = True
66
67 option_spec = {
68 "debug" : directives.flag
69 }
70
71 def warn(self, message, **replace):
72 replace["fname"] = self.state.document.current_source
73 replace["line_no"] = replace.get("line_no", self.lineno)
74 message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
75 self.state.document.settings.env.app.warn(message, prefix="")
76
77 def run(self):
78
79 doc = self.state.document
80 if not doc.settings.file_insertion_enabled:
81 raise self.warning("docutils: file insertion disabled")
82
83 env = doc.settings.env
84 cwd = path.dirname(doc.current_source)
85 cmd = "get_feat.pl rest --dir "
86 cmd += self.arguments[0]
87
88 if len(self.arguments) > 1:
89 cmd += " --arch " + self.arguments[1]
90
91 srctree = path.abspath(os.environ["srctree"])
92
93 fname = cmd
94
95 # extend PATH with $(srctree)/scripts
96 path_env = os.pathsep.join([
97 srctree + os.sep + "scripts",
98 os.environ["PATH"]
99 ])
100 shell_env = os.environ.copy()
101 shell_env["PATH"] = path_env
102 shell_env["srctree"] = srctree
103
104 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
105 nodeList = self.nestedParse(lines, fname)
106 return nodeList
107
108 def runCmd(self, cmd, **kwargs):
Randy Dunlap32211142021-12-21 22:23:54 -0800109 u"""Run command ``cmd`` and return its stdout as unicode."""
Mauro Carvalho Chehabb9721222020-11-30 16:36:33 +0100110
111 try:
112 proc = subprocess.Popen(
113 cmd
114 , stdout = subprocess.PIPE
115 , stderr = subprocess.PIPE
116 , **kwargs
117 )
118 out, err = proc.communicate()
119
120 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
121
122 if proc.returncode != 0:
123 raise self.severe(
124 u"command '%s' failed with return code %d"
125 % (cmd, proc.returncode)
126 )
127 except OSError as exc:
128 raise self.severe(u"problems with '%s' directive: %s."
129 % (self.name, ErrorString(exc)))
130 return out
131
132 def nestedParse(self, lines, fname):
133 content = ViewList()
134 node = nodes.section()
135
136 if "debug" in self.options:
137 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
138 for l in lines.split("\n"):
139 code_block += "\n " + l
140 lines = code_block + "\n\n"
141
142 for c, l in enumerate(lines.split("\n")):
143 content.append(l, fname, c)
144
145 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
146
Jonathan Corbetf546ff02021-02-01 16:26:25 -0700147 with switch_source_input(self.state, content):
148 self.state.nested_parse(content, 0, node, match_titles=1)
Mauro Carvalho Chehabb9721222020-11-30 16:36:33 +0100149
150 return node.children