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
32
"""Check if a branch is clean.
34
:param branch: The branch to check for changes
35
TODO: jam 20051228 This might be better to ask for a WorkingTree
37
:return: (is_clean, message)
29
from bzrlib.osutils import local_time_offset, format_date
32
def get_file_revisions(branch, check=False):
33
"""Get the last changed revision for all files.
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)
41
basis_tree = branch.basis_tree()
42
for path, ie in basis_tree.inventory.iter_entries():
43
file_revisions[path] = ie.revision
46
# Without checking, the tree looks clean
47
return file_revisions, clean
40
49
new_tree = branch.working_tree()
41
50
except NoWorkingTree:
42
# Trees without a working tree can't be dirty :)
45
# Look for unknown files in the new tree
51
# Without a working tree, everything is clean
52
return file_revisions, clean
54
from bzrlib.diff import compare_trees
55
delta = compare_trees(basis_tree, new_tree, want_unchanged=False)
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:
64
file_revisions[old_path] = u'renamed to %s' % (new_path,)
65
for path, file_id, kind in delta.removed:
67
file_revisions[path] = 'removed'
68
for path, file_id, kind in delta.added:
70
file_revisions[path] = 'new'
71
for old_path, new_path, file_id, kind, text_mod, meta_mod in delta.renamed:
73
file_revisions[new_path] = u'renamed from %s' % (old_path,)
74
for path, file_id, kind, text_mod, meta_mod in delta.modified:
76
file_revisions[path] = 'modified'
46
78
for info in new_tree.list_files():
50
return False, 'path %s is unknown' % (path,)
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,)
79
path, status = info[0:2]
81
file_revisions[path] = 'unversioned'
84
return file_revisions, clean
68
87
# This contains a map of format id => formatter
69
88
# None is considered the default formatter
70
89
version_formats = {}
91
def create_date_str(timestamp=None, offset=None):
92
"""Just a wrapper around format_date to provide the right format.
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
97
Without parameters this function yields the current date in the local
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)
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.
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
87
# TODO: jam 20051228 This might be better as the datestamp
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()))
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))
96
133
if branch.nick is not None:
97
134
info.add('branch_nick', branch.nick)
138
if check_for_clean or include_file_revisions:
139
file_revisions, clean = get_file_revisions(branch, check=check_for_clean)
99
141
if check_for_clean:
100
clean, message = is_clean(branch)
102
143
info.add('clean', 'True')
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
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()
166
219
, 'branch_nick':branch.nick
170
if include_revision_history:
171
revs = branch.revision_history()
174
rev = branch.get_revision(rev_id)
175
log.append((rev_id, rev.message))
176
info['revisions'] = log
225
last_rev_id = branch.last_revision()
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)
233
if check_for_clean or include_file_revisions:
234
file_revisions, clean = get_file_revisions(branch, check=check_for_clean)
178
236
if check_for_clean:
179
clean, message = is_clean(branch)
181
238
info['clean'] = True