]>
git.proxmox.com Git - mirror_ovs.git/blob - ovsdb/ovsdb-doc
3 # Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
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:
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 from datetime
import date
21 import xml
.dom
.minidom
24 from ovs
.db
import error
27 from build
.nroff
import *
31 def typeAndConstraintsToNroff(column
):
32 type = column
.type.toEnglish(escape_nroff_literal
)
33 constraints
= column
.type.constraintsToEnglish(escape_nroff_literal
,
36 type += ", " + constraints
38 type += " (must be unique within table)"
41 def columnGroupToNroff(table
, groupXml
, documented_columns
):
44 for node
in groupXml
.childNodes
:
45 if (node
.nodeType
== node
.ELEMENT_NODE
46 and node
.tagName
in ('column', 'group')):
50 and not (node
.nodeType
== node
.TEXT_NODE
51 and node
.data
.isspace())):
52 raise error
.Error("text follows <column> or <group> inside <group>: %s" % node
)
56 intro
= block_xml_to_nroff(introNodes
)
58 for node
in columnNodes
:
59 if node
.tagName
== 'column':
60 name
= node
.attributes
['name'].nodeValue
61 documented_columns
.add(name
)
62 column
= table
.columns
[name
]
63 if node
.hasAttribute('key'):
64 key
= node
.attributes
['key'].nodeValue
65 if node
.hasAttribute('type'):
66 type_string
= node
.attributes
['type'].nodeValue
67 type_json
= ovs
.json
.from_string(str(type_string
))
68 # py2 -> py3 means str -> bytes and unicode -> str
70 if type(type_json
) in (str, unicode):
71 raise error
.Error("%s %s:%s has invalid 'type': %s"
72 % (table
.name
, name
, key
, type_json
))
74 if type(type_json
) in (bytes
, str):
75 raise error
.Error("%s %s:%s has invalid 'type': %s"
76 % (table
.name
, name
, key
, type_json
))
77 type_
= ovs
.db
.types
.BaseType
.from_json(type_json
)
79 type_
= column
.type.value
81 nameNroff
= "%s : %s" % (name
, key
)
84 typeNroff
= "optional %s" % column
.type.value
.toEnglish(
86 if (column
.type.value
.type == ovs
.db
.types
.StringType
and
87 type_
.type == ovs
.db
.types
.BooleanType
):
88 # This is a little more explicit and helpful than
89 # "containing a boolean"
90 typeNroff
+= r
", either \fBtrue\fR or \fBfalse\fR"
92 if type_
.type != column
.type.value
.type:
93 type_english
= type_
.toEnglish()
94 if type_english
[0] in 'aeiou':
95 typeNroff
+= ", containing an %s" % type_english
97 typeNroff
+= ", containing a %s" % type_english
99 type_
.constraintsToEnglish(escape_nroff_literal
,
102 typeNroff
+= ", %s" % constraints
107 typeNroff
= typeAndConstraintsToNroff(column
)
108 if not column
.mutable
:
109 typeNroff
= "immutable %s" % typeNroff
110 body
+= '.IP "\\fB%s\\fR: %s"\n' % (nameNroff
, typeNroff
)
111 body
+= block_xml_to_nroff(node
.childNodes
, '.IP') + "\n"
112 summary
+= [('column', nameNroff
, typeNroff
)]
113 elif node
.tagName
== 'group':
114 title
= node
.attributes
["title"].nodeValue
115 subSummary
, subIntro
, subBody
= columnGroupToNroff(
116 table
, node
, documented_columns
)
117 summary
+= [('group', title
, subSummary
)]
118 body
+= '.ST "%s:"\n' % text_to_nroff(title
)
119 body
+= subIntro
+ subBody
121 raise error
.Error("unknown element %s in <table>" % node
.tagName
)
122 return summary
, intro
, body
124 def tableSummaryToNroff(summary
, level
=0):
126 for type, name
, arg
in summary
:
128 s
+= ".TQ %.2fin\n\\fB%s\\fR\n%s\n" % (3 - level
* .25, name
, arg
)
130 s
+= ".TQ .25in\n\\fI%s:\\fR\n.RS .25in\n" % name
131 s
+= tableSummaryToNroff(arg
, level
+ 1)
135 def tableToNroff(schema
, tableXml
):
136 tableName
= tableXml
.attributes
['name'].nodeValue
137 table
= schema
.tables
[tableName
]
139 documented_columns
= set()
143 summary
, intro
, body
= columnGroupToNroff(table
, tableXml
,
146 s
+= '.SS "Summary:\n'
147 s
+= tableSummaryToNroff(summary
)
148 s
+= '.SS "Details:\n'
151 schema_columns
= set(table
.columns
.keys())
152 undocumented_columns
= schema_columns
- documented_columns
153 for column
in undocumented_columns
:
154 raise error
.Error("table %s has undocumented column %s"
155 % (tableName
, column
))
159 def docsToNroff(schemaFile
, xmlFile
, erFile
, version
=None):
160 schema
= ovs
.db
.schema
.DbSchema
.from_json(ovs
.json
.from_file(schemaFile
))
161 doc
= xml
.dom
.minidom
.parse(xmlFile
).documentElement
163 schemaDate
= os
.stat(schemaFile
).st_mtime
164 xmlDate
= os
.stat(xmlFile
).st_mtime
165 d
= date
.fromtimestamp(max(schemaDate
, xmlDate
))
167 if doc
.hasAttribute('name'):
168 manpage
= doc
.attributes
['name'].nodeValue
170 manpage
= schema
.name
175 # Putting '\" p as the first line tells "man" that the manpage
176 # needs to be preprocessed by "pic".
179 .TH "%s" 5 " DB Schema %s" "Open vSwitch %s" "Open vSwitch Manual"
180 .fp 5 L CR \\" Make fixed-width font available as \\fL.
193 %s \- %s database schema
195 ''' % (manpage
, schema
.version
, version
, text_to_nroff(manpage
), schema
.name
)
201 for dbNode
in doc
.childNodes
:
202 if (dbNode
.nodeType
== dbNode
.ELEMENT_NODE
203 and dbNode
.tagName
== "table"):
204 tableNodes
+= [dbNode
]
206 name
= dbNode
.attributes
['name'].nodeValue
207 if dbNode
.hasAttribute("title"):
208 title
= dbNode
.attributes
['title'].nodeValue
210 title
= name
+ " configuration."
211 summary
+= [(name
, title
)]
213 introNodes
+= [dbNode
]
215 documented_tables
= set((name
for (name
, title
) in summary
))
216 schema_tables
= set(schema
.tables
.keys())
217 undocumented_tables
= schema_tables
- documented_tables
218 for table
in undocumented_tables
:
219 raise error
.Error("undocumented table %s" % table
)
221 s
+= block_xml_to_nroff(introNodes
) + "\n"
226 The following list summarizes the purpose of each of the tables in the
227 \fB%s\fR database. Each table is described in more detail on a later
232 for name
, title
in summary
:
237 """ % (name
, text_to_nroff(title
))
241 .\\" check if in troff mode (TTY)
244 .SH "TABLE RELATIONSHIPS"
246 The following diagram shows the relationship among tables in the
247 database. Each node represents a table. Tables that are part of the
248 ``root set'' are shown with double borders. Each edge leads from the
249 table that contains it and points to the table that its value
250 represents. Edges are labeled with their column names, followed by a
251 constraint on the number of allowed values: \\fB?\\fR for zero or one,
252 \\fB*\\fR for zero or more, \\fB+\\fR for one or more. Thick lines
253 represent strong references; thin lines represent weak references.
256 erStream
= open(erFile
, "r")
257 for line
in erStream
:
262 for node
in tableNodes
:
263 s
+= tableToNroff(schema
, node
) + "\n"
268 %(argv0)s: ovsdb schema documentation generator
269 Prints documentation for an OVSDB schema as an nroff-formatted manpage.
270 usage: %(argv0)s [OPTIONS] SCHEMA XML
271 where SCHEMA is an OVSDB schema in JSON format
272 and XML is OVSDB documentation in XML format.
274 The following options are also available:
275 --er-diagram=DIAGRAM.PIC include E-R diagram from DIAGRAM.PIC
276 --version=VERSION use VERSION to display on document footer
277 -h, --help display this help message\
278 """ % {'argv0': argv0
})
281 if __name__
== "__main__":
284 options
, args
= getopt
.gnu_getopt(sys
.argv
[1:], 'hV',
287 except getopt
.GetoptError
as geo
:
288 sys
.stderr
.write("%s: %s\n" % (argv0
, geo
.msg
))
293 for key
, value
in options
:
294 if key
== '--er-diagram':
296 elif key
== '--version':
298 elif key
in ['-h', '--help']:
304 sys
.stderr
.write("%s: exactly 2 non-option arguments required "
305 "(use --help for help)\n" % argv0
)
308 # XXX we should warn about undocumented tables or columns
309 s
= docsToNroff(args
[0], args
[1], er_diagram
, version
)
310 for line
in s
.split("\n"):
315 except error
.Error
as e
:
316 sys
.stderr
.write("%s: %s\n" % (argv0
, e
.msg
))