^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) # -*- coding: utf-8; mode: python -*-
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) # coding=utf-8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) # SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) u"""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) kernel-abi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) ~~~~~~~~~~
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) Implementation of the ``kernel-abi`` reST-directive.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) :copyright: Copyright (C) 2016 Markus Heiser
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) :copyright: Copyright (C) 2016-2020 Mauro Carvalho Chehab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) :maintained-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) :license: GPL Version 2, June 1991 see Linux/COPYING for details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) scripts/get_abi.pl script to parse the Kernel ABI files.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) Overview of directive's argument and options.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) .. code-block:: rst
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) .. kernel-abi:: <ABI directory location>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) :debug:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) The argument ``<ABI directory location>`` is required. It contains the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) location of the ABI files to be parsed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) ``debug``
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) what reST is generated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) """
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) import codecs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) import os
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) import subprocess
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) import sys
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) import re
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) import kernellog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) from os import path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) from docutils import nodes, statemachine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) from docutils.statemachine import ViewList
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) from docutils.parsers.rst import directives, Directive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) from docutils.utils.error_reporting import ErrorString
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) # AutodocReporter is only good up to Sphinx 1.7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) import sphinx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) Use_SSI = sphinx.__version__[:3] >= '1.7'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if Use_SSI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) from sphinx.util.docutils import switch_source_input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) from sphinx.ext.autodoc import AutodocReporter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) __version__ = '1.0'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) def setup(app):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) app.add_directive("kernel-abi", KernelCmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return dict(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) version = __version__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) , parallel_read_safe = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) , parallel_write_safe = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) class KernelCmd(Directive):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) u"""KernelABI (``kernel-abi``) directive"""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) required_arguments = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) optional_arguments = 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) has_content = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) final_argument_whitespace = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) option_spec = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) "debug" : directives.flag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) "rst" : directives.unchanged
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) def run(self):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) doc = self.state.document
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if not doc.settings.file_insertion_enabled:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) raise self.warning("docutils: file insertion disabled")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) env = doc.settings.env
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) cwd = path.dirname(doc.current_source)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) cmd = "get_abi.pl rest --enable-lineno --dir "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) cmd += self.arguments[0]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if 'rst' in self.options:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) cmd += " --rst-source"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) srctree = path.abspath(os.environ["srctree"])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) fname = cmd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) # extend PATH with $(srctree)/scripts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) path_env = os.pathsep.join([
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) srctree + os.sep + "scripts",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) os.environ["PATH"]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) shell_env = os.environ.copy()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) shell_env["PATH"] = path_env
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) shell_env["srctree"] = srctree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) nodeList = self.nestedParse(lines, self.arguments[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return nodeList
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) def runCmd(self, cmd, **kwargs):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) u"""Run command ``cmd`` and return it's stdout as unicode."""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) proc = subprocess.Popen(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) cmd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) , stdout = subprocess.PIPE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) , stderr = subprocess.PIPE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) , **kwargs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) out, err = proc.communicate()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if proc.returncode != 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) raise self.severe(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) u"command '%s' failed with return code %d"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) % (cmd, proc.returncode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) except OSError as exc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) raise self.severe(u"problems with '%s' directive: %s."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) % (self.name, ErrorString(exc)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) def nestedParse(self, lines, fname):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) content = ViewList()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) node = nodes.section()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if "debug" in self.options:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) code_block = "\n\n.. code-block:: rst\n :linenos:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) for l in lines.split("\n"):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) code_block += "\n " + l
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) lines = code_block + "\n\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) line_regex = re.compile("^#define LINENO (\S+)\#([0-9]+)$")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ln = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) n = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) f = fname
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) for line in lines.split("\n"):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) n = n + 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) match = line_regex.search(line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if match:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) new_f = match.group(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) # Sphinx parser is lazy: it stops parsing contents in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) # middle, if it is too big. So, handle it per input file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if new_f != f and content:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) self.do_parse(content, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) content = ViewList()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) f = new_f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) # sphinx counts lines from 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) ln = int(match.group(2)) - 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) content.append(line, f, ln)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if content:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) self.do_parse(content, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return node.children
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) def do_parse(self, content, node):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if Use_SSI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) with switch_source_input(self.state, content):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) self.state.nested_parse(content, 0, node, match_titles=1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) self.state.memo.title_styles = []
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) self.state.memo.section_level = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) self.state.nested_parse(content, 0, node, match_titles=1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) finally:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf