Rev 2246: New Branch hooks facility, with one initial hook 'set_rh' which triggers in file:///home/robertc/source/baz/branch-hook/

Robert Collins robertc at robertcollins.net
Mon Jan 29 16:58:52 GMT 2007


------------------------------------------------------------
revno: 2246
revision-id: robertc at robertcollins.net-20070129165849-409f5714fa7ebe48
parent: pqm at pqm.ubuntu.com-20070125194626-4ded330415b7276d
committer: Robert Collins <robertc at robertcollins.net>
branch nick: branch-hook
timestamp: Tue 2007-01-30 03:58:49 +1100
message:
  New Branch hooks facility, with one initial hook 'set_rh' which triggers
  whenever the revision history is set. This allows triggering on e.g.
  push, pull, commit, and so on. Developed for use with the branchrss
  plugin. See bzrlib/tests/branch_implementations/test_hooks for more
  details. (Robert Collins)
added:
  bzrlib/tests/branch_implementations/test_hooks.py test_hooks.py-20070129154855-blhpwxmvjs07waei-1
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
  bzrlib/tests/test_branch.py    test_branch.py-20060116013032-97819aa07b8ab3b5
  bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
=== added file 'bzrlib/tests/branch_implementations/test_hooks.py'
--- a/bzrlib/tests/branch_implementations/test_hooks.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/branch_implementations/test_hooks.py	2007-01-29 16:58:49 +0000
@@ -0,0 +1,67 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Tests for branch hooking operations."""
+
+from bzrlib.branch import Branch
+from bzrlib.tests import TestCaseWithMemoryTransport
+
+
+class TestPushHook(TestCaseWithMemoryTransport):
+
+    def setUp(self):
+        self.hook_calls = []
+        TestCaseWithMemoryTransport.setUp(self)
+
+    def capture_set_rh_hook(self, branch, rev_history):
+        """Capture post push hook calls to self.hook_calls.
+        
+        The call is logged, as is some state of the two branches.
+        """
+        self.hook_calls.append(
+            ('set_rh', branch, rev_history, branch.is_locked()))
+
+    def test_set_rh_empty_history(self):
+        branch = self.make_branch('source')
+        Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+        branch.set_revision_history([])
+        self.assertEqual(self.hook_calls,
+            [('set_rh', branch, [], True)])
+
+    def test_set_rh_nonempty_history(self):
+        branch = self.make_branch('source')
+        Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+        branch.set_revision_history([u'foo'])
+        self.assertEqual(self.hook_calls,
+            [('set_rh', branch, [u'foo'], True)])
+
+    def test_set_rh_branch_is_locked(self):
+        branch = self.make_branch('source')
+        Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+        branch.set_revision_history([])
+        self.assertEqual(self.hook_calls,
+            [('set_rh', branch, [], True)])
+
+    def test_set_rh_calls_all_hooks_no_errors(self):
+        branch = self.make_branch('source')
+        Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+        Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+        branch.set_revision_history([])
+        self.assertEqual(self.hook_calls,
+            [('set_rh', branch, [], True),
+             ('set_rh', branch, [], True),
+            ])
+

=== modified file 'NEWS'
--- a/NEWS	2007-01-24 19:42:26 +0000
+++ b/NEWS	2007-01-29 16:58:49 +0000
@@ -25,6 +25,12 @@
       versionedfiles, repositories, branches, and working trees
       (Aaron Bentley)
 
+    * New Branch hooks facility, with one initial hook 'set_rh' which triggers
+      whenever the revision history is set. This allows triggering on e.g.
+      push, pull, commit, and so on. Developed for use with the branchrss
+      plugin. See bzrlib/tests/branch_implementations/test_hooks for more
+      details. (Robert Collins)
+
   BUGFIXES:
 
   TESTING:

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2007-01-17 15:37:08 +0000
+++ b/bzrlib/branch.py	2007-01-29 16:58:49 +0000
@@ -81,6 +81,10 @@
 
     base
         Base directory/url of the branch.
+
+    hooks: A dictionary mapping hook actions to callables to invoke.
+        e.g. 'set_rh':[] is the set_rh hook list. See DefaultHooks for
+        full details.
     """
     # this is really an instance variable - FIXME move it there
     # - RBC 20060112
@@ -104,6 +108,16 @@
             master.break_lock()
 
     @staticmethod
+    def DefaultHooks():
+        """Return a dict of the default branch hook settings."""
+        return {
+            'set_rh':[], # invoked whenever the revision history has been set
+                         # with set_revision_history. The api signature is
+                         # (branch, revision_history), and the branch will
+                         # be write-locked.
+            }
+
+    @staticmethod
     @deprecated_method(zero_eight)
     def open_downlevel(base):
         """Open a branch which may be of an old format."""
@@ -629,6 +643,10 @@
         return checkout.create_workingtree(revision_id)
 
 
+# install the default hooks into the class.
+Branch.hooks = Branch.DefaultHooks()
+
+
 class BranchFormat(object):
     """An encapsulation of the initialization and open routines for a format.
 
@@ -1101,6 +1119,8 @@
             # this call is disabled because revision_history is 
             # not really an object yet, and the transaction is for objects.
             # transaction.register_clean(history)
+        for hook in Branch.hooks['set_rh']:
+            hook(self, rev_history)
 
     @needs_read_lock
     def revision_history(self):

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2007-01-19 19:42:19 +0000
+++ b/bzrlib/tests/__init__.py	2007-01-29 16:58:49 +0000
@@ -569,6 +569,12 @@
         self._startLogFile()
         self._benchcalls = []
         self._benchtime = None
+        # prevent hooks affecting tests
+        self._preserved_hooks = bzrlib.branch.Branch.hooks
+        self.addCleanup(self._restoreHooks)
+        # this list of hooks must be kept in sync with the defaults
+        # in branch.py
+        bzrlib.branch.Branch.hooks = bzrlib.branch.Branch.DefaultHooks()
 
     def _silenceUI(self):
         """Turn off UI for duration of test"""
@@ -835,6 +841,9 @@
         for name, value in self.__old_env.iteritems():
             osutils.set_or_unset_env(name, value)
 
+    def _restoreHooks(self):
+        bzrlib.branch.Branch.hooks = self._preserved_hooks
+
     def tearDown(self):
         self._runCleanups()
         unittest.TestCase.tearDown(self)

=== modified file 'bzrlib/tests/branch_implementations/__init__.py'
--- a/bzrlib/tests/branch_implementations/__init__.py	2006-10-11 23:08:27 +0000
+++ b/bzrlib/tests/branch_implementations/__init__.py	2007-01-29 16:58:49 +0000
@@ -42,6 +42,7 @@
         'bzrlib.tests.branch_implementations.test_bound_sftp',
         'bzrlib.tests.branch_implementations.test_branch',
         'bzrlib.tests.branch_implementations.test_break_lock',
+        'bzrlib.tests.branch_implementations.test_hooks',
         'bzrlib.tests.branch_implementations.test_http',
         'bzrlib.tests.branch_implementations.test_locking',
         'bzrlib.tests.branch_implementations.test_parent',

=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py	2006-09-07 23:31:28 +0000
+++ b/bzrlib/tests/test_branch.py	2007-01-29 16:58:49 +0000
@@ -162,3 +162,17 @@
         self.assertEqual(made_branch.base, target_branch.base)
         opened_branch = branch_dir.open_branch()
         self.assertEqual(opened_branch.base, target_branch.base)
+
+
+class TestHooks(TestCase):
+
+    def test_set_rh_in_defaults(self):
+        """Check that the set_rh hook exists in the defaults."""
+        default_hooks = bzrlib.branch.Branch.DefaultHooks()
+        self.assertTrue("set_rh" in default_hooks,
+            "set_rh not in %s" % default_hooks)
+
+    def test_set_rh_in_actual_hooks(self):
+        """Check that the set_rh hook exists in the saved hook set."""
+        self.assertTrue("set_rh" in self._preserved_hooks,
+            "set_rh not in %s" % self._preserved_hooks)

=== modified file 'bzrlib/tests/test_selftest.py'
--- a/bzrlib/tests/test_selftest.py	2007-01-11 08:45:51 +0000
+++ b/bzrlib/tests/test_selftest.py	2007-01-29 16:58:49 +0000
@@ -852,7 +852,12 @@
         self.assertContainsRe(
             output_stream.getvalue(),
             r"\d+ms/ +\d+ms\n$")
-        
+
+    def test_hooks_sanitised(self):
+        """The bzrlib hooks should be sanitised by setUp."""
+        self.assertEqual(bzrlib.branch.Branch.DefaultHooks(),
+            bzrlib.branch.Branch.hooks)
+
     def test__gather_lsprof_in_benchmarks(self):
         """When _gather_lsprof_in_benchmarks is on, accumulate profile data.
         



More information about the bazaar-commits mailing list