Loading...
1# 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 re
37import subprocess
38import sys
39
40from docutils import nodes, statemachine
41from docutils.statemachine import ViewList
42from docutils.parsers.rst import directives, Directive
43from docutils.utils.error_reporting import ErrorString
44from sphinx.util.docutils import switch_source_input
45
46__version__ = '1.0'
47
48def setup(app):
49
50 app.add_directive("kernel-feat", KernelFeat)
51 return dict(
52 version = __version__
53 , parallel_read_safe = True
54 , parallel_write_safe = True
55 )
56
57class KernelFeat(Directive):
58
59 u"""KernelFeat (``kernel-feat``) directive"""
60
61 required_arguments = 1
62 optional_arguments = 2
63 has_content = False
64 final_argument_whitespace = True
65
66 option_spec = {
67 "debug" : directives.flag
68 }
69
70 def warn(self, message, **replace):
71 replace["fname"] = self.state.document.current_source
72 replace["line_no"] = replace.get("line_no", self.lineno)
73 message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
74 self.state.document.settings.env.app.warn(message, prefix="")
75
76 def run(self):
77 doc = self.state.document
78 if not doc.settings.file_insertion_enabled:
79 raise self.warning("docutils: file insertion disabled")
80
81 env = doc.settings.env
82
83 srctree = os.path.abspath(os.environ["srctree"])
84
85 args = [
86 os.path.join(srctree, 'scripts/get_feat.pl'),
87 'rest',
88 '--enable-fname',
89 '--dir',
90 os.path.join(srctree, 'Documentation', self.arguments[0]),
91 ]
92
93 if len(self.arguments) > 1:
94 args.extend(['--arch', self.arguments[1]])
95
96 lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8')
97
98 line_regex = re.compile(r"^\.\. FILE (\S+)$")
99
100 out_lines = ""
101
102 for line in lines.split("\n"):
103 match = line_regex.search(line)
104 if match:
105 fname = match.group(1)
106
107 # Add the file to Sphinx build dependencies
108 env.note_dependency(os.path.abspath(fname))
109 else:
110 out_lines += line + "\n"
111
112 nodeList = self.nestedParse(out_lines, self.arguments[0])
113 return nodeList
114
115 def nestedParse(self, lines, fname):
116 content = ViewList()
117 node = nodes.section()
118
119 if "debug" in self.options:
120 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
121 for l in lines.split("\n"):
122 code_block += "\n " + l
123 lines = code_block + "\n\n"
124
125 for c, l in enumerate(lines.split("\n")):
126 content.append(l, fname, c)
127
128 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
129
130 with switch_source_input(self.state, content):
131 self.state.nested_parse(content, 0, node, match_titles=1)
132
133 return node.children
1# 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 re
37import subprocess
38import sys
39
40from os import path
41
42from docutils import nodes, statemachine
43from docutils.statemachine import ViewList
44from docutils.parsers.rst import directives, Directive
45from docutils.utils.error_reporting import ErrorString
46from sphinx.util.docutils import switch_source_input
47
48__version__ = '1.0'
49
50def setup(app):
51
52 app.add_directive("kernel-feat", KernelFeat)
53 return dict(
54 version = __version__
55 , parallel_read_safe = True
56 , parallel_write_safe = True
57 )
58
59class KernelFeat(Directive):
60
61 u"""KernelFeat (``kernel-feat``) directive"""
62
63 required_arguments = 1
64 optional_arguments = 2
65 has_content = False
66 final_argument_whitespace = True
67
68 option_spec = {
69 "debug" : directives.flag
70 }
71
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="")
77
78 def run(self):
79
80 doc = self.state.document
81 if not doc.settings.file_insertion_enabled:
82 raise self.warning("docutils: file insertion disabled")
83
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]
88
89 if len(self.arguments) > 1:
90 cmd += " --arch " + self.arguments[1]
91
92 srctree = path.abspath(os.environ["srctree"])
93
94 fname = cmd
95
96 # extend PATH with $(srctree)/scripts
97 path_env = os.pathsep.join([
98 srctree + os.sep + "scripts",
99 os.environ["PATH"]
100 ])
101 shell_env = os.environ.copy()
102 shell_env["PATH"] = path_env
103 shell_env["srctree"] = srctree
104
105 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
106
107 line_regex = re.compile("^\.\. FILE (\S+)$")
108
109 out_lines = ""
110
111 for line in lines.split("\n"):
112 match = line_regex.search(line)
113 if match:
114 fname = match.group(1)
115
116 # Add the file to Sphinx build dependencies
117 env.note_dependency(os.path.abspath(fname))
118 else:
119 out_lines += line + "\n"
120
121 nodeList = self.nestedParse(out_lines, fname)
122 return nodeList
123
124 def runCmd(self, cmd, **kwargs):
125 u"""Run command ``cmd`` and return its stdout as unicode."""
126
127 try:
128 proc = subprocess.Popen(
129 cmd
130 , stdout = subprocess.PIPE
131 , stderr = subprocess.PIPE
132 , **kwargs
133 )
134 out, err = proc.communicate()
135
136 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
137
138 if proc.returncode != 0:
139 raise self.severe(
140 u"command '%s' failed with return code %d"
141 % (cmd, proc.returncode)
142 )
143 except OSError as exc:
144 raise self.severe(u"problems with '%s' directive: %s."
145 % (self.name, ErrorString(exc)))
146 return out
147
148 def nestedParse(self, lines, fname):
149 content = ViewList()
150 node = nodes.section()
151
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"
157
158 for c, l in enumerate(lines.split("\n")):
159 content.append(l, fname, c)
160
161 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
162
163 with switch_source_input(self.state, content):
164 self.state.nested_parse(content, 0, node, match_titles=1)
165
166 return node.children