1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1-or-later
import os
import sys
try:
import lxml.etree as tree
except ImportError as e:
print(str(e), file=sys.stderr)
sys.exit(77)
_parser = tree.XMLParser(resolve_entities=False)
tree.set_default_parser(_parser)
def find_undocumented_functions(pages, ignorelist):
undocumented = []
for page in pages:
filename = os.path.basename(page)
pagetree = tree.parse(page)
assert pagetree.getroot().tag == "refentry"
hist_section = pagetree.find("refsect1[title='History']")
for func in pagetree.findall(".//funcprototype/funcdef/function"):
path = f"./refsynopsisdiv/funcsynopsis/funcprototype/funcdef/function[.='{func.text}']"
assert pagetree.findall(path) == [func]
if (
hist_section is None
or hist_section.find(f"para/function[.='{func.text}()']") is None
):
if func.text not in ignorelist:
undocumented.append((filename, func.text))
return undocumented
def construct_path(element):
tag = element.tag
if tag == "refentry":
return "."
predicate = ""
if tag == "varlistentry":
text = "".join(element.find("term").itertext())
predicate = f'[term="{text}"]'
elif tag.startswith("refsect"):
text = "".join(element.find("title").itertext())
predicate = f'[title="{text}"]'
elif tag == "variablelist":
varlists = element.getparent().findall(tag)
if len(varlists) > 1:
predicate = f"[{varlists.index(element)+1}]"
return construct_path(element.getparent()) + "/" + tag + predicate
def find_undocumented_commands(pages, ignorelist):
undocumented = []
for page in pages:
filename = os.path.basename(page)
pagetree = tree.parse(page)
if pagetree.getroot().tag != "refentry":
continue
for varlistentry in pagetree.findall("*//variablelist/varlistentry"):
path = construct_path(varlistentry)
assert pagetree.findall(path) == [varlistentry]
listitem = varlistentry.find("listitem")
parent = listitem if listitem is not None else varlistentry
rev = parent.getchildren()[-1]
if (
rev.get("href") != "version-info.xml" and
not path.startswith(tuple(entry[1] for entry in ignorelist if entry[0] == filename))
):
undocumented.append((filename, path))
return undocumented
def process_pages(pages):
command_pages = []
function_pages = []
for page in pages:
filename = os.path.basename(page)
if filename.startswith("org.freedesktop."): # dbus
continue
if (
filename.startswith("sd_")
or filename.startswith("sd-")
or filename.startswith("udev_")
):
function_pages.append(page)
continue
command_pages.append(page)
undocumented_commands = find_undocumented_commands(
command_pages, command_ignorelist
)
undocumented_functions = find_undocumented_functions(
function_pages, function_ignorelist
)
return undocumented_commands, undocumented_functions
if __name__ == "__main__":
with open(os.path.join(os.path.dirname(__file__), "command_ignorelist")) as f:
command_ignorelist = []
for l in f.read().splitlines():
if l.startswith("#"):
continue
fname, path = l.split(" ", 1)
path = path.replace("\\n", "\n")
command_ignorelist.append((fname, path))
with open(os.path.join(os.path.dirname(__file__), "function_ignorelist")) as f:
function_ignorelist = f.read().splitlines()
undocumented_commands, undocumented_functions = process_pages(sys.argv[1:])
if undocumented_commands or undocumented_functions:
for filename, func in undocumented_functions:
print(
f"Function {func}() in {filename} isn't documented in the History section."
)
for filename, path in undocumented_commands:
print(filename, path, "is undocumented")
if undocumented_commands:
print(
"Hint: if you reorganized this part of the documentation, "
"please update tools/commands_ignorelist."
)
sys.exit(1)
|