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
48 from sphinx
.util
.docutils
import switch_source_input
54 app
.add_directive("kernel-abi", KernelCmd
)
57 , parallel_read_safe
= True
58 , parallel_write_safe
= True
61 class KernelCmd(Directive
):
63 u
"""KernelABI (``kernel-abi``) directive"""
65 required_arguments
= 1
66 optional_arguments
= 2
68 final_argument_whitespace
= True
71 "debug" : directives
.flag
,
72 "rst" : directives
.unchanged
77 doc
= self
.state
.document
78 if not doc
.settings
.file_insertion_enabled
:
79 raise self
.warning("docutils: file insertion disabled")
81 env
= doc
.settings
.env
82 cwd
= path
.dirname(doc
.current_source
)
83 cmd
= "get_abi.pl rest --enable-lineno --dir "
84 cmd
+= self
.arguments
[0]
86 if 'rst' in self
.options
:
87 cmd
+= " --rst-source"
89 srctree
= path
.abspath(os
.environ
["srctree"])
93 # extend PATH with $(srctree)/scripts
94 path_env
= os
.pathsep
.join([
95 srctree
+ os
.sep
+ "scripts",
98 shell_env
= os
.environ
.copy()
99 shell_env
["PATH"] = path_env
100 shell_env
["srctree"] = srctree
102 lines
= self
.runCmd(cmd
, shell
=True, cwd
=cwd
, env
=shell_env
)
103 nodeList
= self
.nestedParse(lines
, self
.arguments
[0])
106 def runCmd(self
, cmd
, **kwargs
):
107 u
"""Run command ``cmd`` and return it's stdout as unicode."""
110 proc
= subprocess
.Popen(
112 , stdout
= subprocess
.PIPE
113 , stderr
= subprocess
.PIPE
116 out
, err
= proc
.communicate()
118 out
, err
= codecs
.decode(out
, 'utf-8'), codecs
.decode(err
, 'utf-8')
120 if proc
.returncode
!= 0:
122 u
"command '%s' failed with return code %d"
123 % (cmd
, proc
.returncode
)
125 except OSError as exc
:
126 raise self
.severe(u
"problems with '%s' directive: %s."
127 % (self
.name
, ErrorString(exc
)))
130 def nestedParse(self
, lines
, fname
):
132 node
= nodes
.section()
134 if "debug" in self
.options
:
135 code_block
= "\n\n.. code-block:: rst\n :linenos:\n"
136 for l
in lines
.split("\n"):
137 code_block
+= "\n " + l
138 lines
= code_block
+ "\n\n"
140 line_regex
= re
.compile("^#define LINENO (\S+)\#([0-9]+)$")
145 for line
in lines
.split("\n"):
147 match
= line_regex
.search(line
)
149 new_f
= match
.group(1)
151 # Sphinx parser is lazy: it stops parsing contents in the
152 # middle, if it is too big. So, handle it per input file
153 if new_f
!= f
and content
:
154 self
.do_parse(content
, node
)
159 # sphinx counts lines from 0
160 ln
= int(match
.group(2)) - 1
162 content
.append(line
, f
, ln
)
164 kernellog
.info(self
.state
.document
.settings
.env
.app
, "%s: parsed %i lines" % (fname
, n
))
167 self
.do_parse(content
, node
)
171 def do_parse(self
, content
, node
):
172 with
switch_source_input(self
.state
, content
):
173 self
.state
.nested_parse(content
, 0, node
, match_titles
=1)