/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to tools/generate_release_notes.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
# Copyright 2009-2010 Canonical Ltd.
 
4
#
 
5
# This program is free software; you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License as published by
 
7
# the Free Software Foundation; either version 2 of the License, or
 
8
# (at your option) any later version.
 
9
#
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
18
 
 
19
"""Generate doc/en/release-notes/index.txt from the per-series NEWS files.
 
20
 
 
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
 
23
"""
 
24
 
 
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).
 
28
 
 
29
 
 
30
import os.path
 
31
import re
 
32
import sys
 
33
from optparse import OptionParser
 
34
 
 
35
 
 
36
preamble_plain = """\
 
37
####################
 
38
Bazaar Release Notes
 
39
####################
 
40
 
 
41
 
 
42
.. contents:: List of Releases
 
43
   :depth: 2
 
44
 
 
45
"""
 
46
 
 
47
preamble_sphinx = """\
 
48
####################
 
49
Bazaar Release Notes
 
50
####################
 
51
 
 
52
 
 
53
.. toctree::
 
54
   :maxdepth: 2
 
55
 
 
56
"""
 
57
 
 
58
 
 
59
def natural_sort_key(file_name):
 
60
    """Split 'aaa-N.MMbbb' into ('aaa-', N, '.' MM, 'bbb')
 
61
    
 
62
    e.g. 1.10b1 will sort as greater than 1.2::
 
63
 
 
64
        >>> natural_sort_key('bzr-1.10b1.txt') > natural_sort_key('bzr-1.2.txt')
 
65
        True
 
66
    """
 
67
    file_name = os.path.basename(file_name)
 
68
    parts = re.findall(r'(?:[0-9]+|[^0-9]+)', file_name)
 
69
    result = []
 
70
    for part in parts:
 
71
        if re.match('^[0-9]+$', part) is not None:
 
72
            part = int(part)
 
73
        result.append(part)
 
74
    return tuple(result)
 
75
 
 
76
 
 
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'):
 
80
        raise AssertionError(
 
81
            'NEWS file %s does not have .txt extension.'
 
82
            % (news_file_name,))
 
83
    doc_name = news_file_name[:-4]
 
84
    link_text = doc_name.replace('-', ' ')
 
85
    out_file.write('   %s <%s>\n' % (link_text, doc_name))
 
86
 
 
87
 
 
88
def output_news_file_plain(out_file, news_file_name):
 
89
    f = open(news_file_name, 'rb')
 
90
    try:
 
91
        lines = f.readlines()
 
92
    finally:
 
93
        f.close()
 
94
    title = os.path.basename(news_file_name)[len('bzr-'):-len('.txt')]
 
95
    for line in lines:
 
96
        if line == '####################\n':
 
97
            line = '#' * len(title) + '\n'
 
98
        elif line == 'Bazaar Release Notes\n':
 
99
            line = title + '\n'
 
100
        elif line == '.. toctree::\n':
 
101
            continue
 
102
        elif line == '   :maxdepth: 1\n':
 
103
            continue
 
104
        out_file.write(line)
 
105
    out_file.write('\n\n')
 
106
 
 
107
 
 
108
def main(argv):
 
109
    # Check usage
 
110
    parser = OptionParser(usage="%prog OUTPUT_FILE NEWS_FILE [NEWS_FILE ...]")
 
111
    (options, args) = parser.parse_args(argv)
 
112
    if len(args) < 2:
 
113
        parser.print_help()
 
114
        sys.exit(1)
 
115
 
 
116
    # Open the files and do the work
 
117
    out_file_name = args[0]
 
118
    news_file_names = sorted(args[1:], key=natural_sort_key, reverse=True)
 
119
 
 
120
    if os.path.basename(out_file_name) == 'index.txt':
 
121
        preamble = preamble_sphinx
 
122
        output_news_file = output_news_file_sphinx
 
123
    else:
 
124
        preamble = preamble_plain
 
125
        output_news_file = output_news_file_plain
 
126
 
 
127
    out_file = open(out_file_name, 'w')
 
128
    try:
 
129
        out_file.write(preamble)
 
130
        for news_file_name in news_file_names:
 
131
            output_news_file(out_file, news_file_name)
 
132
    finally:
 
133
        out_file.close()
 
134
 
 
135
 
 
136
if __name__ == '__main__':
 
137
    main(sys.argv[1:])