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 os import path
41b9721225SMauro Carvalho Chehab
42b9721225SMauro Carvalho Chehabfrom docutils import nodes, statemachine
43b9721225SMauro Carvalho Chehabfrom docutils.statemachine import ViewList
44b9721225SMauro Carvalho Chehabfrom docutils.parsers.rst import directives, Directive
45b9721225SMauro Carvalho Chehabfrom docutils.utils.error_reporting import ErrorString
46b9721225SMauro Carvalho Chehabfrom sphinx.util.docutils import switch_source_input
47b9721225SMauro Carvalho Chehab
48b9721225SMauro Carvalho Chehab__version__  = '1.0'
49b9721225SMauro Carvalho Chehab
50b9721225SMauro Carvalho Chehabdef setup(app):
51b9721225SMauro Carvalho Chehab
52b9721225SMauro Carvalho Chehab    app.add_directive("kernel-feat", KernelFeat)
53b9721225SMauro Carvalho Chehab    return dict(
54b9721225SMauro Carvalho Chehab        version = __version__
55b9721225SMauro Carvalho Chehab        , parallel_read_safe = True
56b9721225SMauro Carvalho Chehab        , parallel_write_safe = True
57b9721225SMauro Carvalho Chehab    )
58b9721225SMauro Carvalho Chehab
59b9721225SMauro Carvalho Chehabclass KernelFeat(Directive):
60b9721225SMauro Carvalho Chehab
61b9721225SMauro Carvalho Chehab    u"""KernelFeat (``kernel-feat``) directive"""
62b9721225SMauro Carvalho Chehab
63b9721225SMauro Carvalho Chehab    required_arguments = 1
64b9721225SMauro Carvalho Chehab    optional_arguments = 2
65b9721225SMauro Carvalho Chehab    has_content = False
66b9721225SMauro Carvalho Chehab    final_argument_whitespace = True
67b9721225SMauro Carvalho Chehab
68b9721225SMauro Carvalho Chehab    option_spec = {
69b9721225SMauro Carvalho Chehab        "debug"     : directives.flag
70b9721225SMauro Carvalho Chehab    }
71b9721225SMauro Carvalho Chehab
72b9721225SMauro Carvalho Chehab    def warn(self, message, **replace):
73b9721225SMauro Carvalho Chehab        replace["fname"]   = self.state.document.current_source
74b9721225SMauro Carvalho Chehab        replace["line_no"] = replace.get("line_no", self.lineno)
75b9721225SMauro Carvalho Chehab        message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
76b9721225SMauro Carvalho Chehab        self.state.document.settings.env.app.warn(message, prefix="")
77b9721225SMauro Carvalho Chehab
78b9721225SMauro Carvalho Chehab    def run(self):
79b9721225SMauro Carvalho Chehab
80b9721225SMauro Carvalho Chehab        doc = self.state.document
81b9721225SMauro Carvalho Chehab        if not doc.settings.file_insertion_enabled:
82b9721225SMauro Carvalho Chehab            raise self.warning("docutils: file insertion disabled")
83b9721225SMauro Carvalho Chehab
84b9721225SMauro Carvalho Chehab        env = doc.settings.env
85b9721225SMauro Carvalho Chehab        cwd = path.dirname(doc.current_source)
8685999f03SMauro Carvalho Chehab        cmd = "get_feat.pl rest --enable-fname --dir "
87b9721225SMauro Carvalho Chehab        cmd += self.arguments[0]
88b9721225SMauro Carvalho Chehab
89b9721225SMauro Carvalho Chehab        if len(self.arguments) > 1:
90b9721225SMauro Carvalho Chehab            cmd += " --arch " + self.arguments[1]
91b9721225SMauro Carvalho Chehab
92b9721225SMauro Carvalho Chehab        srctree = path.abspath(os.environ["srctree"])
93b9721225SMauro Carvalho Chehab
94b9721225SMauro Carvalho Chehab        fname = cmd
95b9721225SMauro Carvalho Chehab
96b9721225SMauro Carvalho Chehab        # extend PATH with $(srctree)/scripts
97b9721225SMauro Carvalho Chehab        path_env = os.pathsep.join([
98b9721225SMauro Carvalho Chehab            srctree + os.sep + "scripts",
99b9721225SMauro Carvalho Chehab            os.environ["PATH"]
100b9721225SMauro Carvalho Chehab        ])
101b9721225SMauro Carvalho Chehab        shell_env = os.environ.copy()
102b9721225SMauro Carvalho Chehab        shell_env["PATH"]    = path_env
103b9721225SMauro Carvalho Chehab        shell_env["srctree"] = srctree
104b9721225SMauro Carvalho Chehab
105b9721225SMauro Carvalho Chehab        lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
10685999f03SMauro Carvalho Chehab
107*86a0adc0SBenjamin Gray        line_regex = re.compile(r"^\.\. FILE (\S+)$")
10885999f03SMauro Carvalho Chehab
10985999f03SMauro Carvalho Chehab        out_lines = ""
11085999f03SMauro Carvalho Chehab
11185999f03SMauro Carvalho Chehab        for line in lines.split("\n"):
11285999f03SMauro Carvalho Chehab            match = line_regex.search(line)
11385999f03SMauro Carvalho Chehab            if match:
11485999f03SMauro Carvalho Chehab                fname = match.group(1)
11585999f03SMauro Carvalho Chehab
11685999f03SMauro Carvalho Chehab                # Add the file to Sphinx build dependencies
11785999f03SMauro Carvalho Chehab                env.note_dependency(os.path.abspath(fname))
11885999f03SMauro Carvalho Chehab            else:
11985999f03SMauro Carvalho Chehab                out_lines += line + "\n"
12085999f03SMauro Carvalho Chehab
12185999f03SMauro Carvalho Chehab        nodeList = self.nestedParse(out_lines, fname)
122b9721225SMauro Carvalho Chehab        return nodeList
123b9721225SMauro Carvalho Chehab
124b9721225SMauro Carvalho Chehab    def runCmd(self, cmd, **kwargs):
12532211146SRandy Dunlap        u"""Run command ``cmd`` and return its stdout as unicode."""
126b9721225SMauro Carvalho Chehab
127b9721225SMauro Carvalho Chehab        try:
128b9721225SMauro Carvalho Chehab            proc = subprocess.Popen(
129b9721225SMauro Carvalho Chehab                cmd
130b9721225SMauro Carvalho Chehab                , stdout = subprocess.PIPE
131b9721225SMauro Carvalho Chehab                , stderr = subprocess.PIPE
132b9721225SMauro Carvalho Chehab                , **kwargs
133b9721225SMauro Carvalho Chehab            )
134b9721225SMauro Carvalho Chehab            out, err = proc.communicate()
135b9721225SMauro Carvalho Chehab
136b9721225SMauro Carvalho Chehab            out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
137b9721225SMauro Carvalho Chehab
138b9721225SMauro Carvalho Chehab            if proc.returncode != 0:
139b9721225SMauro Carvalho Chehab                raise self.severe(
140b9721225SMauro Carvalho Chehab                    u"command '%s' failed with return code %d"
141b9721225SMauro Carvalho Chehab                    % (cmd, proc.returncode)
142b9721225SMauro Carvalho Chehab                )
143b9721225SMauro Carvalho Chehab        except OSError as exc:
144b9721225SMauro Carvalho Chehab            raise self.severe(u"problems with '%s' directive: %s."
145b9721225SMauro Carvalho Chehab                              % (self.name, ErrorString(exc)))
146b9721225SMauro Carvalho Chehab        return out
147b9721225SMauro Carvalho Chehab
148b9721225SMauro Carvalho Chehab    def nestedParse(self, lines, fname):
149b9721225SMauro Carvalho Chehab        content = ViewList()
150b9721225SMauro Carvalho Chehab        node    = nodes.section()
151b9721225SMauro Carvalho Chehab
152b9721225SMauro Carvalho Chehab        if "debug" in self.options:
153b9721225SMauro Carvalho Chehab            code_block = "\n\n.. code-block:: rst\n    :linenos:\n"
154b9721225SMauro Carvalho Chehab            for l in lines.split("\n"):
155b9721225SMauro Carvalho Chehab                code_block += "\n    " + l
156b9721225SMauro Carvalho Chehab            lines = code_block + "\n\n"
157b9721225SMauro Carvalho Chehab
158b9721225SMauro Carvalho Chehab        for c, l in enumerate(lines.split("\n")):
159b9721225SMauro Carvalho Chehab            content.append(l, fname, c)
160b9721225SMauro Carvalho Chehab
161b9721225SMauro Carvalho Chehab        buf  = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
162b9721225SMauro Carvalho Chehab
163b9721225SMauro Carvalho Chehab        with switch_source_input(self.state, content):
164b9721225SMauro Carvalho Chehab            self.state.nested_parse(content, 0, node, match_titles=1)
165b9721225SMauro Carvalho Chehab
166b9721225SMauro Carvalho Chehab        return node.children
167