16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
"""Generate doc/en/release-notes/index.txt from the per-series NEWS files.
21
NEWS files are kept in doc/en/release-notes/, one file per series, e.g.
22
doc/en/release-notes/brz-2.3.txt
25
# XXX: add test_source test that latest doc/en/release-notes/brz-*.txt has the
26
# NEWS file-id (so that merges of new work will tend to always land new NEWS
27
# entries in the latest series).
33
21
from optparse import OptionParser
42
.. contents:: List of Releases
47
preamble_sphinx = """\
59
def natural_sort_key(file_name):
60
"""Split 'aaa-N.MMbbb' into ('aaa-', N, '.' MM, 'bbb')
62
e.g. 1.10b1 will sort as greater than 1.2::
64
>>> natural_sort_key('brz-1.10b1.txt') > natural_sort_key('brz-1.2.txt')
23
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
26
def split_into_topics(lines, out_file, out_dir):
27
"""Split a large NEWS file into topics, one per release.
29
Releases are detected by matching headings that look like
30
release names. Topics are created with matching names
31
replacing spaces with dashes.
67
file_name = os.path.basename(file_name)
68
parts = re.findall(r'(?:[0-9]+|[^0-9]+)', file_name)
71
if re.match('^[0-9]+$', part) is not None:
77
def output_news_file_sphinx(out_file, news_file_name):
78
news_file_name = os.path.basename(news_file_name)
79
if not news_file_name.endswith('.txt'):
81
'NEWS file %s does not have .txt extension.'
83
doc_name = news_file_name[:-4]
84
link_text = doc_name.replace('-', ' ')
85
out_file.write(' %s <%s>\n' % (link_text, doc_name))
88
def output_news_file_plain(out_file, news_file_name):
89
with open(news_file_name, 'r') as f:
91
title = os.path.basename(news_file_name)[len('brz-'):-len('.txt')]
93
if line == '####################\n':
94
line = '#' * len(title) + '\n'
95
elif line == 'Breezy Release Notes\n':
97
elif line == '.. toctree::\n':
99
elif line == ' :maxdepth: 1\n':
102
out_file.write('\n\n')
34
for index, line in enumerate(lines):
35
maybe_new_topic = line[:4] in ['bzr ', 'bzr-0',]
36
if maybe_new_topic and lines[index + 1].startswith('####'):
37
release = line.strip()
38
if topic_file is None:
40
out_file.write(".. toctree::\n :maxdepth: 1\n\n")
42
# close the current topic
44
topic_file = open_topic_file(out_file, out_dir, release)
46
topic_file.write(line)
48
# Still in the header - dump content straight to output
52
def open_topic_file(out_file, out_dir, release):
53
topic_name = release.replace(' ', '-')
54
out_file.write(" %s\n" % (topic_name,))
55
topic_path = os.path.join(out_dir, "%s.txt" % (topic_name,))
56
result = open(topic_path, 'w')
57
result.write("%s\n" % (release,))
107
parser = OptionParser(usage="%prog OUTPUT_FILE NEWS_FILE [NEWS_FILE ...]")
63
parser = OptionParser(usage="%prog SOURCE DESTINATION")
108
64
(options, args) = parser.parse_args(argv)
110
66
parser.print_help()
113
69
# Open the files and do the work
114
out_file_name = args[0]
115
news_file_names = sorted(args[1:], key=natural_sort_key, reverse=True)
117
if os.path.basename(out_file_name) == 'index.txt':
118
preamble = preamble_sphinx
119
output_news_file = output_news_file_sphinx
121
preamble = preamble_plain
122
output_news_file = output_news_file_plain
124
with open(out_file_name, 'w') as out_file:
125
out_file.write(preamble)
126
for news_file_name in news_file_names:
127
output_news_file(out_file, news_file_name)
71
outfile_name = args[1]
72
outdir = os.path.dirname(outfile_name)
73
infile = open(infile_name, 'r')
75
lines = infile.readlines()
78
outfile = open(outfile_name, 'w')
80
split_into_topics(lines, outfile, outdir)
130
85
if __name__ == '__main__':