Merge tag '5.15-rc-ksmbd-part2' of git://git.samba.org/ksmbd
[linux-2.6-microblaze.git] / Documentation / sphinx / kernel_feat.py
1 # coding=utf-8
2 # SPDX-License-Identifier: GPL-2.0
3 #
4 u"""
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
34 import codecs
35 import os
36 import subprocess
37 import sys
38
39 from os import path
40
41 from docutils import nodes, statemachine
42 from docutils.statemachine import ViewList
43 from docutils.parsers.rst import directives, Directive
44 from docutils.utils.error_reporting import ErrorString
45 from sphinx.util.docutils import switch_source_input
46
47 __version__  = '1.0'
48
49 def 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
58 class 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):
109         u"""Run command ``cmd`` and return it's stdout as unicode."""
110
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
147         with switch_source_input(self.state, content):
148             self.state.nested_parse(content, 0, node, match_titles=1)
149
150         return node.children