142 lines · python
1# -*- coding: utf-8; mode: python -*-2# coding=utf-83# SPDX-License-Identifier: GPL-2.04#5u"""6 kernel-abi7 ~~~~~~~~~~8 9 Implementation of the ``kernel-abi`` reST-directive.10 11 :copyright: Copyright (C) 2016 Markus Heiser12 :copyright: Copyright (C) 2016-2020 Mauro Carvalho Chehab13 :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 the17 scripts/get_abi.pl script to parse the Kernel ABI files.18 19 Overview of directive's argument and options.20 21 .. code-block:: rst22 23 .. kernel-abi:: <ABI directory location>24 :debug:25 26 The argument ``<ABI directory location>`` is required. It contains the27 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 see31 what reST is generated.32 33"""34 35import codecs36import os37import subprocess38import sys39import re40import kernellog41 42from docutils import nodes, statemachine43from docutils.statemachine import ViewList44from docutils.parsers.rst import directives, Directive45from docutils.utils.error_reporting import ErrorString46from sphinx.util.docutils import switch_source_input47 48__version__ = '1.0'49 50def setup(app):51 52 app.add_directive("kernel-abi", KernelCmd)53 return dict(54 version = __version__55 , parallel_read_safe = True56 , parallel_write_safe = True57 )58 59class KernelCmd(Directive):60 61 u"""KernelABI (``kernel-abi``) directive"""62 63 required_arguments = 164 optional_arguments = 265 has_content = False66 final_argument_whitespace = True67 68 option_spec = {69 "debug" : directives.flag,70 "rst" : directives.unchanged71 }72 73 def run(self):74 doc = self.state.document75 if not doc.settings.file_insertion_enabled:76 raise self.warning("docutils: file insertion disabled")77 78 srctree = os.path.abspath(os.environ["srctree"])79 80 args = [81 os.path.join(srctree, 'scripts/get_abi.pl'),82 'rest',83 '--enable-lineno',84 '--dir', os.path.join(srctree, 'Documentation', self.arguments[0]),85 ]86 87 if 'rst' in self.options:88 args.append('--rst-source')89 90 lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8')91 nodeList = self.nestedParse(lines, self.arguments[0])92 return nodeList93 94 def nestedParse(self, lines, fname):95 env = self.state.document.settings.env96 content = ViewList()97 node = nodes.section()98 99 if "debug" in self.options:100 code_block = "\n\n.. code-block:: rst\n :linenos:\n"101 for l in lines.split("\n"):102 code_block += "\n " + l103 lines = code_block + "\n\n"104 105 line_regex = re.compile(r"^\.\. LINENO (\S+)\#([0-9]+)$")106 ln = 0107 n = 0108 f = fname109 110 for line in lines.split("\n"):111 n = n + 1112 match = line_regex.search(line)113 if match:114 new_f = match.group(1)115 116 # Sphinx parser is lazy: it stops parsing contents in the117 # middle, if it is too big. So, handle it per input file118 if new_f != f and content:119 self.do_parse(content, node)120 content = ViewList()121 122 # Add the file to Sphinx build dependencies123 env.note_dependency(os.path.abspath(f))124 125 f = new_f126 127 # sphinx counts lines from 0128 ln = int(match.group(2)) - 1129 else:130 content.append(line, f, ln)131 132 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))133 134 if content:135 self.do_parse(content, node)136 137 return node.children138 139 def do_parse(self, content, node):140 with switch_source_input(self.state, content):141 self.state.nested_parse(content, 0, node, match_titles=1)142