blob: fe69c213716dbda9ed295a3ca536f9f2382ccc68 [file] [log] [blame]
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +01001# -*- coding: utf-8; mode: python -*-
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +01002# coding=utf-8
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +01003# SPDX-License-Identifier: GPL-2.0
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +01004#
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +01005u"""
6 kernel-abi
7 ~~~~~~~~~~
8
9 Implementation of the ``kernel-abi`` reST-directive.
10
11 :copyright: Copyright (C) 2016 Markus Heiser
12 :copyright: Copyright (C) 2016-2020 Mauro Carvalho Chehab
13 :maintained-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
14 :license: GPL Version 2, June 1991 see Linux/COPYING for details.
15
16 The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
17 scripts/get_abi.pl script to parse the Kernel ABI files.
18
19 Overview of directive's argument and options.
20
21 .. code-block:: rst
22
23 .. kernel-abi:: <ABI directory location>
24 :debug:
25
26 The argument ``<ABI directory location>`` is required. It contains the
27 location of the ABI files to be parsed.
28
29 ``debug``
30 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
31 what reST is generated.
32
33"""
34
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +010035import codecs
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010036import sys
37import os
38from os import path
39import subprocess
40
41from sphinx.ext.autodoc import AutodocReporter
42
43from docutils import nodes
44from docutils.parsers.rst import Directive, directives
45from docutils.statemachine import ViewList
46from docutils.utils.error_reporting import ErrorString
47
48
49__version__ = '1.0'
50
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +010051def setup(app):
52
53 app.add_directive("kernel-abi", KernelCmd)
54 return dict(
55 version = __version__
56 , parallel_read_safe = True
57 , parallel_write_safe = True
58 )
59
60class KernelCmd(Directive):
61
62 u"""KernelABI (``kernel-abi``) directive"""
63
64 required_arguments = 1
65 optional_arguments = 0
66 has_content = False
67 final_argument_whitespace = True
68
69 option_spec = {
70 "debug" : directives.flag
71 }
72
73 def warn(self, message, **replace):
74 replace["fname"] = self.state.document.current_source
75 replace["line_no"] = replace.get("line_no", self.lineno)
76 message = ("%(fname)s:%(line_no)s: [kernel-abi WARN] : " + message) % replace
77 self.state.document.settings.env.app.warn(message, prefix="")
78
79 def run(self):
80
81 doc = self.state.document
82 if not doc.settings.file_insertion_enabled:
83 raise self.warning("docutils: file insertion disabled")
84
85 env = doc.settings.env
86 cwd = path.dirname(doc.current_source)
87 cmd = "get_abi.pl rest --dir "
88 cmd += self.arguments[0]
89
90 srctree = path.abspath(os.environ["srctree"])
91
92 fname = cmd
93
94 # extend PATH with $(srctree)/scripts
95 path_env = os.pathsep.join([
96 srctree + os.sep + "scripts",
97 os.environ["PATH"]
98 ])
99 shell_env = os.environ.copy()
100 shell_env["PATH"] = path_env
101 shell_env["srctree"] = srctree
102
103 lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
104 nodeList = self.nestedParse(lines, fname)
105 return nodeList
106
107 def runCmd(self, cmd, **kwargs):
108 u"""Run command ``cmd`` and return it's stdout as unicode."""
109
110 try:
111 proc = subprocess.Popen(
112 cmd
113 , stdout = subprocess.PIPE
114 , stderr = subprocess.PIPE
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100115 , **kwargs
116 )
117 out, err = proc.communicate()
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +0100118
119 out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
120
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100121 if proc.returncode != 0:
122 raise self.severe(
123 u"command '%s' failed with return code %d"
124 % (cmd, proc.returncode)
125 )
126 except OSError as exc:
127 raise self.severe(u"problems with '%s' directive: %s."
128 % (self.name, ErrorString(exc)))
Mauro Carvalho Chehab823830d2020-10-30 08:40:32 +0100129 return out
Mauro Carvalho Chehab9ca876f2020-10-30 08:40:31 +0100130
131 def nestedParse(self, lines, fname):
132 content = ViewList()
133 node = nodes.section()
134
135 if "debug" in self.options:
136 code_block = "\n\n.. code-block:: rst\n :linenos:\n"
137 for l in lines.split("\n"):
138 code_block += "\n " + l
139 lines = code_block + "\n\n"
140
141 for c, l in enumerate(lines.split("\n")):
142 content.append(l, fname, c)
143
144 buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
145 self.state.memo.title_styles = []
146 self.state.memo.section_level = 0
147 self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
148 try:
149 self.state.nested_parse(content, 0, node, match_titles=1)
150 finally:
151 self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf
152 return node.children