docs: sphinx/kernel_abi: parse ABI files only once
Right now, the logic parses ABI files on 4 steps, one for each directory. While this is fine in principle, by doing that, not all symbol cross-references will be created. Change the logic to do the parsing only once in order to get a global dictionary to be used when creating ABI cross-references. Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet <corbet@lwn.net> Link: https://lore.kernel.org/r/5205c53838b6ea25f4cdd4cc1e3d17c0141e75a6.1739182025.git.mchehab+huawei@kernel.orgpull/1183/head
parent
98a4324a8b
commit
5d7871d77f
|
|
@ -9,4 +9,4 @@ marked to be removed at some later point in time.
|
||||||
The description of the interface will document the reason why it is
|
The description of the interface will document the reason why it is
|
||||||
obsolete and when it can be expected to be removed.
|
obsolete and when it can be expected to be removed.
|
||||||
|
|
||||||
.. kernel-abi:: ABI/obsolete
|
.. kernel-abi:: obsolete
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
ABI removed symbols
|
ABI removed symbols
|
||||||
===================
|
===================
|
||||||
|
|
||||||
.. kernel-abi:: ABI/removed
|
.. kernel-abi:: removed
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,4 @@ for at least 2 years.
|
||||||
Most interfaces (like syscalls) are expected to never change and always
|
Most interfaces (like syscalls) are expected to never change and always
|
||||||
be available.
|
be available.
|
||||||
|
|
||||||
.. kernel-abi:: ABI/stable
|
.. kernel-abi:: stable
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,4 @@ Programs that use these interfaces are strongly encouraged to add their
|
||||||
name to the description of these interfaces, so that the kernel
|
name to the description of these interfaces, so that the kernel
|
||||||
developers can easily notify them if any changes occur.
|
developers can easily notify them if any changes occur.
|
||||||
|
|
||||||
.. kernel-abi:: ABI/testing
|
.. kernel-abi:: testing
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,13 @@ from abi_parser import AbiParser
|
||||||
|
|
||||||
__version__ = "1.0"
|
__version__ = "1.0"
|
||||||
|
|
||||||
|
logger = logging.getLogger('kernel_abi')
|
||||||
|
path = os.path.join(srctree, "Documentation/ABI")
|
||||||
|
|
||||||
|
# Parse ABI symbols only once
|
||||||
|
kernel_abi = AbiParser(path, logger=logger)
|
||||||
|
kernel_abi.parse_abi()
|
||||||
|
kernel_abi.check_issues()
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
|
|
||||||
|
|
@ -64,14 +71,15 @@ class KernelCmd(Directive):
|
||||||
u"""KernelABI (``kernel-abi``) directive"""
|
u"""KernelABI (``kernel-abi``) directive"""
|
||||||
|
|
||||||
required_arguments = 1
|
required_arguments = 1
|
||||||
optional_arguments = 2
|
optional_arguments = 3
|
||||||
has_content = False
|
has_content = False
|
||||||
final_argument_whitespace = True
|
final_argument_whitespace = True
|
||||||
logger = logging.getLogger('kernel_abi')
|
|
||||||
parser = None
|
parser = None
|
||||||
|
|
||||||
option_spec = {
|
option_spec = {
|
||||||
"debug": directives.flag,
|
"debug": directives.flag,
|
||||||
|
"no-symbols": directives.flag,
|
||||||
|
"no-files": directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
@ -79,62 +87,67 @@ class KernelCmd(Directive):
|
||||||
if not doc.settings.file_insertion_enabled:
|
if not doc.settings.file_insertion_enabled:
|
||||||
raise self.warning("docutils: file insertion disabled")
|
raise self.warning("docutils: file insertion disabled")
|
||||||
|
|
||||||
path = os.path.join(srctree, "Documentation", self.arguments[0])
|
|
||||||
self.parser = AbiParser(path, logger=self.logger)
|
|
||||||
self.parser.parse_abi()
|
|
||||||
self.parser.check_issues()
|
|
||||||
|
|
||||||
node = self.nested_parse(None, self.arguments[0])
|
|
||||||
return node
|
|
||||||
|
|
||||||
def nested_parse(self, data, fname):
|
|
||||||
env = self.state.document.settings.env
|
env = self.state.document.settings.env
|
||||||
content = ViewList()
|
content = ViewList()
|
||||||
node = nodes.section()
|
node = nodes.section()
|
||||||
|
|
||||||
if data is not None:
|
abi_type = self.arguments[0]
|
||||||
# Handles the .rst file
|
|
||||||
for line in data.split("\n"):
|
|
||||||
content.append(line, fname, 0)
|
|
||||||
|
|
||||||
self.do_parse(content, node)
|
|
||||||
|
|
||||||
|
if "no-symbols" in self.options:
|
||||||
|
show_symbols = False
|
||||||
else:
|
else:
|
||||||
# Handles the ABI parser content, symbol by symbol
|
show_symbols = True
|
||||||
|
|
||||||
old_f = fname
|
if "no-files" in self.options:
|
||||||
n = 0
|
show_file = False
|
||||||
for msg, f, ln in self.parser.doc():
|
else:
|
||||||
msg_list = statemachine.string2lines(msg, tab_width,
|
show_file = True
|
||||||
convert_whitespace=True)
|
|
||||||
if "debug" in self.options:
|
|
||||||
lines = [
|
|
||||||
"", "", ".. code-block:: rst",
|
|
||||||
" :linenos:", ""
|
|
||||||
]
|
|
||||||
for m in msg_list:
|
|
||||||
lines.append(" " + m)
|
|
||||||
else:
|
|
||||||
lines = msg_list
|
|
||||||
|
|
||||||
for line in lines:
|
tab_width = self.options.get('tab-width',
|
||||||
# sphinx counts lines from 0
|
self.state.document.settings.tab_width)
|
||||||
content.append(line, f, ln - 1)
|
|
||||||
n += 1
|
|
||||||
|
|
||||||
if f != old_f:
|
old_f = None
|
||||||
# Add the file to Sphinx build dependencies
|
n = 0
|
||||||
env.note_dependency(os.path.abspath(f))
|
n_sym = 0
|
||||||
|
for msg, f, ln in kernel_abi.doc(show_file=show_file,
|
||||||
|
show_symbols=show_symbols,
|
||||||
|
filter_path=abi_type):
|
||||||
|
n_sym += 1
|
||||||
|
msg_list = statemachine.string2lines(msg, tab_width,
|
||||||
|
convert_whitespace=True)
|
||||||
|
if "debug" in self.options:
|
||||||
|
lines = [
|
||||||
|
"", "", ".. code-block:: rst",
|
||||||
|
" :linenos:", ""
|
||||||
|
]
|
||||||
|
for m in msg_list:
|
||||||
|
lines.append(" " + m)
|
||||||
|
else:
|
||||||
|
lines = msg_list
|
||||||
|
|
||||||
old_f = f
|
for line in lines:
|
||||||
|
# sphinx counts lines from 0
|
||||||
|
content.append(line, f, ln - 1)
|
||||||
|
n += 1
|
||||||
|
|
||||||
# Sphinx doesn't like to parse big messages. So, let's
|
if f != old_f:
|
||||||
# add content symbol by symbol
|
# Add the file to Sphinx build dependencies
|
||||||
if content:
|
env.note_dependency(os.path.abspath(f))
|
||||||
self.do_parse(content, node)
|
|
||||||
content = ViewList()
|
|
||||||
|
|
||||||
self.logger.info("%s: parsed %i lines" % (fname, n))
|
old_f = f
|
||||||
|
|
||||||
|
# Sphinx doesn't like to parse big messages. So, let's
|
||||||
|
# add content symbol by symbol
|
||||||
|
if content:
|
||||||
|
self.do_parse(content, node)
|
||||||
|
content = ViewList()
|
||||||
|
|
||||||
|
if show_symbols and not show_file:
|
||||||
|
logger.verbose("%s ABI: %i symbols (%i ReST lines)" % (abi_type, n_sym, n))
|
||||||
|
elif not show_symbols and show_file:
|
||||||
|
logger.verbose("%s ABI: %i files (%i ReST lines)" % (abi_type, n_sym, n))
|
||||||
|
else:
|
||||||
|
logger.verbose("%s ABI: %i data (%i ReST lines)" % (abi_type, n_sym, n))
|
||||||
|
|
||||||
return node.children
|
return node.children
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -266,12 +266,20 @@ class AbiParser:
|
||||||
def parse_readme(self, nametag, fname):
|
def parse_readme(self, nametag, fname):
|
||||||
"""Parse ABI README file"""
|
"""Parse ABI README file"""
|
||||||
|
|
||||||
|
nametag["what"] = ["ABI file contents"]
|
||||||
|
nametag["path"] = "README"
|
||||||
with open(fname, "r", encoding="utf8", errors="backslashreplace") as fp:
|
with open(fname, "r", encoding="utf8", errors="backslashreplace") as fp:
|
||||||
nametag["description"] = "```\n"
|
|
||||||
for line in fp:
|
for line in fp:
|
||||||
nametag["description"] += " " + line
|
match = self.re_tag.match(line)
|
||||||
|
if match:
|
||||||
|
new = match.group(1).lower()
|
||||||
|
|
||||||
nametag["description"] += "```\n"
|
match = self.re_valid.search(new)
|
||||||
|
if match:
|
||||||
|
nametag["description"] += "\n:" + line
|
||||||
|
continue
|
||||||
|
|
||||||
|
nametag["description"] += line
|
||||||
|
|
||||||
def parse_file(self, fname, path, basename):
|
def parse_file(self, fname, path, basename):
|
||||||
"""Parse a single file"""
|
"""Parse a single file"""
|
||||||
|
|
@ -459,12 +467,8 @@ class AbiParser:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if filter_path:
|
if filter_path:
|
||||||
if filter_path == "README":
|
if v.get("path") != filter_path:
|
||||||
if not names[0].endswith("README"):
|
continue
|
||||||
continue
|
|
||||||
else:
|
|
||||||
if v.get("path") != filter_path:
|
|
||||||
continue
|
|
||||||
|
|
||||||
msg = ""
|
msg = ""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue