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