[systemd-devel] [PATCH 1/2] build-sys: move python helpers to tools directory

Tom Gundersen teg at jklm.no
Mon Feb 10 04:11:53 PST 2014


On Mon, Feb 10, 2014 at 10:37 AM, Karel Zak <kzak at redhat.com> wrote:
> Note that make-man-rules.py is missing in EXTRA_DIST=, this patch
> fixes this mistake too.

Applied both patches. Thanks!

Cheers,

Tom

> ---
>  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>zbyszek at 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>lennart at 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>zbyszek at 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>lennart at 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
>


More information about the systemd-devel mailing list