WIP FPC-III support
[linux/fpc-iii.git] / Documentation / sphinx / kernel_abi.py
blobf3da859c9878e09ec4da011a852c8644752bfc91
1 # -*- coding: utf-8; mode: python -*-
2 # coding=utf-8
3 # SPDX-License-Identifier: GPL-2.0
5 u"""
6 kernel-abi
7 ~~~~~~~~~~
9 Implementation of the ``kernel-abi`` reST-directive.
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.
16 The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
17 scripts/get_abi.pl script to parse the Kernel ABI files.
19 Overview of directive's argument and options.
21 .. code-block:: rst
23 .. kernel-abi:: <ABI directory location>
24 :debug:
26 The argument ``<ABI directory location>`` is required. It contains the
27 location of the ABI files to be parsed.
29 ``debug``
30 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
31 what reST is generated.
33 """
35 import codecs
36 import os
37 import subprocess
38 import sys
39 import re
40 import kernellog
42 from os import path
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
50 # AutodocReporter is only good up to Sphinx 1.7
52 import sphinx
54 Use_SSI = sphinx.__version__[:3] >= '1.7'
55 if Use_SSI:
56 from sphinx.util.docutils import switch_source_input
57 else:
58 from sphinx.ext.autodoc import AutodocReporter
60 __version__ = '1.0'
62 def setup(app):
64 app.add_directive("kernel-abi", KernelCmd)
65 return dict(
66 version = __version__
67 , parallel_read_safe = True
68 , parallel_write_safe = True
71 class KernelCmd(Directive):
73 u"""KernelABI (``kernel-abi``) directive"""
75 required_arguments = 1
76 optional_arguments = 2
77 has_content = False
78 final_argument_whitespace = True
80 option_spec = {
81 "debug" : directives.flag,
82 "rst" : directives.unchanged
85 def run(self):
87 doc = self.state.document
88 if not doc.settings.file_insertion_enabled:
89 raise self.warning("docutils: file insertion disabled")
91 env = doc.settings.env
92 cwd = path.dirname(doc.current_source)
93 cmd = "get_abi.pl rest --enable-lineno --dir "
94 cmd += self.arguments[0]
96 if 'rst' in self.options:
97 cmd += " --rst-source"
99 srctree = path.abspath(os.environ["srctree"])
101 fname = cmd
103 # extend PATH with $(srctree)/scripts
104 path_env = os.pathsep.join([
105 srctree + os.sep + "scripts",
106 os.environ["PATH"]
108 shell_env = os.environ.copy()
109 shell_env["PATH"] = path_env
110 shell_env["srctree"] = srctree
112 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
113 nodeList = self.nestedParse(lines, self.arguments[0])
114 return nodeList
116 def runCmd(self, cmd, **kwargs):
117 u"""Run command ``cmd`` and return it's stdout as unicode."""
119 try:
120 proc = subprocess.Popen(
122 , stdout = subprocess.PIPE
123 , stderr = subprocess.PIPE
124 , **kwargs
126 out, err = proc.communicate()
128 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
130 if proc.returncode != 0:
131 raise self.severe(
132 u"command '%s' failed with return code %d"
133 % (cmd, proc.returncode)
135 except OSError as exc:
136 raise self.severe(u"problems with '%s' directive: %s."
137 % (self.name, ErrorString(exc)))
138 return out
140 def nestedParse(self, lines, fname):
141 content = ViewList()
142 node = nodes.section()
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"
150 line_regex = re.compile("^#define LINENO (\S+)\#([0-9]+)$")
151 ln = 0
152 n = 0
153 f = fname
155 for line in lines.split("\n"):
156 n = n + 1
157 match = line_regex.search(line)
158 if match:
159 new_f = match.group(1)
161 # Sphinx parser is lazy: it stops parsing contents in the
162 # middle, if it is too big. So, handle it per input file
163 if new_f != f and content:
164 self.do_parse(content, node)
165 content = ViewList()
167 f = new_f
169 # sphinx counts lines from 0
170 ln = int(match.group(2)) - 1
171 else:
172 content.append(line, f, ln)
174 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
176 if content:
177 self.do_parse(content, node)
179 return node.children
181 def do_parse(self, content, node):
182 if Use_SSI:
183 with switch_source_input(self.state, content):
184 self.state.nested_parse(content, 0, node, match_titles=1)
185 else:
186 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
188 self.state.memo.title_styles = []
189 self.state.memo.section_level = 0
190 self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
191 try:
192 self.state.nested_parse(content, 0, node, match_titles=1)
193 finally:
194 self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf