1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
#!/usr/bin/env python3
# Copyright (C) 2019-2024 Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http:#mozilla.org/MPL/2.0/.
# Produce System Messages Manual
#
# This tool reads all the message files given on the command line.
# It pulls all the messages and description out, sorts them by
# message ID, and writes them out as a single (formatted) file.
#
# Invocation:
# The code is invoked using the command line:
#
# mes2doc.py [-o <output-file>] <files>
#
# If no output file is specified, output is written to stdout.
# The produced format is ReStructuredText.
import argparse
import os
import pathlib
import re
import sys
def parse_args():
parser = argparse.ArgumentParser(description='Convert set of *.mes files to .rst documentation format')
parser.add_argument('-o', '--output', help='Output file name (default to stdout).')
parser.add_argument('files', help='Input .mes files.', nargs='?')
args = parser.parse_args()
return args
def read_input_files(files):
messages = {}
for f in files:
if '/premium/' in f and not pathlib.Path(f).is_file():
# Premium can be missing which is fine for daily development, and CI tasks.
print(f'Ignoring non-existing file {f}')
continue
with open(f, encoding='utf-8') as fp:
print(f'Processing {f}')
msg_descr = None
msg_id = None
msg_text = None
for line in fp.readlines():
line = line.strip()
if not line or line.startswith('#'):
pass
elif line.startswith('//'):
pass
elif line.startswith('$'):
pass
elif line.startswith('%'):
# end previous message
if msg_id is not None:
section = msg_id.split('_')[0]
messages[msg_id] = (section, msg_id, msg_text, msg_descr)
# start next message
m = re.search(r'^%\s?([A-Z0-9_]+)\s+(.*)', line)
msg_id, msg_text = m.groups()
msg_descr = []
else:
msg_descr.append(line)
return messages
def generate_rst(messages):
rst = '..\n'
rst += ' File generated by "doc/sphinx/mes2doc.py" or by "make -C doc/sphinx". Do not edit by hand.\n\n'
rst += '''.. _kea-messages:
###################
Kea Messages Manual
###################
Kea is an open source implementation of the Dynamic Host Configuration
Protocol (DHCP) servers, developed and maintained by Internet Systems
Consortium (ISC).
This is the reference guide for Kea version |release|.
Links to the most up-to-date version of this document (in PDF, HTML,
and plain text formats), along with other useful information about
Kea, can be found in ISC's `Knowledgebase <https://kea.readthedocs.io>`_.
Please note that in the messages below, the percent sign (``%``) followed by a number is
used to indicate a placeholder for data that is provided by the Kea code during its operation.
.. toctree::
:numbered:
:maxdepth: 5
'''
prev_section = None
for _, msg in sorted(messages.items()):
section, msg_id, msg_text, msg_descr = msg
if section != prev_section:
prev_section = section
rst += '*' * len(section) + '\n'
rst += section + '\n'
rst += '*' * len(section) + '\n'
rst += '\n'
rst += msg_id + '\n'
rst += '=' * len(msg_id) + '\n'
rst += '\n'
rst += '.. code-block:: text\n'
rst += '\n'
rst += ' ' + msg_text + '\n'
rst += '\n'
rst += ''.join([line + '\n' for line in msg_descr])
rst += '\n'
rst += '''.. _kea-debug-messages:
*******************************
Kea Debug Messages By Log Level
*******************************
'''
rst += '.. include:: debug-messages.rst'
rst += '\n'
return rst
def generate(in_files, out_file):
messages = read_input_files(in_files)
rst = generate_rst(messages)
if out_file:
with open(out_file, 'w', encoding='utf-8') as f:
f.write(rst)
print('Wrote generated RST content to: %s' % out_file)
else:
print(rst)
def main():
args = parse_args()
if args.files is None:
parent_dir = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0])))
mes_files = sorted(pathlib.Path(f'{parent_dir}/../..').glob('**/*.mes'))
# Convert from Path to str.
mes_files = [str(i) for i in mes_files]
else:
mes_files = args.files
generate(mes_files, args.output)
if __name__ == '__main__':
main()
|