autohelp.py: switch to jinja templates

Change-Id: Ice55c665adf4c0ede819cfc7264ed13feeca14db
This commit is contained in:
Gauvain Pocentek 2015-11-15 19:36:31 +01:00
parent c8a4549621
commit 52537d2341
4 changed files with 120 additions and 147 deletions

View File

@ -27,7 +27,7 @@ import pickle
import re import re
import sys import sys
from lxml import etree import jinja2
import stevedore import stevedore
from hooks import HOOKS # noqa from hooks import HOOKS # noqa
@ -73,62 +73,6 @@ IGNORE = [
] ]
BASE_XML = '''<?xml version="1.0"?>
<para xmlns="http://docbook.org/ns/docbook"
version="5.0">
<!--
###################################################################
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
###################################################################
Warning: Do not edit this file. It is automatically
generated from the software project's code and your changes
will be overwritten.
The tool to generate this file lives in openstack-doc-tools
repository.
Please make any changes needed in the code, then run the
autogenerate-config-doc tool from the openstack-doc-tools
repository, or ask for help on the documentation mailing list,
IRC channel or meeting.
###################################################################
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
###################################################################
-->
<table rules="all" xml:id="config_table_%(pkg)s_%(cat)s">
<caption>Description of %(nice_cat)s configuration options</caption>
<col width="50%%"/>
<col width="50%%"/>
<thead>
<tr>
<th>Configuration option = Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody></tbody>
</table>
</para>'''
BASE_RST = '''
.. list-table:: Description of %(nice_cat)s configuration options
:header-rows: 2
:widths: 100 100
:class: config-ref-table
* - Configuration option = Default value
- Description
'''
NEW_GROUP_RST = '''
.. list-table::
:header-rows: 1
:widths: 100 100
:class: config-ref-table
'''
register_re = re.compile(r'''^ +.*\.register_opts\((?P<opts>[^,)]+)''' register_re = re.compile(r'''^ +.*\.register_opts\((?P<opts>[^,)]+)'''
r'''(, (group=)?["'](?P<group>.*)["'])?\)''') r'''(, (group=)?["'](?P<group>.*)["'])?\)''')
@ -435,12 +379,16 @@ def _get_category_names(package_name):
return category_names return category_names
def write_docbook(package_name, options, target, verbose=0): def write_files(package_name, options, target, output_format):
"""Write DocBook tables. """Write tables.
Prints a docbook-formatted table for every group of options. Prints a table for every group of options.
""" """
target = target or '../../doc/common/tables/' if not target:
if output_format == 'rst':
target = '../../doc/config-ref-rst/source/tables'
else:
target = '../../doc/common/tables/'
options_by_cat = _get_options_by_cat(package_name) options_by_cat = _get_options_by_cat(package_name)
category_names = _get_category_names(package_name) category_names = _get_category_names(package_name)
@ -448,101 +396,53 @@ def write_docbook(package_name, options, target, verbose=0):
os.makedirs(target) os.makedirs(target)
for cat in options_by_cat.keys(): for cat in options_by_cat.keys():
parser = etree.XMLParser(remove_blank_text=True) env = {
'pkg': package_name,
'cat': cat,
'groups': [],
'items': [],
}
if cat in category_names: if cat in category_names:
nice_cat = category_names[cat] env['nice_cat'] = category_names[cat]
else: else:
nice_cat = cat env['nice_cat'] = cat
print("No nicename for %s" % cat) print("No nicename for %s" % cat)
xml = etree.XML(BASE_XML %
{'pkg': package_name, 'cat': cat,
'nice_cat': nice_cat},
parser)
tbody = xml.find(".//{http://docbook.org/ns/docbook}tbody")
curgroup = None curgroup = None
items = None
for optname in options_by_cat[cat]: for optname in options_by_cat[cat]:
group, option = options.get_option(optname) group, option = options.get_option(optname)
if group != curgroup: if group != curgroup:
curgroup = group if group is not None:
tr = etree.Element('tr') curgroup = group
th = etree.Element('th', colspan="2") env['groups'].append(group)
th.text = "[%s]" % group if items is not None:
tr.append(th) env['items'].append(items)
tbody.append(tr) items = []
if not option.help: if not option.help:
option.help = "No help text available for this option." option.help = "No help text available for this option."
default = _sanitize_default(option) item = (option.dest,
_sanitize_default(option),
"(%s) %s" % (type(option).__name__, option.help.strip()))
items.append(item)
tr = etree.Element('tr') env['items'].append(items)
tbody.append(tr)
td = etree.Element('td') ext = 'rst' if output_format == 'rst' else 'xml'
option_xml = etree.SubElement(td, 'option') file_path = ("%(target)s/%(package_name)s-%(cat)s.%(ext)s" %
option_xml.text = "%s" % option.dest
option_xml.tail = " = "
replaceable_xml = etree.SubElement(td, 'replaceable')
replaceable_xml.text = "%s" % default
tr.append(td)
td = etree.Element('td')
td.text = "(%s) %s" % (type(option).__name__, option.help.strip())
tr.append(td)
file_path = ("%(target)s/%(package_name)s-%(cat)s.xml" %
{'target': target, 'package_name': package_name, {'target': target, 'package_name': package_name,
'cat': cat}) 'cat': cat, 'ext': ext})
tmpl_file = os.path.join(os.path.dirname(__file__),
'templates/autohelp.%s.j2' % output_format)
with open(tmpl_file) as fd:
template = jinja2.Template(fd.read(), trim_blocks=True)
output = template.render(filename=file_path, **env)
with open(file_path, 'w') as fd: with open(file_path, 'w') as fd:
fd.write(etree.tostring(xml, pretty_print=True, fd.write(output)
xml_declaration=True,
encoding="UTF-8"))
def write_rst(package_name, options, target, verbose=0):
"""Write RST tables.
Prints an RST-formatted table for every group of options.
"""
target = target or '../../doc/common/tables/rst/'
options_by_cat = _get_options_by_cat(package_name)
category_names = _get_category_names(package_name)
if not os.path.isdir(target):
os.makedirs(target)
for cat in options_by_cat.keys():
if cat in category_names:
nice_cat = category_names[cat]
else:
nice_cat = cat
print("No nicename for %s" % cat)
rst_table = (BASE_RST % {'pkg': package_name,
'cat': cat,
'nice_cat': nice_cat})
curgroup = None
for optname in options_by_cat[cat]:
group, option = options.get_option(optname)
if group != curgroup:
if curgroup is not None:
rst_table += NEW_GROUP_RST
rst_table += ' * - **[%s]**\n -\n' % group
curgroup = group
if not option.help:
option.help = "No help text available for this option."
default = _sanitize_default(option)
option_text = "%s = %s" % (option.dest, default)
option_text = "``%s``" % option_text.strip()
option_help = "(%s) %s" % (type(option).__name__,
option.help.strip())
rst_table += " * - %s\n - %s\n" % (option_text, option_help)
file_path = ("%(target)s/%(package_name)s-%(cat)s.rst" %
{'target': target, 'package_name': package_name,
'cat': cat})
with open(file_path, 'w') as fd:
fd.write(rst_table)
def create_flagmappings(package_name, options, verbose=0): def create_flagmappings(package_name, options, verbose=0):
@ -663,11 +563,8 @@ def main():
elif args.subcommand == 'update': elif args.subcommand == 'update':
update_flagmappings(args.package, options, verbose=args.verbose) update_flagmappings(args.package, options, verbose=args.verbose)
elif args.subcommand == 'docbook': elif args.subcommand in ('docbook', 'rst'):
write_docbook(args.package, options, args.target, verbose=args.verbose) write_files(args.package, options, args.target, args.subcommand)
elif args.subcommand == 'rst':
write_rst(args.package, options, args.target, verbose=args.verbose)
elif args.subcommand == 'dump': elif args.subcommand == 'dump':
options.dump() options.dump()

View File

@ -0,0 +1,3 @@
---
other:
- Use jinja templating system to generate configuration reference tables.

View File

@ -0,0 +1,49 @@
<?xml version='1.0' encoding='UTF-8'?>
<para xmlns="http://docbook.org/ns/docbook" version="5.0">
<!--
###################################################################
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
###################################################################
Warning: Do not edit this file. It is automatically
generated from the software project's code and your changes
will be overwritten.
The tool to generate this file lives in openstack-doc-tools
repository.
Please make any changes needed in the code, then run the
autogenerate-config-doc tool from the openstack-doc-tools
repository, or ask for help on the documentation mailing list,
IRC channel or meeting.
###################################################################
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
###################################################################
-->
<table rules="all" xml:id="config_table_{{ pkg }}_{{ cat }}">
<caption>Description of {{ nice_cat }} configuration options</caption>
<col width="50%"/>
<col width="50%"/>
<thead>
<tr>
<th>Configuration option = Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<th colspan="2">[{{ group }}]</th>
</tr>
{% for item in items[loop.index0] %}
<tr>
<td><option>{{ item[0] }}</option> = <replaceable>{{ item[1] }}</replaceable></td>
<td>{{ item[2]|replace('<', '&lt;')|replace('>', '&gt;') }}</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
</para>

View File

@ -0,0 +1,24 @@
..
Warning: Do not edit this file. It is automatically generated from the
software project's code and your changes will be overwritten.
The tool to generate this file lives in openstack-doc-tools repository.
Please make any changes needed in the code, then run the
autogenerate-config-doc tool from the openstack-doc-tools repository, or
ask for help on the documentation mailing list, IRC channel or meeting.
.. list-table:: Description of {{ nice_cat }} configuration options
:header-rows: 1
:class: config-ref-table
* - Configuration option = Default value
- Description
{% for group in groups %}
* - **[{{ group }}]**
-
{% for item in items[loop.index0] %}
* - ``{{ item[0] }}`` = ``{{ item[1]|default(' ') }}``
- {{ item[2] }}
{% endfor %}
{% endfor %}