1# coding=utf-8 2# SPDX-License-Identifier: GPL-2.0 3# 4""" 5 kernel-feat 6 ~~~~~~~~~~~ 7 8 Implementation of the ``kernel-feat`` reST-directive. 9 10 :copyright: Copyright (C) 2016 Markus Heiser 11 :copyright: Copyright (C) 2016-2019 Mauro Carvalho Chehab 12 :maintained-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> 13 :license: GPL Version 2, June 1991 see Linux/COPYING for details. 14 15 The ``kernel-feat`` (:py:class:`KernelFeat`) directive calls the 16 tools/docs/get_feat.pl script to parse the Kernel ABI files. 17 18 Overview of directive's argument and options. 19 20 .. code-block:: rst 21 22 .. kernel-feat:: <ABI directory location> 23 :debug: 24 25 The argument ``<ABI directory location>`` is required. It contains the 26 location of the ABI files to be parsed. 27 28 ``debug`` 29 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see 30 what reST is generated. 31 32""" 33 34import codecs 35import os 36import re 37import subprocess 38import sys 39 40from docutils import nodes, statemachine 41from docutils.statemachine import ViewList 42from docutils.parsers.rst import directives, Directive 43from sphinx.util.docutils import switch_source_input 44 45srctree = os.path.abspath(os.environ["srctree"]) 46sys.path.insert(0, os.path.join(srctree, "tools/docs/lib")) 47 48from parse_features import ParseFeature # pylint: disable=C0413 49 50def ErrorString(exc): # Shamelessly stolen from docutils 51 return f'{exc.__class__.__name}: {exc}' 52 53__version__ = '1.0' 54 55def setup(app): 56 57 app.add_directive("kernel-feat", KernelFeat) 58 return dict( 59 version = __version__ 60 , parallel_read_safe = True 61 , parallel_write_safe = True 62 ) 63 64class KernelFeat(Directive): 65 66 """KernelFeat (``kernel-feat``) directive""" 67 68 required_arguments = 1 69 optional_arguments = 2 70 has_content = False 71 final_argument_whitespace = True 72 73 option_spec = { 74 "debug" : directives.flag 75 } 76 77 def warn(self, message, **replace): 78 replace["fname"] = self.state.document.current_source 79 replace["line_no"] = replace.get("line_no", self.lineno) 80 message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace 81 self.state.document.settings.env.app.warn(message, prefix="") 82 83 def run(self): 84 doc = self.state.document 85 if not doc.settings.file_insertion_enabled: 86 raise self.warning("docutils: file insertion disabled") 87 88 env = doc.settings.env 89 90 srctree = os.path.abspath(os.environ["srctree"]) 91 92 args = [ 93 os.path.join(srctree, 'tools/docs/get_feat.pl'), 94 'rest', 95 '--enable-fname', 96 '--dir', 97 os.path.join(srctree, 'Documentation', self.arguments[0]), 98 ] 99 100 if len(self.arguments) > 1: 101 args.extend(['--arch', self.arguments[1]]) 102 103 lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8') 104 105 line_regex = re.compile(r"^\.\. FILE (\S+)$") 106 107 out_lines = "" 108 109 for line in lines.split("\n"): 110 match = line_regex.search(line) 111 if match: 112 fname = match.group(1) 113 114 # Add the file to Sphinx build dependencies 115 env.note_dependency(os.path.abspath(fname)) 116 else: 117 out_lines += line + "\n" 118 119 nodeList = self.nestedParse(out_lines, self.arguments[0]) 120 return nodeList 121 122 def nestedParse(self, lines, fname): 123 content = ViewList() 124 node = nodes.section() 125 126 if "debug" in self.options: 127 code_block = "\n\n.. code-block:: rst\n :linenos:\n" 128 for l in lines.split("\n"): 129 code_block += "\n " + l 130 lines = code_block + "\n\n" 131 132 for c, l in enumerate(lines.split("\n")): 133 content.append(l, fname, c) 134 135 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter 136 137 with switch_source_input(self.state, content): 138 self.state.nested_parse(content, 0, node, match_titles=1) 139 140 return node.children 141