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/bzr-2.3.txt
25
# XXX: add test_source test that latest doc/en/release-notes/bzr-*.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).
21
33
from optparse import OptionParser
24
def split_into_topics(lines, out_file, out_dir):
25
"""Split a large NEWS file into topics, one per release.
27
Releases are detected by matching headings that look like
28
release names. Topics are created with matching names
29
replacing spaces with dashes.
48
def natural_sort_key(file_name):
49
"""Split 'aaa-N.MMbbb' into ('aaa-', N, '.' MM, 'bbb')
51
e.g. 1.10b1 will sort as greater than 1.2::
53
>>> natural_sort_key('bzr-1.10b1.txt') > natural_sort_key('bzr-1.2.txt')
32
for index, line in enumerate(lines):
33
maybe_new_topic = line[:4] in ('bzr ', 'bzr-',)
34
if maybe_new_topic and lines[index + 1].startswith('####'):
35
release = line.strip()
36
if topic_file is None:
38
out_file.write(".. toctree::\n :maxdepth: 1\n\n")
40
# close the current topic
42
topic_file = open_topic_file(out_file, out_dir, release)
44
topic_file.write(line)
46
# FIXME: the 'content' directive is used for rst2html (and
47
# conflicts with the 'toctree' we insert), we should get rid of
48
# that once we fully switch to sphinx -- vila 20100505
49
if (line.startswith('.. contents::')
50
or line.startswith(' :depth:')):
52
# Still in the header - dump content straight to output
54
if topic_file is not None:
55
# Close the last topic_file opened
59
def open_topic_file(out_file, out_dir, release):
60
topic_name = release.replace(' ', '-')
61
out_file.write(" %s <%s>\n" % (release, topic_name,))
62
topic_path = os.path.join(out_dir, "%s.txt" % (topic_name,))
63
result = open(topic_path, 'w')
64
result.write("%s\n" % (release,))
56
parts = re.findall(r'(?:[0-9]+|[^0-9]+)', file_name)
59
if re.match('^[0-9]+$', part) is not None:
70
parser = OptionParser(usage="%prog SOURCE DESTINATION")
67
parser = OptionParser(usage="%prog OUTPUT_FILE NEWS_FILE [NEWS_FILE ...]")
71
68
(options, args) = parser.parse_args(argv)
73
70
parser.print_help()
76
73
# Open the files and do the work
78
outfile_name = args[1]
79
outdir = os.path.dirname(outfile_name)
80
infile = open(infile_name, 'r')
82
lines = infile.readlines()
85
outfile = open(outfile_name, 'w')
87
split_into_topics(lines, outfile, outdir)
74
out_file_name = args[0]
75
news_file_names = map(os.path.basename, args[1:])
76
news_file_names = sorted(news_file_names, key=natural_sort_key,
79
out_file = open(out_file_name, 'w')
81
out_file.write(preamble)
82
for news_file_name in news_file_names:
83
if not news_file_name.endswith('.txt'):
85
'NEWS file %s does not have .txt extension.'
87
doc_name = news_file_name[:-4]
88
link_text = doc_name.replace('-', ' ')
89
out_file.write(' %s <%s>\n' % (link_text, doc_name))
92
94
if __name__ == '__main__':