1#!/usr/bin/env python3 2# SPDX-License-Identifier: LGPL-2.1-or-later 3 4from __future__ import print_function 5import collections 6import glob 7import sys 8from pathlib import Path 9import pprint 10from xml_helper import xml_parse 11 12def man(page, number): 13 return '{}.{}'.format(page, number) 14 15def add_rules(rules, name): 16 xml = xml_parse(name) 17 # print('parsing {}'.format(name), file=sys.stderr) 18 if xml.getroot().tag != 'refentry': 19 return 20 conditional = xml.getroot().get('conditional') or '' 21 rulegroup = rules[conditional] 22 refmeta = xml.find('./refmeta') 23 title = refmeta.find('./refentrytitle').text 24 number = refmeta.find('./manvolnum').text 25 refnames = xml.findall('./refnamediv/refname') 26 target = man(refnames[0].text, number) 27 if title != refnames[0].text: 28 raise ValueError('refmeta and refnamediv disagree: ' + name) 29 for refname in refnames: 30 assert all(refname not in group 31 for group in rules.values()), "duplicate page name" 32 alias = man(refname.text, number) 33 rulegroup[alias] = target 34 # print('{} => {} [{}]'.format(alias, target, conditional), file=sys.stderr) 35 36def create_rules(xml_files): 37 " {conditional => {alias-name => source-name}} " 38 rules = collections.defaultdict(dict) 39 for name in xml_files: 40 try: 41 add_rules(rules, name) 42 except Exception: 43 print("Failed to process", name, file=sys.stderr) 44 raise 45 return rules 46 47def mjoin(files): 48 return ' \\\n\t'.join(sorted(files) or '#') 49 50MESON_HEADER = '''\ 51# SPDX-License-Identifier: LGPL-2.1-or-later 52 53# Do not edit. Generated by update-man-rules.py. 54# Update with: 55# ninja -C build update-man-rules 56manpages = [''' 57 58MESON_FOOTER = '''\ 59] 60# Really, do not edit. 61''' 62 63def make_mesonfile(rules, dist_files): 64 # reformat rules as 65 # grouped = [ [name, section, [alias...], condition], ...] 66 # 67 # but first create a dictionary like 68 # lists = { (name, condition) => [alias...] 69 grouped = collections.defaultdict(list) 70 for condition, items in rules.items(): 71 for alias, name in items.items(): 72 group = grouped[(name, condition)] 73 if name != alias: 74 group.append(alias) 75 76 lines = [ [p[0][:-2], p[0][-1], sorted(a[:-2] for a in aliases), p[1]] 77 for p, aliases in sorted(grouped.items()) ] 78 return '\n'.join((MESON_HEADER, pprint.pformat(lines)[1:-1], MESON_FOOTER)) 79 80if __name__ == '__main__': 81 source_glob = sys.argv[1] 82 target = Path(sys.argv[2]) 83 84 pages = glob.glob(source_glob) 85 pages = (p for p in pages 86 if Path(p).name not in { 87 'systemd.directives.xml', 88 'systemd.index.xml', 89 'directives-template.xml'}) 90 91 rules = create_rules(pages) 92 dist_files = (Path(p).name for p in pages) 93 text = make_mesonfile(rules, dist_files) 94 95 tmp = target.with_suffix('.tmp') 96 tmp.write_text(text) 97 tmp.rename(target) 98