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
|
#!/usr/bin/env python3
import sys
import argparse
import xml.etree.ElementTree as ET
from pathlib import Path
def register_all_namespaces(filename):
namespaces = dict([node for _, node in ET.iterparse(filename, events=['start-ns'])])
for ns in namespaces:
ET.register_namespace(ns, namespaces[ns])
def check_sections(args):
tree = ET.parse(args.gir)
root = tree.getroot()
register_all_namespaces(args.gir)
namespace = {
'goi': 'http://www.gtk.org/introspection/core/1.0',
'glib': 'http://www.gtk.org/introspection/glib/1.0',
}
namespace_node = root.find('goi:namespace', namespace)
file_dict = {}
for file in args.files:
content = Path(file).read_text()
comment_start_idx = content.find('<!-- ')
if comment_start_idx == -1:
print(f"ERROR: File '{file}' does not contain a HTML comment",
file=sys.stderr)
sys.exit(1)
comment_end_idx = content.find(' -->', comment_start_idx)
section_covers = content[comment_start_idx + 5:comment_end_idx]
file_dict[section_covers] = {'file': file, 'content': content}
tag_parser_dict = {
f'{{{namespace["goi"]}}}alias': lambda n, _ : f'[alias@{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}bitfield': lambda n, _ : f'[flags@{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}callback': lambda n, _ : f'[callback@{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}class': lambda n, _ : f'[class@{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}constructor': lambda n, p : f'[ctor@{p}{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}method': lambda n, p : f'[method@{p}{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}constant': lambda n, _ : f'[const@{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}enumeration': lambda n, _ : f'[enum@{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}function-macro': lambda n, _ : f'[func@{n.attrib["name"]}]',
f'{{{namespace["goi"]}}}function': lambda n, p : f'[func@{p}{n.attrib["name"]}]',
# each struct has its own documentation
# f'{{{namespace["goi"]}}}record': lambda n, _ : f'[struct@{n.attrib["name"]}]',
# struct and enum members do not need to be listed
# f'{{{namespace["goi"]}}}field': lambda n, p : f'[struct@Vips.{p}{n.attrib["name"]}]',
# f'{{{namespace["goi"]}}}member': lambda n, p : f'[enum@Vips.{p}{n.attrib["name"]}]',
}
exitcode = 0
parent_map = {c: p for p in namespace_node.iter() for c in p}
for node in parent_map:
if 'moved-to' in node.attrib:
continue
child = node.find('goi:doc', namespace)
if child is None:
continue
filename = child.attrib['filename']
section = next((k for k in file_dict.keys() if filename.startswith(k)), None)
if section is None:
continue
parser_method = tag_parser_dict.get(node.tag, None)
if parser_method is None:
continue
parent_name = parent_map.get(node, {}).attrib.get('name') or ''
if parent_name == 'Vips':
parent_name = ''
if parent_name:
parent_name += '.'
symbol = parser_method(node, parent_name)
if f'* {symbol}' not in file_dict[section]['content']:
print(f"ERROR: Symbol '{symbol}' is not listed in '{file_dict[section]['file']}'",
file=sys.stderr)
exitcode = 1
sys.exit(exitcode)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--gir', help='input GIR file', type=Path)
parser.add_argument('files', help='markdown files', type=Path, nargs=argparse.REMAINDER)
args = parser.parse_args()
check_sections(args)
if __name__ == '__main__':
main()
|