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 sys 38 39from docutils import nodes, statemachine 40from docutils.statemachine import ViewList 41from docutils.parsers.rst import directives, Directive 42from sphinx.util.docutils import switch_source_input 43 44srctree = os.path.abspath(os.environ["srctree"]) 45sys.path.insert(0, os.path.join(srctree, "tools/lib/python")) 46 47from feat.parse_features import ParseFeature # pylint: disable=C0413 48 49def ErrorString(exc): # Shamelessly stolen from docutils 50 return f'{exc.__class__.__name}: {exc}' 51 52__version__ = '1.0' 53 54def setup(app): 55 56 app.add_directive("kernel-feat", KernelFeat) 57 return dict( 58 version = __version__ 59 , parallel_read_safe = True 60 , parallel_write_safe = True 61 ) 62 63class KernelFeat(Directive): 64 65 """KernelFeat (``kernel-feat``) directive""" 66 67 required_arguments = 1 68 optional_arguments = 2 69 has_content = False 70 final_argument_whitespace = True 71 72 option_spec = { 73 "debug" : directives.flag 74 } 75 76 def warn(self, message, **replace): 77 replace["fname"] = self.state.document.current_source 78 replace["line_no"] = replace.get("line_no", self.lineno) 79 message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace 80 self.state.document.settings.env.app.warn(message, prefix="") 81 82 def run(self): 83 doc = self.state.document 84 if not doc.settings.file_insertion_enabled: 85 raise self.warning("docutils: file insertion disabled") 86 87 env = doc.settings.env 88 89 srctree = os.path.abspath(os.environ["srctree"]) 90 91 feature_dir = os.path.join(srctree, 'Documentation', self.arguments[0]) 92 93 feat = ParseFeature(feature_dir, False, True) 94 feat.parse() 95 96 if len(self.arguments) > 1: 97 arch = self.arguments[1] 98 lines = feat.output_arch_table(arch) 99 else: 100 lines = feat.output_matrix() 101 102 line_regex = re.compile(r"^\.\. FILE (\S+)$") 103 104 out_lines = "" 105 106 for line in lines.split("\n"): 107 match = line_regex.search(line) 108 if match: 109 fname = match.group(1) 110 111 # Add the file to Sphinx build dependencies 112 env.note_dependency(os.path.abspath(fname)) 113 else: 114 out_lines += line + "\n" 115 116 nodeList = self.nestedParse(out_lines, self.arguments[0]) 117 return nodeList 118 119 def nestedParse(self, lines, fname): 120 content = ViewList() 121 node = nodes.section() 122 123 if "debug" in self.options: 124 code_block = "\n\n.. code-block:: rst\n :linenos:\n" 125 for l in lines.split("\n"): 126 code_block += "\n " + l 127 lines = code_block + "\n\n" 128 129 for c, l in enumerate(lines.split("\n")): 130 content.append(l, fname, c) 131 132 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter 133 134 with switch_source_input(self.state, content): 135 self.state.nested_parse(content, 0, node, match_titles=1) 136 137 return node.children 138