Merge tag 'loongarch-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai...
[linux-block.git] / Documentation / sphinx / kernel_abi.py
CommitLineData
9ca876f9 1# -*- coding: utf-8; mode: python -*-
823830d4 2# coding=utf-8
9ca876f9 3# SPDX-License-Identifier: GPL-2.0
823830d4 4#
9ca876f9
MCC
5u"""
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
823830d4 35import codecs
9ca876f9 36import os
9ca876f9 37import subprocess
c830fa9a 38import sys
997b7c8b 39import re
3c543d29 40import kernellog
9ca876f9 41
c830fa9a 42from os import path
9ca876f9 43
c830fa9a 44from docutils import nodes, statemachine
9ca876f9 45from docutils.statemachine import ViewList
c830fa9a 46from docutils.parsers.rst import directives, Directive
9ca876f9 47from docutils.utils.error_reporting import ErrorString
f546ff0c 48from sphinx.util.docutils import switch_source_input
9ca876f9
MCC
49
50__version__ = '1.0'
51
9ca876f9
MCC
52def 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
61class KernelCmd(Directive):
62
63 u"""KernelABI (``kernel-abi``) directive"""
64
65 required_arguments = 1
642514df 66 optional_arguments = 2
9ca876f9
MCC
67 has_content = False
68 final_argument_whitespace = True
69
70 option_spec = {
642514df
MCC
71 "debug" : directives.flag,
72 "rst" : directives.unchanged
9ca876f9
MCC
73 }
74
9ca876f9
MCC
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)
997b7c8b 83 cmd = "get_abi.pl rest --enable-lineno --dir "
9ca876f9
MCC
84 cmd += self.arguments[0]
85
642514df
MCC
86 if 'rst' in self.options:
87 cmd += " --rst-source"
88
9ca876f9
MCC
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)
3c543d29 103 nodeList = self.nestedParse(lines, self.arguments[0])
9ca876f9
MCC
104 return nodeList
105
106 def runCmd(self, cmd, **kwargs):
32211146 107 u"""Run command ``cmd`` and return its stdout as unicode."""
9ca876f9
MCC
108
109 try:
110 proc = subprocess.Popen(
111 cmd
112 , stdout = subprocess.PIPE
113 , stderr = subprocess.PIPE
9ca876f9
MCC
114 , **kwargs
115 )
116 out, err = proc.communicate()
823830d4
MCC
117
118 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
119
9ca876f9
MCC
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)))
823830d4 128 return out
9ca876f9 129
3c543d29 130 def nestedParse(self, lines, fname):
b4541803 131 env = self.state.document.settings.env
9ca876f9 132 content = ViewList()
3c543d29 133 node = nodes.section()
9ca876f9
MCC
134
135 if "debug" in self.options:
136 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
137 for l in lines.split("\n"):
138 code_block += "\n " + l
139 lines = code_block + "\n\n"
140
92b6de17 141 line_regex = re.compile("^\.\. LINENO (\S+)\#([0-9]+)$")
997b7c8b 142 ln = 0
3c543d29
MCC
143 n = 0
144 f = fname
997b7c8b
MCC
145
146 for line in lines.split("\n"):
3c543d29 147 n = n + 1
997b7c8b
MCC
148 match = line_regex.search(line)
149 if match:
3c543d29
MCC
150 new_f = match.group(1)
151
152 # Sphinx parser is lazy: it stops parsing contents in the
153 # middle, if it is too big. So, handle it per input file
154 if new_f != f and content:
155 self.do_parse(content, node)
156 content = ViewList()
157
b4541803
MCC
158 # Add the file to Sphinx build dependencies
159 env.note_dependency(os.path.abspath(f))
160
3c543d29
MCC
161 f = new_f
162
997b7c8b
MCC
163 # sphinx counts lines from 0
164 ln = int(match.group(2)) - 1
165 else:
166 content.append(line, f, ln)
9ca876f9 167
3c543d29
MCC
168 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
169
170 if content:
171 self.do_parse(content, node)
c830fa9a 172
3c543d29
MCC
173 return node.children
174
175 def do_parse(self, content, node):
f546ff0c
JC
176 with switch_source_input(self.state, content):
177 self.state.nested_parse(content, 0, node, match_titles=1)