6
6
import bzrlib, bzrlib.errors
10
from bzrlib.inventory import ROOT_ID
11
15
from sets import Set as set
13
def _canonicalize_revision(branch, revision=None):
17
def _canonicalize_revision(branch, revno):
14
18
"""Turn some sort of revision information into a single
15
19
set of from-to revision ids.
21
25
# This is a little clumsy because revision parsing may return
22
26
# a single entry, or a list
25
elif isinstance(revision, (list, tuple)):
26
if len(revision) == 0:
28
elif len(revision) == 1:
31
elif len(revision) == 2:
35
raise bzrlib.errors.BzrCommandError('revision can be'
36
' at most 2 entries.')
42
new = branch.lookup_revision(new)
44
old = branch.last_patch()
46
old = branch.lookup_revision(old)
28
new = branch.last_patch()
30
new = branch.lookup_revision(revno)
33
raise BzrCommandError('Cannot generate a changset with no commits in tree.')
35
old = branch.get_revision(new).precursor
51
40
"""Get the old and new trees based on revision.
53
42
if revisions[0] is None:
54
old_tree = branch.basis_tree()
43
if hasattr(branch, 'get_root_id'): # Watch out for trees with labeled ROOT ids
44
old_tree = EmptyTree(branch.get_root_id)
46
old_tree = EmptyTree()
56
48
old_tree = branch.revision_tree(revisions[0])
58
50
if revisions[1] is None:
51
# This is for the future, once we support rollup revisions
52
# Or working tree revisions
59
53
new_tree = branch.working_tree()
61
55
new_tree = branch.revision_tree(revisions[1])
62
56
return old_tree, new_tree
64
58
def _fake_working_revision(branch):
65
"""Fake a Revision object for the working tree."""
59
"""Fake a Revision object for the working tree.
61
This is for the future, to support changesets against the working tree.
66
63
from bzrlib.revision import Revision
68
65
from bzrlib.osutils import local_time_offset, \
102
98
self.new_label = new_label
103
99
self.old_tree = old_tree
104
100
self.new_tree = new_tree
103
self.precursor_revno = None
105
self._get_revision_list(revisions)
106
107
def _get_revision_list(self, revisions):
107
108
"""This generates the list of all revisions from->to.
110
This is for the future, when we support having a rollup changeset.
111
For now, the list should only be one long.
118
122
self.revision_list = []
119
123
if old_revno is None:
120
self.base_revision = None
124
self.base_revision = None # Effectively the EmptyTree()
123
127
self.base_revision = self.branch.get_revision(rh[old_revno])
124
if new_revno is not None:
125
for rev_id in rh[old_revno+1:new_revno+1]:
126
self.revision_list.append(self.branch.get_revision(rev_id))
128
if new_revno is None:
129
# For the future, when we support working tree changesets.
128
130
for rev_id in rh[old_revno+1:]:
129
131
self.revision_list.append(self.branch.get_revision(rev_id))
130
132
self.revision_list.append(_fake_working_revision(self.branch))
134
for rev_id in rh[old_revno+1:new_revno+1]:
135
self.revision_list.append(self.branch.get_revision(rev_id))
136
self.precursor_revno = old_revno
137
self.revno = new_revno
139
def _write(self, txt, key=None):
141
self.to_file.write('# ' + key + ': ' + txt + '\n')
143
self.to_file.write('# ' + txt + '\n')
132
145
def write_meta_info(self, to_file):
133
146
"""Write out the meta-info portion to the supplied file.
135
148
:param to_file: Write out the meta information to the supplied
138
from bzrlib.osutils import username
139
def write(txt, key=None):
141
to_file.write('# ' + key + ': ' + txt + '\n')
143
to_file.write('# ' + txt + '\n')
145
write('Bazaar-NG (bzr) changeset v0.0.5')
146
write('This changeset can be applied with bzr apply-changeset')
151
self.to_file = to_file
157
def _write_header(self):
158
"""Write the stuff that comes before the patches."""
159
from bzrlib.osutils import username, format_date
162
for line in common.get_header():
165
# This grabs the current username, what we really want is the
166
# username from the actual patches.
167
#write(username(), key='committer')
168
assert len(self.revision_list) == 1
169
rev = self.revision_list[0]
170
write(rev.committer, key='committer')
171
write(format_date(rev.timestamp, offset=rev.timezone), key='date')
172
write(str(self.revno), key='revno')
173
write(rev.revision_id, key='revision')
175
if self.base_revision:
176
write(self.base_revision.revision_id, key='precursor')
177
write(str(self.precursor_revno), key='precursor revno')
149
write(username(), key='committer')
181
self.to_file.write('\n')
183
def _write_footer(self):
184
"""Write the stuff that comes after the patches.
186
This is meant to be more meta-information, which people probably don't want
187
to read, but which is required for proper bzr operation.
191
write('BEGIN BZR FOOTER')
193
assert len(self.revision_list) == 1 # We only handle single revision entries
194
write(self.branch.get_revision_sha1(self.revision_list[0].revision_id), key='revision sha1')
151
195
if self.base_revision:
152
write(self.base_revision.revision_id, key='precursor')
196
write(self.branch.get_revision_sha1(self.base_revision.revision_id), 'precursor sha1')
200
write('END BZR FOOTER')
202
def _write_revisions(self):
203
"""Not used. Used for writing multiple revisions."""
155
205
for rev in self.revision_list:
156
206
if rev.revision_id is not None:
158
write(rev.revision_id, key='revisions')
208
self._write('revisions:')
161
write(' '*11 + rev.revision_id)
163
self._write_diffs(to_file)
164
self._write_ids(to_file)
166
def _write_ids(self, to_file):
167
seen_ids = set(['TREE_ROOT'])
210
self._write(' '*4 + rev.revision_id + '\t' + self.branch.get_revision_sha1(rev.revision_id))
213
def _write_ids(self):
214
if hasattr(self.branch, 'get_root_id'):
215
root_id = self.branch.get_root_id()
218
seen_ids = set([root_id])
221
to_file = self.to_file
170
223
def _write_entry(file_id, path=None):
171
224
if file_id in self.new_tree.inventory:
172
225
ie = self.new_tree.inventory[file_id]
246
299
diff_file = internal_diff
248
301
for path, file_id, kind in self.delta.removed:
249
print >>to_file, '*** removed %s %r' % (kind, path)
302
print >>self.to_file, '*** removed %s %r' % (kind, path)
250
303
if kind == 'file' and self.full_remove:
251
304
diff_file(self.old_label + path,
252
305
self.old_tree.get_file(file_id).readlines(),
257
310
for path, file_id, kind in self.delta.added:
258
print >>to_file, '*** added %s %r' % (kind, path)
311
print >>self.to_file, '*** added %s %r' % (kind, path)
259
312
if kind == 'file':
260
313
diff_file(DEVNULL,
262
315
self.new_label + path,
263
316
self.new_tree.get_file(file_id).readlines(),
266
319
for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
267
print >>to_file, '*** renamed %s %r => %r' % (kind, old_path, new_path)
320
print >>self.to_file, '*** renamed %s %r => %r' % (kind, old_path, new_path)
268
321
if self.full_rename and kind == 'file':
269
322
diff_file(self.old_label + old_path,
270
323
self.old_tree.get_file(file_id).readlines(),
274
327
diff_file(DEVNULL,
276
329
self.new_label + new_path,
277
330
self.new_tree.get_file(file_id).readlines(),
279
332
elif text_modified:
280
333
diff_file(self.old_label + old_path,
281
334
self.old_tree.get_file(file_id).readlines(),
282
335
self.new_label + new_path,
283
336
self.new_tree.get_file(file_id).readlines(),
286
339
for path, file_id, kind in self.delta.modified:
287
print >>to_file, '*** modified %s %r' % (kind, path)
340
print >>self.to_file, '*** modified %s %r' % (kind, path)
288
341
if kind == 'file':
289
342
diff_file(self.old_label + path,
290
343
self.old_tree.get_file(file_id).readlines(),
291
344
self.new_label + path,
292
345
self.new_tree.get_file(file_id).readlines(),
295
348
def show_changeset(branch, revision=None, specific_files=None,
296
349
external_diff_options=None, to_file=None,