Rev 3965: Optionally show diff in log (Ian Clatworthy) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Wed Jan 28 09:41:18 GMT 2009


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 3965
revision-id: pqm at pqm.ubuntu.com-20090128094113-ze5jnburw91g2e4n
parent: pqm at pqm.ubuntu.com-20090127202443-ty2bu1hh91dumasz
parent: ian.clatworthy at canonical.com-20090127230635-70o18gj41uukrrzx
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2009-01-28 09:41:13 +0000
message:
  Optionally show diff in log (Ian Clatworthy)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
  bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
    ------------------------------------------------------------
    revno: 3964.1.1
    revision-id: ian.clatworthy at canonical.com-20090127230635-70o18gj41uukrrzx
    parent: pqm at pqm.ubuntu.com-20090127202443-ty2bu1hh91dumasz
    parent: ian.clatworthy at canonical.com-20090127230221-mqumav0ghxkpybba
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: ianc-integration
    timestamp: Wed 2009-01-28 09:06:35 +1000
    message:
      Optionally show diff in log (Ian Clatworthy)
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
    ------------------------------------------------------------
    revno: 3943.5.6
    revision-id: ian.clatworthy at canonical.com-20090127230221-mqumav0ghxkpybba
    parent: ian.clatworthy at canonical.com-20090118033218-y15x0aja8awnjog3
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-show-diff
    timestamp: Wed 2009-01-28 09:02:21 +1000
    message:
      feedback from jam's review
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
    ------------------------------------------------------------
    revno: 3943.5.5
    revision-id: ian.clatworthy at canonical.com-20090118033218-y15x0aja8awnjog3
    parent: ian.clatworthy at canonical.com-20090118031815-gb1m2e7p7ar4ayv1
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-show-diff
    timestamp: Sun 2009-01-18 13:32:18 +1000
    message:
      tweak option name as requested in bug report
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
    ------------------------------------------------------------
    revno: 3943.5.4
    revision-id: ian.clatworthy at canonical.com-20090118031815-gb1m2e7p7ar4ayv1
    parent: ian.clatworthy at canonical.com-20090118023732-adg1rvlk94cw7wup
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-show-diff
    timestamp: Sun 2009-01-18 13:18:15 +1000
    message:
      filter diff by file
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
    ------------------------------------------------------------
    revno: 3943.5.3
    revision-id: ian.clatworthy at canonical.com-20090118023732-adg1rvlk94cw7wup
    parent: ian.clatworthy at canonical.com-20090118013701-ogz42t2c8611fwx4
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-show-diff
    timestamp: Sun 2009-01-18 12:37:32 +1000
    message:
      add tests
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
    ------------------------------------------------------------
    revno: 3943.5.2
    revision-id: ian.clatworthy at canonical.com-20090118013701-ogz42t2c8611fwx4
    parent: ian.clatworthy at canonical.com-20090118005224-rkr66k4s31mgwy0z
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-show-diff
    timestamp: Sun 2009-01-18 11:37:01 +1000
    message:
      hand control of diff formatting to the log formatter
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3943.5.1
    revision-id: ian.clatworthy at canonical.com-20090118005224-rkr66k4s31mgwy0z
    parent: pqm at pqm.ubuntu.com-20090115233242-4bxyn4zcj2a0ksfk
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-show-diff
    timestamp: Sun 2009-01-18 10:52:24 +1000
    message:
      first cut at log --show-diff
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
=== modified file 'NEWS'
--- a/NEWS	2009-01-27 18:43:45 +0000
+++ b/NEWS	2009-01-27 23:06:35 +0000
@@ -37,6 +37,10 @@
 
   NEW FEATURES:
 
+    * ``bzr log -p`` displays the patch diff for each revision.
+      When logging a file, the diff only includes changes to that file.
+      (Ian Clatworthy, #202331, #227335)
+
   IMPROVEMENTS:
 
     * ``bzr init`` will now print a little less verbose output.

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2009-01-23 22:36:22 +0000
+++ b/bzrlib/builtins.py	2009-01-27 23:06:35 +0000
@@ -1862,6 +1862,9 @@
                    help='Limit the output to the first N revisions.',
                    argname='N',
                    type=_parse_limit),
+            Option('show-diff',
+                   short_name='p',
+                   help='Show changes made in each revision as a patch.'),
             ]
     encoding_type = 'replace'
 
@@ -1874,7 +1877,8 @@
             change=None,
             log_format=None,
             message=None,
-            limit=None):
+            limit=None,
+            show_diff=False):
         from bzrlib.log import show_log
         direction = (forward and 'forward') or 'reverse'
 
@@ -1931,7 +1935,8 @@
                      start_revision=rev1,
                      end_revision=rev2,
                      search=message,
-                     limit=limit)
+                     limit=limit,
+                     show_diff=show_diff)
         finally:
             b.unlock()
 

=== modified file 'bzrlib/log.py'
--- a/bzrlib/log.py	2009-01-23 02:29:42 +0000
+++ b/bzrlib/log.py	2009-01-27 23:06:35 +0000
@@ -50,6 +50,7 @@
 """
 
 import codecs
+from cStringIO import StringIO
 from itertools import (
     izip,
     )
@@ -64,6 +65,7 @@
 
 from bzrlib import (
     config,
+    diff,
     errors,
     repository as _mod_repository,
     revision as _mod_revision,
@@ -144,7 +146,8 @@
              start_revision=None,
              end_revision=None,
              search=None,
-             limit=None):
+             limit=None,
+             show_diff=False):
     """Write out human-readable log of commits to this branch.
 
     :param lf: The LogFormatter object showing the output.
@@ -166,6 +169,8 @@
 
     :param limit: If set, shows only 'limit' revisions, all revisions are shown
         if None or 0.
+
+    :param show_diff: If True, output a diff after each revision.
     """
     branch.lock_read()
     try:
@@ -173,7 +178,7 @@
             lf.begin_log()
 
         _show_log(branch, lf, specific_fileid, verbose, direction,
-                  start_revision, end_revision, search, limit)
+                  start_revision, end_revision, search, limit, show_diff)
 
         if getattr(lf, 'end_log', None):
             lf.end_log()
@@ -189,7 +194,8 @@
              start_revision=None,
              end_revision=None,
              search=None,
-             limit=None):
+             limit=None,
+             show_diff=False):
     """Worker function for show_log - see show_log."""
     if not isinstance(lf, LogFormatter):
         warn("not a LogFormatter instance: %r" % lf)
@@ -211,15 +217,21 @@
             rev_tag_dict = branch.tags.get_reverse_tag_dict()
 
     generate_delta = verbose and getattr(lf, 'supports_delta', False)
+    generate_diff = show_diff and getattr(lf, 'supports_diff', False)
 
     # now we just print all the revisions
+    repo = branch.repository
     log_count = 0
     revision_iterator = make_log_rev_iterator(branch, view_revisions,
         generate_delta, search)
     for revs in revision_iterator:
         for (rev_id, revno, merge_depth), rev, delta in revs:
+            if generate_diff:
+                diff = _format_diff(repo, rev, rev_id, specific_fileid)
+            else:
+                diff = None
             lr = LogRevision(rev, revno, merge_depth, delta,
-                             rev_tag_dict.get(rev_id))
+                             rev_tag_dict.get(rev_id), diff)
             lf.log_revision(lr)
             if limit:
                 log_count += 1
@@ -227,6 +239,23 @@
                     return
 
 
+def _format_diff(repo, rev, rev_id, specific_fileid):
+    if len(rev.parent_ids) == 0:
+        ancestor_id = _mod_revision.NULL_REVISION
+    else:
+        ancestor_id = rev.parent_ids[0]
+    tree_1 = repo.revision_tree(ancestor_id)
+    tree_2 = repo.revision_tree(rev_id)
+    if specific_fileid:
+        specific_files = [tree_2.id2path(specific_fileid)]
+    else:
+        specific_files = None
+    s = StringIO()
+    diff.show_diff_trees(tree_1, tree_2, s, specific_files, old_label='',
+        new_label='')
+    return s.getvalue()
+
+
 def calculate_view_revisions(branch, start_revision, end_revision, direction,
                              specific_fileid, generate_merge_revisions,
                              allow_single_merge_revision):
@@ -694,12 +723,13 @@
     """
 
     def __init__(self, rev=None, revno=None, merge_depth=0, delta=None,
-                 tags=None):
+                 tags=None, diff=None):
         self.rev = rev
         self.revno = revno
         self.merge_depth = merge_depth
         self.delta = delta
         self.tags = tags
+        self.diff = diff
 
 
 class LogFormatter(object):
@@ -722,12 +752,17 @@
         merge revisions.  If not, and if supports_single_merge_revisions is
         also not True, then only mainline revisions will be passed to the 
         formatter.
+
     - supports_single_merge_revision must be True if this log formatter
         supports logging only a single merge revision.  This flag is
         only relevant if supports_merge_revisions is not True.
+
     - supports_tags must be True if this log formatter supports tags.
         Otherwise the tags attribute may not be populated.
 
+    - supports_diff must be True if this log formatter supports diffs.
+        Otherwise the diff attribute may not be populated.
+
     Plugins can register functions to show custom revision properties using
     the properties_handler_registry. The registered function
     must respect the following interface description:
@@ -777,12 +812,17 @@
             for key, value in handler(revision).items():
                 self.to_file.write(indent + key + ': ' + value + '\n')
 
+    def show_diff(self, to_file, diff, indent):
+        for l in diff.rstrip().split('\n'):
+            to_file.write(indent + '%s\n' % (l,))
+
 
 class LongLogFormatter(LogFormatter):
 
     supports_merge_revisions = True
     supports_delta = True
     supports_tags = True
+    supports_diff = True
 
     def log_revision(self, revision):
         """Log a revision, either merged or not."""
@@ -825,6 +865,11 @@
             # We don't respect delta_format for compatibility
             revision.delta.show(to_file, self.show_ids, indent=indent,
                                 short_status=False)
+        if revision.diff is not None:
+            to_file.write(indent + 'diff:\n')
+            # Note: we explicitly don't indent the diff (relative to the
+            # revision information) so that the output can be fed to patch -p0
+            self.show_diff(to_file, revision.diff, indent)
 
 
 class ShortLogFormatter(LogFormatter):
@@ -832,6 +877,7 @@
     supports_delta = True
     supports_tags = True
     supports_single_merge_revision = True
+    supports_diff = True
 
     def log_revision(self, revision):
         to_file = self.to_file
@@ -862,6 +908,8 @@
         if revision.delta is not None:
             revision.delta.show(to_file, self.show_ids,
                                 short_status=self.delta_format==1)
+        if revision.diff is not None:
+            self.show_diff(to_file, revision.diff, '      ')
         to_file.write('\n')
 
 

=== modified file 'bzrlib/tests/blackbox/test_log.py'
--- a/bzrlib/tests/blackbox/test_log.py	2009-01-15 14:05:13 +0000
+++ b/bzrlib/tests/blackbox/test_log.py	2009-01-27 23:02:21 +0000
@@ -403,6 +403,170 @@
         self.assertContainsRe(err, err_msg)
 
 
+def subst_dates(string):
+    """Replace date strings with constant values."""
+    return re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]\d{4}',
+                  'YYYY-MM-DD HH:MM:SS +ZZZZ', string)
+
+
+class TestLogDiff(TestCaseWithoutPropsHandler):
+
+    def _prepare(self):
+        parent_tree = self.make_branch_and_tree('parent')
+        self.build_tree(['parent/file1', 'parent/file2'])
+        parent_tree.add('file1')
+        parent_tree.add('file2')
+        parent_tree.commit(message='first post',
+            timestamp=1132586655, timezone=36000,
+            committer='Lorem Ipsum <test at example.com>')
+        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
+        self.build_tree_contents([('child/file2', 'hello\n')])
+        child_tree.commit(message='branch 1',
+            timestamp=1132586700, timezone=36000,
+            committer='Lorem Ipsum <test at example.com>')
+        parent_tree.merge_from_branch(child_tree.branch)
+        parent_tree.commit(message='merge branch 1',
+            timestamp=1132586800, timezone=36000,
+            committer='Lorem Ipsum <test at example.com>')
+        os.chdir('parent')
+
+    def test_log_show_diff_long(self):
+        self._prepare()
+        out,err = self.run_bzr('log -p')
+        self.assertEqual('', err)
+        log = normalize_log(out)
+        self.assertEqualDiff(subst_dates(log), """\
+------------------------------------------------------------
+revno: 2
+committer: Lorem Ipsum <test at example.com>
+branch nick: parent
+timestamp: Just now
+message:
+  merge branch 1
+diff:
+=== modified file 'file2'
+--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
++++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+@@ -1,1 +1,1 @@
+-contents of parent/file2
++hello
+    ------------------------------------------------------------
+    revno: 1.1.1
+    committer: Lorem Ipsum <test at example.com>
+    branch nick: child
+    timestamp: Just now
+    message:
+      branch 1
+    diff:
+    === modified file 'file2'
+    --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+    +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+    @@ -1,1 +1,1 @@
+    -contents of parent/file2
+    +hello
+------------------------------------------------------------
+revno: 1
+committer: Lorem Ipsum <test at example.com>
+branch nick: parent
+timestamp: Just now
+message:
+  first post
+diff:
+=== added file 'file1'
+--- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
++++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
+@@ -0,0 +1,1 @@
++contents of parent/file1
+
+=== added file 'file2'
+--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
++++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+@@ -0,0 +1,1 @@
++contents of parent/file2
+""")
+
+    def test_log_show_diff_short(self):
+        self._prepare()
+        out,err = self.run_bzr('log -p --short')
+        self.assertEqual('', err)
+        log = normalize_log(out)
+        self.assertEqualDiff(subst_dates(log), """\
+    2 Lorem Ipsum\t2005-11-22 [merge]
+      merge branch 1
+      === modified file 'file2'
+      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      @@ -1,1 +1,1 @@
+      -contents of parent/file2
+      +hello
+
+    1 Lorem Ipsum\t2005-11-22
+      first post
+      === added file 'file1'
+      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      @@ -0,0 +1,1 @@
+      +contents of parent/file1
+      
+      === added file 'file2'
+      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      @@ -0,0 +1,1 @@
+      +contents of parent/file2
+
+""")
+
+    def test_log_show_diff_line(self):
+        self._prepare()
+        out,err = self.run_bzr('log -p --line')
+        self.assertEqual('', err)
+        log = normalize_log(out)
+        # Not supported by this formatter so expect plain output
+        self.assertEqualDiff(subst_dates(log), """\
+2: Lorem Ipsum 2005-11-22 merge branch 1
+1: Lorem Ipsum 2005-11-22 first post
+""")
+
+    def test_log_show_diff_file(self):
+        """Only the diffs for the given file are to be shown"""
+        self._prepare()
+        out,err = self.run_bzr('log -p --short file2')
+        self.assertEqual('', err)
+        log = normalize_log(out)
+        self.assertEqualDiff(subst_dates(log), """\
+    2 Lorem Ipsum\t2005-11-22 [merge]
+      merge branch 1
+      === modified file 'file2'
+      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      @@ -1,1 +1,1 @@
+      -contents of parent/file2
+      +hello
+
+    1 Lorem Ipsum\t2005-11-22
+      first post
+      === added file 'file2'
+      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      @@ -0,0 +1,1 @@
+      +contents of parent/file2
+
+""")
+        out,err = self.run_bzr('log -p --short file1')
+        self.assertEqual('', err)
+        log = normalize_log(out)
+        self.assertEqualDiff(subst_dates(log), """\
+    1 Lorem Ipsum\t2005-11-22
+      first post
+      === added file 'file1'
+      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
+      @@ -0,0 +1,1 @@
+      +contents of parent/file1
+
+""")
+
+
 class TestLogEncodings(TestCaseInTempDir):
 
     _mu = u'\xb5'




More information about the bazaar-commits mailing list