~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to generate_version_info.py

  • Committer: John Arbash Meinel
  • Date: 2006-01-03 18:18:11 UTC
  • mto: (2022.1.1 version-info-55794)
  • mto: This revision was merged to the branch mainline in revision 2028.
  • Revision ID: john@arbash-meinel.com-20060103181811-384fb3f4168f72fc
Including file-revisions fields, updated test suite.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
from bzrlib.errors import NoWorkingTree
27
27
from bzrlib.log import show_log, log_formatter
28
28
from bzrlib.rio import RioReader, RioWriter, Stanza
29
 
 
30
 
 
31
 
def is_clean(branch):
32
 
    """Check if a branch is clean.
33
 
 
34
 
    :param branch: The branch to check for changes
35
 
    TODO: jam 20051228 This might be better to ask for a WorkingTree
36
 
            instead of a Branch.
37
 
    :return: (is_clean, message)
 
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)
38
38
    """
 
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
39
48
    try:
40
49
        new_tree = branch.working_tree()
41
50
    except NoWorkingTree:
42
 
        # Trees without a working tree can't be dirty :)
43
 
        return True, ''
44
 
 
45
 
    # Look for unknown files in the new tree
 
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
 
46
78
    for info in new_tree.list_files():
47
 
        path = info[0]
48
 
        file_class = info[1]
49
 
        if file_class == '?':
50
 
            return False, 'path %s is unknown' % (path,)
51
 
 
52
 
    from bzrlib.diff import compare_trees
53
 
    # See if there is anything that has been changed
54
 
    old_tree = branch.basis_tree()
55
 
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
56
 
    if len(delta.added) > 0:
57
 
        return False, 'have added files: %r' % (delta.added,)
58
 
    if len(delta.removed) > 0:
59
 
        return False, 'have removed files: %r' % (delta.removed,)
60
 
    if len(delta.modified) > 0:
61
 
        return False, 'have modified files: %r' % (delta.modified,)
62
 
    if len(delta.renamed) > 0:
63
 
        return False, 'have renamed files: %r' % (delta.renamed,)
64
 
 
65
 
    return True, ''
 
79
        path, status = info[0:2]
 
80
        if status == '?':
 
81
            file_revisions[path] = 'unversioned'
 
82
            clean = False
 
83
 
 
84
    return file_revisions, clean
66
85
 
67
86
 
68
87
# This contains a map of format id => formatter
69
88
# None is considered the default formatter
70
89
version_formats = {}
71
90
 
 
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
 
72
106
 
73
107
def generate_rio_version(branch, to_file,
74
108
        check_for_clean=False,
75
 
        include_revision_history=False):
 
109
        include_revision_history=False,
 
110
        include_file_revisions=False):
76
111
    """Create the version file for this project.
77
112
 
78
113
    :param branch: The branch to write information about
82
117
        valid for branches with working trees.
83
118
    :param include_revision_history: Write out the list of revisions, and
84
119
        the commit message associated with each
 
120
    :param include_file_revisions: Write out the set of last changed revision
 
121
        for each file.
85
122
    """
86
123
    info = Stanza()
87
 
    # TODO: jam 20051228 This might be better as the datestamp 
88
 
    #       of the last commit
89
 
    info.add('date', time.strftime('%Y-%m-%d %H:%M:%S'))
 
124
    info.add('build-date', create_date_str())
90
125
    info.add('revno', str(branch.revno()))
91
126
 
92
 
    last_rev = branch.last_revision()
93
 
    if last_rev is not None:
94
 
        info.add('revision_id', last_rev)
 
127
    last_rev_id = branch.last_revision()
 
128
    if last_rev_id is not None:
 
129
        info.add('revision_id', last_rev_id)
 
130
        rev = branch.get_revision(last_rev_id)
 
131
        info.add('date', create_date_str(rev.timestamp, rev.timezone))
95
132
 
96
133
    if branch.nick is not None:
97
134
        info.add('branch_nick', branch.nick)
98
135
 
 
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
 
99
141
    if check_for_clean:
100
 
        clean, message = is_clean(branch)
101
142
        if clean:
102
143
            info.add('clean', 'True')
103
144
        else:
115
156
        log_writer.write_stanza(log)
116
157
        info.add('revisions', sio.getvalue())
117
158
 
 
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
 
118
169
    writer = RioWriter(to_file=to_file)
119
170
    writer.write_stanza(info)
120
171
 
146
197
 
147
198
def generate_python_version(branch, to_file,
148
199
        check_for_clean=False,
149
 
        include_revision_history=False):
 
200
        include_revision_history=False,
 
201
        include_file_revisions=False):
150
202
    """Create a python version file for this project.
151
203
 
152
204
    :param branch: The branch to write information about
156
208
        valid for branches with working trees.
157
209
    :param include_revision_history: Write out the list of revisions, and
158
210
        the commit message associated with each
 
211
    :param include_file_revisions: Write out the set of last changed revision
 
212
        for each file.
159
213
    """
160
214
    # TODO: jam 20051228 The python output doesn't actually need to be
161
215
    #       encoded, because it should only generate ascii safe output.
162
 
    info = {'date':time.strftime('%Y-%m-%d %H:%M:%S')
 
216
    info = {'build-date':create_date_str()
163
217
              , 'revno':branch.revno()
164
 
              , 'revision_id':branch.last_revision()
165
 
              , 'revisions':None
 
218
              , 'revision_id':None
166
219
              , 'branch_nick':branch.nick
167
220
              , 'clean':None
 
221
              , 'date':None
168
222
    }
169
 
 
170
 
    if include_revision_history:
171
 
        revs = branch.revision_history()
172
 
        log = []
173
 
        for rev_id in revs:
174
 
            rev = branch.get_revision(rev_id)
175
 
            log.append((rev_id, rev.message))
176
 
        info['revisions'] = log
 
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)
177
235
 
178
236
    if check_for_clean:
179
 
        clean, message = is_clean(branch)
180
237
        if clean:
181
238
            info['clean'] = True
182
239
        else:
187
244
    to_file.write('version_info =')
188
245
    to_file.write(info_str)
189
246
    to_file.write('\n')
 
247
 
 
248
    if include_revision_history:
 
249
        revs = branch.revision_history()
 
250
        for rev_id in revs:
 
251
            rev = branch.get_revision(rev_id)
 
252
            revisions.append((rev_id, rev.message))
 
253
        revision_str = pprint.pformat(revisions)
 
254
        to_file.write('revisions = ')
 
255
        to_file.write(revision_str)
 
256
        to_file.write('\n')
 
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)
 
264
        to_file.write('\n')
 
265
    else:
 
266
        to_file.write('file_revisions = {}\n\n')
 
267
 
190
268
    to_file.write(_py_version_footer)
191
269
 
 
270
 
192
271
version_formats['python'] = generate_python_version
193
272