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 from sphinx.util.docutils import switch_source_input 47 49 48 __version__ = '1.0' 50 __version__ = '1.0' 49 51 50 def setup(app): 52 def setup(app): 51 53 52 app.add_directive("kernel-abi", KernelCmd) 54 app.add_directive("kernel-abi", KernelCmd) 53 return dict( 55 return dict( 54 version = __version__ 56 version = __version__ 55 , parallel_read_safe = True 57 , parallel_read_safe = True 56 , parallel_write_safe = True 58 , parallel_write_safe = True 57 ) 59 ) 58 60 59 class KernelCmd(Directive): 61 class KernelCmd(Directive): 60 62 61 u"""KernelABI (``kernel-abi``) directive"" 63 u"""KernelABI (``kernel-abi``) directive""" 62 64 63 required_arguments = 1 65 required_arguments = 1 64 optional_arguments = 2 66 optional_arguments = 2 65 has_content = False 67 has_content = False 66 final_argument_whitespace = True 68 final_argument_whitespace = True 67 69 68 option_spec = { 70 option_spec = { 69 "debug" : directives.flag, 71 "debug" : directives.flag, 70 "rst" : directives.unchanged 72 "rst" : directives.unchanged 71 } 73 } 72 74 73 def run(self): 75 def run(self): >> 76 74 doc = self.state.document 77 doc = self.state.document 75 if not doc.settings.file_insertion_ena 78 if not doc.settings.file_insertion_enabled: 76 raise self.warning("docutils: file 79 raise self.warning("docutils: file insertion disabled") 77 80 78 srctree = os.path.abspath(os.environ[" !! 81 env = doc.settings.env 79 !! 82 cwd = path.dirname(doc.current_source) 80 args = [ !! 83 cmd = "get_abi.pl rest --enable-lineno --dir " 81 os.path.join(srctree, 'scripts/get !! 84 cmd += self.arguments[0] 82 'rest', << 83 '--enable-lineno', << 84 '--dir', os.path.join(srctree, 'Do << 85 ] << 86 85 87 if 'rst' in self.options: 86 if 'rst' in self.options: 88 args.append('--rst-source') !! 87 cmd += " --rst-source" >> 88 >> 89 srctree = path.abspath(os.environ["srctree"]) 89 90 90 lines = subprocess.check_output(args, !! 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) 91 nodeList = self.nestedParse(lines, sel 103 nodeList = self.nestedParse(lines, self.arguments[0]) 92 return nodeList 104 return nodeList 93 105 >> 106 def runCmd(self, cmd, **kwargs): >> 107 u"""Run command ``cmd`` and return its stdout as unicode.""" >> 108 >> 109 try: >> 110 proc = subprocess.Popen( >> 111 cmd >> 112 , stdout = subprocess.PIPE >> 113 , stderr = subprocess.PIPE >> 114 , **kwargs >> 115 ) >> 116 out, err = proc.communicate() >> 117 >> 118 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') >> 119 >> 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))) >> 128 return out >> 129 94 def nestedParse(self, lines, fname): 130 def nestedParse(self, lines, fname): 95 env = self.state.document.settings.env 131 env = self.state.document.settings.env 96 content = ViewList() 132 content = ViewList() 97 node = nodes.section() 133 node = nodes.section() 98 134 99 if "debug" in self.options: 135 if "debug" in self.options: 100 code_block = "\n\n.. code-block:: 136 code_block = "\n\n.. code-block:: rst\n :linenos:\n" 101 for l in lines.split("\n"): 137 for l in lines.split("\n"): 102 code_block += "\n " + l 138 code_block += "\n " + l 103 lines = code_block + "\n\n" 139 lines = code_block + "\n\n" 104 140 105 line_regex = re.compile(r"^\.\. LINENO !! 141 line_regex = re.compile("^\.\. LINENO (\S+)\#([0-9]+)$") 106 ln = 0 142 ln = 0 107 n = 0 143 n = 0 108 f = fname 144 f = fname 109 145 110 for line in lines.split("\n"): 146 for line in lines.split("\n"): 111 n = n + 1 147 n = n + 1 112 match = line_regex.search(line) 148 match = line_regex.search(line) 113 if match: 149 if match: 114 new_f = match.group(1) 150 new_f = match.group(1) 115 151 116 # Sphinx parser is lazy: it st 152 # Sphinx parser is lazy: it stops parsing contents in the 117 # middle, if it is too big. So 153 # middle, if it is too big. So, handle it per input file 118 if new_f != f and content: 154 if new_f != f and content: 119 self.do_parse(content, nod 155 self.do_parse(content, node) 120 content = ViewList() 156 content = ViewList() 121 157 122 # Add the file to Sphinx b 158 # Add the file to Sphinx build dependencies 123 env.note_dependency(os.pat 159 env.note_dependency(os.path.abspath(f)) 124 160 125 f = new_f 161 f = new_f 126 162 127 # sphinx counts lines from 0 163 # sphinx counts lines from 0 128 ln = int(match.group(2)) - 1 164 ln = int(match.group(2)) - 1 129 else: 165 else: 130 content.append(line, f, ln) 166 content.append(line, f, ln) 131 167 132 kernellog.info(self.state.document.set 168 kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n)) 133 169 134 if content: 170 if content: 135 self.do_parse(content, node) 171 self.do_parse(content, node) 136 172 137 return node.children 173 return node.children 138 174 139 def do_parse(self, content, node): 175 def do_parse(self, content, node): 140 with switch_source_input(self.state, c 176 with switch_source_input(self.state, content): 141 self.state.nested_parse(content, 0 177 self.state.nested_parse(content, 0, node, match_titles=1)
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.