Rev 5174: (vila) Add 'post_repo_init', 'post_branch_init' and 'post_switch' hooks. (Marco Pantaleoni) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Apr 22 18:08:48 BST 2010


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

------------------------------------------------------------
revno: 5174 [merge]
revision-id: pqm at pqm.ubuntu.com-20100422170827-h0bb41yq5nkosu6t
parent: pqm at pqm.ubuntu.com-20100422154421-eeit8sxsvtxxherb
parent: panta at elasticworld.org-20100326071129-fzwihjpyb43wn2j5
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2010-04-22 18:08:27 +0100
message:
  (vila) Add 'post_repo_init', 'post_branch_init' and 'post_switch' hooks. (Marco Pantaleoni)
modified:
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
  bzrlib/repofmt/knitrepo.py     knitrepo.py-20070206081537-pyy4a00xdas0j4pf-1
  bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
  bzrlib/repofmt/weaverepo.py    presplitout.py-20070125045333-wfav3tsh73oxu3zk-1
  bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
  bzrlib/switch.py               switch.py-20071116011000-v5lnw7d2wkng9eux-1
  bzrlib/tests/blackbox/test_branch.py test_branch.py-20060524161337-noms9gmcwqqrfi8y-1
  bzrlib/tests/blackbox/test_shared_repository.py test_shared_repository.py-20060317053531-ed30c0d79325e483
  bzrlib/tests/blackbox/test_switch.py test_switch.py-20071122111948-0c5en6uz92bwl76h-1
  bzrlib/tests/test_branch.py    test_branch.py-20060116013032-97819aa07b8ab3b5
  bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2010-04-10 18:03:54 +0000
+++ b/bzrlib/branch.py	2010-04-22 17:08:27 +0000
@@ -1543,6 +1543,14 @@
         """Return the short format description for this format."""
         raise NotImplementedError(self.get_format_description)
 
+    def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
+        hooks = Branch.hooks['post_branch_init']
+        if not hooks:
+            return
+        params = BranchInitHookParams(self, a_bzrdir, name, branch)
+        for hook in hooks:
+            hook(params)
+
     def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
                            lock_type='metadir', set_format=True):
         """Initialize a branch in a bzrdir, with specified files
@@ -1584,7 +1592,9 @@
         finally:
             if lock_taken:
                 control_files.unlock()
-        return self.open(a_bzrdir, name, _found=True)
+        branch = self.open(a_bzrdir, name, _found=True)
+        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
+        return branch
 
     def initialize(self, a_bzrdir, name=None):
         """Create a branch of this format in a_bzrdir.
@@ -1750,6 +1760,16 @@
             "should return a tag name or None if no tag name could be "
             "determined. The first non-None tag name returned will be used.",
             (2, 2), None))
+        self.create_hook(HookPoint('post_branch_init',
+            "Called after new branch initialization completes. "
+            "post_branch_init is called with a "
+            "bzrlib.branch.BranchInitHookParams. "
+            "Note that init, branch and checkout (both heavyweight and "
+            "lightweight) will all trigger this hook.", (2, 2), None))
+        self.create_hook(HookPoint('post_switch',
+            "Called after a checkout switches branch. "
+            "post_switch is called with a "
+            "bzrlib.branch.SwitchHookParams.", (2, 2), None))
 
 
 
@@ -1795,6 +1815,84 @@
             self.old_revno, self.old_revid, self.new_revno, self.new_revid)
 
 
+class BranchInitHookParams(object):
+    """Object holding parameters passed to *_branch_init hooks.
+
+    There are 4 fields that hooks may wish to access:
+
+    :ivar format: the branch format
+    :ivar bzrdir: the BzrDir where the branch will be/has been initialized
+    :ivar name: name of colocated branch, if any (or None)
+    :ivar branch: the branch created
+
+    Note that for lightweight checkouts, the bzrdir and format fields refer to
+    the checkout, hence they are different from the corresponding fields in
+    branch, which refer to the original branch.
+    """
+
+    def __init__(self, format, a_bzrdir, name, branch):
+        """Create a group of BranchInitHook parameters.
+
+        :param format: the branch format
+        :param a_bzrdir: the BzrDir where the branch will be/has been
+            initialized
+        :param name: name of colocated branch, if any (or None)
+        :param branch: the branch created
+
+        Note that for lightweight checkouts, the bzrdir and format fields refer
+        to the checkout, hence they are different from the corresponding fields
+        in branch, which refer to the original branch.
+        """
+        self.format = format
+        self.bzrdir = a_bzrdir
+        self.name = name
+        self.branch = branch
+
+    def __eq__(self, other):
+        return self.__dict__ == other.__dict__
+
+    def __repr__(self):
+        if self.branch:
+            return "<%s of %s>" % (self.__class__.__name__, self.branch)
+        else:
+            return "<%s of format:%s bzrdir:%s>" % (
+                self.__class__.__name__, self.branch,
+                self.format, self.bzrdir)
+
+
+class SwitchHookParams(object):
+    """Object holding parameters passed to *_switch hooks.
+
+    There are 4 fields that hooks may wish to access:
+
+    :ivar control_dir: BzrDir of the checkout to change
+    :ivar to_branch: branch that the checkout is to reference
+    :ivar force: skip the check for local commits in a heavy checkout
+    :ivar revision_id: revision ID to switch to (or None)
+    """
+
+    def __init__(self, control_dir, to_branch, force, revision_id):
+        """Create a group of SwitchHook parameters.
+
+        :param control_dir: BzrDir of the checkout to change
+        :param to_branch: branch that the checkout is to reference
+        :param force: skip the check for local commits in a heavy checkout
+        :param revision_id: revision ID to switch to (or None)
+        """
+        self.control_dir = control_dir
+        self.to_branch = to_branch
+        self.force = force
+        self.revision_id = revision_id
+
+    def __eq__(self, other):
+        return self.__dict__ == other.__dict__
+
+    def __repr__(self):
+        return "<%s for %s to (%s, %s)>" % (self.__class__.__name__,
+            self.control_dir, self.to_branch,
+            self.revision_id)
+
+
 class BzrBranchFormat4(BranchFormat):
     """Bzr branch format 4.
 
@@ -2069,9 +2167,11 @@
         branch_transport.put_bytes('location',
             target_branch.bzrdir.root_transport.base)
         branch_transport.put_bytes('format', self.get_format_string())
-        return self.open(
+        branch = self.open(
             a_bzrdir, name, _found=True,
             possible_transports=[target_branch.bzrdir.root_transport])
+        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
+        return branch
 
     def __init__(self):
         super(BranchReferenceFormat, self).__init__()

=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py	2010-04-16 07:56:51 +0000
+++ b/bzrlib/bzrdir.py	2010-04-22 17:08:27 +0000
@@ -1330,11 +1330,52 @@
         self.create_hook(hooks.HookPoint('pre_open',
             "Invoked before attempting to open a BzrDir with the transport "
             "that the open will use.", (1, 14), None))
+        self.create_hook(hooks.HookPoint('post_repo_init',
+            "Invoked after a repository has been initialized. "
+            "post_repo_init is called with a "
+            "bzrlib.bzrdir.RepoInitHookParams.",
+            (2, 2), None))
 
 # install the default hooks
 BzrDir.hooks = BzrDirHooks()
 
 
+class RepoInitHookParams(object):
+    """Object holding parameters passed to *_repo_init hooks.
+
+    There are 4 fields that hooks may wish to access:
+
+    :ivar repository: Repository created
+    :ivar format: Repository format
+    :ivar bzrdir: The bzrdir for the repository
+    :ivar shared: The repository is shared
+    """
+
+    def __init__(self, repository, format, a_bzrdir, shared):
+        """Create a group of RepoInitHook parameters.
+
+        :param repository: Repository created
+        :param format: Repository format
+        :param bzrdir: The bzrdir for the repository
+        :param shared: The repository is shared
+        """
+        self.repository = repository
+        self.format = format
+        self.bzrdir = a_bzrdir
+        self.shared = shared
+
+    def __eq__(self, other):
+        return self.__dict__ == other.__dict__
+
+    def __repr__(self):
+        if self.repository:
+            return "<%s for %s>" % (self.__class__.__name__,
+                self.repository)
+        else:
+            return "<%s for %s>" % (self.__class__.__name__,
+                self.bzrdir)
+
+
 class BzrDirPreSplitOut(BzrDir):
     """A common class for the all-in-one formats."""
 

=== modified file 'bzrlib/repofmt/knitrepo.py'
--- a/bzrlib/repofmt/knitrepo.py	2010-01-29 10:59:12 +0000
+++ b/bzrlib/repofmt/knitrepo.py	2010-03-24 14:35:25 +0000
@@ -360,6 +360,7 @@
         result.revisions.get_parent_map([('A',)])
         result.signatures.get_parent_map([('A',)])
         result.unlock()
+        self._run_post_repo_init_hooks(result, a_bzrdir, shared)
         return result
 
     def open(self, a_bzrdir, _found=False, _override_transport=None):

=== modified file 'bzrlib/repofmt/pack_repo.py'
--- a/bzrlib/repofmt/pack_repo.py	2010-04-19 13:04:30 +0000
+++ b/bzrlib/repofmt/pack_repo.py	2010-04-22 17:08:27 +0000
@@ -2546,7 +2546,9 @@
         utf8_files = [('format', self.get_format_string())]
 
         self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
-        return self.open(a_bzrdir=a_bzrdir, _found=True)
+        repository = self.open(a_bzrdir=a_bzrdir, _found=True)
+        self._run_post_repo_init_hooks(repository, a_bzrdir, shared)
+        return repository
 
     def open(self, a_bzrdir, _found=False, _override_transport=None):
         """See RepositoryFormat.open().

=== modified file 'bzrlib/repofmt/weaverepo.py'
--- a/bzrlib/repofmt/weaverepo.py	2009-09-16 17:19:07 +0000
+++ b/bzrlib/repofmt/weaverepo.py	2010-03-24 14:35:25 +0000
@@ -302,7 +302,9 @@
                 mode=a_bzrdir._get_file_mode())
         finally:
             control_files.unlock()
-        return self.open(a_bzrdir, _found=True)
+        repository = self.open(a_bzrdir, _found=True)
+        self._run_post_repo_init_hooks(repository, a_bzrdir, shared)
+        return repository
 
     def open(self, a_bzrdir, _found=False):
         """See RepositoryFormat.open()."""

=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py	2010-04-19 13:04:30 +0000
+++ b/bzrlib/repository.py	2010-04-22 17:08:27 +0000
@@ -3171,6 +3171,15 @@
         """
         raise NotImplementedError(self.open)
 
+    def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
+        from bzrlib.bzrdir import BzrDir, RepoInitHookParams
+        hooks = BzrDir.hooks['post_repo_init']
+        if not hooks:
+            return
+        params = RepoInitHookParams(repository, self, a_bzrdir, shared)
+        for hook in hooks:
+            hook(params)
+
 
 class MetaDirRepositoryFormat(RepositoryFormat):
     """Common base class for the new repositories using the metadir layout."""

=== modified file 'bzrlib/switch.py'
--- a/bzrlib/switch.py	2010-02-17 17:11:16 +0000
+++ b/bzrlib/switch.py	2010-03-25 14:22:41 +0000
@@ -22,6 +22,15 @@
 from bzrlib.trace import note
 
 
+def _run_post_switch_hooks(control_dir, to_branch, force, revision_id):
+    from bzrlib.branch import SwitchHookParams
+    hooks = Branch.hooks['post_switch']
+    if not hooks:
+        return
+    params = SwitchHookParams(control_dir, to_branch, force, revision_id)
+    for hook in hooks:
+        hook(params)
+
 def switch(control_dir, to_branch, force=False, quiet=False, revision_id=None):
     """Switch the branch associated with a checkout.
 
@@ -38,7 +47,7 @@
     _set_branch_location(control_dir, to_branch, force)
     tree = control_dir.open_workingtree()
     _update(tree, source_repository, quiet, revision_id)
-
+    _run_post_switch_hooks(control_dir, to_branch, force, revision_id)
 
 def _check_pending_merges(control, force=False):
     """Check that there are no outstanding pending merges before switching.

=== modified file 'bzrlib/tests/blackbox/test_branch.py'
--- a/bzrlib/tests/blackbox/test_branch.py	2010-03-25 07:34:15 +0000
+++ b/bzrlib/tests/blackbox/test_branch.py	2010-04-22 17:08:27 +0000
@@ -217,6 +217,36 @@
         b = branch.Branch.open('b')
         self.assertEndsWith(b.get_bound_location(), '/a/')
 
+    def test_branch_with_post_branch_init_hook(self):
+        calls = []
+        branch.Branch.hooks.install_named_hook('post_branch_init',
+            calls.append, None)
+        self.assertLength(0, calls)
+        self.example_branch('a')
+        self.assertLength(1, calls)
+        self.run_bzr('branch a b')
+        self.assertLength(2, calls)
+
+    def test_checkout_with_post_branch_init_hook(self):
+        calls = []
+        branch.Branch.hooks.install_named_hook('post_branch_init',
+            calls.append, None)
+        self.assertLength(0, calls)
+        self.example_branch('a')
+        self.assertLength(1, calls)
+        self.run_bzr('checkout a b')
+        self.assertLength(2, calls)
+
+    def test_lightweight_checkout_with_post_branch_init_hook(self):
+        calls = []
+        branch.Branch.hooks.install_named_hook('post_branch_init',
+            calls.append, None)
+        self.assertLength(0, calls)
+        self.example_branch('a')
+        self.assertLength(1, calls)
+        self.run_bzr('checkout --lightweight a b')
+        self.assertLength(2, calls)
+
 
 class TestBranchStacked(ExternalBase):
     """Tests for branch --stacked"""

=== modified file 'bzrlib/tests/blackbox/test_shared_repository.py'
--- a/bzrlib/tests/blackbox/test_shared_repository.py	2010-02-17 17:11:16 +0000
+++ b/bzrlib/tests/blackbox/test_shared_repository.py	2010-03-25 18:02:45 +0000
@@ -138,3 +138,10 @@
         self.assertRaises(errors.NoRepositoryPresent, dir.open_repository)
         e = self.assertRaises(errors.NotBranchError, dir.open_branch)
         self.assertNotContainsRe(str(e), "location is a repository")
+
+    def test_init_repo_with_post_repo_init_hook(self):
+        calls = []
+        BzrDir.hooks.install_named_hook('post_repo_init', calls.append, None)
+        self.assertLength(0, calls)
+        self.run_bzr("init-repository a")
+        self.assertLength(1, calls)

=== modified file 'bzrlib/tests/blackbox/test_switch.py'
--- a/bzrlib/tests/blackbox/test_switch.py	2010-02-17 17:11:16 +0000
+++ b/bzrlib/tests/blackbox/test_switch.py	2010-03-26 07:08:56 +0000
@@ -225,3 +225,29 @@
         self.run_bzr('switch -b foo:branch2', working_dir='tree')
         tree = WorkingTree.open('tree')
         self.assertEndsWith(tree.branch.base, 'foo-branch2/')
+
+    def test_switch_with_post_switch_hook(self):
+        from bzrlib import branch as _mod_branch
+        calls = []
+        _mod_branch.Branch.hooks.install_named_hook('post_switch',
+            calls.append, None)
+        self.make_branch_and_tree('branch')
+        self.run_bzr('branch branch branch2')
+        self.run_bzr('checkout branch checkout')
+        os.chdir('checkout')
+        self.assertLength(0, calls)
+        out, err = self.run_bzr('switch ../branch2')
+        self.assertLength(1, calls)
+
+    def test_switch_lightweight_co_with_post_switch_hook(self):
+        from bzrlib import branch as _mod_branch
+        calls = []
+        _mod_branch.Branch.hooks.install_named_hook('post_switch',
+            calls.append, None)
+        self.make_branch_and_tree('branch')
+        self.run_bzr('branch branch branch2')
+        self.run_bzr('checkout --lightweight branch checkout')
+        os.chdir('checkout')
+        self.assertLength(0, calls)
+        out, err = self.run_bzr('switch ../branch2')
+        self.assertLength(1, calls)

=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py	2010-03-11 13:14:37 +0000
+++ b/bzrlib/tests/test_branch.py	2010-03-25 14:22:41 +0000
@@ -455,7 +455,7 @@
             _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
 
 
-class TestHooks(tests.TestCase):
+class TestHooks(tests.TestCaseWithTransport):
 
     def test_constructor(self):
         """Check that creating a BranchHooks instance has the right defaults."""
@@ -469,6 +469,10 @@
                         "post_uncommit not in %s" % hooks)
         self.assertTrue("post_change_branch_tip" in hooks,
                         "post_change_branch_tip not in %s" % hooks)
+        self.assertTrue("post_branch_init" in hooks,
+                        "post_branch_init not in %s" % hooks)
+        self.assertTrue("post_switch" in hooks,
+                        "post_switch not in %s" % hooks)
 
     def test_installed_hooks_are_BranchHooks(self):
         """The installed hooks object should be a BranchHooks."""
@@ -476,6 +480,40 @@
         self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
                               _mod_branch.BranchHooks)
 
+    def test_post_branch_init_hook(self):
+        calls = []
+        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
+            calls.append, None)
+        self.assertLength(0, calls)
+        branch = self.make_branch('a')
+        self.assertLength(1, calls)
+        params = calls[0]
+        self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
+        self.assertTrue(hasattr(params, 'bzrdir'))
+        self.assertTrue(hasattr(params, 'branch'))
+
+    def test_post_switch_hook(self):
+        from bzrlib import switch
+        calls = []
+        _mod_branch.Branch.hooks.install_named_hook('post_switch',
+            calls.append, None)
+        tree = self.make_branch_and_tree('branch-1')
+        self.build_tree(['branch-1/file-1'])
+        tree.add('file-1')
+        tree.commit('rev1')
+        to_branch = tree.bzrdir.sprout('branch-2').open_branch()
+        self.build_tree(['branch-1/file-2'])
+        tree.add('file-2')
+        tree.remove('file-1')
+        tree.commit('rev2')
+        checkout = tree.branch.create_checkout('checkout')
+        self.assertLength(0, calls)
+        switch.switch(checkout.bzrdir, to_branch)
+        self.assertLength(1, calls)
+        params = calls[0]
+        self.assertIsInstance(params, _mod_branch.SwitchHookParams)
+        self.assertTrue(hasattr(params, 'to_branch'))
+        self.assertTrue(hasattr(params, 'revision_id'))
 
 class TestPullResult(tests.TestCase):
 

=== modified file 'bzrlib/tests/test_bzrdir.py'
--- a/bzrlib/tests/test_bzrdir.py	2010-03-02 22:25:58 +0000
+++ b/bzrlib/tests/test_bzrdir.py	2010-03-25 14:22:41 +0000
@@ -1339,3 +1339,15 @@
         url = transport.base
         err = self.assertRaises(errors.BzrError, bzrdir.BzrDir.open, url)
         self.assertEqual('fail', err._preformatted_string)
+
+    def test_post_repo_init(self):
+        from bzrlib.bzrdir import RepoInitHookParams
+        calls = []
+        bzrdir.BzrDir.hooks.install_named_hook('post_repo_init',
+            calls.append, None)
+        self.make_repository('foo')
+        self.assertLength(1, calls)
+        params = calls[0]
+        self.assertIsInstance(params, RepoInitHookParams)
+        self.assertTrue(hasattr(params, 'bzrdir'))
+        self.assertTrue(hasattr(params, 'repository'))




More information about the bazaar-commits mailing list