[MERGE] (0.17) reworked LogFormatter API
Kent Gibson
warthog618 at gmail.com
Wed May 9 15:29:50 BST 2007
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Just a minor change to the previous patch - moved the begin/end calls
from _show_log to show_log. That is both tidier and more correct.
And fixed a long line.
Kent Gibson wrote:
> The attached bundle reworks the LogFormatter API to increase
> extensibility and to support formatters that require log begin and
> end markers. The API is made more extensible by passing the
> revision details to the LogFormatter in a wrapper object of type
> LogRevision, which can be extended without requiring further API
> changes. The show, show_merge and show_merge_revno methods have
> been unified into a single log_revision method. The patch also
> extends the use of formatter capabilities (supports_XXX) to
> determine which attributes of LogRevision need to be populated.
>
> Given this patch it should be pretty straight forward to
> incorporate other log changes that have been proposed recently,
> such as James Westby's XMLLogFormatter and John Arbash Meinel's
> deltas for merge revisions.
>
> The patch also includes a couple of incidental fixes. For the long
> formatter, it makes the display of revision ids consistent between
> mainline and merge revisions. And `bzr log --verbose --line` will
> run faster since it doesn't bother generating deltas that the line
> formatter can't display. I doubt anyone in their right mind is
> using that particular combination, but there you go.
>
> Btw, the patch makes the changes to _show_log look more complicated
> than they actually are. They are mainly indentation changes and
> variable renaming.
>
>
> Cheers, Kent.
- ----------------------------------------------------------------------
# Bazaar revision bundle v0.9
#
# message:
# Reworked LogFormatter API to simplify extending the attributes of
the revision being logged. Added support for begin_log() and end_log()
hooks in LogFormatters.
# Fixed minor inconsistency between display of revids in mainline
and merge revisions in long log format. Both now labelled
"revision-id:" and are only displayed when --show-ids is specified.
#
# committer: Kent Gibson <warthog618 at gmail.com>
# date: Sun 2007-04-29 11:46:30.565999985 +0800
=== modified file NEWS
- --- NEWS
+++ NEWS
@@ -1,5 +1,13 @@
IN DEVELOPMENT
+ INTERNALS:
+ * Rework of LogFormatter API to provide beginning/end of log
hooks and to
+ encapsulate the details of the revision to be logged in a
LogRevision
+ object.
+ In long log formats, merge revision ids are only shown when
- --show-ids
+ is specified, and are labelled "revision-id:", as per mainline
+ revisions, instead of "merged:". (Kent Gibson)
+
BUGFIXES:
* Handle the case when you delete a file, and then rename another
file
=== modified file bzrlib/builtins.py
- --- bzrlib/builtins.py
+++ bzrlib/builtins.py
@@ -2972,7 +2972,7 @@
def run(self, other_branch=None, reverse=False, mine_only=False,
theirs_only=False, log_format=None, long=False,
short=False, line=False,
show_ids=False, verbose=False):
- - from bzrlib.missing import find_unmerged, iter_log_data
+ from bzrlib.missing import find_unmerged, iter_log_revisions
from bzrlib.log import log_formatter
local_branch = Branch.open_containing(u".")[0]
parent = local_branch.get_parent()
@@ -3003,9 +3003,10 @@
remote_extra.reverse()
if local_extra and not theirs_only:
print "You have %d extra revision(s):" %
len(local_extra)
- - for data in iter_log_data(local_extra,
local_branch.repository,
- - verbose):
- - lf.show(*data)
+ for revision in iter_log_revisions(local_extra,
+ local_branch.repository,
+ verbose):
+ lf.log_revision(revision)
printed_local = True
else:
printed_local = False
@@ -3013,9 +3014,10 @@
if printed_local is True:
print "\n\n"
print "You are missing %d revision(s):" %
len(remote_extra)
- - for data in iter_log_data(remote_extra,
remote_branch.repository,
- - verbose):
- - lf.show(*data)
+ for revision in iter_log_revisions(remote_extra,
+ remote_branch.repository,
+ verbose):
+ lf.log_revision(revision)
if not remote_extra and not local_extra:
status_code = 0
print "Branches are up to date."
=== modified file bzrlib/log.py
- --- bzrlib/log.py
+++ bzrlib/log.py
@@ -59,7 +59,11 @@
symbol_versioning,
)
import bzrlib.errors as errors
- -from bzrlib.symbol_versioning import deprecated_method, zero_eleven
+from bzrlib.symbol_versioning import(
+ deprecated_method,
+ zero_eleven,
+ zero_seventeen,
+ )
from bzrlib.trace import mutter
from bzrlib.tsort import(
merge_sort,
@@ -210,22 +214,28 @@
mainline_revs.insert(0, None)
else:
mainline_revs.insert(0, which_revs[start_revision-2][1])
- - # how should we show merged revisions ?
- - # old api: show_merge. New api: show_merge_revno
- - show_merge_revno = getattr(lf, 'show_merge_revno', None)
- - show_merge = getattr(lf, 'show_merge', None)
- - if show_merge is None and show_merge_revno is None:
- - # no merged-revno support
- - include_merges = False
- - else:
- - include_merges = True
- - if show_merge is not None and show_merge_revno is None:
+ legacy_lf = not getattr(lf,'log_revision',None)
+ if legacy_lf:
+ # pre-0.17 formatters use show for mainline revisions.
+ # how should we show merged revisions ?
+ # pre-0.11 api: show_merge
+ # 0.11-0.16 api: show_merge_revno
+ show_merge_revno = getattr(lf, 'show_merge_revno', None)
+ show_merge = getattr(lf, 'show_merge', None)
+ if show_merge is None and show_merge_revno is None:
+ # no merged-revno support
+ generate_merge_revisions = False
+ else:
+ generate_merge_revisions = True
# tell developers to update their code
- - symbol_versioning.warn('LogFormatters should provide
show_merge_revno '
- - 'instead of show_merge since bzr 0.11.',
+ symbol_versioning.warn('LogFormatters should provide
log_revision '
+ 'instead of show and show_merge_revno since bzr 0.17.',
DeprecationWarning, stacklevel=3)
+ else:
+ generate_merge_revisions = getattr(lf,
'supports_merge_revisions',
+ False)
view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
- - direction, include_merges=include_merges)
+ direction,
include_merges=generate_merge_revisions)
if specific_fileid:
view_revisions = _get_revisions_touching_file_id(branch,
specific_fileid,
@@ -234,12 +244,14 @@
else:
view_revisions = list(view_revs_iter)
- - use_tags = getattr(lf, 'supports_tags', False)
- - if use_tags:
- - rev_tag_dict = {}
+ rev_tag_dict = {}
+ generate_tags = getattr(lf, 'supports_tags', False)
+ if generate_tags:
if branch.supports_tags():
rev_tag_dict = branch.tags.get_reverse_tag_dict()
+ generate_delta = verbose and getattr(lf, 'supports_delta', False)
+
def iter_revisions():
# r = revision, n = revno, d = merge depth
revision_ids = [r for r, n, d in view_revisions]
@@ -249,7 +261,7 @@
while revision_ids:
cur_deltas = {}
revisions = repository.get_revisions(revision_ids[:num])
- - if verbose:
+ if generate_delta:
delta_revisions = [r for r in revisions if
r.revision_id in zeros]
deltas =
repository.get_deltas_for_revisions(delta_revisions)
@@ -262,7 +274,10 @@
yield revision, cur_deltas.get(revision.revision_id)
revision_ids = revision_ids[num:]
num = min(int(num * 1.5), 200)
- -
+
+ if getattr(lf, 'begin_log', None):
+ lf.begin_log()
+
# now we just print all the revisions
for ((rev_id, revno, merge_depth), (rev, delta)) in \
izip(view_revisions, iter_revisions()):
@@ -271,20 +286,28 @@
if not searchRE.search(rev.message):
continue
- - if merge_depth == 0:
- - if use_tags:
- - lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
- - else:
- - lf.show(revno, rev, delta)
+ if not legacy_lf:
+ lr =
LogRevision(rev,revno,merge_depth,delta,rev_tag_dict.get(rev_id))
+ lf.log_revision(lr)
else:
- - if show_merge_revno is None:
- - lf.show_merge(rev, merge_depth)
+ # support for legacy (pre-0.17) LogFormatters
+ if merge_depth == 0:
+ if generate_tags:
+ lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
+ else:
+ lf.show(revno, rev, delta)
else:
- - if use_tags:
- - lf.show_merge_revno(rev, merge_depth, revno,
- - rev_tag_dict.get(rev_id))
+ if show_merge_revno is None:
+ lf.show_merge(rev, merge_depth)
else:
- - lf.show_merge_revno(rev, merge_depth, revno)
+ if generate_tags:
+ lf.show_merge_revno(rev, merge_depth, revno,
+ rev_tag_dict.get(rev_id))
+ else:
+ lf.show_merge_revno(rev, merge_depth, revno)
+
+ if getattr(lf, 'end_log', None):
+ lf.end_log()
def _get_revisions_touching_file_id(branch, file_id, mainline_revisions,
@@ -398,14 +421,58 @@
return result
+class LogRevision(object):
+ """A revision to be logged (by LogFormatter.log_revision).
+
+ A simple wrapper for the attributes of a revision to be logged.
+ The attributes may or may not be populated, as determined by the
+ logging options and the log formatter capabilities.
+ """
+
+ def
__init__(self,rev=None,revno=None,merge_depth=0,delta=None,tags=None):
+ self.rev = rev
+ self.revno = revno
+ self.merge_depth = merge_depth
+ self.delta = delta
+ self.tags = tags
+
+
class LogFormatter(object):
- - """Abstract class to display log messages."""
+ """Abstract class to display log messages.
+
+ At a minimum, a derived class must implement the log_revision method.
+
+ If the LogFormatter needs to be informed of the beginning or end of
+ a log it should implement the begin_log and/or end_log hook methods.
+
+ A LogFormatter should define the following supports_XXX flags
+ to indicate which LogRevision attributes it supports:
+
+ - supports_delta must be True if this log formatter supports delta.
+ Otherwise the delta attribute may not be populated.
+ - supports_merge_revisions must be True if this log formatter
supports
+ merge revisions. If not, only revisions mainline revisions
(those
+ with merge_depth == 0) will be passed to the formatter.
+ - supports_tags must be True if this log formatter supports tags.
+ Otherwise the tags attribute may not be populated.
+ """
def __init__(self, to_file, show_ids=False,
show_timezone='original'):
self.to_file = to_file
self.show_ids = show_ids
self.show_timezone = show_timezone
+# TODO: uncomment this block after show() has been removed.
+# Until then defining log_revision would prevent _show_log calling
show()
+# in legacy formatters.
+# def log_revision(self, revision):
+# """Log a revision.
+#
+# :param revision: The LogRevision to be logged.
+# """
+# raise NotImplementedError('not implemented in abstract base')
+
+ @deprecated_method(zero_seventeen)
def show(self, revno, rev, delta):
raise NotImplementedError('not implemented in abstract base')
@@ -415,92 +482,108 @@
class LongLogFormatter(LogFormatter):
- - supports_tags = True # must exist and be True
- - # if this log formatter support tags.
- - # .show() and .show_merge_revno() must
then accept
- - # the 'tags'-argument with list of tags
+ supports_merge_revisions = True
+ supports_delta = True
+ supports_tags = True
+ @deprecated_method(zero_seventeen)
def show(self, revno, rev, delta, tags=None):
- - return self._show_helper(revno=revno, rev=rev, delta=delta,
tags=tags)
+ lr = LogRevision(rev,revno,0,delta,tags)
+ return self.log_revision(lr)
@deprecated_method(zero_eleven)
def show_merge(self, rev, merge_depth):
- - return self._show_helper(rev=rev, indent=' '*merge_depth,
- - merged=True, delta=None)
+ lr = LogRevision(rev,merge_depth=merge_depth)
+ return self.log_revision(lr)
+ @deprecated_method(zero_seventeen)
def show_merge_revno(self, rev, merge_depth, revno, tags=None):
"""Show a merged revision rev, with merge_depth and a revno."""
- - return self._show_helper(rev=rev, revno=revno,
- - indent=' '*merge_depth, merged=True, delta=None,
tags=tags)
+ lr = LogRevision(rev,revno,merge_depth,tags=tags)
+ return self.log_revision(lr)
- - def _show_helper(self, rev=None, revno=None, indent='', merged=False,
- - delta=None, tags=None):
- - """Show a revision, either merged or not."""
+ def log_revision(self, revision):
+ """Log a revision, either merged or not."""
from bzrlib.osutils import format_date
+ indent = ' '*revision.merge_depth
to_file = self.to_file
print >>to_file, indent+'-' * 60
- - if revno is not None:
- - print >>to_file, indent+'revno:', revno
- - if tags:
- - print >>to_file, indent+'tags: %s' % (', '.join(tags))
- - if merged:
- - print >>to_file, indent+'merged:', rev.revision_id
- - elif self.show_ids:
- - print >>to_file, indent+'revision-id:', rev.revision_id
+ if revision.revno is not None:
+ print >>to_file, indent+'revno:', revision.revno
+ if revision.tags:
+ print >>to_file, indent+'tags: %s' % (',
'.join(revision.tags))
if self.show_ids:
- - for parent_id in rev.parent_ids:
+ print >>to_file, indent+'revision-id:',
revision.rev.revision_id
+ for parent_id in revision.rev.parent_ids:
print >>to_file, indent+'parent:', parent_id
- - print >>to_file, indent+'committer:', rev.committer
+ print >>to_file, indent+'committer:', revision.rev.committer
try:
print >>to_file, indent+'branch nick: %s' % \
- - rev.properties['branch-nick']
+ revision.rev.properties['branch-nick']
except KeyError:
pass
- - date_str = format_date(rev.timestamp,
- - rev.timezone or 0,
+ date_str = format_date(revision.rev.timestamp,
+ revision.rev.timezone or 0,
self.show_timezone)
print >>to_file, indent+'timestamp: %s' % date_str
print >>to_file, indent+'message:'
- - if not rev.message:
+ if not revision.rev.message:
print >>to_file, indent+' (no message)'
else:
- - message = rev.message.rstrip('\r\n')
+ message = revision.rev.message.rstrip('\r\n')
for l in message.split('\n'):
print >>to_file, indent+' ' + l
- - if delta is not None:
- - delta.show(to_file, self.show_ids)
+ if revision.delta is not None:
+ revision.delta.show(to_file, self.show_ids)
class ShortLogFormatter(LogFormatter):
+
+ supports_delta = True
+
+ @deprecated_method(zero_seventeen)
def show(self, revno, rev, delta):
+ lr = LogRevision(rev,revno,0,delta)
+ return self.log_revision(lr)
+
+ def log_revision(self, revision):
from bzrlib.osutils import format_date
to_file = self.to_file
- - date_str = format_date(rev.timestamp, rev.timezone or 0,
- - self.show_timezone)
- - print >>to_file, "%5s %s\t%s" % (revno,
self.short_committer(rev),
- - format_date(rev.timestamp, rev.timezone or 0,
+ date_str = format_date(revision.rev.timestamp,
+ revision.rev.timezone or 0,
+ self.show_timezone)
+ print >>to_file, "%5s %s\t%s" % (revision.revno,
+ self.short_committer(revision.rev),
+ format_date(revision.rev.timestamp,
+ revision.rev.timezone or 0,
self.show_timezone, date_fmt="%Y-%m-%d",
- - show_offset=False))
+ show_offset=False))
if self.show_ids:
- - print >>to_file, ' revision-id:', rev.revision_id
- - if not rev.message:
+ print >>to_file, ' revision-id:',
revision.rev.revision_id
+ if not revision.rev.message:
print >>to_file, ' (no message)'
else:
- - message = rev.message.rstrip('\r\n')
+ message = revision.rev.message.rstrip('\r\n')
for l in message.split('\n'):
print >>to_file, ' ' + l
# TODO: Why not show the modified files in a shorter form as
# well? rewrap them single lines of appropriate length
- - if delta is not None:
- - delta.show(to_file, self.show_ids)
+ if revision.delta is not None:
+ revision.delta.show(to_file, self.show_ids)
print >>to_file, ''
class LineLogFormatter(LogFormatter):
+
+ def __init__(self, *args, **kwargs):
+ from bzrlib.osutils import terminal_width
+ super(LineLogFormatter, self).__init__(*args, **kwargs)
+ self._max_chars = terminal_width() - 1
+
def truncate(self, str, max_len):
if len(str) <= max_len:
return str
@@ -518,10 +601,15 @@
else:
return rev.message
+ @deprecated_method(zero_seventeen)
def show(self, revno, rev, delta):
from bzrlib.osutils import terminal_width
print >> self.to_file, self.log_string(revno, rev,
terminal_width()-1)
+ def log_revision(self, revision):
+ print >> self.to_file, self.log_string(revision.revno,
revision.rev,
+ self._max_chars)
+
def log_string(self, revno, rev, max_chars):
"""Format log info into one string. Truncate tail of string
:param revno: revision number (int) or None.
=== modified file bzrlib/missing.py
- --- bzrlib/missing.py
+++ bzrlib/missing.py
@@ -16,10 +16,23 @@
"""Display what revisions are missing in 'other' from 'this' and vice
versa."""
+from bzrlib.log import(
+ LogRevision,
+ )
+from bzrlib.symbol_versioning import(
+ deprecated_function,
+ zero_seventeen,
+ )
import bzrlib.ui as ui
+ at deprecated_function(zero_seventeen)
def iter_log_data(revisions, revision_source, verbose):
+ for revision in iter_log_revisions(revisions, revision_source,
verbose):
+ yield revision.revno, revision.rev, revision.delta
+
+
+def iter_log_revisions(revisions, revision_source, verbose):
last_tree = revision_source.revision_tree(None)
last_rev_id = None
for revno, rev_id in revisions:
@@ -37,7 +50,7 @@
delta = revision_tree.changes_from(parent_tree)
else:
delta = None
- - yield revno, rev, delta
+ yield LogRevision(rev,revno,delta=delta)
def find_unmerged(local_branch, remote_branch):
=== modified file bzrlib/symbol_versioning.py
- --- bzrlib/symbol_versioning.py
+++ bzrlib/symbol_versioning.py
@@ -35,6 +35,7 @@
'zero_fourteen',
'zero_fifteen',
'zero_sixteen',
+ 'zero_seventeen',
]
from warnings import warn
@@ -51,6 +52,7 @@
zero_fourteen = "%s was deprecated in version 0.14."
zero_fifteen = "%s was deprecated in version 0.15."
zero_sixteen = "%s was deprecated in version 0.16."
+zero_seventeen = "%s was deprecated in version 0.17."
def set_warning_method(method):
=== modified file bzrlib/tests/test_log.py
- --- bzrlib/tests/test_log.py
+++ bzrlib/tests/test_log.py
@@ -21,6 +21,7 @@
from bzrlib.tests import BzrTestBase, TestCaseWithTransport
from bzrlib.log import (show_log,
get_view_revisions,
+ LogRevision,
LogFormatter,
LongLogFormatter,
ShortLogFormatter,
@@ -29,11 +30,6 @@
from bzrlib.errors import InvalidRevisionNumber
- -class _LogEntry(object):
- - # should probably move into bzrlib.log?
- - pass
- -
- -
class LogCatcher(LogFormatter):
"""Pull log messages into list rather than displaying them.
@@ -43,16 +39,15 @@
We should also test the LogFormatter.
"""
+
+ supports_delta = True
+
def __init__(self):
super(LogCatcher, self).__init__(to_file=None)
self.logs = []
- - def show(self, revno, rev, delta):
- - le = _LogEntry()
- - le.revno = revno
- - le.rev = rev
- - le.delta = delta
- - self.logs.append(le)
+ def log_revision(self, revision):
+ self.logs.append(revision)
class SimpleLogTest(TestCaseWithTransport):
=== modified file bzrlib/tests/test_missing.py
- --- bzrlib/tests/test_missing.py
+++ bzrlib/tests/test_missing.py
@@ -18,7 +18,10 @@
from bzrlib.builtins import merge
- -from bzrlib.missing import find_unmerged, iter_log_data
+from bzrlib.missing import(
+ find_unmerged,
+ iter_log_revisions,
+ )
from bzrlib.tests import TestCaseWithTransport
from bzrlib.workingtree import WorkingTree
@@ -53,7 +56,7 @@
merger_tree.commit('d', rev_id='d')
self.assertEqual(find_unmerged(original, merger), ([], [(2,
'd')]))
- - def test_iter_log_data(self):
+ def test_iter_log_revisions(self):
base_tree = self.make_branch_and_tree('base')
self.build_tree(['base/a'])
base_tree.add(['a'], ['a-id'])
@@ -76,43 +79,45 @@
base_extra, child_extra = find_unmerged(base_tree.branch,
child_tree.branch)
- - results = list(iter_log_data(base_extra,
base_tree.branch.repository,
- - verbose=True))
+ results = list(iter_log_revisions(base_extra,
+ base_tree.branch.repository,
+ verbose=True))
self.assertEqual([], results)
- - results = list(iter_log_data(child_extra,
child_tree.branch.repository,
- - verbose=True))
+ results = list(iter_log_revisions(child_extra,
+ child_tree.branch.repository,
+ verbose=True))
self.assertEqual(4, len(results))
r0,r1,r2,r3 = results
- - self.assertEqual((2, 'c-2'), (r0[0], r0[1].revision_id))
- - self.assertEqual((3, 'c-3'), (r1[0], r1[1].revision_id))
- - self.assertEqual((4, 'c-4'), (r2[0], r2[1].revision_id))
- - self.assertEqual((5, 'c-5'), (r3[0], r3[1].revision_id))
+ self.assertEqual((2, 'c-2'), (r0.revno, r0.rev.revision_id))
+ self.assertEqual((3, 'c-3'), (r1.revno, r1.rev.revision_id))
+ self.assertEqual((4, 'c-4'), (r2.revno, r2.rev.revision_id))
+ self.assertEqual((5, 'c-5'), (r3.revno, r3.rev.revision_id))
- - delta0 = r0[2]
+ delta0 = r0.delta
self.assertNotEqual(None, delta0)
self.assertEqual([('b', 'b-id', 'file')], delta0.added)
self.assertEqual([], delta0.removed)
self.assertEqual([], delta0.renamed)
self.assertEqual([], delta0.modified)
- - delta1 = r1[2]
+ delta1 = r1.delta
self.assertNotEqual(None, delta1)
self.assertEqual([], delta1.added)
self.assertEqual([('a', 'a-id', 'file')], delta1.removed)
self.assertEqual([], delta1.renamed)
self.assertEqual([], delta1.modified)
- - delta2 = r2[2]
+ delta2 = r2.delta
self.assertNotEqual(None, delta2)
self.assertEqual([], delta2.added)
self.assertEqual([], delta2.removed)
self.assertEqual([], delta2.renamed)
self.assertEqual([('b', 'b-id', 'file', True, False)],
delta2.modified)
- - delta3 = r3[2]
+ delta3 = r3.delta
self.assertNotEqual(None, delta3)
self.assertEqual([], delta3.added)
self.assertEqual([], delta3.removed)
=== modified directory //
last-changed:warthog618 at gmail.com-20070429034630-p3x
... bitz2xyl6pbie
# revision id: warthog618 at gmail.com-20070429034630-p3xbitz2xyl6pbie
# sha1: ac9a17dd3c134862f42d2623e8ee31a066d1afc2
# inventory sha1: 3ef61d148226b3513c2d1b16eac658252f081b6a
# parent ids:
# pqm at pqm.ubuntu.com-20070426211103-h84prqh7a4ad3ez2
# base id: pqm at pqm.ubuntu.com-20070426211103-h84prqh7a4ad3ez2
# properties:
# branch-nick: bzr.kg
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFGQdrdgoxTFTi1P8QRAhzzAJ93jdIicLJ5LVNUag2BWfGr12h8fACePbJG
0h3z4lrnLNNnzB0RFJr+tOY=
=S8OP
-----END PGP SIGNATURE-----
-------------- next part --------------
A non-text attachment was scrubbed...
Name: lf_rework_b.patch
Type: text/x-patch
Size: 57258 bytes
Desc: not available
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20070509/67db065a/attachment-0001.bin
More information about the bazaar
mailing list