diff options
Diffstat (limited to 'Documentation/sphinx/kernel_abi.py')
| -rw-r--r-- | Documentation/sphinx/kernel_abi.py | 194 | 
1 files changed, 194 insertions, 0 deletions
| diff --git a/Documentation/sphinx/kernel_abi.py b/Documentation/sphinx/kernel_abi.py new file mode 100644 index 000000000000..f3da859c9878 --- /dev/null +++ b/Documentation/sphinx/kernel_abi.py @@ -0,0 +1,194 @@ +# -*- coding: utf-8; mode: python -*- +# coding=utf-8 +# SPDX-License-Identifier: GPL-2.0 +# +u""" +    kernel-abi +    ~~~~~~~~~~ + +    Implementation of the ``kernel-abi`` reST-directive. + +    :copyright:  Copyright (C) 2016  Markus Heiser +    :copyright:  Copyright (C) 2016-2020  Mauro Carvalho Chehab +    :maintained-by: Mauro Carvalho Chehab <[email protected]> +    :license:    GPL Version 2, June 1991 see Linux/COPYING for details. + +    The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the +    scripts/get_abi.pl script to parse the Kernel ABI files. + +    Overview of directive's argument and options. + +    .. code-block:: rst + +        .. kernel-abi:: <ABI directory location> +            :debug: + +    The argument ``<ABI directory location>`` is required. It contains the +    location of the ABI files to be parsed. + +    ``debug`` +      Inserts a code-block with the *raw* reST. Sometimes it is helpful to see +      what reST is generated. + +""" + +import codecs +import os +import subprocess +import sys +import re +import kernellog + +from os import path + +from docutils import nodes, statemachine +from docutils.statemachine import ViewList +from docutils.parsers.rst import directives, Directive +from docutils.utils.error_reporting import ErrorString + +# +# AutodocReporter is only good up to Sphinx 1.7 +# +import sphinx + +Use_SSI = sphinx.__version__[:3] >= '1.7' +if Use_SSI: +    from sphinx.util.docutils import switch_source_input +else: +    from sphinx.ext.autodoc import AutodocReporter + +__version__  = '1.0' + +def setup(app): + +    app.add_directive("kernel-abi", KernelCmd) +    return dict( +        version = __version__ +        , parallel_read_safe = True +        , parallel_write_safe = True +    ) + +class KernelCmd(Directive): + +    u"""KernelABI (``kernel-abi``) directive""" + +    required_arguments = 1 +    optional_arguments = 2 +    has_content = False +    final_argument_whitespace = True + +    option_spec = { +        "debug"     : directives.flag, +        "rst"       : directives.unchanged +    } + +    def run(self): + +        doc = self.state.document +        if not doc.settings.file_insertion_enabled: +            raise self.warning("docutils: file insertion disabled") + +        env = doc.settings.env +        cwd = path.dirname(doc.current_source) +        cmd = "get_abi.pl rest --enable-lineno --dir " +        cmd += self.arguments[0] + +        if 'rst' in self.options: +            cmd += " --rst-source" + +        srctree = path.abspath(os.environ["srctree"]) + +        fname = cmd + +        # extend PATH with $(srctree)/scripts +        path_env = os.pathsep.join([ +            srctree + os.sep + "scripts", +            os.environ["PATH"] +        ]) +        shell_env = os.environ.copy() +        shell_env["PATH"]    = path_env +        shell_env["srctree"] = srctree + +        lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env) +        nodeList = self.nestedParse(lines, self.arguments[0]) +        return nodeList + +    def runCmd(self, cmd, **kwargs): +        u"""Run command ``cmd`` and return it's stdout as unicode.""" + +        try: +            proc = subprocess.Popen( +                cmd +                , stdout = subprocess.PIPE +                , stderr = subprocess.PIPE +                , **kwargs +            ) +            out, err = proc.communicate() + +            out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') + +            if proc.returncode != 0: +                raise self.severe( +                    u"command '%s' failed with return code %d" +                    % (cmd, proc.returncode) +                ) +        except OSError as exc: +            raise self.severe(u"problems with '%s' directive: %s." +                              % (self.name, ErrorString(exc))) +        return out + +    def nestedParse(self, lines, fname): +        content = ViewList() +        node = nodes.section() + +        if "debug" in self.options: +            code_block = "\n\n.. code-block:: rst\n    :linenos:\n" +            for l in lines.split("\n"): +                code_block += "\n    " + l +            lines = code_block + "\n\n" + +        line_regex = re.compile("^#define LINENO (\S+)\#([0-9]+)$") +        ln = 0 +        n = 0 +        f = fname + +        for line in lines.split("\n"): +            n = n + 1 +            match = line_regex.search(line) +            if match: +                new_f = match.group(1) + +                # Sphinx parser is lazy: it stops parsing contents in the +                # middle, if it is too big. So, handle it per input file +                if new_f != f and content: +                    self.do_parse(content, node) +                    content = ViewList() + +                f = new_f + +                # sphinx counts lines from 0 +                ln = int(match.group(2)) - 1 +            else: +                content.append(line, f, ln) + +        kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n)) + +        if content: +            self.do_parse(content, node) + +        return node.children + +    def do_parse(self, content, node): +        if Use_SSI: +            with switch_source_input(self.state, content): +                self.state.nested_parse(content, 0, node, match_titles=1) +        else: +            buf  = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter + +            self.state.memo.title_styles  = [] +            self.state.memo.section_level = 0 +            self.state.memo.reporter      = AutodocReporter(content, self.state.memo.reporter) +            try: +                self.state.nested_parse(content, 0, node, match_titles=1) +            finally: +                self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf |