1#!/usr/bin/env python3
2# SPDX-License-Identifier: LGPL-2.1-or-later
3
4import collections
5import sys
6import re
7from xml_helper import xml_parse, xml_print, tree
8
9MDASH = ' — ' if sys.version_info.major >= 3 else ' -- '
10
11TEMPLATE = '''\
12<refentry id="systemd.index">
13
14  <refentryinfo>
15    <title>systemd.index</title>
16    <productname>systemd</productname>
17  </refentryinfo>
18
19  <refmeta>
20    <refentrytitle>systemd.index</refentrytitle>
21    <manvolnum>7</manvolnum>
22  </refmeta>
23
24  <refnamediv>
25    <refname>systemd.index</refname>
26    <refpurpose>List all manpages from the systemd project</refpurpose>
27  </refnamediv>
28</refentry>
29'''
30
31SUMMARY = '''\
32  <refsect1>
33    <title>See Also</title>
34    <para>
35      <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
36    </para>
37
38    <para id='counts' />
39  </refsect1>
40'''
41
42COUNTS = '\
43This index contains {count} entries, referring to {pages} individual manual pages.'
44
45
46def check_id(page, t):
47    id = t.getroot().get('id')
48    if not re.search('/' + id + '[.]', page):
49        raise ValueError("id='{}' is not the same as page name '{}'".format(id, page))
50
51def make_index(pages):
52    index = collections.defaultdict(list)
53    for p in pages:
54        t = xml_parse(p)
55        check_id(p, t)
56        section = t.find('./refmeta/manvolnum').text
57        refname = t.find('./refnamediv/refname').text
58        purpose_text = ' '.join(t.find('./refnamediv/refpurpose').itertext())
59        purpose = ' '.join(purpose_text.split())
60        for f in t.findall('./refnamediv/refname'):
61            infos = (f.text, section, purpose, refname)
62            index[f.text[0].upper()].append(infos)
63    return index
64
65def add_letter(template, letter, pages):
66    refsect1 = tree.SubElement(template, 'refsect1')
67    title = tree.SubElement(refsect1, 'title')
68    title.text = letter
69    para = tree.SubElement(refsect1, 'para')
70    for info in sorted(pages, key=lambda info: str.lower(info[0])):
71        refname, section, purpose, realname = info
72
73        b = tree.SubElement(para, 'citerefentry')
74        c = tree.SubElement(b, 'refentrytitle')
75        c.text = refname
76        d = tree.SubElement(b, 'manvolnum')
77        d.text = section
78
79        b.tail = MDASH + purpose # + ' (' + p + ')'
80
81        tree.SubElement(para, 'sbr')
82
83def add_summary(template, indexpages):
84    count = 0
85    pages = set()
86    for group in indexpages:
87        count += len(group)
88        for info in group:
89            refname, section, purpose, realname = info
90            pages.add((realname, section))
91
92    refsect1 = tree.fromstring(SUMMARY)
93    template.append(refsect1)
94
95    para = template.find(".//para[@id='counts']")
96    para.text = COUNTS.format(count=count, pages=len(pages))
97
98def make_page(*xml_files):
99    template = tree.fromstring(TEMPLATE)
100    index = make_index(xml_files)
101
102    for letter in sorted(index):
103        add_letter(template, letter, index[letter])
104
105    add_summary(template, index.values())
106
107    return template
108
109if __name__ == '__main__':
110    with open(sys.argv[1], 'wb') as f:
111        f.write(xml_print(make_page(*sys.argv[2:])))
112