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