blob: 096dec482e9665ed3e3ef81d9ae78c4f3fee2868 [file] [log] [blame]
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +01001# -*- coding: utf-8; mode: python -*-
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +01002# coding=utf-8
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +01003# SPDX-License-Identifier: GPL-2.0
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +01004#
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +01005u"""
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
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +010035import codecs
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010036import os
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010037import subprocess
Mauro Carvalho Chehabc830fa92020-10-30 08:40:33 +010038import sys
Mauro Carvalho Chehab997b7c82020-10-30 08:40:34 +010039import re
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010040
Mauro Carvalho Chehabc830fa92020-10-30 08:40:33 +010041from os import path
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010042
Mauro Carvalho Chehabc830fa92020-10-30 08:40:33 +010043from docutils import nodes, statemachine
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010044from docutils.statemachine import ViewList
Mauro Carvalho Chehabc830fa92020-10-30 08:40:33 +010045from docutils.parsers.rst import directives, Directive
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010046from docutils.utils.error_reporting import ErrorString
47
Mauro Carvalho Chehabc830fa92020-10-30 08:40:33 +010048#
49# AutodocReporter is only good up to Sphinx 1.7
50#
51import sphinx
52
53Use_SSI = sphinx.__version__[:3] >= '1.7'
54if Use_SSI:
55 from sphinx.util.docutils import switch_source_input
56else:
57 from sphinx.ext.autodoc import AutodocReporter
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010058
59__version__ = '1.0'
60
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010061def setup(app):
62
63 app.add_directive("kernel-abi", KernelCmd)
64 return dict(
65 version = __version__
66 , parallel_read_safe = True
67 , parallel_write_safe = True
68 )
69
70class KernelCmd(Directive):
71
72 u"""KernelABI (``kernel-abi``) directive"""
73
74 required_arguments = 1
75 optional_arguments = 0
76 has_content = False
77 final_argument_whitespace = True
78
79 option_spec = {
80 "debug" : directives.flag
81 }
82
83 def warn(self, message, **replace):
84 replace["fname"] = self.state.document.current_source
85 replace["line_no"] = replace.get("line_no", self.lineno)
86 message = ("%(fname)s:%(line_no)s: [kernel-abi WARN] : " + message) % replace
87 self.state.document.settings.env.app.warn(message, prefix="")
88
89 def run(self):
90
91 doc = self.state.document
92 if not doc.settings.file_insertion_enabled:
93 raise self.warning("docutils: file insertion disabled")
94
95 env = doc.settings.env
96 cwd = path.dirname(doc.current_source)
Mauro Carvalho Chehab997b7c82020-10-30 08:40:34 +010097 cmd = "get_abi.pl rest --enable-lineno --dir "
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010098 cmd += self.arguments[0]
99
100 srctree = path.abspath(os.environ["srctree"])
101
102 fname = cmd
103
104 # extend PATH with $(srctree)/scripts
105 path_env = os.pathsep.join([
106 srctree + os.sep + "scripts",
107 os.environ["PATH"]
108 ])
109 shell_env = os.environ.copy()
110 shell_env["PATH"] = path_env
111 shell_env["srctree"] = srctree
112
113 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
114 nodeList = self.nestedParse(lines, fname)
115 return nodeList
116
117 def runCmd(self, cmd, **kwargs):
118 u"""Run command ``cmd`` and return it's stdout as unicode."""
119
120 try:
121 proc = subprocess.Popen(
122 cmd
123 , stdout = subprocess.PIPE
124 , stderr = subprocess.PIPE
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100125 , **kwargs
126 )
127 out, err = proc.communicate()
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +0100128
129 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
130
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100131 if proc.returncode != 0:
132 raise self.severe(
133 u"command '%s' failed with return code %d"
134 % (cmd, proc.returncode)
135 )
136 except OSError as exc:
137 raise self.severe(u"problems with '%s' directive: %s."
138 % (self.name, ErrorString(exc)))
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +0100139 return out
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100140
Mauro Carvalho Chehab997b7c82020-10-30 08:40:34 +0100141 def nestedParse(self, lines, f):
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100142 content = ViewList()
143 node = nodes.section()
144
145 if "debug" in self.options:
146 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
147 for l in lines.split("\n"):
148 code_block += "\n " + l
149 lines = code_block + "\n\n"
150
Mauro Carvalho Chehab997b7c82020-10-30 08:40:34 +0100151 line_regex = re.compile("^#define LINENO (\S+)\#([0-9]+)$")
152 ln = 0
153
154 for line in lines.split("\n"):
155 match = line_regex.search(line)
156 if match:
157 f = match.group(1)
158 # sphinx counts lines from 0
159 ln = int(match.group(2)) - 1
160 else:
161 content.append(line, f, ln)
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100162
163 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
Mauro Carvalho Chehabc830fa92020-10-30 08:40:33 +0100164
165 if Use_SSI:
166 with switch_source_input(self.state, content):
167 self.state.nested_parse(content, 0, node, match_titles=1)
168 else:
169 self.state.memo.title_styles = []
170 self.state.memo.section_level = 0
171 self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
172 try:
173 self.state.nested_parse(content, 0, node, match_titles=1)
174 finally:
175 self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf
176
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100177 return node.children