Back to home page

OSCL-LXR

 
 

    


0001 # coding=utf-8
0002 # SPDX-License-Identifier: GPL-2.0
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         # extend PATH with $(srctree)/scripts
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                 # Add the file to Sphinx build dependencies
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