Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[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
46 #
47 # AutodocReporter is only good up to Sphinx 1.7
48 #
49 import sphinx
50
51 Use_SSI = sphinx.__version__[:3] >= '1.7'
52 if Use_SSI:
53     from sphinx.util.docutils import switch_source_input
54 else:
55     from sphinx.ext.autodoc import AutodocReporter
56
57 __version__  = '1.0'
58
59 def 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
68 class 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