]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - Documentation/sphinx/kernel_abi.py
Merge branch 'stable/for-linus-5.15' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.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 import re
40 import kernellog
41
42 from os import path
43
44 from docutils import nodes, statemachine
45 from docutils.statemachine import ViewList
46 from docutils.parsers.rst import directives, Directive
47 from docutils.utils.error_reporting import ErrorString
48 from sphinx.util.docutils import switch_source_input
49
50 __version__ = '1.0'
51
52 def setup(app):
53
54 app.add_directive("kernel-abi", KernelCmd)
55 return dict(
56 version = __version__
57 , parallel_read_safe = True
58 , parallel_write_safe = True
59 )
60
61 class KernelCmd(Directive):
62
63 u"""KernelABI (``kernel-abi``) directive"""
64
65 required_arguments = 1
66 optional_arguments = 2
67 has_content = False
68 final_argument_whitespace = True
69
70 option_spec = {
71 "debug" : directives.flag,
72 "rst" : directives.unchanged
73 }
74
75 def run(self):
76
77 doc = self.state.document
78 if not doc.settings.file_insertion_enabled:
79 raise self.warning("docutils: file insertion disabled")
80
81 env = doc.settings.env
82 cwd = path.dirname(doc.current_source)
83 cmd = "get_abi.pl rest --enable-lineno --dir "
84 cmd += self.arguments[0]
85
86 if 'rst' in self.options:
87 cmd += " --rst-source"
88
89 srctree = path.abspath(os.environ["srctree"])
90
91 fname = cmd
92
93 # extend PATH with $(srctree)/scripts
94 path_env = os.pathsep.join([
95 srctree + os.sep + "scripts",
96 os.environ["PATH"]
97 ])
98 shell_env = os.environ.copy()
99 shell_env["PATH"] = path_env
100 shell_env["srctree"] = srctree
101
102 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
103 nodeList = self.nestedParse(lines, self.arguments[0])
104 return nodeList
105
106 def runCmd(self, cmd, **kwargs):
107 u"""Run command ``cmd`` and return it's stdout as unicode."""
108
109 try:
110 proc = subprocess.Popen(
111 cmd
112 , stdout = subprocess.PIPE
113 , stderr = subprocess.PIPE
114 , **kwargs
115 )
116 out, err = proc.communicate()
117
118 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
119
120 if proc.returncode != 0:
121 raise self.severe(
122 u"command '%s' failed with return code %d"
123 % (cmd, proc.returncode)
124 )
125 except OSError as exc:
126 raise self.severe(u"problems with '%s' directive: %s."
127 % (self.name, ErrorString(exc)))
128 return out
129
130 def nestedParse(self, lines, fname):
131 content = ViewList()
132 node = nodes.section()
133
134 if "debug" in self.options:
135 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
136 for l in lines.split("\n"):
137 code_block += "\n " + l
138 lines = code_block + "\n\n"
139
140 line_regex = re.compile("^#define LINENO (\S+)\#([0-9]+)$")
141 ln = 0
142 n = 0
143 f = fname
144
145 for line in lines.split("\n"):
146 n = n + 1
147 match = line_regex.search(line)
148 if match:
149 new_f = match.group(1)
150
151 # Sphinx parser is lazy: it stops parsing contents in the
152 # middle, if it is too big. So, handle it per input file
153 if new_f != f and content:
154 self.do_parse(content, node)
155 content = ViewList()
156
157 f = new_f
158
159 # sphinx counts lines from 0
160 ln = int(match.group(2)) - 1
161 else:
162 content.append(line, f, ln)
163
164 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
165
166 if content:
167 self.do_parse(content, node)
168
169 return node.children
170
171 def do_parse(self, content, node):
172 with switch_source_input(self.state, content):
173 self.state.nested_parse(content, 0, node, match_titles=1)