Skip to content

Commit 9d9bec3

Browse files
mchehabJonathan Corbet
authored andcommitted
docs: sphinx: kerneldoc: Use python class if available
Better integrate with the new kernel-doc tool by calling the Python classes directly if KERNELDOC=scripts/kernel-doc.py. This way, warnings won't be duplicated anymore, as files will be parsed only once. Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet <corbet@lwn.net> Link: https://lore.kernel.org/r/1556a6c005d8e0fafa951f74725e984e1c7459bf.1744685912.git.mchehab+huawei@kernel.org
1 parent 47c2d41 commit 9d9bec3

1 file changed

Lines changed: 130 additions & 8 deletions

File tree

Documentation/sphinx/kerneldoc.py

Lines changed: 130 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@
4141
from sphinx.util.docutils import switch_source_input
4242
from sphinx.util import logging
4343

44+
srctree = os.path.abspath(os.environ["srctree"])
45+
sys.path.insert(0, os.path.join(srctree, "scripts/lib/kdoc"))
46+
47+
from kdoc_files import KernelFiles
48+
from kdoc_output import RestFormat
49+
4450
__version__ = '1.0'
51+
use_kfiles = False
4552

4653
def cmd_str(cmd):
4754
"""
@@ -82,11 +89,32 @@ class KernelDocDirective(Directive):
8289
logger = logging.getLogger('kerneldoc')
8390
verbose = 0
8491

85-
def run(self):
92+
parse_args = {}
93+
msg_args = {}
94+
95+
def handle_args(self):
96+
8697
env = self.state.document.settings.env
8798
cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno']
8899

89100
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
101+
102+
# Arguments used by KernelFiles.parse() function
103+
self.parse_args = {
104+
"file_list": [filename],
105+
"export_file": []
106+
}
107+
108+
# Arguments used by KernelFiles.msg() function
109+
self.msg_args = {
110+
"enable_lineno": True,
111+
"export": False,
112+
"internal": False,
113+
"symbol": [],
114+
"nosymbol": [],
115+
"no_doc_sections": False
116+
}
117+
90118
export_file_patterns = []
91119

92120
verbose = os.environ.get("V")
@@ -99,7 +127,8 @@ def run(self):
99127
# Tell sphinx of the dependency
100128
env.note_dependency(os.path.abspath(filename))
101129

102-
tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
130+
self.tab_width = self.options.get('tab-width',
131+
self.state.document.settings.tab_width)
103132

104133
# 'function' is an alias of 'identifiers'
105134
if 'functions' in self.options:
@@ -108,12 +137,16 @@ def run(self):
108137
# FIXME: make this nicer and more robust against errors
109138
if 'export' in self.options:
110139
cmd += ['-export']
140+
self.msg_args["export"] = True
111141
export_file_patterns = str(self.options.get('export')).split()
112142
elif 'internal' in self.options:
113143
cmd += ['-internal']
144+
self.msg_args["internal"] = True
114145
export_file_patterns = str(self.options.get('internal')).split()
115146
elif 'doc' in self.options:
116-
cmd += ['-function', str(self.options.get('doc'))]
147+
func = str(self.options.get('doc'))
148+
cmd += ['-function', func]
149+
self.msg_args["symbol"].append(func)
117150
elif 'identifiers' in self.options:
118151
identifiers = self.options.get('identifiers').split()
119152
if identifiers:
@@ -123,8 +156,10 @@ def run(self):
123156
continue
124157

125158
cmd += ['-function', i]
159+
self.msg_args["symbol"].append(i)
126160
else:
127161
cmd += ['-no-doc-sections']
162+
self.msg_args["no_doc_sections"] = True
128163

129164
if 'no-identifiers' in self.options:
130165
no_identifiers = self.options.get('no-identifiers').split()
@@ -135,6 +170,7 @@ def run(self):
135170
continue
136171

137172
cmd += ['-nosymbol', i]
173+
self.msg_args["nosymbol"].append(i)
138174

139175
for pattern in export_file_patterns:
140176
pattern = pattern.rstrip("\\").strip()
@@ -144,12 +180,29 @@ def run(self):
144180
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
145181
env.note_dependency(os.path.abspath(f))
146182
cmd += ['-export-file', f]
183+
self.parse_args["export_file"].append(f)
184+
185+
# Export file is needed by both parse and msg, as kernel-doc
186+
# cache exports.
187+
self.msg_args["export_file"] = self.parse_args["export_file"]
147188

148189
cmd += [filename]
149190

191+
return cmd
192+
193+
def run_cmd(self):
194+
"""
195+
Execute an external kernel-doc command.
196+
"""
197+
198+
env = self.state.document.settings.env
199+
cmd = self.handle_args()
200+
150201
if self.verbose >= 1:
151202
print(cmd_str(cmd))
152203

204+
node = nodes.section()
205+
153206
try:
154207
self.logger.verbose("calling kernel-doc '%s'" % (" ".join(cmd)))
155208

@@ -167,7 +220,29 @@ def run(self):
167220
elif env.config.kerneldoc_verbosity > 0:
168221
sys.stderr.write(err)
169222

170-
lines = statemachine.string2lines(out, tab_width, convert_whitespace=True)
223+
except Exception as e: # pylint: disable=W0703
224+
self.logger.warning("kernel-doc '%s' processing failed with: %s" %
225+
(" ".join(cmd), str(e)))
226+
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
227+
228+
filenames = self.parse_args["file_list"]
229+
for filename in filenames:
230+
ret = self.parse_msg(filename, node, out, cmd)
231+
if ret:
232+
return ret
233+
234+
return node.children
235+
236+
def parse_msg(self, filename, node, out, cmd):
237+
"""
238+
Handles a kernel-doc output for a given file
239+
"""
240+
241+
env = self.state.document.settings.env
242+
243+
try:
244+
lines = statemachine.string2lines(out, self.tab_width,
245+
convert_whitespace=True)
171246
result = ViewList()
172247

173248
lineoffset = 0;
@@ -183,27 +258,74 @@ def run(self):
183258
result.append(line, doc + ": " + filename, lineoffset)
184259
lineoffset += 1
185260

186-
node = nodes.section()
187261
self.do_parse(result, node)
188262

189-
return node.children
190-
191263
except Exception as e: # pylint: disable=W0703
192264
self.logger.warning("kernel-doc '%s' processing failed with: %s" %
193-
(" ".join(cmd), str(e)))
265+
(cmd_str(cmd), str(e)))
194266
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
195267

268+
return None
269+
270+
def run_kdoc(self, kfiles):
271+
"""
272+
Execute kernel-doc classes directly instead of running as a separate
273+
command.
274+
"""
275+
276+
cmd = self.handle_args()
277+
env = self.state.document.settings.env
278+
279+
node = nodes.section()
280+
281+
kfiles.parse(**self.parse_args)
282+
filenames = self.parse_args["file_list"]
283+
284+
for filename, out in kfiles.msg(**self.msg_args, filenames=filenames):
285+
if self.verbose >= 1:
286+
print(cmd_str(cmd))
287+
288+
ret = self.parse_msg(filename, node, out, cmd)
289+
if ret:
290+
return ret
291+
292+
return node.children
293+
294+
def run(self):
295+
global use_kfiles
296+
297+
if use_kfiles:
298+
out_style = RestFormat()
299+
kfiles = KernelFiles(out_style=out_style, logger=self.logger)
300+
return self.run_kdoc(kfiles)
301+
else:
302+
return self.run_cmd()
303+
196304
def do_parse(self, result, node):
197305
with switch_source_input(self.state, result):
198306
self.state.nested_parse(result, 0, node, match_titles=1)
199307

308+
def setup_kfiles(app):
309+
global use_kfiles
310+
311+
kerneldoc_bin = app.env.config.kerneldoc_bin
312+
313+
if kerneldoc_bin and kerneldoc_bin.endswith("kernel-doc.py"):
314+
print("Using Python kernel-doc")
315+
use_kfiles = True
316+
else:
317+
print(f"Using {kerneldoc_bin}")
318+
319+
200320
def setup(app):
201321
app.add_config_value('kerneldoc_bin', None, 'env')
202322
app.add_config_value('kerneldoc_srctree', None, 'env')
203323
app.add_config_value('kerneldoc_verbosity', 1, 'env')
204324

205325
app.add_directive('kernel-doc', KernelDocDirective)
206326

327+
app.connect('builder-inited', setup_kfiles)
328+
207329
return dict(
208330
version = __version__,
209331
parallel_read_safe = True,

0 commit comments

Comments
 (0)