/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
1
# Copyright (C) 2005 Canonical Ltd
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""\
18
Routines for extracting all version information from a bzr branch.
19
"""
20
21
import time
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
22
import pprint
23
0.8.3 by John Arbash Meinel
Playing around with some formats
24
from StringIO import StringIO
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
25
0.8.3 by John Arbash Meinel
Playing around with some formats
26
from bzrlib.errors import NoWorkingTree
27
from bzrlib.log import show_log, log_formatter
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
28
from bzrlib.rio import RioReader, RioWriter, Stanza
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
29
from bzrlib.osutils import local_time_offset, format_date
30
31
32
def get_file_revisions(branch, check=False):
33
    """Get the last changed revision for all files.
34
35
    :param branch: The branch we are checking.
36
    :param check: See if there are uncommitted changes.
37
    :return: ({file_path => last changed revision}, Tree_is_clean)
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
38
    """
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
39
    clean = True
40
    file_revisions = {}
41
    basis_tree = branch.basis_tree()
42
    for path, ie in basis_tree.inventory.iter_entries():
43
        file_revisions[path] = ie.revision
44
45
    if not check:
46
        # Without checking, the tree looks clean
47
        return file_revisions, clean
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
48
    try:
49
        new_tree = branch.working_tree()
50
    except NoWorkingTree:
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
51
        # Without a working tree, everything is clean
52
        return file_revisions, clean
53
54
    from bzrlib.diff import compare_trees
55
    delta = compare_trees(basis_tree, new_tree, want_unchanged=False)
56
57
    # Using a 2-pass algorithm for renames. This is because you might have
58
    # renamed something out of the way, and then created a new file
59
    # in which case we would rather see the new marker
60
    # Or you might have removed the target, and then renamed
61
    # in which case we would rather see the renamed marker
62
    for old_path, new_path, file_id, kind, text_mod, meta_mod in delta.renamed:
63
        clean = False
64
        file_revisions[old_path] = u'renamed to %s' % (new_path,)
65
    for path, file_id, kind in delta.removed:
66
        clean = False
67
        file_revisions[path] = 'removed'
68
    for path, file_id, kind in delta.added:
69
        clean = False
70
        file_revisions[path] = 'new'
71
    for old_path, new_path, file_id, kind, text_mod, meta_mod in delta.renamed:
72
        clean = False
73
        file_revisions[new_path] = u'renamed from %s' % (old_path,)
74
    for path, file_id, kind, text_mod, meta_mod in delta.modified:
75
        clean = False
76
        file_revisions[path] = 'modified'
77
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
78
    for info in new_tree.list_files():
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
79
        path, status = info[0:2]
80
        if status == '?':
81
            file_revisions[path] = 'unversioned'
82
            clean = False
83
84
    return file_revisions, clean
0.8.3 by John Arbash Meinel
Playing around with some formats
85
86
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
87
# This contains a map of format id => formatter
88
# None is considered the default formatter
0.8.3 by John Arbash Meinel
Playing around with some formats
89
version_formats = {}
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
90
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
91
def create_date_str(timestamp=None, offset=None):
92
    """Just a wrapper around format_date to provide the right format.
93
    
94
    We don't want to use '%a' in the time string, because it is locale
95
    dependant. We also want to force timezone original, and show_offset
96
97
    Without parameters this function yields the current date in the local
98
    time zone.
99
    """
100
    if timestamp is None and offset is None:
101
        timestamp = time.time()
102
        offset = local_time_offset()
103
    return format_date(timestamp, offset, date_fmt='%Y-%m-%d %H:%M:%S',
104
                       timezone='original', show_offset=True)
105
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
106
0.8.2 by John Arbash Meinel
Have working rio output
107
def generate_rio_version(branch, to_file,
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
108
        check_for_clean=False,
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
109
        include_revision_history=False,
110
        include_file_revisions=False):
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
111
    """Create the version file for this project.
112
113
    :param branch: The branch to write information about
114
    :param to_file: The file to write the information
115
    :param check_for_clean: If true, check if the branch is clean.
116
        This can be expensive for large trees. This is also only
117
        valid for branches with working trees.
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
118
    :param include_revision_history: Write out the list of revisions, and
119
        the commit message associated with each
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
120
    :param include_file_revisions: Write out the set of last changed revision
121
        for each file.
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
122
    """
123
    info = Stanza()
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
124
    info.add('build-date', create_date_str())
0.8.2 by John Arbash Meinel
Have working rio output
125
    info.add('revno', str(branch.revno()))
0.8.3 by John Arbash Meinel
Playing around with some formats
126
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
127
    last_rev_id = branch.last_revision()
128
    if last_rev_id is not None:
0.8.16 by John Arbash Meinel
Using revision-id for rio, and revision_id for python
129
        info.add('revision-id', last_rev_id)
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
130
        rev = branch.get_revision(last_rev_id)
131
        info.add('date', create_date_str(rev.timestamp, rev.timezone))
0.8.3 by John Arbash Meinel
Playing around with some formats
132
0.8.2 by John Arbash Meinel
Have working rio output
133
    if branch.nick is not None:
0.8.16 by John Arbash Meinel
Using revision-id for rio, and revision_id for python
134
        info.add('branch-nick', branch.nick)
0.8.3 by John Arbash Meinel
Playing around with some formats
135
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
136
    file_revisions = {}
137
    clean = True
138
    if check_for_clean or include_file_revisions:
139
        file_revisions, clean = get_file_revisions(branch, check=check_for_clean)
140
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
141
    if check_for_clean:
0.8.3 by John Arbash Meinel
Playing around with some formats
142
        if clean:
143
            info.add('clean', 'True')
144
        else:
0.8.2 by John Arbash Meinel
Have working rio output
145
            info.add('clean', 'False')
0.8.3 by John Arbash Meinel
Playing around with some formats
146
147
    if include_revision_history:
148
        revs = branch.revision_history()
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
149
        log = Stanza()
150
        for rev_id in revs:
151
            rev = branch.get_revision(rev_id)
0.8.6 by John Arbash Meinel
Updated the blackbox tests.
152
            log.add('id', rev_id)
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
153
            log.add('message', rev.message)
0.8.15 by John Arbash Meinel
Including the date stamp for all revisions.
154
            log.add('date', create_date_str(rev.timestamp, rev.timezone))
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
155
        sio = StringIO()
156
        log_writer = RioWriter(to_file=sio)
157
        log_writer.write_stanza(log)
158
        info.add('revisions', sio.getvalue())
0.8.3 by John Arbash Meinel
Playing around with some formats
159
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
160
    if include_file_revisions:
161
        files = Stanza()
162
        for path in sorted(file_revisions.keys()):
163
            files.add('path', path)
164
            files.add('revision', file_revisions[path])
165
        sio = StringIO()
166
        file_writer = RioWriter(to_file=sio)
167
        file_writer.write_stanza(files)
168
        info.add('file-revisions', sio.getvalue())
169
0.8.2 by John Arbash Meinel
Have working rio output
170
    writer = RioWriter(to_file=to_file)
171
    writer.write_stanza(info)
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
172
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
173
0.8.3 by John Arbash Meinel
Playing around with some formats
174
version_formats['rio'] = generate_rio_version
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
175
# Default format is rio
0.8.3 by John Arbash Meinel
Playing around with some formats
176
version_formats[None] = generate_rio_version
177
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
178
179
# Header and footer for the python format
180
_py_version_header = '''#!/usr/bin/env python
0.8.3 by John Arbash Meinel
Playing around with some formats
181
"""\\
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
182
This file is automatically generated by generate_version_info
0.8.3 by John Arbash Meinel
Playing around with some formats
183
It uses the current working tree to determine the revision.
184
So don't edit it. :)
185
"""
186
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
187
'''
188
189
190
_py_version_footer = '''
0.8.3 by John Arbash Meinel
Playing around with some formats
191
192
if __name__ == '__main__':
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
193
    print 'revision: %(revno)d' % version_info
194
    print 'nick: %(branch_nick)s' % version_info
195
    print 'revision id: %(revision_id)s' % version_info
0.8.3 by John Arbash Meinel
Playing around with some formats
196
'''
197
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
198
0.8.3 by John Arbash Meinel
Playing around with some formats
199
def generate_python_version(branch, to_file,
200
        check_for_clean=False,
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
201
        include_revision_history=False,
202
        include_file_revisions=False):
0.8.3 by John Arbash Meinel
Playing around with some formats
203
    """Create a python version file for this project.
204
205
    :param branch: The branch to write information about
206
    :param to_file: The file to write the information
207
    :param check_for_clean: If true, check if the branch is clean.
208
        This can be expensive for large trees. This is also only
209
        valid for branches with working trees.
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
210
    :param include_revision_history: Write out the list of revisions, and
211
        the commit message associated with each
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
212
    :param include_file_revisions: Write out the set of last changed revision
213
        for each file.
0.8.3 by John Arbash Meinel
Playing around with some formats
214
    """
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
215
    # TODO: jam 20051228 The python output doesn't actually need to be
216
    #       encoded, because it should only generate ascii safe output.
0.8.16 by John Arbash Meinel
Using revision-id for rio, and revision_id for python
217
    info = {'build_date':create_date_str()
0.8.3 by John Arbash Meinel
Playing around with some formats
218
              , 'revno':branch.revno()
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
219
              , 'revision_id':None
0.8.3 by John Arbash Meinel
Playing around with some formats
220
              , 'branch_nick':branch.nick
221
              , 'clean':None
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
222
              , 'date':None
0.8.3 by John Arbash Meinel
Playing around with some formats
223
    }
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
224
    revisions = []
225
226
    last_rev_id = branch.last_revision()
227
    if last_rev_id:
228
        rev = branch.get_revision(last_rev_id)
229
        info['revision_id'] = last_rev_id
230
        info['date'] = create_date_str(rev.timestamp, rev.timezone)
231
232
    file_revisions = {}
233
    clean = True
234
    if check_for_clean or include_file_revisions:
235
        file_revisions, clean = get_file_revisions(branch, check=check_for_clean)
0.8.3 by John Arbash Meinel
Playing around with some formats
236
237
    if check_for_clean:
0.8.5 by John Arbash Meinel
Adding some whitebox tests for the output of generate_version_info
238
        if clean:
0.8.3 by John Arbash Meinel
Playing around with some formats
239
            info['clean'] = True
240
        else:
241
            info['clean'] = False
242
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
243
    info_str = pprint.pformat(info)
244
    to_file.write(_py_version_header)
0.8.14 by John Arbash Meinel
Clean up whitespace in --format=python
245
    to_file.write('version_info = ')
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
246
    to_file.write(info_str)
0.8.14 by John Arbash Meinel
Clean up whitespace in --format=python
247
    to_file.write('\n\n')
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
248
249
    if include_revision_history:
250
        revs = branch.revision_history()
251
        for rev_id in revs:
252
            rev = branch.get_revision(rev_id)
0.8.15 by John Arbash Meinel
Including the date stamp for all revisions.
253
            revisions.append((rev_id, rev.message, rev.timestamp, rev.timezone))
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
254
        revision_str = pprint.pformat(revisions)
255
        to_file.write('revisions = ')
256
        to_file.write(revision_str)
0.8.14 by John Arbash Meinel
Clean up whitespace in --format=python
257
        to_file.write('\n\n')
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
258
    else:
259
        to_file.write('revisions = {}\n\n')
260
261
    if include_file_revisions:
262
        file_rev_str = pprint.pformat(file_revisions)
263
        to_file.write('file_revisions = ')
264
        to_file.write(file_rev_str)
0.8.14 by John Arbash Meinel
Clean up whitespace in --format=python
265
        to_file.write('\n\n')
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
266
    else:
267
        to_file.write('file_revisions = {}\n\n')
268
0.8.4 by John Arbash Meinel
Cleaned up formats include-history always displays the log message.
269
    to_file.write(_py_version_footer)
0.8.3 by John Arbash Meinel
Playing around with some formats
270
0.8.13 by John Arbash Meinel
Including file-revisions fields, updated test suite.
271
0.8.3 by John Arbash Meinel
Playing around with some formats
272
version_formats['python'] = generate_python_version
0.8.1 by John Arbash Meinel
Creating a plugin to ease generating version information from a tree.
273