1 # -*- coding: utf-8; mode: python -*-
3 # SPDX-License-Identifier: GPL-2.0
9 Implementation of the ``kernel-abi`` reST-directive.
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.
16 The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
17 scripts/get_abi.pl script to parse the Kernel ABI files.
19 Overview of directive's argument and options.
23 .. kernel-abi:: <ABI directory location>
26 The argument ``<ABI directory location>`` is required. It contains the
27 location of the ABI files to be parsed.
30 Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
31 what reST is generated.
44 from docutils
import nodes
, statemachine
45 from docutils
.statemachine
import ViewList
46 from docutils
.parsers
.rst
import directives
, Directive
47 from docutils
.utils
.error_reporting
import ErrorString
50 # AutodocReporter is only good up to Sphinx 1.7
54 Use_SSI
= sphinx
.__version
__[:3] >= '1.7'
56 from sphinx
.util
.docutils
import switch_source_input
58 from sphinx
.ext
.autodoc
import AutodocReporter
64 app
.add_directive("kernel-abi", KernelCmd
)
67 , parallel_read_safe
= True
68 , parallel_write_safe
= True
71 class KernelCmd(Directive
):
73 u
"""KernelABI (``kernel-abi``) directive"""
75 required_arguments
= 1
76 optional_arguments
= 2
78 final_argument_whitespace
= True
81 "debug" : directives
.flag
,
82 "rst" : directives
.unchanged
87 doc
= self
.state
.document
88 if not doc
.settings
.file_insertion_enabled
:
89 raise self
.warning("docutils: file insertion disabled")
91 env
= doc
.settings
.env
92 cwd
= path
.dirname(doc
.current_source
)
93 cmd
= "get_abi.pl rest --enable-lineno --dir "
94 cmd
+= self
.arguments
[0]
96 if 'rst' in self
.options
:
97 cmd
+= " --rst-source"
99 srctree
= path
.abspath(os
.environ
["srctree"])
103 # extend PATH with $(srctree)/scripts
104 path_env
= os
.pathsep
.join([
105 srctree
+ os
.sep
+ "scripts",
108 shell_env
= os
.environ
.copy()
109 shell_env
["PATH"] = path_env
110 shell_env
["srctree"] = srctree
112 lines
= self
.runCmd(cmd
, shell
=True, cwd
=cwd
, env
=shell_env
)
113 nodeList
= self
.nestedParse(lines
, self
.arguments
[0])
116 def runCmd(self
, cmd
, **kwargs
):
117 u
"""Run command ``cmd`` and return it's stdout as unicode."""
120 proc
= subprocess
.Popen(
122 , stdout
= subprocess
.PIPE
123 , stderr
= subprocess
.PIPE
126 out
, err
= proc
.communicate()
128 out
, err
= codecs
.decode(out
, 'utf-8'), codecs
.decode(err
, 'utf-8')
130 if proc
.returncode
!= 0:
132 u
"command '%s' failed with return code %d"
133 % (cmd
, proc
.returncode
)
135 except OSError as exc
:
136 raise self
.severe(u
"problems with '%s' directive: %s."
137 % (self
.name
, ErrorString(exc
)))
140 def nestedParse(self
, lines
, fname
):
142 node
= nodes
.section()
144 if "debug" in self
.options
:
145 code_block
= "\n\n.. code-block:: rst\n :linenos:\n"
146 for l
in lines
.split("\n"):
147 code_block
+= "\n " + l
148 lines
= code_block
+ "\n\n"
150 line_regex
= re
.compile("^#define LINENO (\S+)\#([0-9]+)$")
155 for line
in lines
.split("\n"):
157 match
= line_regex
.search(line
)
159 new_f
= match
.group(1)
161 # Sphinx parser is lazy: it stops parsing contents in the
162 # middle, if it is too big. So, handle it per input file
163 if new_f
!= f
and content
:
164 self
.do_parse(content
, node
)
169 # sphinx counts lines from 0
170 ln
= int(match
.group(2)) - 1
172 content
.append(line
, f
, ln
)
174 kernellog
.info(self
.state
.document
.settings
.env
.app
, "%s: parsed %i lines" % (fname
, n
))
177 self
.do_parse(content
, node
)
181 def do_parse(self
, content
, node
):
183 with
switch_source_input(self
.state
, content
):
184 self
.state
.nested_parse(content
, 0, node
, match_titles
=1)
186 buf
= self
.state
.memo
.title_styles
, self
.state
.memo
.section_level
, self
.state
.memo
.reporter
188 self
.state
.memo
.title_styles
= []
189 self
.state
.memo
.section_level
= 0
190 self
.state
.memo
.reporter
= AutodocReporter(content
, self
.state
.memo
.reporter
)
192 self
.state
.nested_parse(content
, 0, node
, match_titles
=1)
194 self
.state
.memo
.title_styles
, self
.state
.memo
.section_level
, self
.state
.memo
.reporter
= buf