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