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