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