~ubuntu-branches/ubuntu/wily/openvswitch/wily

« back to all changes in this revision

Viewing changes to ovsdb/ovsdb-doc

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-08-10 11:35:15 UTC
  • mfrom: (1.1.30)
  • Revision ID: package-import@ubuntu.com-20150810113515-575vj06oq29emxsn
Tags: 2.4.0~git20150810.97bab95-0ubuntu1
* New upstream snapshot from 2.4 branch:
  - d/*: Align any relevant packaging changes with upstream.
* d/*: wrap-and-sort.
* d/openvswitch-{common,vswitch}.install: Correct install location for
  bash completion files.
* d/tests/openflow.py: Explicitly use ovs-testcontroller as provided
  by 2.4.0 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#! /usr/bin/python
2
2
 
 
3
# Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
 
4
#
 
5
# Licensed under the Apache License, Version 2.0 (the "License");
 
6
# you may not use this file except in compliance with the License.
 
7
# You may obtain a copy of the License at:
 
8
#
 
9
#     http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
11
# Unless required by applicable law or agreed to in writing, software
 
12
# distributed under the License is distributed on an "AS IS" BASIS,
 
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
# See the License for the specific language governing permissions and
 
15
# limitations under the License.
 
16
 
3
17
from datetime import date
4
18
import getopt
5
19
import os
6
 
import re
7
20
import sys
8
21
import xml.dom.minidom
9
22
 
11
24
from ovs.db import error
12
25
import ovs.db.schema
13
26
 
 
27
from build.nroff import *
 
28
 
14
29
argv0 = sys.argv[0]
15
30
 
16
 
def textToNroff(s, font=r'\fR'):
17
 
    def escape(match):
18
 
        c = match.group(0)
19
 
        if c.startswith('-'):
20
 
            if c != '-' or font == r'\fB':
21
 
                return '\\' + c
22
 
            else:
23
 
                return '-'
24
 
        if c == '\\':
25
 
            return r'\e'
26
 
        elif c == '"':
27
 
            return r'\(dq'
28
 
        elif c == "'":
29
 
            return r'\(cq'
30
 
        else:
31
 
            raise error.Error("bad escape")
32
 
 
33
 
    # Escape - \ " ' as needed by nroff.
34
 
    s = re.sub('(-[0-9]|[-"\'\\\\])', escape, s)
35
 
    if s.startswith('.'):
36
 
        s = '\\' + s
37
 
    return s
38
 
 
39
 
def escapeNroffLiteral(s):
40
 
    return r'\fB%s\fR' % textToNroff(s, r'\fB')
41
 
 
42
 
def inlineXmlToNroff(node, font):
43
 
    if node.nodeType == node.TEXT_NODE:
44
 
        return textToNroff(node.data, font)
45
 
    elif node.nodeType == node.ELEMENT_NODE:
46
 
        if node.tagName in ['code', 'em', 'option']:
47
 
            s = r'\fB'
48
 
            for child in node.childNodes:
49
 
                s += inlineXmlToNroff(child, r'\fB')
50
 
            return s + font
51
 
        elif node.tagName == 'ref':
52
 
            s = r'\fB'
53
 
            if node.hasAttribute('column'):
54
 
                s += node.attributes['column'].nodeValue
55
 
                if node.hasAttribute('key'):
56
 
                    s += ':' + node.attributes['key'].nodeValue
57
 
            elif node.hasAttribute('table'):
58
 
                s += node.attributes['table'].nodeValue
59
 
            elif node.hasAttribute('group'):
60
 
                s += node.attributes['group'].nodeValue
61
 
            else:
62
 
                raise error.Error("'ref' lacks required attributes: %s" % node.attributes.keys())
63
 
            return s + font
64
 
        elif node.tagName == 'var':
65
 
            s = r'\fI'
66
 
            for child in node.childNodes:
67
 
                s += inlineXmlToNroff(child, r'\fI')
68
 
            return s + font
69
 
        else:
70
 
            raise error.Error("element <%s> unknown or invalid here" % node.tagName)
71
 
    else:
72
 
        raise error.Error("unknown node %s in inline xml" % node)
73
 
 
74
 
def blockXmlToNroff(nodes, para='.PP'):
75
 
    s = ''
76
 
    for node in nodes:
77
 
        if node.nodeType == node.TEXT_NODE:
78
 
            s += textToNroff(node.data)
79
 
            s = s.lstrip()
80
 
        elif node.nodeType == node.ELEMENT_NODE:
81
 
            if node.tagName in ['ul', 'ol']:
82
 
                if s != "":
83
 
                    s += "\n"
84
 
                s += ".RS\n"
85
 
                i = 0
86
 
                for liNode in node.childNodes:
87
 
                    if (liNode.nodeType == node.ELEMENT_NODE
88
 
                        and liNode.tagName == 'li'):
89
 
                        i += 1
90
 
                        if node.tagName == 'ul':
91
 
                            s += ".IP \\(bu\n"
92
 
                        else:
93
 
                            s += ".IP %d. .25in\n" % i
94
 
                        s += blockXmlToNroff(liNode.childNodes, ".IP")
95
 
                    elif (liNode.nodeType != node.TEXT_NODE
96
 
                          or not liNode.data.isspace()):
97
 
                        raise error.Error("<%s> element may only have <li> children" % node.tagName)
98
 
                s += ".RE\n"
99
 
            elif node.tagName == 'dl':
100
 
                if s != "":
101
 
                    s += "\n"
102
 
                s += ".RS\n"
103
 
                prev = "dd"
104
 
                for liNode in node.childNodes:
105
 
                    if (liNode.nodeType == node.ELEMENT_NODE
106
 
                        and liNode.tagName == 'dt'):
107
 
                        if prev == 'dd':
108
 
                            s += '.TP\n'
109
 
                        else:
110
 
                            s += '.TQ\n'
111
 
                        prev = 'dt'
112
 
                    elif (liNode.nodeType == node.ELEMENT_NODE
113
 
                          and liNode.tagName == 'dd'):
114
 
                        if prev == 'dd':
115
 
                            s += '.IP\n'
116
 
                        prev = 'dd'
117
 
                    elif (liNode.nodeType != node.TEXT_NODE
118
 
                          or not liNode.data.isspace()):
119
 
                        raise error.Error("<dl> element may only have <dt> and <dd> children")
120
 
                    s += blockXmlToNroff(liNode.childNodes, ".IP")
121
 
                s += ".RE\n"
122
 
            elif node.tagName == 'p':
123
 
                if s != "":
124
 
                    if not s.endswith("\n"):
125
 
                        s += "\n"
126
 
                    s += para + "\n"
127
 
                s += blockXmlToNroff(node.childNodes, para)
128
 
            elif node.tagName in ('h1', 'h2', 'h3'):
129
 
                if s != "":
130
 
                    if not s.endswith("\n"):
131
 
                        s += "\n"
132
 
                nroffTag = {'h1': 'SH', 'h2': 'SS', 'h3': 'ST'}[node.tagName]
133
 
                s += ".%s " % nroffTag
134
 
                for child_node in node.childNodes:
135
 
                    s += inlineXmlToNroff(child_node, r'\fR')
136
 
                s += "\n"
137
 
            else:
138
 
                s += inlineXmlToNroff(node, r'\fR')
139
 
        else:
140
 
            raise error.Error("unknown node %s in block xml" % node)
141
 
    if s != "" and not s.endswith('\n'):
142
 
        s += '\n'
143
 
    return s
144
 
 
145
31
def typeAndConstraintsToNroff(column):
146
32
    type = column.type.toEnglish(escapeNroffLiteral)
147
33
    constraints = column.type.constraintsToEnglish(escapeNroffLiteral,
152
38
        type += " (must be unique within table)"
153
39
    return type
154
40
 
155
 
def columnGroupToNroff(table, groupXml):
 
41
def columnGroupToNroff(table, groupXml, documented_columns):
156
42
    introNodes = []
157
43
    columnNodes = []
158
44
    for node in groupXml.childNodes:
172
58
    for node in columnNodes:
173
59
        if node.tagName == 'column':
174
60
            name = node.attributes['name'].nodeValue
 
61
            documented_columns.add(name)
175
62
            column = table.columns[name]
176
63
            if node.hasAttribute('key'):
177
64
                key = node.attributes['key'].nodeValue
219
106
            summary += [('column', nameNroff, typeNroff)]
220
107
        elif node.tagName == 'group':
221
108
            title = node.attributes["title"].nodeValue
222
 
            subSummary, subIntro, subBody = columnGroupToNroff(table, node)
 
109
            subSummary, subIntro, subBody = columnGroupToNroff(
 
110
                table, node, documented_columns)
223
111
            summary += [('group', title, subSummary)]
224
112
            body += '.ST "%s:"\n' % textToNroff(title)
225
113
            body += subIntro + subBody
242
130
    tableName = tableXml.attributes['name'].nodeValue
243
131
    table = schema.tables[tableName]
244
132
 
 
133
    documented_columns = set()
245
134
    s = """.bp
246
135
.SH "%s TABLE"
247
136
""" % tableName
248
 
    summary, intro, body = columnGroupToNroff(table, tableXml)
 
137
    summary, intro, body = columnGroupToNroff(table, tableXml,
 
138
                                              documented_columns)
249
139
    s += intro
250
140
    s += '.SS "Summary:\n'
251
141
    s += tableSummaryToNroff(summary)
252
142
    s += '.SS "Details:\n'
253
143
    s += body
 
144
 
 
145
    schema_columns = set(table.columns.keys())
 
146
    undocumented_columns = schema_columns - documented_columns
 
147
    for column in undocumented_columns:
 
148
        raise error.Error("table %s has undocumented column %s"
 
149
                          % (tableName, column))
 
150
 
254
151
    return s
255
152
 
256
 
def docsToNroff(schemaFile, xmlFile, erFile, title=None, version=None):
 
153
def docsToNroff(schemaFile, xmlFile, erFile, version=None):
257
154
    schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schemaFile))
258
155
    doc = xml.dom.minidom.parse(xmlFile).documentElement
259
156
 
261
158
    xmlDate = os.stat(xmlFile).st_mtime
262
159
    d = date.fromtimestamp(max(schemaDate, xmlDate))
263
160
 
264
 
    if title == None:
265
 
        title = schema.name
 
161
    if doc.hasAttribute('name'):
 
162
        manpage = doc.attributes['name'].nodeValue
 
163
    else:
 
164
        manpage = schema.name
266
165
 
267
166
    if version == None:
268
167
        version = "UNKNOWN"
270
169
    # Putting '\" p as the first line tells "man" that the manpage
271
170
    # needs to be preprocessed by "pic".
272
171
    s = r''''\" p
 
172
.\" -*- nroff -*-
273
173
.TH "%s" 5 " DB Schema %s" "Open vSwitch %s" "Open vSwitch Manual"
274
 
.\" -*- nroff -*-
 
174
.fp 5 L CR              \\" Make fixed-width font available as \\fL.
275
175
.de TQ
276
176
.  br
277
177
.  ns
286
186
.SH NAME
287
187
%s \- %s database schema
288
188
.PP
289
 
''' % (title, schema.version, version, textToNroff(schema.name), schema.name)
 
189
''' % (manpage, schema.version, version, textToNroff(manpage), schema.name)
290
190
 
291
191
    tables = ""
292
192
    introNodes = []
306
206
        else:
307
207
            introNodes += [dbNode]
308
208
 
 
209
    documented_tables = set((name for (name, title) in summary))
 
210
    schema_tables = set(schema.tables.keys())
 
211
    undocumented_tables = schema_tables - documented_tables
 
212
    for table in undocumented_tables:
 
213
        raise error.Error("undocumented table %s" % table)
 
214
 
309
215
    s += blockXmlToNroff(introNodes) + "\n"
310
216
 
311
217
    s += r"""
361
267
 
362
268
The following options are also available:
363
269
  --er-diagram=DIAGRAM.PIC    include E-R diagram from DIAGRAM.PIC
364
 
  --title=TITLE               use TITLE as title instead of schema name
365
270
  --version=VERSION           use VERSION to display on document footer
366
271
  -h, --help                  display this help message\
367
272
""" % {'argv0': argv0}
371
276
    try:
372
277
        try:
373
278
            options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
374
 
                                              ['er-diagram=', 'title=',
 
279
                                              ['er-diagram=',
375
280
                                               'version=', 'help'])
376
281
        except getopt.GetoptError, geo:
377
282
            sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
378
283
            sys.exit(1)
379
284
 
380
285
        er_diagram = None
381
 
        title = None
382
286
        version = None
383
287
        for key, value in options:
384
288
            if key == '--er-diagram':
385
289
                er_diagram = value
386
 
            elif key == '--title':
387
 
                title = value
388
290
            elif key == '--version':
389
291
                version = value
390
292
            elif key in ['-h', '--help']:
398
300
            sys.exit(1)
399
301
 
400
302
        # XXX we should warn about undocumented tables or columns
401
 
        s = docsToNroff(args[0], args[1], er_diagram, title, version)
 
303
        s = docsToNroff(args[0], args[1], er_diagram, version)
402
304
        for line in s.split("\n"):
403
305
            line = line.strip()
404
306
            if len(line):