[ovs-dev] [PATCH 6/8] ovsdb-doc: Factor out nroff formatting into a separate Python module.

Gurucharan Shetty shettyg at nicira.com
Thu Feb 19 12:02:01 UTC 2015


I don't understand nroff well enough to review patch 6 and patch 7. If
anyone else is up for it, please review.

On Thu, Feb 19, 2015 at 12:12 AM, Ben Pfaff <blp at nicira.com> wrote:
> This will make it cleaner to add another build-time program that generates
> nroff from XML.
>
> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
>  ovsdb/ovsdb-doc          | 135 +-------------------------------
>  python/automake.mk       |   6 ++
>  python/build/__init__.py |   0
>  python/build/nroff.py    | 196 +++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 206 insertions(+), 131 deletions(-)
>  create mode 100644 python/build/__init__.py
>  create mode 100644 python/build/nroff.py
>
> diff --git a/ovsdb/ovsdb-doc b/ovsdb/ovsdb-doc
> index 15618ef..369efa9 100755
> --- a/ovsdb/ovsdb-doc
> +++ b/ovsdb/ovsdb-doc
> @@ -3,7 +3,6 @@
>  from datetime import date
>  import getopt
>  import os
> -import re
>  import sys
>  import xml.dom.minidom
>
> @@ -11,136 +10,9 @@ import ovs.json
>  from ovs.db import error
>  import ovs.db.schema
>
> -argv0 = sys.argv[0]
> -
> -def textToNroff(s, font=r'\fR'):
> -    def escape(match):
> -        c = match.group(0)
> -        if c.startswith('-'):
> -            if c != '-' or font == r'\fB':
> -                return '\\' + c
> -            else:
> -                return '-'
> -        if c == '\\':
> -            return r'\e'
> -        elif c == '"':
> -            return r'\(dq'
> -        elif c == "'":
> -            return r'\(cq'
> -        else:
> -            raise error.Error("bad escape")
> +from build.nroff import *
>
> -    # Escape - \ " ' as needed by nroff.
> -    s = re.sub('(-[0-9]|[-"\'\\\\])', escape, s)
> -    if s.startswith('.'):
> -        s = '\\' + s
> -    return s
> -
> -def escapeNroffLiteral(s):
> -    return r'\fB%s\fR' % textToNroff(s, r'\fB')
> -
> -def inlineXmlToNroff(node, font):
> -    if node.nodeType == node.TEXT_NODE:
> -        return textToNroff(node.data, font)
> -    elif node.nodeType == node.ELEMENT_NODE:
> -        if node.tagName in ['code', 'em', 'option']:
> -            s = r'\fB'
> -            for child in node.childNodes:
> -                s += inlineXmlToNroff(child, r'\fB')
> -            return s + font
> -        elif node.tagName == 'ref':
> -            s = r'\fB'
> -            if node.hasAttribute('column'):
> -                s += node.attributes['column'].nodeValue
> -                if node.hasAttribute('key'):
> -                    s += ':' + node.attributes['key'].nodeValue
> -            elif node.hasAttribute('table'):
> -                s += node.attributes['table'].nodeValue
> -            elif node.hasAttribute('group'):
> -                s += node.attributes['group'].nodeValue
> -            else:
> -                raise error.Error("'ref' lacks required attributes: %s" % node.attributes.keys())
> -            return s + font
> -        elif node.tagName == 'var':
> -            s = r'\fI'
> -            for child in node.childNodes:
> -                s += inlineXmlToNroff(child, r'\fI')
> -            return s + font
> -        else:
> -            raise error.Error("element <%s> unknown or invalid here" % node.tagName)
> -    else:
> -        raise error.Error("unknown node %s in inline xml" % node)
> -
> -def blockXmlToNroff(nodes, para='.PP'):
> -    s = ''
> -    for node in nodes:
> -        if node.nodeType == node.TEXT_NODE:
> -            s += textToNroff(node.data)
> -            s = s.lstrip()
> -        elif node.nodeType == node.ELEMENT_NODE:
> -            if node.tagName in ['ul', 'ol']:
> -                if s != "":
> -                    s += "\n"
> -                s += ".RS\n"
> -                i = 0
> -                for liNode in node.childNodes:
> -                    if (liNode.nodeType == node.ELEMENT_NODE
> -                        and liNode.tagName == 'li'):
> -                        i += 1
> -                        if node.tagName == 'ul':
> -                            s += ".IP \\(bu\n"
> -                        else:
> -                            s += ".IP %d. .25in\n" % i
> -                        s += blockXmlToNroff(liNode.childNodes, ".IP")
> -                    elif (liNode.nodeType != node.TEXT_NODE
> -                          or not liNode.data.isspace()):
> -                        raise error.Error("<%s> element may only have <li> children" % node.tagName)
> -                s += ".RE\n"
> -            elif node.tagName == 'dl':
> -                if s != "":
> -                    s += "\n"
> -                s += ".RS\n"
> -                prev = "dd"
> -                for liNode in node.childNodes:
> -                    if (liNode.nodeType == node.ELEMENT_NODE
> -                        and liNode.tagName == 'dt'):
> -                        if prev == 'dd':
> -                            s += '.TP\n'
> -                        else:
> -                            s += '.TQ\n'
> -                        prev = 'dt'
> -                    elif (liNode.nodeType == node.ELEMENT_NODE
> -                          and liNode.tagName == 'dd'):
> -                        if prev == 'dd':
> -                            s += '.IP\n'
> -                        prev = 'dd'
> -                    elif (liNode.nodeType != node.TEXT_NODE
> -                          or not liNode.data.isspace()):
> -                        raise error.Error("<dl> element may only have <dt> and <dd> children")
> -                    s += blockXmlToNroff(liNode.childNodes, ".IP")
> -                s += ".RE\n"
> -            elif node.tagName == 'p':
> -                if s != "":
> -                    if not s.endswith("\n"):
> -                        s += "\n"
> -                    s += para + "\n"
> -                s += blockXmlToNroff(node.childNodes, para)
> -            elif node.tagName in ('h1', 'h2', 'h3'):
> -                if s != "":
> -                    if not s.endswith("\n"):
> -                        s += "\n"
> -                nroffTag = {'h1': 'SH', 'h2': 'SS', 'h3': 'ST'}[node.tagName]
> -                s += ".%s " % nroffTag
> -                for child_node in node.childNodes:
> -                    s += inlineXmlToNroff(child_node, r'\fR')
> -                s += "\n"
> -            else:
> -                s += inlineXmlToNroff(node, r'\fR')
> -        else:
> -            raise error.Error("unknown node %s in block xml" % node)
> -    if s != "" and not s.endswith('\n'):
> -        s += '\n'
> -    return s
> +argv0 = sys.argv[0]
>
>  def typeAndConstraintsToNroff(column):
>      type = column.type.toEnglish(escapeNroffLiteral)
> @@ -283,8 +155,9 @@ def docsToNroff(schemaFile, xmlFile, erFile, version=None):
>      # Putting '\" p as the first line tells "man" that the manpage
>      # needs to be preprocessed by "pic".
>      s = r''''\" p
> -.TH "%s" 5 " DB Schema %s" "Open vSwitch %s" "Open vSwitch Manual"
>  .\" -*- nroff -*-
> +.TH "%s" 5 " DB Schema %s" "Open vSwitch %s" "Open vSwitch Manual"
> +.fp 5 L CR              \\" Make fixed-width font available as \\fL.
>  .de TQ
>  .  br
>  .  ns
> diff --git a/python/automake.mk b/python/automake.mk
> index 08e1204..f6ab606 100644
> --- a/python/automake.mk
> +++ b/python/automake.mk
> @@ -35,6 +35,12 @@ ovs_pyfiles = \
>         python/ovs/version.py \
>         python/ovs/vlog.py
>
> +# These python files are used at build time but not runtime,
> +# so they are not installed.
> +EXTRA_DIST += \
> +       python/build/__init__.py \
> +       python/build/nroff.py
> +
>  PYFILES = $(ovs_pyfiles) python/ovs/dirs.py $(ovstest_pyfiles)
>  EXTRA_DIST += $(PYFILES)
>  PYCOV_CLEAN_FILES += $(PYFILES:.py=.py,cover)
> diff --git a/python/build/__init__.py b/python/build/__init__.py
> new file mode 100644
> index 0000000..e69de29
> diff --git a/python/build/nroff.py b/python/build/nroff.py
> new file mode 100644
> index 0000000..c277399
> --- /dev/null
> +++ b/python/build/nroff.py
> @@ -0,0 +1,196 @@
> +# Copyright (c) 2010, 2011, 2012, 2015 Nicira, Inc.
> +#
> +# Licensed under the Apache License, Version 2.0 (the "License");
> +# you may not use this file except in compliance with the License.
> +# You may obtain a copy of the License at:
> +#
> +#     http://www.apache.org/licenses/LICENSE-2.0
> +#
> +# Unless required by applicable law or agreed to in writing, software
> +# distributed under the License is distributed on an "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +# See the License for the specific language governing permissions and
> +# limitations under the License.
> +
> +import re
> +
> +from ovs.db import error
> +
> +def textToNroff(s, font=r'\fR'):
> +    def escape(match):
> +        c = match.group(0)
> +
> +        # In Roman type, let -- in XML be \- in nroff.  That gives us a way to
> +        # write minus signs, which is important in some places in manpages.
> +        #
> +        # Bold in nroff usually represents literal text, where there's no
> +        # distinction between hyphens and minus sign.  The convention in nroff
> +        # appears to be to use a minus sign in such cases, so we follow that
> +        # convention.
> +        #
> +        # Finally, we always output - as a minus sign when it is followed by a
> +        # digit.
> +        if c.startswith('-'):
> +            if c == '--' and font == r'\fR':
> +                return r'\-'
> +            if c != '-' or font in (r'\fB', r'\fL'):
> +                return c.replace('-', r'\-')
> +            else:
> +                return '-'
> +
> +        if c == '\\':
> +            return r'\e'
> +        elif c == '"':
> +            return r'\(dq'
> +        elif c == "'":
> +            return r'\(cq'
> +        elif c == ".":
> +            # groff(7) says that . can be escaped by \. but in practice groff
> +            # still gives an error with \. at the beginning of a line.
> +            return font + "."
> +        else:
> +            raise error.Error("bad escape")
> +
> +    # Escape - \ " ' . as needed by nroff.
> +    s = re.sub('(-[0-9]|--|[-"\'\\\\.])', escape, s)
> +    return s
> +
> +def escapeNroffLiteral(s, font=r'\fB'):
> +    return font + r'%s\fR' % textToNroff(s, font)
> +
> +def pic_to_nroff(nodes, para):
> +    s = para + '\n.PS\n'
> +    for node in nodes:
> +        if node.nodeType != node.TEXT_NODE:
> +            fatal("<pic> element may only have text children")
> +        s += node.data + '\n'
> +    s += '.PE\n'
> +    return s
> +
> +def inlineXmlToNroff(node, font, to_upper=False):
> +    if node.nodeType == node.TEXT_NODE:
> +        if to_upper:
> +            return textToNroff(node.data.upper(), font)
> +        else:
> +            return textToNroff(node.data, font)
> +    elif node.nodeType == node.ELEMENT_NODE:
> +        if node.tagName in ['code', 'em', 'option']:
> +            s = r'\fB'
> +            for child in node.childNodes:
> +                s += inlineXmlToNroff(child, r'\fB')
> +            return s + font
> +        elif node.tagName == 'ref':
> +            s = r'\fB'
> +            if node.hasAttribute('column'):
> +                s += node.attributes['column'].nodeValue
> +                if node.hasAttribute('key'):
> +                    s += ':' + node.attributes['key'].nodeValue
> +            elif node.hasAttribute('table'):
> +                s += node.attributes['table'].nodeValue
> +            elif node.hasAttribute('group'):
> +                s += node.attributes['group'].nodeValue
> +            elif node.hasAttribute('db'):
> +                s += node.attributes['db'].nodeValue
> +            else:
> +                raise error.Error("'ref' lacks required attributes: %s" % node.attributes.keys())
> +            return s + font
> +        elif node.tagName == 'var' or node.tagName == 'dfn':
> +            s = r'\fI'
> +            for child in node.childNodes:
> +                s += inlineXmlToNroff(child, r'\fI')
> +            return s + font
> +        else:
> +            raise error.Error("element <%s> unknown or invalid here" % node.tagName)
> +    else:
> +        raise error.Error("unknown node %s in inline xml" % node)
> +
> +def pre_to_nroff(nodes, para, font):
> +    s = para + '\n.nf\n'
> +    for node in nodes:
> +        if node.nodeType != node.TEXT_NODE:
> +            fatal("<pre> element may only have text children")
> +        for line in node.data.split('\n'):
> +            s += escapeNroffLiteral(line, font) + '\n.br\n'
> +    s += '.fi\n'
> +    return s
> +
> +def blockXmlToNroff(nodes, para='.PP'):
> +    s = ''
> +    for node in nodes:
> +        if node.nodeType == node.TEXT_NODE:
> +            s += textToNroff(node.data)
> +            s = s.lstrip()
> +        elif node.nodeType == node.ELEMENT_NODE:
> +            if node.tagName in ['ul', 'ol']:
> +                if s != "":
> +                    s += "\n"
> +                s += ".RS\n"
> +                i = 0
> +                for liNode in node.childNodes:
> +                    if (liNode.nodeType == node.ELEMENT_NODE
> +                        and liNode.tagName == 'li'):
> +                        i += 1
> +                        if node.tagName == 'ul':
> +                            s += ".IP \\(bu\n"
> +                        else:
> +                            s += ".IP %d. .25in\n" % i
> +                        s += blockXmlToNroff(liNode.childNodes, ".IP")
> +                    elif (liNode.nodeType != node.TEXT_NODE
> +                          or not liNode.data.isspace()):
> +                        raise error.Error("<%s> element may only have <li> children" % node.tagName)
> +                s += ".RE\n"
> +            elif node.tagName == 'dl':
> +                if s != "":
> +                    s += "\n"
> +                s += ".RS\n"
> +                prev = "dd"
> +                for liNode in node.childNodes:
> +                    if (liNode.nodeType == node.ELEMENT_NODE
> +                        and liNode.tagName == 'dt'):
> +                        if prev == 'dd':
> +                            s += '.TP\n'
> +                        else:
> +                            s += '.TQ .5in\n'
> +                        prev = 'dt'
> +                    elif (liNode.nodeType == node.ELEMENT_NODE
> +                          and liNode.tagName == 'dd'):
> +                        if prev == 'dd':
> +                            s += '.IP\n'
> +                        prev = 'dd'
> +                    elif (liNode.nodeType != node.TEXT_NODE
> +                          or not liNode.data.isspace()):
> +                        raise error.Error("<dl> element may only have <dt> and <dd> children")
> +                    s += blockXmlToNroff(liNode.childNodes, ".IP")
> +                s += ".RE\n"
> +            elif node.tagName == 'p':
> +                if s != "":
> +                    if not s.endswith("\n"):
> +                        s += "\n"
> +                    s += para + "\n"
> +                s += blockXmlToNroff(node.childNodes, para)
> +            elif node.tagName in ('h1', 'h2', 'h3'):
> +                if s != "":
> +                    if not s.endswith("\n"):
> +                        s += "\n"
> +                nroffTag = {'h1': 'SH', 'h2': 'SS', 'h3': 'ST'}[node.tagName]
> +                s += '.%s "' % nroffTag
> +                for child_node in node.childNodes:
> +                    s += inlineXmlToNroff(child_node, r'\fR',
> +                                          to_upper=(nroffTag == 'SH'))
> +                s += '"\n'
> +            elif node.tagName == 'pre':
> +                fixed = node.getAttribute('fixed')
> +                if fixed == 'yes':
> +                    font = r'\fL'
> +                else:
> +                    font = r'\fB'
> +                s += pre_to_nroff(node.childNodes, para, font)
> +            elif node.tagName == 'pic':
> +                s += pic_to_nroff(node.childNodes, para)
> +            else:
> +                s += inlineXmlToNroff(node, r'\fR')
> +        else:
> +            raise error.Error("unknown node %s in block xml" % node)
> +    if s != "" and not s.endswith('\n'):
> +        s += '\n'
> +    return s
> --
> 2.1.3
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev



More information about the dev mailing list