0001
0002
0003
0004 u"""
0005 kernel-feat
0006 ~~~~~~~~~~~
0007
0008 Implementation of the ``kernel-feat`` reST-directive.
0009
0010 :copyright: Copyright (C) 2016 Markus Heiser
0011 :copyright: Copyright (C) 2016-2019 Mauro Carvalho Chehab
0012 :maintained-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
0013 :license: GPL Version 2, June 1991 see Linux/COPYING for details.
0014
0015 The ``kernel-feat`` (:py:class:`KernelFeat`) directive calls the
0016 scripts/get_feat.pl script to parse the Kernel ABI files.
0017
0018 Overview of directive's argument and options.
0019
0020 .. code-block:: rst
0021
0022 .. kernel-feat:: <ABI directory location>
0023 :debug:
0024
0025 The argument ``<ABI directory location>`` is required. It contains the
0026 location of the ABI files to be parsed.
0027
0028 ``debug``
0029 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
0030 what reST is generated.
0031
0032 """
0033
0034 import codecs
0035 import os
0036 import re
0037 import subprocess
0038 import sys
0039
0040 from os import path
0041
0042 from docutils import nodes, statemachine
0043 from docutils.statemachine import ViewList
0044 from docutils.parsers.rst import directives, Directive
0045 from docutils.utils.error_reporting import ErrorString
0046 from sphinx.util.docutils import switch_source_input
0047
0048 __version__ = '1.0'
0049
0050 def setup(app):
0051
0052 app.add_directive("kernel-feat", KernelFeat)
0053 return dict(
0054 version = __version__
0055 , parallel_read_safe = True
0056 , parallel_write_safe = True
0057 )
0058
0059 class KernelFeat(Directive):
0060
0061 u"""KernelFeat (``kernel-feat``) directive"""
0062
0063 required_arguments = 1
0064 optional_arguments = 2
0065 has_content = False
0066 final_argument_whitespace = True
0067
0068 option_spec = {
0069 "debug" : directives.flag
0070 }
0071
0072 def warn(self, message, **replace):
0073 replace["fname"] = self.state.document.current_source
0074 replace["line_no"] = replace.get("line_no", self.lineno)
0075 message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
0076 self.state.document.settings.env.app.warn(message, prefix="")
0077
0078 def run(self):
0079
0080 doc = self.state.document
0081 if not doc.settings.file_insertion_enabled:
0082 raise self.warning("docutils: file insertion disabled")
0083
0084 env = doc.settings.env
0085 cwd = path.dirname(doc.current_source)
0086 cmd = "get_feat.pl rest --enable-fname --dir "
0087 cmd += self.arguments[0]
0088
0089 if len(self.arguments) > 1:
0090 cmd += " --arch " + self.arguments[1]
0091
0092 srctree = path.abspath(os.environ["srctree"])
0093
0094 fname = cmd
0095
0096
0097 path_env = os.pathsep.join([
0098 srctree + os.sep + "scripts",
0099 os.environ["PATH"]
0100 ])
0101 shell_env = os.environ.copy()
0102 shell_env["PATH"] = path_env
0103 shell_env["srctree"] = srctree
0104
0105 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
0106
0107 line_regex = re.compile("^\.\. FILE (\S+)$")
0108
0109 out_lines = ""
0110
0111 for line in lines.split("\n"):
0112 match = line_regex.search(line)
0113 if match:
0114 fname = match.group(1)
0115
0116
0117 env.note_dependency(os.path.abspath(fname))
0118 else:
0119 out_lines += line + "\n"
0120
0121 nodeList = self.nestedParse(out_lines, fname)
0122 return nodeList
0123
0124 def runCmd(self, cmd, **kwargs):
0125 u"""Run command ``cmd`` and return its stdout as unicode."""
0126
0127 try:
0128 proc = subprocess.Popen(
0129 cmd
0130 , stdout = subprocess.PIPE
0131 , stderr = subprocess.PIPE
0132 , **kwargs
0133 )
0134 out, err = proc.communicate()
0135
0136 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
0137
0138 if proc.returncode != 0:
0139 raise self.severe(
0140 u"command '%s' failed with return code %d"
0141 % (cmd, proc.returncode)
0142 )
0143 except OSError as exc:
0144 raise self.severe(u"problems with '%s' directive: %s."
0145 % (self.name, ErrorString(exc)))
0146 return out
0147
0148 def nestedParse(self, lines, fname):
0149 content = ViewList()
0150 node = nodes.section()
0151
0152 if "debug" in self.options:
0153 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
0154 for l in lines.split("\n"):
0155 code_block += "\n " + l
0156 lines = code_block + "\n\n"
0157
0158 for c, l in enumerate(lines.split("\n")):
0159 content.append(l, fname, c)
0160
0161 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
0162
0163 with switch_source_input(self.state, content):
0164 self.state.nested_parse(content, 0, node, match_titles=1)
0165
0166 return node.children