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