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