Note that make-man-rules.py is missing in EXTRA_DIST=, this patch fixes this mistake too. --- Makefile.am | 13 +- make-directive-index.py | 320 ------------------------------------------ make-man-index.py | 136 ------------------ make-man-rules.py | 113 --------------- tools/make-directive-index.py | 320 ++++++++++++++++++++++++++++++++++++++++++ tools/make-man-index.py | 136 ++++++++++++++++++ tools/make-man-rules.py | 113 +++++++++++++++ tools/xml_helper.py | 41 ++++++ xml_helper.py | 41 ------ 9 files changed, 617 insertions(+), 616 deletions(-) delete mode 100755 make-directive-index.py delete mode 100755 make-man-index.py delete mode 100644 make-man-rules.py create mode 100755 tools/make-directive-index.py create mode 100755 tools/make-man-index.py create mode 100644 tools/make-man-rules.py create mode 100644 tools/xml_helper.py delete mode 100644 xml_helper.py
diff --git a/Makefile.am b/Makefile.am index 4f5e036..e3c1145 100644 --- a/Makefile.am +++ b/Makefile.am @@ -610,16 +610,16 @@ XML_GLOB = $(wildcard $(top_srcdir)/man/*.xml $(top_builddir)/man/*.xml) NON_INDEX_XML_FILES = $(filter-out man/systemd.index.xml,$(XML_FILES)) SOURCE_XML_FILES = $(filter-out man/systemd.directives.xml,$(NON_INDEX_XML_FILES)) -update-man-list: make-man-rules.py $(XML_GLOB) +update-man-list: $(top_srcdir)/tools/make-man-rules.py $(XML_GLOB) $(AM_V_GEN)$(PYTHON) $^ > $(top_srcdir)/Makefile-man.tmp $(AM_V_at)mv $(top_srcdir)/Makefile-man.tmp $(top_srcdir)/Makefile-man.am @echo "Makefile-man.am has been regenerated" -man/systemd.index.xml: make-man-index.py $(NON_INDEX_XML_FILES) +man/systemd.index.xml: $(top_srcdir)/tools/make-man-index.py $(NON_INDEX_XML_FILES) $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_GEN)$(PYTHON) $< $@ $(filter-out $<,$^) -man/systemd.directives.xml: make-directive-index.py $(SOURCE_XML_FILES) +man/systemd.directives.xml: $(top_srcdir)/tools/make-directive-index.py $(SOURCE_XML_FILES) $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_GEN)$(PYTHON) $< $@ $(filter-out $<,$^) @@ -641,9 +641,10 @@ EXTRA_DIST += \ $(HTML_FILES) \ $(HTML_ALIAS) \ $(man_MANS) \ - make-man-index.py \ - make-directive-index.py \ - xml_helper.py + tools/make-man-index.py \ + tools/make-directive-index.py \ + tools/make-man-rules.py \ + tools/xml_helper.py # ------------------------------------------------------------------------------ noinst_LTLIBRARIES += \ diff --git a/make-directive-index.py b/make-directive-index.py deleted file mode 100755 index 2ff304f..0000000 --- a/make-directive-index.py +++ /dev/null @@ -1,320 +0,0 @@ -# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ -# -# This file is part of systemd. -# -# Copyright 2012-2013 Zbigniew J??drzejewski-Szmek -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# systemd is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with systemd; If not, see <http://www.gnu.org/licenses/>. - -import sys -import collections -import re -from xml_helper import * -from copy import deepcopy - -TEMPLATE = '''\ -<refentry id="systemd.directives" conditional="HAVE_PYTHON"> - - <refentryinfo> - <title>systemd.directives</title> - <productname>systemd</productname> - - <authorgroup> - <author> - <contrib>Developer</contrib> - <firstname>Zbigniew</firstname> - <surname>J??drzejewski-Szmek</surname> - <email>zbys...@in.waw.pl</email> - </author> - </authorgroup> - </refentryinfo> - - <refmeta> - <refentrytitle>systemd.directives</refentrytitle> - <manvolnum>7</manvolnum> - </refmeta> - - <refnamediv> - <refname>systemd.directives</refname> - <refpurpose>Index of configuration directives</refpurpose> - </refnamediv> - - <refsect1> - <title>Unit directives</title> - - <para>Directives for configuring units, used in unit - files.</para> - - <variablelist id='unit-directives' /> - </refsect1> - - <refsect1> - <title>Options on the kernel command line</title> - - <para>Kernel boot options for configuring the behaviour of the - systemd process.</para> - - <variablelist id='kernel-commandline-options' /> - </refsect1> - - <refsect1> - <title>Environment variables</title> - - <para>Environment variables understood by the systemd - manager and other programs.</para> - - <variablelist id='environment-variables' /> - </refsect1> - - <refsect1> - <title>UDEV directives</title> - - <para>Directives for configuring systemd units through the - udev database.</para> - - <variablelist id='udev-directives' /> - </refsect1> - - <refsect1> - <title>Network directives</title> - - <para>Directives for configuring network links through the - net-setup-link udev builtin and networks through - systemd-networkd.</para> - - <variablelist id='network-directives' /> - </refsect1> - - <refsect1> - <title>Journal fields</title> - - <para>Fields in the journal events with a well known meaning.</para> - - <variablelist id='journal-directives' /> - </refsect1> - - <refsect1> - <title>PAM configuration directives</title> - - <para>Directives for configuring PAM behaviour.</para> - - <variablelist id='pam-directives' /> - </refsect1> - - <refsect1> - <title>crypttab options</title> - - <para>Options which influence mounted filesystems and - encrypted volumes.</para> - - <variablelist id='crypttab-options' /> - </refsect1> - - <refsect1> - <title>System manager directives</title> - - <para>Directives for configuring the behaviour of the - systemd process.</para> - - <variablelist id='systemd-directives' /> - </refsect1> - - <refsect1> - <title>bootchart.conf directives</title> - - <para>Directives for configuring the behaviour of the - systemd-bootchart process.</para> - - <variablelist id='bootchart-directives' /> - </refsect1> - - <refsect1> - <title>command-line options</title> - - <para>Command-line options accepted by programs in the - systemd suite.</para> - - <variablelist id='options' /> - </refsect1> - - <refsect1> - <title>Constants</title> - - <para>Various constant used and/or defined by systemd.</para> - - <variablelist id='constants' /> - </refsect1> - - <refsect1> - <title>Miscellaneous options and directives</title> - - <para>Other configuration elements which don't fit in - any of the above groups.</para> - - <variablelist id='miscellaneous' /> - </refsect1> - - <refsect1> - <title>Files and directories</title> - - <para>Paths and file names referred to in the - documentation.</para> - - <variablelist id='filenames' /> - </refsect1> - - <refsect1> - <title>Colophon</title> - <para id='colophon' /> - </refsect1> -</refentry> -''' - -COLOPHON = '''\ -This index contains {count} entries in {sections} sections, -referring to {pages} individual manual pages. -''' - -def _extract_directives(directive_groups, formatting, page): - t = xml_parse(page) - section = t.find('./refmeta/manvolnum').text - pagename = t.find('./refmeta/refentrytitle').text - - storopt = directive_groups['options'] - for variablelist in t.iterfind('.//variablelist'): - klass = variablelist.attrib.get('class') - storvar = directive_groups[klass or 'miscellaneous'] - # <option>s go in OPTIONS, unless class is specified - for xpath, stor in (('./varlistentry/term/varname', storvar), - ('./varlistentry/term/option', - storvar if klass else storopt)): - for name in variablelist.iterfind(xpath): - text = re.sub(r'([= ]).*', r'\1', name.text).rstrip() - stor[text].append((pagename, section)) - if text not in formatting: - # use element as formatted display - if name.text[-1] in '= ': - name.clear() - else: - name.tail = '' - name.text = text - formatting[text] = name - - storfile = directive_groups['filenames'] - for xpath, absolute_only in (('.//refsynopsisdiv//filename', False), - ('.//refsynopsisdiv//command', False), - ('.//filename', True)): - for name in t.iterfind(xpath): - if absolute_only and not (name.text and name.text.startswith('/')): - continue - if name.attrib.get('noindex'): - continue - name.tail = '' - if name.text: - if name.text.endswith('*'): - name.text = name.text[:-1] - if not name.text.startswith('.'): - text = name.text.partition(' ')[0] - if text != name.text: - name.clear() - name.text = text - if text.endswith('/'): - text = text[:-1] - storfile[text].append((pagename, section)) - if text not in formatting: - # use element as formatted display - formatting[text] = name - else: - text = ' '.join(name.itertext()) - storfile[text].append((pagename, section)) - formatting[text] = name - - storfile = directive_groups['constants'] - for name in t.iterfind('.//constant'): - if name.attrib.get('noindex'): - continue - name.tail = '' - if name.text.startswith('('): # a cast, strip it - name.text = name.text.partition(' ')[2] - storfile[name.text].append((pagename, section)) - formatting[name.text] = name - -def _make_section(template, name, directives, formatting): - varlist = template.find(".//*[@id='{}']".format(name)) - for varname, manpages in sorted(directives.items()): - entry = tree.SubElement(varlist, 'varlistentry') - term = tree.SubElement(entry, 'term') - display = deepcopy(formatting[varname]) - term.append(display) - - para = tree.SubElement(tree.SubElement(entry, 'listitem'), 'para') - - b = None - for manpage, manvolume in sorted(set(manpages)): - if b is not None: - b.tail = ', ' - b = tree.SubElement(para, 'citerefentry') - c = tree.SubElement(b, 'refentrytitle') - c.text = manpage - d = tree.SubElement(b, 'manvolnum') - d.text = manvolume - entry.tail = '\n\n' - -def _make_colophon(template, groups): - count = 0 - pages = set() - for group in groups: - count += len(group) - for pagelist in group.values(): - pages |= set(pagelist) - - para = template.find(".//para[@id='colophon']") - para.text = COLOPHON.format(count=count, - sections=len(groups), - pages=len(pages)) - -def _make_page(template, directive_groups, formatting): - """Create an XML tree from directive_groups. - - directive_groups = { - 'class': {'variable': [('manpage', 'manvolume'), ...], - 'variable2': ...}, - ... - } - """ - for name, directives in directive_groups.items(): - _make_section(template, name, directives, formatting) - - _make_colophon(template, directive_groups.values()) - - return template - -def make_page(*xml_files): - "Extract directives from xml_files and return XML index tree." - template = tree.fromstring(TEMPLATE) - names = [vl.get('id') for vl in template.iterfind('.//variablelist')] - directive_groups = {name:collections.defaultdict(list) - for name in names} - formatting = {} - for page in xml_files: - try: - _extract_directives(directive_groups, formatting, page) - except Exception: - raise ValueError("failed to process " + page) - - return _make_page(template, directive_groups, formatting) - -if __name__ == '__main__': - with open(sys.argv[1], 'wb') as f: - f.write(xml_print(make_page(*sys.argv[2:]))) diff --git a/make-man-index.py b/make-man-index.py deleted file mode 100755 index 74a47b8..0000000 --- a/make-man-index.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ -# -# This file is part of systemd. -# -# Copyright 2012 Lennart Poettering -# Copyright 2013 Zbigniew J??drzejewski-Szmek -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# systemd is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with systemd; If not, see <http://www.gnu.org/licenses/>. - -import collections -import sys -import re -from xml_helper import * - -MDASH = ' ??? ' if sys.version_info.major >= 3 else ' -- ' - -TEMPLATE = '''\ -<refentry id="systemd.index" conditional="HAVE_PYTHON"> - - <refentryinfo> - <title>systemd.index</title> - <productname>systemd</productname> - - <authorgroup> - <author> - <contrib>Developer</contrib> - <firstname>Lennart</firstname> - <surname>Poettering</surname> - <email>lenn...@poettering.net</email> - </author> - </authorgroup> - </refentryinfo> - - <refmeta> - <refentrytitle>systemd.index</refentrytitle> - <manvolnum>7</manvolnum> - </refmeta> - - <refnamediv> - <refname>systemd.index</refname> - <refpurpose>List all manpages from the systemd project</refpurpose> - </refnamediv> -</refentry> -''' - -SUMMARY = '''\ - <refsect1> - <title>See Also</title> - <para> - <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry> - </para> - - <para id='counts' /> - </refsect1> -''' - -COUNTS = '\ -This index contains {count} entries, referring to {pages} individual manual pages.' - - -def check_id(page, t): - id = t.getroot().get('id') - if not re.search('/' + id + '[.]', page): - raise ValueError("id='{}' is not the same as page name '{}'".format(id, page)) - -def make_index(pages): - index = collections.defaultdict(list) - for p in pages: - t = xml_parse(p) - check_id(p, t) - section = t.find('./refmeta/manvolnum').text - refname = t.find('./refnamediv/refname').text - purpose = ' '.join(t.find('./refnamediv/refpurpose').text.split()) - for f in t.findall('./refnamediv/refname'): - infos = (f.text, section, purpose, refname) - index[f.text[0].upper()].append(infos) - return index - -def add_letter(template, letter, pages): - refsect1 = tree.SubElement(template, 'refsect1') - title = tree.SubElement(refsect1, 'title') - title.text = letter - para = tree.SubElement(refsect1, 'para') - for info in sorted(pages, key=lambda info: str.lower(info[0])): - refname, section, purpose, realname = info - - b = tree.SubElement(para, 'citerefentry') - c = tree.SubElement(b, 'refentrytitle') - c.text = refname - d = tree.SubElement(b, 'manvolnum') - d.text = section - - b.tail = MDASH + purpose # + ' (' + p + ')' - - tree.SubElement(para, 'sbr') - -def add_summary(template, indexpages): - count = 0 - pages = set() - for group in indexpages: - count += len(group) - for info in group: - refname, section, purpose, realname = info - pages.add((realname, section)) - - refsect1 = tree.fromstring(SUMMARY) - template.append(refsect1) - - para = template.find(".//para[@id='counts']") - para.text = COUNTS.format(count=count, pages=len(pages)) - -def make_page(*xml_files): - template = tree.fromstring(TEMPLATE) - index = make_index(xml_files) - - for letter in sorted(index): - add_letter(template, letter, index[letter]) - - add_summary(template, index.values()) - - return template - -if __name__ == '__main__': - with open(sys.argv[1], 'wb') as f: - f.write(xml_print(make_page(*sys.argv[2:]))) diff --git a/make-man-rules.py b/make-man-rules.py deleted file mode 100644 index 0d1ca24..0000000 --- a/make-man-rules.py +++ /dev/null @@ -1,113 +0,0 @@ -# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ -# -# This file is part of systemd. -# -# Copyright 2013 Zbigniew J??drzejewski-Szmek -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# systemd is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with systemd; If not, see <http://www.gnu.org/licenses/>. - -from __future__ import print_function -import collections -import sys -import os.path -from xml_helper import * - -SECTION = '''\ -MANPAGES += \\ - {manpages} -MANPAGES_ALIAS += \\ - {aliases} -{rules} -{htmlrules} -''' - -CONDITIONAL = '''\ -if {conditional} -''' \ -+ SECTION + \ -'''\ -endif -''' - -HEADER = '''\ -# Do not edit. Generated by make-man-rules.py. -# Regenerate with 'make all update-man-list'. - -''' - -HTML_ALIAS_RULE = '''\ -{}.html: {}.html - $(html-alias) -''' - -FOOTER = '''\ - -EXTRA_DIST += \\ - {files} -''' - -def man(page, number): - return 'man/{}.{}'.format(page, number) - -def xml(file): - return 'man/{}'.format(os.path.basename(file)) - -def add_rules(rules, name): - xml = xml_parse(name) - # print('parsing {}'.format(name), file=sys.stderr) - conditional = xml.getroot().get('conditional') or '' - rulegroup = rules[conditional] - refmeta = xml.find('./refmeta') - title = refmeta.find('./refentrytitle').text - number = refmeta.find('./manvolnum').text - refnames = xml.findall('./refnamediv/refname') - target = man(refnames[0].text, number) - if title != refnames[0].text: - raise ValueError('refmeta and refnamediv disagree: ' + name) - for refname in refnames: - assert all(refname not in group - for group in rules.values()), "duplicate page name" - alias = man(refname.text, number) - rulegroup[alias] = target - # print('{} => {} [{}]'.format(alias, target, conditional), file=sys.stderr) - -def create_rules(xml_files): - " {conditional => {alias-name => source-name}} " - rules = collections.defaultdict(dict) - for name in xml_files: - add_rules(rules, name) - return rules - -def mjoin(files): - return ' \\\n\t'.join(sorted(files) or '#') - -def make_makefile(rules, files): - return HEADER + '\n'.join( - (CONDITIONAL if conditional else SECTION).format( - manpages=mjoin(set(rulegroup.values())), - aliases=mjoin(k for k,v in rulegroup.items() if k != v), - rules='\n'.join('{}: {}'.format(k,v) - for k,v in sorted(rulegroup.items()) - if k != v), - htmlrules='\n'.join(HTML_ALIAS_RULE.format(k[:-2],v[:-2]) - for k,v in sorted(rulegroup.items()) - if k != v), - conditional=conditional) - for conditional,rulegroup in sorted(rules.items()) - ) + FOOTER.format(files=mjoin(sorted(files))) - -if __name__ == '__main__': - rules = create_rules(sys.argv[1:]) - files = (xml(file) for file in sys.argv[1:]) - print(make_makefile(rules, files), end='') diff --git a/tools/make-directive-index.py b/tools/make-directive-index.py new file mode 100755 index 0000000..2ff304f --- /dev/null +++ b/tools/make-directive-index.py @@ -0,0 +1,320 @@ +# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2012-2013 Zbigniew J??drzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +import sys +import collections +import re +from xml_helper import * +from copy import deepcopy + +TEMPLATE = '''\ +<refentry id="systemd.directives" conditional="HAVE_PYTHON"> + + <refentryinfo> + <title>systemd.directives</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Zbigniew</firstname> + <surname>J??drzejewski-Szmek</surname> + <email>zbys...@in.waw.pl</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>systemd.directives</refentrytitle> + <manvolnum>7</manvolnum> + </refmeta> + + <refnamediv> + <refname>systemd.directives</refname> + <refpurpose>Index of configuration directives</refpurpose> + </refnamediv> + + <refsect1> + <title>Unit directives</title> + + <para>Directives for configuring units, used in unit + files.</para> + + <variablelist id='unit-directives' /> + </refsect1> + + <refsect1> + <title>Options on the kernel command line</title> + + <para>Kernel boot options for configuring the behaviour of the + systemd process.</para> + + <variablelist id='kernel-commandline-options' /> + </refsect1> + + <refsect1> + <title>Environment variables</title> + + <para>Environment variables understood by the systemd + manager and other programs.</para> + + <variablelist id='environment-variables' /> + </refsect1> + + <refsect1> + <title>UDEV directives</title> + + <para>Directives for configuring systemd units through the + udev database.</para> + + <variablelist id='udev-directives' /> + </refsect1> + + <refsect1> + <title>Network directives</title> + + <para>Directives for configuring network links through the + net-setup-link udev builtin and networks through + systemd-networkd.</para> + + <variablelist id='network-directives' /> + </refsect1> + + <refsect1> + <title>Journal fields</title> + + <para>Fields in the journal events with a well known meaning.</para> + + <variablelist id='journal-directives' /> + </refsect1> + + <refsect1> + <title>PAM configuration directives</title> + + <para>Directives for configuring PAM behaviour.</para> + + <variablelist id='pam-directives' /> + </refsect1> + + <refsect1> + <title>crypttab options</title> + + <para>Options which influence mounted filesystems and + encrypted volumes.</para> + + <variablelist id='crypttab-options' /> + </refsect1> + + <refsect1> + <title>System manager directives</title> + + <para>Directives for configuring the behaviour of the + systemd process.</para> + + <variablelist id='systemd-directives' /> + </refsect1> + + <refsect1> + <title>bootchart.conf directives</title> + + <para>Directives for configuring the behaviour of the + systemd-bootchart process.</para> + + <variablelist id='bootchart-directives' /> + </refsect1> + + <refsect1> + <title>command-line options</title> + + <para>Command-line options accepted by programs in the + systemd suite.</para> + + <variablelist id='options' /> + </refsect1> + + <refsect1> + <title>Constants</title> + + <para>Various constant used and/or defined by systemd.</para> + + <variablelist id='constants' /> + </refsect1> + + <refsect1> + <title>Miscellaneous options and directives</title> + + <para>Other configuration elements which don't fit in + any of the above groups.</para> + + <variablelist id='miscellaneous' /> + </refsect1> + + <refsect1> + <title>Files and directories</title> + + <para>Paths and file names referred to in the + documentation.</para> + + <variablelist id='filenames' /> + </refsect1> + + <refsect1> + <title>Colophon</title> + <para id='colophon' /> + </refsect1> +</refentry> +''' + +COLOPHON = '''\ +This index contains {count} entries in {sections} sections, +referring to {pages} individual manual pages. +''' + +def _extract_directives(directive_groups, formatting, page): + t = xml_parse(page) + section = t.find('./refmeta/manvolnum').text + pagename = t.find('./refmeta/refentrytitle').text + + storopt = directive_groups['options'] + for variablelist in t.iterfind('.//variablelist'): + klass = variablelist.attrib.get('class') + storvar = directive_groups[klass or 'miscellaneous'] + # <option>s go in OPTIONS, unless class is specified + for xpath, stor in (('./varlistentry/term/varname', storvar), + ('./varlistentry/term/option', + storvar if klass else storopt)): + for name in variablelist.iterfind(xpath): + text = re.sub(r'([= ]).*', r'\1', name.text).rstrip() + stor[text].append((pagename, section)) + if text not in formatting: + # use element as formatted display + if name.text[-1] in '= ': + name.clear() + else: + name.tail = '' + name.text = text + formatting[text] = name + + storfile = directive_groups['filenames'] + for xpath, absolute_only in (('.//refsynopsisdiv//filename', False), + ('.//refsynopsisdiv//command', False), + ('.//filename', True)): + for name in t.iterfind(xpath): + if absolute_only and not (name.text and name.text.startswith('/')): + continue + if name.attrib.get('noindex'): + continue + name.tail = '' + if name.text: + if name.text.endswith('*'): + name.text = name.text[:-1] + if not name.text.startswith('.'): + text = name.text.partition(' ')[0] + if text != name.text: + name.clear() + name.text = text + if text.endswith('/'): + text = text[:-1] + storfile[text].append((pagename, section)) + if text not in formatting: + # use element as formatted display + formatting[text] = name + else: + text = ' '.join(name.itertext()) + storfile[text].append((pagename, section)) + formatting[text] = name + + storfile = directive_groups['constants'] + for name in t.iterfind('.//constant'): + if name.attrib.get('noindex'): + continue + name.tail = '' + if name.text.startswith('('): # a cast, strip it + name.text = name.text.partition(' ')[2] + storfile[name.text].append((pagename, section)) + formatting[name.text] = name + +def _make_section(template, name, directives, formatting): + varlist = template.find(".//*[@id='{}']".format(name)) + for varname, manpages in sorted(directives.items()): + entry = tree.SubElement(varlist, 'varlistentry') + term = tree.SubElement(entry, 'term') + display = deepcopy(formatting[varname]) + term.append(display) + + para = tree.SubElement(tree.SubElement(entry, 'listitem'), 'para') + + b = None + for manpage, manvolume in sorted(set(manpages)): + if b is not None: + b.tail = ', ' + b = tree.SubElement(para, 'citerefentry') + c = tree.SubElement(b, 'refentrytitle') + c.text = manpage + d = tree.SubElement(b, 'manvolnum') + d.text = manvolume + entry.tail = '\n\n' + +def _make_colophon(template, groups): + count = 0 + pages = set() + for group in groups: + count += len(group) + for pagelist in group.values(): + pages |= set(pagelist) + + para = template.find(".//para[@id='colophon']") + para.text = COLOPHON.format(count=count, + sections=len(groups), + pages=len(pages)) + +def _make_page(template, directive_groups, formatting): + """Create an XML tree from directive_groups. + + directive_groups = { + 'class': {'variable': [('manpage', 'manvolume'), ...], + 'variable2': ...}, + ... + } + """ + for name, directives in directive_groups.items(): + _make_section(template, name, directives, formatting) + + _make_colophon(template, directive_groups.values()) + + return template + +def make_page(*xml_files): + "Extract directives from xml_files and return XML index tree." + template = tree.fromstring(TEMPLATE) + names = [vl.get('id') for vl in template.iterfind('.//variablelist')] + directive_groups = {name:collections.defaultdict(list) + for name in names} + formatting = {} + for page in xml_files: + try: + _extract_directives(directive_groups, formatting, page) + except Exception: + raise ValueError("failed to process " + page) + + return _make_page(template, directive_groups, formatting) + +if __name__ == '__main__': + with open(sys.argv[1], 'wb') as f: + f.write(xml_print(make_page(*sys.argv[2:]))) diff --git a/tools/make-man-index.py b/tools/make-man-index.py new file mode 100755 index 0000000..74a47b8 --- /dev/null +++ b/tools/make-man-index.py @@ -0,0 +1,136 @@ +# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# Copyright 2013 Zbigniew J??drzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +import collections +import sys +import re +from xml_helper import * + +MDASH = ' ??? ' if sys.version_info.major >= 3 else ' -- ' + +TEMPLATE = '''\ +<refentry id="systemd.index" conditional="HAVE_PYTHON"> + + <refentryinfo> + <title>systemd.index</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lenn...@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>systemd.index</refentrytitle> + <manvolnum>7</manvolnum> + </refmeta> + + <refnamediv> + <refname>systemd.index</refname> + <refpurpose>List all manpages from the systemd project</refpurpose> + </refnamediv> +</refentry> +''' + +SUMMARY = '''\ + <refsect1> + <title>See Also</title> + <para> + <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry> + </para> + + <para id='counts' /> + </refsect1> +''' + +COUNTS = '\ +This index contains {count} entries, referring to {pages} individual manual pages.' + + +def check_id(page, t): + id = t.getroot().get('id') + if not re.search('/' + id + '[.]', page): + raise ValueError("id='{}' is not the same as page name '{}'".format(id, page)) + +def make_index(pages): + index = collections.defaultdict(list) + for p in pages: + t = xml_parse(p) + check_id(p, t) + section = t.find('./refmeta/manvolnum').text + refname = t.find('./refnamediv/refname').text + purpose = ' '.join(t.find('./refnamediv/refpurpose').text.split()) + for f in t.findall('./refnamediv/refname'): + infos = (f.text, section, purpose, refname) + index[f.text[0].upper()].append(infos) + return index + +def add_letter(template, letter, pages): + refsect1 = tree.SubElement(template, 'refsect1') + title = tree.SubElement(refsect1, 'title') + title.text = letter + para = tree.SubElement(refsect1, 'para') + for info in sorted(pages, key=lambda info: str.lower(info[0])): + refname, section, purpose, realname = info + + b = tree.SubElement(para, 'citerefentry') + c = tree.SubElement(b, 'refentrytitle') + c.text = refname + d = tree.SubElement(b, 'manvolnum') + d.text = section + + b.tail = MDASH + purpose # + ' (' + p + ')' + + tree.SubElement(para, 'sbr') + +def add_summary(template, indexpages): + count = 0 + pages = set() + for group in indexpages: + count += len(group) + for info in group: + refname, section, purpose, realname = info + pages.add((realname, section)) + + refsect1 = tree.fromstring(SUMMARY) + template.append(refsect1) + + para = template.find(".//para[@id='counts']") + para.text = COUNTS.format(count=count, pages=len(pages)) + +def make_page(*xml_files): + template = tree.fromstring(TEMPLATE) + index = make_index(xml_files) + + for letter in sorted(index): + add_letter(template, letter, index[letter]) + + add_summary(template, index.values()) + + return template + +if __name__ == '__main__': + with open(sys.argv[1], 'wb') as f: + f.write(xml_print(make_page(*sys.argv[2:]))) diff --git a/tools/make-man-rules.py b/tools/make-man-rules.py new file mode 100644 index 0000000..0d1ca24 --- /dev/null +++ b/tools/make-man-rules.py @@ -0,0 +1,113 @@ +# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2013 Zbigniew J??drzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function +import collections +import sys +import os.path +from xml_helper import * + +SECTION = '''\ +MANPAGES += \\ + {manpages} +MANPAGES_ALIAS += \\ + {aliases} +{rules} +{htmlrules} +''' + +CONDITIONAL = '''\ +if {conditional} +''' \ ++ SECTION + \ +'''\ +endif +''' + +HEADER = '''\ +# Do not edit. Generated by make-man-rules.py. +# Regenerate with 'make all update-man-list'. + +''' + +HTML_ALIAS_RULE = '''\ +{}.html: {}.html + $(html-alias) +''' + +FOOTER = '''\ + +EXTRA_DIST += \\ + {files} +''' + +def man(page, number): + return 'man/{}.{}'.format(page, number) + +def xml(file): + return 'man/{}'.format(os.path.basename(file)) + +def add_rules(rules, name): + xml = xml_parse(name) + # print('parsing {}'.format(name), file=sys.stderr) + conditional = xml.getroot().get('conditional') or '' + rulegroup = rules[conditional] + refmeta = xml.find('./refmeta') + title = refmeta.find('./refentrytitle').text + number = refmeta.find('./manvolnum').text + refnames = xml.findall('./refnamediv/refname') + target = man(refnames[0].text, number) + if title != refnames[0].text: + raise ValueError('refmeta and refnamediv disagree: ' + name) + for refname in refnames: + assert all(refname not in group + for group in rules.values()), "duplicate page name" + alias = man(refname.text, number) + rulegroup[alias] = target + # print('{} => {} [{}]'.format(alias, target, conditional), file=sys.stderr) + +def create_rules(xml_files): + " {conditional => {alias-name => source-name}} " + rules = collections.defaultdict(dict) + for name in xml_files: + add_rules(rules, name) + return rules + +def mjoin(files): + return ' \\\n\t'.join(sorted(files) or '#') + +def make_makefile(rules, files): + return HEADER + '\n'.join( + (CONDITIONAL if conditional else SECTION).format( + manpages=mjoin(set(rulegroup.values())), + aliases=mjoin(k for k,v in rulegroup.items() if k != v), + rules='\n'.join('{}: {}'.format(k,v) + for k,v in sorted(rulegroup.items()) + if k != v), + htmlrules='\n'.join(HTML_ALIAS_RULE.format(k[:-2],v[:-2]) + for k,v in sorted(rulegroup.items()) + if k != v), + conditional=conditional) + for conditional,rulegroup in sorted(rules.items()) + ) + FOOTER.format(files=mjoin(sorted(files))) + +if __name__ == '__main__': + rules = create_rules(sys.argv[1:]) + files = (xml(file) for file in sys.argv[1:]) + print(make_makefile(rules, files), end='') diff --git a/tools/xml_helper.py b/tools/xml_helper.py new file mode 100644 index 0000000..08e226f --- /dev/null +++ b/tools/xml_helper.py @@ -0,0 +1,41 @@ +# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2012-2013 Zbigniew J??drzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +try: + from lxml import etree as tree + + class CustomResolver(tree.Resolver): + def resolve(self, url, id, context): + if 'custom-entities.ent' in url: + return self.resolve_filename('man/custom-entities.ent', context) + + _parser = tree.XMLParser() + _parser.resolvers.add(CustomResolver()) + xml_parse = lambda page: tree.parse(page, _parser) + xml_print = lambda xml: tree.tostring(xml, pretty_print=True, + encoding='utf-8') +except ImportError: + import xml.etree.ElementTree as tree + import re as _re + import io as _io + + def xml_parse(page): + s = _re.sub(b'&[a-zA-Z0-9_]+;', b'', open(page, 'rb').read()) + return tree.parse(_io.BytesIO(s)) + xml_print = lambda xml: tree.tostring(xml, encoding='utf-8') diff --git a/xml_helper.py b/xml_helper.py deleted file mode 100644 index 08e226f..0000000 --- a/xml_helper.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ -# -# This file is part of systemd. -# -# Copyright 2012-2013 Zbigniew J??drzejewski-Szmek -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# systemd is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with systemd; If not, see <http://www.gnu.org/licenses/>. - -try: - from lxml import etree as tree - - class CustomResolver(tree.Resolver): - def resolve(self, url, id, context): - if 'custom-entities.ent' in url: - return self.resolve_filename('man/custom-entities.ent', context) - - _parser = tree.XMLParser() - _parser.resolvers.add(CustomResolver()) - xml_parse = lambda page: tree.parse(page, _parser) - xml_print = lambda xml: tree.tostring(xml, pretty_print=True, - encoding='utf-8') -except ImportError: - import xml.etree.ElementTree as tree - import re as _re - import io as _io - - def xml_parse(page): - s = _re.sub(b'&[a-zA-Z0-9_]+;', b'', open(page, 'rb').read()) - return tree.parse(_io.BytesIO(s)) - xml_print = lambda xml: tree.tostring(xml, encoding='utf-8') -- 1.8.5.3
_______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel