162306a36Sopenharmony_ci# coding=utf-8
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ciu"""
562306a36Sopenharmony_ci    kernel-feat
662306a36Sopenharmony_ci    ~~~~~~~~~~~
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci    Implementation of the ``kernel-feat`` reST-directive.
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci    :copyright:  Copyright (C) 2016  Markus Heiser
1162306a36Sopenharmony_ci    :copyright:  Copyright (C) 2016-2019  Mauro Carvalho Chehab
1262306a36Sopenharmony_ci    :maintained-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
1362306a36Sopenharmony_ci    :license:    GPL Version 2, June 1991 see Linux/COPYING for details.
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci    The ``kernel-feat`` (:py:class:`KernelFeat`) directive calls the
1662306a36Sopenharmony_ci    scripts/get_feat.pl script to parse the Kernel ABI files.
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci    Overview of directive's argument and options.
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci    .. code-block:: rst
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci        .. kernel-feat:: <ABI directory location>
2362306a36Sopenharmony_ci            :debug:
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci    The argument ``<ABI directory location>`` is required. It contains the
2662306a36Sopenharmony_ci    location of the ABI files to be parsed.
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci    ``debug``
2962306a36Sopenharmony_ci      Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
3062306a36Sopenharmony_ci      what reST is generated.
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci"""
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciimport codecs
3562306a36Sopenharmony_ciimport os
3662306a36Sopenharmony_ciimport re
3762306a36Sopenharmony_ciimport subprocess
3862306a36Sopenharmony_ciimport sys
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cifrom docutils import nodes, statemachine
4162306a36Sopenharmony_cifrom docutils.statemachine import ViewList
4262306a36Sopenharmony_cifrom docutils.parsers.rst import directives, Directive
4362306a36Sopenharmony_cifrom docutils.utils.error_reporting import ErrorString
4462306a36Sopenharmony_cifrom sphinx.util.docutils import switch_source_input
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci__version__  = '1.0'
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cidef setup(app):
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci    app.add_directive("kernel-feat", KernelFeat)
5162306a36Sopenharmony_ci    return dict(
5262306a36Sopenharmony_ci        version = __version__
5362306a36Sopenharmony_ci        , parallel_read_safe = True
5462306a36Sopenharmony_ci        , parallel_write_safe = True
5562306a36Sopenharmony_ci    )
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciclass KernelFeat(Directive):
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci    u"""KernelFeat (``kernel-feat``) directive"""
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci    required_arguments = 1
6262306a36Sopenharmony_ci    optional_arguments = 2
6362306a36Sopenharmony_ci    has_content = False
6462306a36Sopenharmony_ci    final_argument_whitespace = True
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci    option_spec = {
6762306a36Sopenharmony_ci        "debug"     : directives.flag
6862306a36Sopenharmony_ci    }
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci    def warn(self, message, **replace):
7162306a36Sopenharmony_ci        replace["fname"]   = self.state.document.current_source
7262306a36Sopenharmony_ci        replace["line_no"] = replace.get("line_no", self.lineno)
7362306a36Sopenharmony_ci        message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
7462306a36Sopenharmony_ci        self.state.document.settings.env.app.warn(message, prefix="")
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci    def run(self):
7762306a36Sopenharmony_ci        doc = self.state.document
7862306a36Sopenharmony_ci        if not doc.settings.file_insertion_enabled:
7962306a36Sopenharmony_ci            raise self.warning("docutils: file insertion disabled")
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci        env = doc.settings.env
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci        srctree = os.path.abspath(os.environ["srctree"])
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci        args = [
8662306a36Sopenharmony_ci            os.path.join(srctree, 'scripts/get_feat.pl'),
8762306a36Sopenharmony_ci            'rest',
8862306a36Sopenharmony_ci            '--enable-fname',
8962306a36Sopenharmony_ci            '--dir',
9062306a36Sopenharmony_ci            os.path.join(srctree, 'Documentation', self.arguments[0]),
9162306a36Sopenharmony_ci        ]
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci        if len(self.arguments) > 1:
9462306a36Sopenharmony_ci            args.extend(['--arch', self.arguments[1]])
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci        lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8')
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci        line_regex = re.compile(r"^\.\. FILE (\S+)$")
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci        out_lines = ""
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci        for line in lines.split("\n"):
10362306a36Sopenharmony_ci            match = line_regex.search(line)
10462306a36Sopenharmony_ci            if match:
10562306a36Sopenharmony_ci                fname = match.group(1)
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci                # Add the file to Sphinx build dependencies
10862306a36Sopenharmony_ci                env.note_dependency(os.path.abspath(fname))
10962306a36Sopenharmony_ci            else:
11062306a36Sopenharmony_ci                out_lines += line + "\n"
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci        nodeList = self.nestedParse(out_lines, self.arguments[0])
11362306a36Sopenharmony_ci        return nodeList
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci    def nestedParse(self, lines, fname):
11662306a36Sopenharmony_ci        content = ViewList()
11762306a36Sopenharmony_ci        node    = nodes.section()
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci        if "debug" in self.options:
12062306a36Sopenharmony_ci            code_block = "\n\n.. code-block:: rst\n    :linenos:\n"
12162306a36Sopenharmony_ci            for l in lines.split("\n"):
12262306a36Sopenharmony_ci                code_block += "\n    " + l
12362306a36Sopenharmony_ci            lines = code_block + "\n\n"
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci        for c, l in enumerate(lines.split("\n")):
12662306a36Sopenharmony_ci            content.append(l, fname, c)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci        buf  = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci        with switch_source_input(self.state, content):
13162306a36Sopenharmony_ci            self.state.nested_parse(content, 0, node, match_titles=1)
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci        return node.children
134