17 """A dumb configuration.rst generator that relies on source comments.""" 22 TARGET =
'docs/source/configuration.rst' 24 PREFIX =
""".. Copyright 2016 The Cartographer Authors 26 .. Licensed under the Apache License, Version 2.0 (the "License"); 27 you may not use this file except in compliance with the License. 28 You may obtain a copy of the License at 30 .. http://www.apache.org/licenses/LICENSE-2.0 32 .. Unless required by applicable law or agreed to in writing, software 33 distributed under the License is distributed on an "AS IS" BASIS, 34 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 See the License for the specific language governing permissions and 36 limitations under the License. 42 .. DO NOT EDIT! This documentation is AUTOGENERATED, please edit .proto files as 43 .. needed and run scripts/update_configuration_doc.py. 48 NODOC =
'Not yet documented.' 52 def __init__(self, name, package, preceding_comments):
63 self.options.append((option_type, name, comments))
67 """Computes the list of Message objects of the option messages in a file.""" 68 line_iter = iter(proto_file)
71 for line
in line_iter:
73 if line.startswith(
'package'):
74 assert line[-1] ==
';' 75 package = line[7:-1].strip()
78 assert '}' not in line
84 for line
in line_iter:
89 elif line.startswith(
'//'):
91 comment = line[2:].strip()
92 if not comment.startswith(
'NEXT ID:'):
93 message_comments.append(comment)
94 elif line.startswith(
'message')
and line.endswith(
'Options {'):
95 message_name = package +
'.' + line[7:-1].strip()
100 print(
" Found '%s'." % message_name)
101 message =
Message(message_name, package, message_comments)
102 message_list.append(message)
107 for line
in line_iter:
111 message.AddTrailingComments(option_comments)
113 elif line.startswith(
'//'):
114 comment = line[2:].strip()
115 if not comment.startswith(
'NEXT ID:'):
116 option_comments.append(comment)
118 assert not line.startswith(
'required')
119 if multiline
is None:
120 if line.startswith(
'optional'):
125 multiline +=
' ' + line
126 if not multiline.endswith(
';'):
128 assert len(multiline) < 200
129 option = multiline[8:-1].strip().rstrip(
'0123456789').strip()
130 assert option.endswith(
'=')
131 option_type, option_name = option[:-1].strip().split();
132 print(
" Option '%s'." % option_name)
134 message.AddOption(option_type, option_name, option_comments)
141 """Recursively parses all proto files into a list of Message objects.""" 143 for dirpath, dirnames, filenames
in os.walk(root):
144 for name
in filenames:
145 if name.endswith(
'.proto'):
146 path = os.path.join(dirpath, name)
147 print(
"Found '%s'..." % path)
148 assert not os.path.islink(path)
149 message_list.extend(
ParseProtoFile(io.open(path, encoding=
'UTF-8')))
154 """Raised when resolving a message name fails.""" 157 class Resolver(object):
161 def Resolve(self, message_name, package_name):
162 if message_name
in (
'bool',
'double',
'float',
'int32'):
164 if message_name.startswith(
'.'):
165 return message_name[1:]
166 package = package_name.split(
'.')
167 for levels
in range(len(package), -1, -1):
168 candidate =
'.'.join(package[0:levels]) +
'.' + message_name
172 'Resolving %s in %s failed.' % (message_name, package_name))
176 """Recursively generates documentation, sorts and writes it.""" 178 resolver =
Resolver(message.name
for message
in message_list)
181 for message
in message_list:
182 content = [message.name,
'=' * len(message.name),
'']
183 assert message.name
not in output_dict
184 output_dict[message.name] = content
185 if message.preceding_comments:
186 content.extend(preceding_comments)
188 for option_type, option_name, option_comments
in message.options:
190 resolver.Resolve(option_type, message.package) +
' ' + option_name)
191 if not option_comments:
192 option_comments.append(NODOC)
193 for comment
in option_comments:
194 content.append(
' ' + comment)
196 if message.trailing_comments:
197 content.extend(message.trailing_comments)
200 output = [
'\n'.join(doc)
for key, doc
in sorted(list(output_dict.items()))]
201 print(
'\n\n'.join(output), file=output_file)
205 assert not os.path.islink(TARGET)
and os.path.isfile(TARGET)
206 assert not os.path.islink(ROOT)
and os.path.isdir(ROOT)
207 output_file = io.open(TARGET, mode=
'w', encoding=
'UTF-8', newline=
'\n')
208 output_file.write(PREFIX)
210 output_file.write(SUFFIX)
214 if __name__ ==
"__main__":
def Resolve(self, message_name, package_name)
def __init__(self, name_set)
def AddTrailingComments(self, comments)
def GenerateDocumentation(output_file, root)
def ParseProtoFile(proto_file)
def ParseProtoFilesRecursively(root)
def AddOption(self, option_type, name, comments)
def __init__(self, name, package, preceding_comments)