153
223
# although we calculated it, throw it away without display
156
if searchRE is None or searchRE.search(rev.message):
157
lf.show(revno, rev, delta)
226
rev = branch.get_revision(rev_id)
229
if not searchRE.search(rev.message):
232
lf.show(revno, rev, delta)
233
if hasattr(lf, 'show_merge'):
237
# revno is 1 based, so -2 to get back 1 less.
238
excludes = set(branch.get_ancestry(revision_history[revno - 2]))
239
pending = list(rev.parent_ids)
241
rev_id = pending.pop()
242
if rev_id in excludes:
244
# prevent showing merged revs twice if they multi-path.
247
rev = branch.get_revision(rev_id)
248
except errors.NoSuchRevision:
250
pending.extend(rev.parent_ids)
161
254
def deltas_for_log_dummy(branch, which_revs):
255
"""Return all the revisions without intermediate deltas.
257
Useful for log commands that won't need the delta information.
162
260
for revno, revision_id in which_revs:
163
261
yield revno, branch.get_revision(revision_id), None
166
264
def deltas_for_log_reverse(branch, which_revs):
167
"""Compute deltas for display in reverse log.
169
Given a sequence of (revno, revision_id) pairs, return
265
"""Compute deltas for display in latest-to-earliest order.
271
Sequence of (revno, revision_id) for the subset of history to examine
274
Sequence of (revno, rev, delta)
172
276
The delta is from the given revision to the next one in the
173
277
sequence, which makes sense if the log is being displayed from
174
278
newest to oldest.
176
from tree import EmptyTree
177
from diff import compare_trees
179
280
last_revno = last_revision_id = last_tree = None
180
281
for revno, revision_id in which_revs:
181
282
this_tree = branch.revision_tree(revision_id)
238
336
class LogFormatter(object):
239
337
"""Abstract class to display log messages."""
240
def __init__(self, to_file, show_ids=False, show_timezone=False):
338
def __init__(self, to_file, show_ids=False, show_timezone='original'):
241
339
self.to_file = to_file
242
340
self.show_ids = show_ids
243
341
self.show_timezone = show_timezone
344
def show(self, revno, rev, delta):
345
raise NotImplementedError('not implemented in abstract base')
347
def short_committer(self, rev):
348
return re.sub('<.*@.*>', '', rev.committer).strip(' ')
250
351
class LongLogFormatter(LogFormatter):
251
352
def show(self, revno, rev, delta):
252
from osutils import format_date
353
return self._show_helper(revno=revno, rev=rev, delta=delta)
355
def show_merge(self, rev):
356
return self._show_helper(rev=rev, indent=' ', merged=True, delta=None)
358
def _show_helper(self, rev=None, revno=None, indent='', merged=False, delta=None):
359
"""Show a revision, either merged or not."""
360
from bzrlib.osutils import format_date
254
361
to_file = self.to_file
256
print >>to_file, '-' * 60
257
print >>to_file, 'revno:', revno
362
print >>to_file, indent+'-' * 60
363
if revno is not None:
364
print >>to_file, 'revno:', revno
366
print >>to_file, indent+'merged:', rev.revision_id
368
print >>to_file, indent+'revision-id:', rev.revision_id
258
369
if self.show_ids:
259
print >>to_file, 'revision-id:', rev.revision_id
260
print >>to_file, 'committer:', rev.committer
261
print >>to_file, 'timestamp: %s' % (format_date(rev.timestamp, rev.timezone or 0,
370
for parent_id in rev.parent_ids:
371
print >>to_file, indent+'parent:', parent_id
372
print >>to_file, indent+'committer:', rev.committer
374
print >>to_file, indent+'branch nick: %s' % \
375
rev.properties['branch-nick']
378
date_str = format_date(rev.timestamp,
381
print >>to_file, indent+'timestamp: %s' % date_str
264
print >>to_file, 'message:'
383
print >>to_file, indent+'message:'
265
384
if not rev.message:
266
print >>to_file, ' (no message)'
385
print >>to_file, indent+' (no message)'
268
for l in rev.message.split('\n'):
269
print >>to_file, ' ' + l
387
message = rev.message.rstrip('\r\n')
388
for l in message.split('\n'):
389
print >>to_file, indent+' ' + l
271
390
if delta != None:
272
391
delta.show(to_file, self.show_ids)
276
394
class ShortLogFormatter(LogFormatter):
277
395
def show(self, revno, rev, delta):
278
396
from bzrlib.osutils import format_date
280
398
to_file = self.to_file
282
print >>to_file, "%5d %s\t%s" % (revno, rev.committer,
399
date_str = format_date(rev.timestamp, rev.timezone or 0,
401
print >>to_file, "%5d %s\t%s" % (revno, self.short_committer(rev),
283
402
format_date(rev.timestamp, rev.timezone or 0,
403
self.show_timezone, date_fmt="%Y-%m-%d",
285
405
if self.show_ids:
286
406
print >>to_file, ' revision-id:', rev.revision_id
287
407
if not rev.message:
288
408
print >>to_file, ' (no message)'
290
for l in rev.message.split('\n'):
410
message = rev.message.rstrip('\r\n')
411
for l in message.split('\n'):
291
412
print >>to_file, ' ' + l
414
# TODO: Why not show the modified files in a shorter form as
415
# well? rewrap them single lines of appropriate length
293
416
if delta != None:
294
417
delta.show(to_file, self.show_ids)
420
class LineLogFormatter(LogFormatter):
421
def truncate(self, str, max_len):
422
if len(str) <= max_len:
424
return str[:max_len-3]+'...'
426
def date_string(self, rev):
427
from bzrlib.osutils import format_date
428
return format_date(rev.timestamp, rev.timezone or 0,
429
self.show_timezone, date_fmt="%Y-%m-%d",
432
def message(self, rev):
434
return '(no message)'
438
def show(self, revno, rev, delta):
439
print >> self.to_file, self.log_string(rev, 79)
441
def log_string(self, rev, max_chars):
442
out = [self.truncate(self.short_committer(rev), 20)]
443
out.append(self.date_string(rev))
444
out.append(self.message(rev).replace('\n', ' '))
445
return self.truncate(" ".join(out).rstrip('\n'), max_chars)
447
def line_log(rev, max_chars):
448
lf = LineLogFormatter(None)
449
return lf.log_string(rev, max_chars)
299
451
FORMATTERS = {'long': LongLogFormatter,
300
452
'short': ShortLogFormatter,
453
'line': LineLogFormatter,
304
457
def log_formatter(name, *args, **kwargs):
458
"""Construct a formatter from arguments.
460
name -- Name of the formatter to construct; currently 'long', 'short' and
461
'line' are supported.
305
463
from bzrlib.errors import BzrCommandError
308
465
return FORMATTERS[name](*args, **kwargs)
309
466
except IndexError:
310
467
raise BzrCommandError("unknown log formatter: %r" % name)
469
def show_one_log(revno, rev, delta, verbose, to_file, show_timezone):
470
# deprecated; for compatability
471
lf = LongLogFormatter(to_file=to_file, show_timezone=show_timezone)
472
lf.show(revno, rev, delta)
474
def show_changed_revisions(branch, old_rh, new_rh, to_file=None, log_format='long'):
475
"""Show the change in revision history comparing the old revision history to the new one.
477
:param branch: The branch where the revisions exist
478
:param old_rh: The old revision history
479
:param new_rh: The new revision history
480
:param to_file: A file to write the results to. If None, stdout will be used
486
to_file = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
487
lf = log_formatter(log_format,
490
show_timezone='original')
492
# This is the first index which is different between
495
for i in xrange(max(len(new_rh),
499
or new_rh[i] != old_rh[i]):
504
to_file.write('Nothing seems to have changed\n')
506
## TODO: It might be nice to do something like show_log
507
## and show the merged entries. But since this is the
508
## removed revisions, it shouldn't be as important
509
if base_idx < len(old_rh):
510
to_file.write('*'*60)
511
to_file.write('\nRemoved Revisions:\n')
512
for i in range(base_idx, len(old_rh)):
513
rev = branch.get_revision(old_rh[i])
514
lf.show(i+1, rev, None)
515
to_file.write('*'*60)
516
to_file.write('\n\n')
517
if base_idx < len(new_rh):
518
to_file.write('Added Revisions:\n')
524
start_revision=base_idx+1,
525
end_revision=len(new_rh),