1b9721225SMauro Carvalho Chehab# coding=utf-8
2b9721225SMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0
3b9721225SMauro Carvalho Chehab#
4b9721225SMauro Carvalho Chehabu"""
5b9721225SMauro Carvalho Chehab    kernel-feat
6b9721225SMauro Carvalho Chehab    ~~~~~~~~~~~
7b9721225SMauro Carvalho Chehab
8b9721225SMauro Carvalho Chehab    Implementation of the ``kernel-feat`` reST-directive.
9b9721225SMauro Carvalho Chehab
10b9721225SMauro Carvalho Chehab    :copyright:  Copyright (C) 2016  Markus Heiser
11b9721225SMauro Carvalho Chehab    :copyright:  Copyright (C) 2016-2019  Mauro Carvalho Chehab
12b9721225SMauro Carvalho Chehab    :maintained-by: Mauro Carvalho Chehab <[email protected]>
13b9721225SMauro Carvalho Chehab    :license:    GPL Version 2, June 1991 see Linux/COPYING for details.
14b9721225SMauro Carvalho Chehab
15b9721225SMauro Carvalho Chehab    The ``kernel-feat`` (:py:class:`KernelFeat`) directive calls the
16b9721225SMauro Carvalho Chehab    scripts/get_feat.pl script to parse the Kernel ABI files.
17b9721225SMauro Carvalho Chehab
18b9721225SMauro Carvalho Chehab    Overview of directive's argument and options.
19b9721225SMauro Carvalho Chehab
20b9721225SMauro Carvalho Chehab    .. code-block:: rst
21b9721225SMauro Carvalho Chehab
22b9721225SMauro Carvalho Chehab        .. kernel-feat:: <ABI directory location>
23b9721225SMauro Carvalho Chehab            :debug:
24b9721225SMauro Carvalho Chehab
25b9721225SMauro Carvalho Chehab    The argument ``<ABI directory location>`` is required. It contains the
26b9721225SMauro Carvalho Chehab    location of the ABI files to be parsed.
27b9721225SMauro Carvalho Chehab
28b9721225SMauro Carvalho Chehab    ``debug``
29b9721225SMauro Carvalho Chehab      Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
30b9721225SMauro Carvalho Chehab      what reST is generated.
31b9721225SMauro Carvalho Chehab
32b9721225SMauro Carvalho Chehab"""
33b9721225SMauro Carvalho Chehab
34b9721225SMauro Carvalho Chehabimport codecs
35b9721225SMauro Carvalho Chehabimport os
3685999f03SMauro Carvalho Chehabimport re
37b9721225SMauro Carvalho Chehabimport subprocess
38b9721225SMauro Carvalho Chehabimport sys
39b9721225SMauro Carvalho Chehab
40b9721225SMauro Carvalho Chehabfrom docutils import nodes, statemachine
41b9721225SMauro Carvalho Chehabfrom docutils.statemachine import ViewList
42b9721225SMauro Carvalho Chehabfrom docutils.parsers.rst import directives, Directive
43b9721225SMauro Carvalho Chehabfrom docutils.utils.error_reporting import ErrorString
44b9721225SMauro Carvalho Chehabfrom sphinx.util.docutils import switch_source_input
45b9721225SMauro Carvalho Chehab
46b9721225SMauro Carvalho Chehab__version__  = '1.0'
47b9721225SMauro Carvalho Chehab
48b9721225SMauro Carvalho Chehabdef setup(app):
49b9721225SMauro Carvalho Chehab
50b9721225SMauro Carvalho Chehab    app.add_directive("kernel-feat", KernelFeat)
51b9721225SMauro Carvalho Chehab    return dict(
52b9721225SMauro Carvalho Chehab        version = __version__
53b9721225SMauro Carvalho Chehab        , parallel_read_safe = True
54b9721225SMauro Carvalho Chehab        , parallel_write_safe = True
55b9721225SMauro Carvalho Chehab    )
56b9721225SMauro Carvalho Chehab
57b9721225SMauro Carvalho Chehabclass KernelFeat(Directive):
58b9721225SMauro Carvalho Chehab
59b9721225SMauro Carvalho Chehab    u"""KernelFeat (``kernel-feat``) directive"""
60b9721225SMauro Carvalho Chehab
61b9721225SMauro Carvalho Chehab    required_arguments = 1
62b9721225SMauro Carvalho Chehab    optional_arguments = 2
63b9721225SMauro Carvalho Chehab    has_content = False
64b9721225SMauro Carvalho Chehab    final_argument_whitespace = True
65b9721225SMauro Carvalho Chehab
66b9721225SMauro Carvalho Chehab    option_spec = {
67b9721225SMauro Carvalho Chehab        "debug"     : directives.flag
68b9721225SMauro Carvalho Chehab    }
69b9721225SMauro Carvalho Chehab
70b9721225SMauro Carvalho Chehab    def warn(self, message, **replace):
71b9721225SMauro Carvalho Chehab        replace["fname"]   = self.state.document.current_source
72b9721225SMauro Carvalho Chehab        replace["line_no"] = replace.get("line_no", self.lineno)
73b9721225SMauro Carvalho Chehab        message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
74b9721225SMauro Carvalho Chehab        self.state.document.settings.env.app.warn(message, prefix="")
75b9721225SMauro Carvalho Chehab
76b9721225SMauro Carvalho Chehab    def run(self):
77b9721225SMauro Carvalho Chehab        doc = self.state.document
78b9721225SMauro Carvalho Chehab        if not doc.settings.file_insertion_enabled:
79b9721225SMauro Carvalho Chehab            raise self.warning("docutils: file insertion disabled")
80b9721225SMauro Carvalho Chehab
81b9721225SMauro Carvalho Chehab        env = doc.settings.env
82*c48a7c44SVegard Nossum
83*c48a7c44SVegard Nossum        srctree = os.path.abspath(os.environ["srctree"])
84*c48a7c44SVegard Nossum
85*c48a7c44SVegard Nossum        args = [
86*c48a7c44SVegard Nossum            os.path.join(srctree, 'scripts/get_feat.pl'),
87*c48a7c44SVegard Nossum            'rest',
88*c48a7c44SVegard Nossum            '--enable-fname',
89*c48a7c44SVegard Nossum            '--dir',
90*c48a7c44SVegard Nossum            os.path.join(srctree, 'Documentation', self.arguments[0]),
91*c48a7c44SVegard Nossum        ]
92b9721225SMauro Carvalho Chehab
93b9721225SMauro Carvalho Chehab        if len(self.arguments) > 1:
94*c48a7c44SVegard Nossum            args.extend(['--arch', self.arguments[1]])
95b9721225SMauro Carvalho Chehab
96*c48a7c44SVegard Nossum        lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8')
9785999f03SMauro Carvalho Chehab
9886a0adc0SBenjamin Gray        line_regex = re.compile(r"^\.\. FILE (\S+)$")
9985999f03SMauro Carvalho Chehab
10085999f03SMauro Carvalho Chehab        out_lines = ""
10185999f03SMauro Carvalho Chehab
10285999f03SMauro Carvalho Chehab        for line in lines.split("\n"):
10385999f03SMauro Carvalho Chehab            match = line_regex.search(line)
10485999f03SMauro Carvalho Chehab            if match:
10585999f03SMauro Carvalho Chehab                fname = match.group(1)
10685999f03SMauro Carvalho Chehab
10785999f03SMauro Carvalho Chehab                # Add the file to Sphinx build dependencies
10885999f03SMauro Carvalho Chehab                env.note_dependency(os.path.abspath(fname))
10985999f03SMauro Carvalho Chehab            else:
11085999f03SMauro Carvalho Chehab                out_lines += line + "\n"
11185999f03SMauro Carvalho Chehab
11285999f03SMauro Carvalho Chehab        nodeList = self.nestedParse(out_lines, fname)
113b9721225SMauro Carvalho Chehab        return nodeList
114b9721225SMauro Carvalho Chehab
115b9721225SMauro Carvalho Chehab    def nestedParse(self, lines, fname):
116b9721225SMauro Carvalho Chehab        content = ViewList()
117b9721225SMauro Carvalho Chehab        node    = nodes.section()
118b9721225SMauro Carvalho Chehab
119b9721225SMauro Carvalho Chehab        if "debug" in self.options:
120b9721225SMauro Carvalho Chehab            code_block = "\n\n.. code-block:: rst\n    :linenos:\n"
121b9721225SMauro Carvalho Chehab            for l in lines.split("\n"):
122b9721225SMauro Carvalho Chehab                code_block += "\n    " + l
123b9721225SMauro Carvalho Chehab            lines = code_block + "\n\n"
124b9721225SMauro Carvalho Chehab
125b9721225SMauro Carvalho Chehab        for c, l in enumerate(lines.split("\n")):
126b9721225SMauro Carvalho Chehab            content.append(l, fname, c)
127b9721225SMauro Carvalho Chehab
128b9721225SMauro Carvalho Chehab        buf  = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
129b9721225SMauro Carvalho Chehab
130b9721225SMauro Carvalho Chehab        with switch_source_input(self.state, content):
131b9721225SMauro Carvalho Chehab            self.state.nested_parse(content, 0, node, match_titles=1)
132b9721225SMauro Carvalho Chehab
133b9721225SMauro Carvalho Chehab        return node.children
134