Merge lp:~jelmer/bzr/more-lazy-hooks into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 5748
Proposed branch: lp:~jelmer/bzr/more-lazy-hooks
Merge into: lp:bzr
Prerequisite: lp:~jelmer/bzr/reset-lazy-hooks
Diff against target: 747 lines (+137/-160)
21 files modified
bzrlib/branch.py (+28/-28)
bzrlib/bzrdir.py (+5/-5)
bzrlib/commands.py (+10/-10)
bzrlib/hooks.py (+4/-2)
bzrlib/info.py (+3/-4)
bzrlib/lock.py (+11/-11)
bzrlib/merge.py (+3/-3)
bzrlib/merge_directive.py (+3/-3)
bzrlib/msgeditor.py (+4/-4)
bzrlib/mutabletree.py (+5/-5)
bzrlib/plugins/changelog_merge/__init__.py (+6/-17)
bzrlib/plugins/launchpad/lp_propose.py (+6/-13)
bzrlib/plugins/news_merge/__init__.py (+7/-16)
bzrlib/smart/client.py (+3/-3)
bzrlib/smart/server.py (+8/-8)
bzrlib/status.py (+5/-5)
bzrlib/tests/test_hooks.py (+15/-16)
bzrlib/tests/test_selftest.py (+5/-5)
bzrlib/tests/transport_util.py (+2/-1)
bzrlib/version_info_formats/format_rio.py (+1/-1)
doc/en/release-notes/bzr-2.4.txt (+3/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/more-lazy-hooks
Reviewer Review Type Date Requested Status
Vincent Ladeuil Needs Fixing
Review via email: mp+55523@code.launchpad.net

Commit message

Support installing lazy hooks for all existing hook points, deprecate Hooks.create_hook.

Description of the change

Support installing lazy hooks for all existing hook points, like was already done for bzrlib.version_info_formats.format_rio.

Deprecate Hooks.create_hook, which doesn't work well together with lazy hooks.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

One test failure when run on babune:
http://babune.ladeuil.net:24842/view/debug/job/selftest-subset-all/108/aggregatedTestReport/

<<< bzrlib.tests.test_branch.TestHooks.test_constructor
Stack Trace

_StringException: Text attachment: log
------------
1426.373 opening working tree '/private/tmp/testbzr-EefziM.tmp'
------------
Text attachment: traceback
------------
Traceback (most recent call last):
  File "/home/vila/lib/python/testtools/runtest.py", line 144, in _run_user
  File "/home/vila/lib/python/testtools/testcase.py", line 487, in _run_test_method
  File "/Users/babune/babune/slaves/macadam.local/workspace/selftest-subset-macadam/bzrlib/tests/test_branch.py", line 574, in test_constructor
    hooks = _mod_branch.BranchHooks("bzrlib.tests.test_branch", "branch.hooks")
TypeError: __init__() takes exactly 1 argument (3 given)
------------

Since the changes are pretty mechanical, it's probably shallow, so tweak.

review: Needs Fixing
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

On Thu, 2011-03-31 at 14:26 +0000, Vincent Ladeuil wrote:
> Review: Needs Fixing
> One test failure when run on babune:
> http://babune.ladeuil.net:24842/view/debug/job/selftest-subset-all/108/aggregatedTestReport/
>
> <<< bzrlib.tests.test_branch.TestHooks.test_constructor
> Stack Trace
>
> _StringException: Text attachment: log
> ------------
> 1426.373 opening working tree '/private/tmp/testbzr-EefziM.tmp'
> ------------
> Text attachment: traceback
> ------------
> Traceback (most recent call last):
> File "/home/vila/lib/python/testtools/runtest.py", line 144, in _run_user
> File "/home/vila/lib/python/testtools/testcase.py", line 487, in _run_test_method
> File "/Users/babune/babune/slaves/macadam.local/workspace/selftest-subset-macadam/bzrlib/tests/test_branch.py", line 574, in test_constructor
> hooks = _mod_branch.BranchHooks("bzrlib.tests.test_branch", "branch.hooks")
> TypeError: __init__() takes exactly 1 argument (3 given)
> ------------
>
> Since the changes are pretty mechanical, it's probably shallow, so tweak.
Fixed, thanks for the review!

Cheers,

Jelmer

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 2011-03-26 01:37:08 +0000
+++ bzrlib/branch.py 2011-03-31 15:13:30 +0000
@@ -57,7 +57,7 @@
57 needs_write_lock,57 needs_write_lock,
58 only_raises,58 only_raises,
59 )59 )
60from bzrlib.hooks import HookPoint, Hooks60from bzrlib.hooks import Hooks
61from bzrlib.inter import InterObject61from bzrlib.inter import InterObject
62from bzrlib.lock import _RelockDebugMixin, LogicalLockResult62from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
63from bzrlib import registry63from bzrlib import registry
@@ -1808,25 +1808,25 @@
1808 These are all empty initially, because by default nothing should get1808 These are all empty initially, because by default nothing should get
1809 notified.1809 notified.
1810 """1810 """
1811 Hooks.__init__(self)1811 Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
1812 self.create_hook(HookPoint('set_rh',1812 self.add_hook('set_rh',
1813 "Invoked whenever the revision history has been set via "1813 "Invoked whenever the revision history has been set via "
1814 "set_revision_history. The api signature is (branch, "1814 "set_revision_history. The api signature is (branch, "
1815 "revision_history), and the branch will be write-locked. "1815 "revision_history), and the branch will be write-locked. "
1816 "The set_rh hook can be expensive for bzr to trigger, a better "1816 "The set_rh hook can be expensive for bzr to trigger, a better "
1817 "hook to use is Branch.post_change_branch_tip.", (0, 15), None))1817 "hook to use is Branch.post_change_branch_tip.", (0, 15))
1818 self.create_hook(HookPoint('open',1818 self.add_hook('open',
1819 "Called with the Branch object that has been opened after a "1819 "Called with the Branch object that has been opened after a "
1820 "branch is opened.", (1, 8), None))1820 "branch is opened.", (1, 8))
1821 self.create_hook(HookPoint('post_push',1821 self.add_hook('post_push',
1822 "Called after a push operation completes. post_push is called "1822 "Called after a push operation completes. post_push is called "
1823 "with a bzrlib.branch.BranchPushResult object and only runs in the "1823 "with a bzrlib.branch.BranchPushResult object and only runs in the "
1824 "bzr client.", (0, 15), None))1824 "bzr client.", (0, 15))
1825 self.create_hook(HookPoint('post_pull',1825 self.add_hook('post_pull',
1826 "Called after a pull operation completes. post_pull is called "1826 "Called after a pull operation completes. post_pull is called "
1827 "with a bzrlib.branch.PullResult object and only runs in the "1827 "with a bzrlib.branch.PullResult object and only runs in the "
1828 "bzr client.", (0, 15), None))1828 "bzr client.", (0, 15))
1829 self.create_hook(HookPoint('pre_commit',1829 self.add_hook('pre_commit',
1830 "Called after a commit is calculated but before it is "1830 "Called after a commit is calculated but before it is "
1831 "completed. pre_commit is called with (local, master, old_revno, "1831 "completed. pre_commit is called with (local, master, old_revno, "
1832 "old_revid, future_revno, future_revid, tree_delta, future_tree"1832 "old_revid, future_revno, future_revid, tree_delta, future_tree"
@@ -1835,29 +1835,29 @@
1835 "basis revision. hooks MUST NOT modify this delta. "1835 "basis revision. hooks MUST NOT modify this delta. "
1836 " future_tree is an in-memory tree obtained from "1836 " future_tree is an in-memory tree obtained from "
1837 "CommitBuilder.revision_tree() and hooks MUST NOT modify this "1837 "CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1838 "tree.", (0,91), None))1838 "tree.", (0,91))
1839 self.create_hook(HookPoint('post_commit',1839 self.add_hook('post_commit',
1840 "Called in the bzr client after a commit has completed. "1840 "Called in the bzr client after a commit has completed. "
1841 "post_commit is called with (local, master, old_revno, old_revid, "1841 "post_commit is called with (local, master, old_revno, old_revid, "
1842 "new_revno, new_revid). old_revid is NULL_REVISION for the first "1842 "new_revno, new_revid). old_revid is NULL_REVISION for the first "
1843 "commit to a branch.", (0, 15), None))1843 "commit to a branch.", (0, 15))
1844 self.create_hook(HookPoint('post_uncommit',1844 self.add_hook('post_uncommit',
1845 "Called in the bzr client after an uncommit completes. "1845 "Called in the bzr client after an uncommit completes. "
1846 "post_uncommit is called with (local, master, old_revno, "1846 "post_uncommit is called with (local, master, old_revno, "
1847 "old_revid, new_revno, new_revid) where local is the local branch "1847 "old_revid, new_revno, new_revid) where local is the local branch "
1848 "or None, master is the target branch, and an empty branch "1848 "or None, master is the target branch, and an empty branch "
1849 "receives new_revno of 0, new_revid of None.", (0, 15), None))1849 "receives new_revno of 0, new_revid of None.", (0, 15))
1850 self.create_hook(HookPoint('pre_change_branch_tip',1850 self.add_hook('pre_change_branch_tip',
1851 "Called in bzr client and server before a change to the tip of a "1851 "Called in bzr client and server before a change to the tip of a "
1852 "branch is made. pre_change_branch_tip is called with a "1852 "branch is made. pre_change_branch_tip is called with a "
1853 "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "1853 "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1854 "commit, uncommit will all trigger this hook.", (1, 6), None))1854 "commit, uncommit will all trigger this hook.", (1, 6))
1855 self.create_hook(HookPoint('post_change_branch_tip',1855 self.add_hook('post_change_branch_tip',
1856 "Called in bzr client and server after a change to the tip of a "1856 "Called in bzr client and server after a change to the tip of a "
1857 "branch is made. post_change_branch_tip is called with a "1857 "branch is made. post_change_branch_tip is called with a "
1858 "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "1858 "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1859 "commit, uncommit will all trigger this hook.", (1, 4), None))1859 "commit, uncommit will all trigger this hook.", (1, 4))
1860 self.create_hook(HookPoint('transform_fallback_location',1860 self.add_hook('transform_fallback_location',
1861 "Called when a stacked branch is activating its fallback "1861 "Called when a stacked branch is activating its fallback "
1862 "locations. transform_fallback_location is called with (branch, "1862 "locations. transform_fallback_location is called with (branch, "
1863 "url), and should return a new url. Returning the same url "1863 "url), and should return a new url. Returning the same url "
@@ -1868,23 +1868,23 @@
1868 "fallback locations have not been activated. When there are "1868 "fallback locations have not been activated. When there are "
1869 "multiple hooks installed for transform_fallback_location, "1869 "multiple hooks installed for transform_fallback_location, "
1870 "all are called with the url returned from the previous hook."1870 "all are called with the url returned from the previous hook."
1871 "The order is however undefined.", (1, 9), None))1871 "The order is however undefined.", (1, 9))
1872 self.create_hook(HookPoint('automatic_tag_name',1872 self.add_hook('automatic_tag_name',
1873 "Called to determine an automatic tag name for a revision. "1873 "Called to determine an automatic tag name for a revision. "
1874 "automatic_tag_name is called with (branch, revision_id) and "1874 "automatic_tag_name is called with (branch, revision_id) and "
1875 "should return a tag name or None if no tag name could be "1875 "should return a tag name or None if no tag name could be "
1876 "determined. The first non-None tag name returned will be used.",1876 "determined. The first non-None tag name returned will be used.",
1877 (2, 2), None))1877 (2, 2))
1878 self.create_hook(HookPoint('post_branch_init',1878 self.add_hook('post_branch_init',
1879 "Called after new branch initialization completes. "1879 "Called after new branch initialization completes. "
1880 "post_branch_init is called with a "1880 "post_branch_init is called with a "
1881 "bzrlib.branch.BranchInitHookParams. "1881 "bzrlib.branch.BranchInitHookParams. "
1882 "Note that init, branch and checkout (both heavyweight and "1882 "Note that init, branch and checkout (both heavyweight and "
1883 "lightweight) will all trigger this hook.", (2, 2), None))1883 "lightweight) will all trigger this hook.", (2, 2))
1884 self.create_hook(HookPoint('post_switch',1884 self.add_hook('post_switch',
1885 "Called after a checkout switches branch. "1885 "Called after a checkout switches branch. "
1886 "post_switch is called with a "1886 "post_switch is called with a "
1887 "bzrlib.branch.SwitchHookParams.", (2, 2), None))1887 "bzrlib.branch.SwitchHookParams.", (2, 2))
18881888
18891889
18901890
18911891
=== modified file 'bzrlib/bzrdir.py'
--- bzrlib/bzrdir.py 2011-03-24 01:23:35 +0000
+++ bzrlib/bzrdir.py 2011-03-31 15:13:30 +0000
@@ -1082,15 +1082,15 @@
10821082
1083 def __init__(self):1083 def __init__(self):
1084 """Create the default hooks."""1084 """Create the default hooks."""
1085 hooks.Hooks.__init__(self)1085 hooks.Hooks.__init__(self, "bzrlib.bzrdir", "BzrDir.hooks")
1086 self.create_hook(hooks.HookPoint('pre_open',1086 self.add_hook('pre_open',
1087 "Invoked before attempting to open a BzrDir with the transport "1087 "Invoked before attempting to open a BzrDir with the transport "
1088 "that the open will use.", (1, 14), None))1088 "that the open will use.", (1, 14))
1089 self.create_hook(hooks.HookPoint('post_repo_init',1089 self.add_hook('post_repo_init',
1090 "Invoked after a repository has been initialized. "1090 "Invoked after a repository has been initialized. "
1091 "post_repo_init is called with a "1091 "post_repo_init is called with a "
1092 "bzrlib.bzrdir.RepoInitHookParams.",1092 "bzrlib.bzrdir.RepoInitHookParams.",
1093 (2, 2), None))1093 (2, 2))
10941094
1095# install the default hooks1095# install the default hooks
1096BzrDir.hooks = BzrDirHooks()1096BzrDir.hooks = BzrDirHooks()
10971097
=== modified file 'bzrlib/commands.py'
--- bzrlib/commands.py 2011-02-04 22:25:59 +0000
+++ bzrlib/commands.py 2011-03-31 15:13:30 +0000
@@ -46,7 +46,7 @@
46 )46 )
47""")47""")
4848
49from bzrlib.hooks import HookPoint, Hooks49from bzrlib.hooks import Hooks
50# Compatibility - Option used to be in commands.50# Compatibility - Option used to be in commands.
51from bzrlib.option import Option51from bzrlib.option import Option
52from bzrlib.plugin import disable_plugins, load_plugins52from bzrlib.plugin import disable_plugins, load_plugins
@@ -775,30 +775,30 @@
775 These are all empty initially, because by default nothing should get775 These are all empty initially, because by default nothing should get
776 notified.776 notified.
777 """777 """
778 Hooks.__init__(self)778 Hooks.__init__(self, "bzrlib.commands", "Command.hooks")
779 self.create_hook(HookPoint('extend_command',779 self.add_hook('extend_command',
780 "Called after creating a command object to allow modifications "780 "Called after creating a command object to allow modifications "
781 "such as adding or removing options, docs etc. Called with the "781 "such as adding or removing options, docs etc. Called with the "
782 "new bzrlib.commands.Command object.", (1, 13), None))782 "new bzrlib.commands.Command object.", (1, 13))
783 self.create_hook(HookPoint('get_command',783 self.add_hook('get_command',
784 "Called when creating a single command. Called with "784 "Called when creating a single command. Called with "
785 "(cmd_or_None, command_name). get_command should either return "785 "(cmd_or_None, command_name). get_command should either return "
786 "the cmd_or_None parameter, or a replacement Command object that "786 "the cmd_or_None parameter, or a replacement Command object that "
787 "should be used for the command. Note that the Command.hooks "787 "should be used for the command. Note that the Command.hooks "
788 "hooks are core infrastructure. Many users will prefer to use "788 "hooks are core infrastructure. Many users will prefer to use "
789 "bzrlib.commands.register_command or plugin_cmds.register_lazy.",789 "bzrlib.commands.register_command or plugin_cmds.register_lazy.",
790 (1, 17), None))790 (1, 17))
791 self.create_hook(HookPoint('get_missing_command',791 self.add_hook('get_missing_command',
792 "Called when creating a single command if no command could be "792 "Called when creating a single command if no command could be "
793 "found. Called with (command_name). get_missing_command should "793 "found. Called with (command_name). get_missing_command should "
794 "either return None, or a Command object to be used for the "794 "either return None, or a Command object to be used for the "
795 "command.", (1, 17), None))795 "command.", (1, 17))
796 self.create_hook(HookPoint('list_commands',796 self.add_hook('list_commands',
797 "Called when enumerating commands. Called with a set of "797 "Called when enumerating commands. Called with a set of "
798 "cmd_name strings for all the commands found so far. This set "798 "cmd_name strings for all the commands found so far. This set "
799 " is safe to mutate - e.g. to remove a command. "799 " is safe to mutate - e.g. to remove a command. "
800 "list_commands should return the updated set of command names.",800 "list_commands should return the updated set of command names.",
801 (1, 17), None))801 (1, 17))
802802
803Command.hooks = CommandHooks()803Command.hooks = CommandHooks()
804804
805805
=== modified file 'bzrlib/hooks.py'
--- bzrlib/hooks.py 2011-02-18 17:44:53 +0000
+++ bzrlib/hooks.py 2011-03-31 15:13:30 +0000
@@ -145,10 +145,10 @@
145 else:145 else:
146 callbacks = None146 callbacks = None
147 hookpoint = HookPoint(name=name, doc=doc, introduced=introduced,147 hookpoint = HookPoint(name=name, doc=doc, introduced=introduced,
148 deprecated=deprecated,148 deprecated=deprecated, callbacks=callbacks)
149 callbacks=callbacks)
150 self[name] = hookpoint149 self[name] = hookpoint
151150
151 @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
152 def create_hook(self, hook):152 def create_hook(self, hook):
153 """Create a hook which can have callbacks registered for it.153 """Create a hook which can have callbacks registered for it.
154154
@@ -392,6 +392,8 @@
392 return '\n'.join(segments)392 return '\n'.join(segments)
393393
394394
395# Lazily registered hooks. Maps (module, name, hook_name) tuples
396# to lists of tuples with objectgetters and names
395_lazy_hooks = {}397_lazy_hooks = {}
396398
397399
398400
=== modified file 'bzrlib/info.py'
--- bzrlib/info.py 2010-04-30 11:35:43 +0000
+++ bzrlib/info.py 2011-03-31 15:13:30 +0000
@@ -481,12 +481,11 @@
481 """Hooks for the info command."""481 """Hooks for the info command."""
482482
483 def __init__(self):483 def __init__(self):
484 super(InfoHooks, self).__init__()484 super(InfoHooks, self).__init__("bzrlib.info", "hooks")
485 self.create_hook(_mod_hooks.HookPoint('repository',485 self.add_hook('repository',
486 "Invoked when displaying the statistics for a repository. "486 "Invoked when displaying the statistics for a repository. "
487 "repository is called with a statistics dictionary as returned "487 "repository is called with a statistics dictionary as returned "
488 "by the repository and a file-like object to write to.", (1, 15), 488 "by the repository and a file-like object to write to.", (1, 15))
489 None))
490489
491490
492hooks = InfoHooks()491hooks = InfoHooks()
493492
=== modified file 'bzrlib/lock.py'
--- bzrlib/lock.py 2010-05-11 08:36:16 +0000
+++ bzrlib/lock.py 2011-03-31 15:13:30 +0000
@@ -45,22 +45,22 @@
45 osutils,45 osutils,
46 trace,46 trace,
47 )47 )
48from bzrlib.hooks import HookPoint, Hooks48from bzrlib.hooks import Hooks
4949
5050
51class LockHooks(Hooks):51class LockHooks(Hooks):
5252
53 def __init__(self):53 def __init__(self):
54 Hooks.__init__(self)54 Hooks.__init__(self, "bzrlib.lock", "Lock.hooks")
55 self.create_hook(HookPoint('lock_acquired',55 self.add_hook('lock_acquired',
56 "Called with a bzrlib.lock.LockResult when a physical lock is "56 "Called with a bzrlib.lock.LockResult when a physical lock is "
57 "acquired.", (1, 8), None))57 "acquired.", (1, 8))
58 self.create_hook(HookPoint('lock_released',58 self.add_hook('lock_released',
59 "Called with a bzrlib.lock.LockResult when a physical lock is "59 "Called with a bzrlib.lock.LockResult when a physical lock is "
60 "released.", (1, 8), None))60 "released.", (1, 8))
61 self.create_hook(HookPoint('lock_broken',61 self.add_hook('lock_broken',
62 "Called with a bzrlib.lock.LockResult when a physical lock is "62 "Called with a bzrlib.lock.LockResult when a physical lock is "
63 "broken.", (1, 15), None))63 "broken.", (1, 15))
6464
6565
66class Lock(object):66class Lock(object):
6767
=== modified file 'bzrlib/merge.py'
--- bzrlib/merge.py 2011-02-07 04:14:29 +0000
+++ bzrlib/merge.py 2011-03-31 15:13:30 +0000
@@ -62,8 +62,8 @@
62class MergeHooks(hooks.Hooks):62class MergeHooks(hooks.Hooks):
6363
64 def __init__(self):64 def __init__(self):
65 hooks.Hooks.__init__(self)65 hooks.Hooks.__init__(self, "bzrlib.merge", "Merger.hooks")
66 self.create_hook(hooks.HookPoint('merge_file_content',66 self.add_hook('merge_file_content',
67 "Called with a bzrlib.merge.Merger object to create a per file "67 "Called with a bzrlib.merge.Merger object to create a per file "
68 "merge object when starting a merge. "68 "merge object when starting a merge. "
69 "Should return either None or a subclass of "69 "Should return either None or a subclass of "
@@ -73,7 +73,7 @@
73 "side has deleted the file and the other has changed it). "73 "side has deleted the file and the other has changed it). "
74 "See the AbstractPerFileMerger API docs for details on how it is "74 "See the AbstractPerFileMerger API docs for details on how it is "
75 "used by merge.",75 "used by merge.",
76 (2, 1), None))76 (2, 1))
7777
7878
79class AbstractPerFileMerger(object):79class AbstractPerFileMerger(object):
8080
=== modified file 'bzrlib/merge_directive.py'
--- bzrlib/merge_directive.py 2011-02-19 21:00:05 +0000
+++ bzrlib/merge_directive.py 2011-03-31 15:13:30 +0000
@@ -59,12 +59,12 @@
59 """Hooks for MergeDirective classes."""59 """Hooks for MergeDirective classes."""
6060
61 def __init__(self):61 def __init__(self):
62 hooks.Hooks.__init__(self)62 hooks.Hooks.__init__(self, "bzrlib.merge_directive", "BaseMergeDirective.hooks")
63 self.create_hook(hooks.HookPoint('merge_request_body',63 self.add_hook('merge_request_body',
64 "Called with a MergeRequestBodyParams when a body is needed for"64 "Called with a MergeRequestBodyParams when a body is needed for"
65 " a merge request. Callbacks must return a body. If more"65 " a merge request. Callbacks must return a body. If more"
66 " than one callback is registered, the output of one callback is"66 " than one callback is registered, the output of one callback is"
67 " provided to the next.", (1, 15, 0), False))67 " provided to the next.", (1, 15, 0))
6868
6969
70class BaseMergeDirective(object):70class BaseMergeDirective(object):
7171
=== modified file 'bzrlib/msgeditor.py'
--- bzrlib/msgeditor.py 2011-02-07 01:30:38 +0000
+++ bzrlib/msgeditor.py 2011-03-31 15:13:30 +0000
@@ -31,7 +31,7 @@
31 ui,31 ui,
32 )32 )
33from bzrlib.errors import BzrError, BadCommitMessageEncoding33from bzrlib.errors import BzrError, BadCommitMessageEncoding
34from bzrlib.hooks import HookPoint, Hooks34from bzrlib.hooks import Hooks
3535
3636
37def _get_editor():37def _get_editor():
@@ -302,8 +302,8 @@
302302
303 These are all empty initially.303 These are all empty initially.
304 """304 """
305 Hooks.__init__(self)305 Hooks.__init__(self, "bzrlib.msgeditor", "hooks")
306 self.create_hook(HookPoint('commit_message_template',306 self.add_hook('commit_message_template',
307 "Called when a commit message is being generated. "307 "Called when a commit message is being generated. "
308 "commit_message_template is called with the bzrlib.commit.Commit "308 "commit_message_template is called with the bzrlib.commit.Commit "
309 "object and the message that is known so far. "309 "object and the message that is known so far. "
@@ -311,7 +311,7 @@
311 "could be the same as it was given. When there are multiple "311 "could be the same as it was given. When there are multiple "
312 "hooks registered for commit_message_template, they are chained "312 "hooks registered for commit_message_template, they are chained "
313 "with the result from the first passed into the second, and so "313 "with the result from the first passed into the second, and so "
314 "on.", (1, 10), None))314 "on.", (1, 10))
315315
316316
317hooks = MessageEditorHooks()317hooks = MessageEditorHooks()
318318
=== modified file 'bzrlib/mutabletree.py'
--- bzrlib/mutabletree.py 2011-03-06 18:10:47 +0000
+++ bzrlib/mutabletree.py 2011-03-31 15:13:30 +0000
@@ -652,17 +652,17 @@
652 """Create the default hooks.652 """Create the default hooks.
653653
654 """654 """
655 hooks.Hooks.__init__(self)655 hooks.Hooks.__init__(self, "bzrlib.mutabletree", "MutableTree.hooks")
656 self.create_hook(hooks.HookPoint('start_commit',656 self.add_hook('start_commit',
657 "Called before a commit is performed on a tree. The start commit "657 "Called before a commit is performed on a tree. The start commit "
658 "hook is able to change the tree before the commit takes place. "658 "hook is able to change the tree before the commit takes place. "
659 "start_commit is called with the bzrlib.mutabletree.MutableTree "659 "start_commit is called with the bzrlib.mutabletree.MutableTree "
660 "that the commit is being performed on.", (1, 4), None))660 "that the commit is being performed on.", (1, 4))
661 self.create_hook(hooks.HookPoint('post_commit',661 self.add_hook('post_commit',
662 "Called after a commit is performed on a tree. The hook is "662 "Called after a commit is performed on a tree. The hook is "
663 "called with a bzrlib.mutabletree.PostCommitHookParams object. "663 "called with a bzrlib.mutabletree.PostCommitHookParams object. "
664 "The mutable tree the commit was performed on is available via "664 "The mutable tree the commit was performed on is available via "
665 "the mutable_tree attribute of that object.", (2, 0), None))665 "the mutable_tree attribute of that object.", (2, 0))
666666
667667
668# install the default hooks into the MutableTree class.668# install the default hooks into the MutableTree class.
669669
=== modified file 'bzrlib/plugins/changelog_merge/__init__.py'
--- bzrlib/plugins/changelog_merge/__init__.py 2011-03-15 07:56:42 +0000
+++ bzrlib/plugins/changelog_merge/__init__.py 2011-03-31 15:13:30 +0000
@@ -55,27 +55,17 @@
5555
56# Since we are a built-in plugin we share the bzrlib version56# Since we are a built-in plugin we share the bzrlib version
57from bzrlib import version_info57from bzrlib import version_info
58from bzrlib.hooks import install_lazy_named_hook
5859
59# Put most of the code in a separate module that we lazy-import to keep the60# Put most of the code in a separate module that we lazy-import to keep the
60# overhead of this plugin as minimal as possible.61# overhead of this plugin as minimal as possible.
61from bzrlib.lazy_import import lazy_import
62lazy_import(globals(), """
63from bzrlib.plugins.changelog_merge import changelog_merge as _mod_changelog_merge
64""")
65
66from bzrlib.merge import Merger
67
68
69def changelog_merge_hook(merger):62def changelog_merge_hook(merger):
70 """Merger.merge_file_content hook for GNU-format ChangeLog files."""63 """Merger.merge_file_content hook for GNU-format ChangeLog files."""
71 return _mod_changelog_merge.ChangeLogMerger(merger)64 from bzrlib.plugins.changelog_merge.changelog_merge import ChangeLogMerger
7265 return ChangeLogMerger(merger)
7366
74def install_hook():67install_lazy_named_hook("bzrlib.merge", "Merger.hooks", "merge_file_content",
75 Merger.hooks.install_named_hook(68 changelog_merge_hook, 'GNU ChangeLog file merge')
76 'merge_file_content', changelog_merge_hook, 'GNU ChangeLog file merge')
77install_hook()
78
7969
80def load_tests(basic_tests, module, loader):70def load_tests(basic_tests, module, loader):
81 testmod_names = [71 testmod_names = [
@@ -84,4 +74,3 @@
84 basic_tests.addTest(loader.loadTestsFromModuleNames(74 basic_tests.addTest(loader.loadTestsFromModuleNames(
85 ["%s.%s" % (__name__, tmn) for tmn in testmod_names]))75 ["%s.%s" % (__name__, tmn) for tmn in testmod_names]))
86 return basic_tests76 return basic_tests
87
8877
=== modified file 'bzrlib/plugins/launchpad/lp_propose.py'
--- bzrlib/plugins/launchpad/lp_propose.py 2011-01-19 16:57:38 +0000
+++ bzrlib/plugins/launchpad/lp_propose.py 2011-03-31 15:13:30 +0000
@@ -36,19 +36,12 @@
36 """Hooks for proposing a merge on Launchpad."""36 """Hooks for proposing a merge on Launchpad."""
3737
38 def __init__(self):38 def __init__(self):
39 hooks.Hooks.__init__(self)39 hooks.Hooks.__init__(self, "bzrlib.plugins.launchpad.lp_propose",
40 self.create_hook(40 "Proposer.hooks")
41 hooks.HookPoint(41 self.add_hook('get_prerequisite',
42 'get_prerequisite',42 "Return the prerequisite branch for proposing as merge.", (2, 1))
43 "Return the prerequisite branch for proposing as merge.",43 self.add_hook('merge_proposal_body',
44 (2, 1), None),44 "Return an initial body for the merge proposal message.", (2, 1))
45 )
46 self.create_hook(
47 hooks.HookPoint(
48 'merge_proposal_body',
49 "Return an initial body for the merge proposal message.",
50 (2, 1), None),
51 )
5245
5346
54class Proposer(object):47class Proposer(object):
5548
=== modified file 'bzrlib/plugins/news_merge/__init__.py'
--- bzrlib/plugins/news_merge/__init__.py 2010-05-03 04:08:50 +0000
+++ bzrlib/plugins/news_merge/__init__.py 2011-03-31 15:13:30 +0000
@@ -33,26 +33,17 @@
3333
34# Since we are a built-in plugin we share the bzrlib version34# Since we are a built-in plugin we share the bzrlib version
35from bzrlib import version_info35from bzrlib import version_info
3636from bzrlib.hooks import install_lazy_named_hook
37# Put most of the code in a separate module that we lazy-import to keep the
38# overhead of this plugin as minimal as possible.
39from bzrlib.lazy_import import lazy_import
40lazy_import(globals(), """
41from bzrlib.plugins.news_merge import news_merge as _mod_news_merge
42""")
43
44from bzrlib.merge import Merger
4537
4638
47def news_merge_hook(merger):39def news_merge_hook(merger):
48 """Merger.merge_file_content hook for bzr-format NEWS files."""40 """Merger.merge_file_content hook for bzr-format NEWS files."""
49 return _mod_news_merge.NewsMerger(merger)41 from bzrlib.plugins.news_merge.news_merge import NewsMerger
5042 return NewsMerger(merger)
5143
52def install_hook():44
53 Merger.hooks.install_named_hook(45install_lazy_named_hook("bzrlib.merge", "Merger.hooks", "merge_file_content",
54 'merge_file_content', news_merge_hook, 'NEWS file merge')46 news_merge_hook, "NEWS file merge")
55install_hook()
5647
5748
58def load_tests(basic_tests, module, loader):49def load_tests(basic_tests, module, loader):
5950
=== modified file 'bzrlib/smart/client.py'
--- bzrlib/smart/client.py 2010-02-17 17:11:16 +0000
+++ bzrlib/smart/client.py 2011-03-31 15:13:30 +0000
@@ -194,12 +194,12 @@
194class SmartClientHooks(hooks.Hooks):194class SmartClientHooks(hooks.Hooks):
195195
196 def __init__(self):196 def __init__(self):
197 hooks.Hooks.__init__(self)197 hooks.Hooks.__init__(self, "bzrlib.smart.client", "_SmartClient.hooks")
198 self.create_hook(hooks.HookPoint('call',198 self.add_hook('call',
199 "Called when the smart client is submitting a request to the "199 "Called when the smart client is submitting a request to the "
200 "smart server. Called with a bzrlib.smart.client.CallHookParams "200 "smart server. Called with a bzrlib.smart.client.CallHookParams "
201 "object. Streaming request bodies, and responses, are not "201 "object. Streaming request bodies, and responses, are not "
202 "accessible.", None, None))202 "accessible.", None)
203203
204204
205_SmartClient.hooks = SmartClientHooks()205_SmartClient.hooks = SmartClientHooks()
206206
=== modified file 'bzrlib/smart/server.py'
--- bzrlib/smart/server.py 2011-03-05 02:26:26 +0000
+++ bzrlib/smart/server.py 2011-03-31 15:13:30 +0000
@@ -22,7 +22,7 @@
22import sys22import sys
23import threading23import threading
2424
25from bzrlib.hooks import HookPoint, Hooks25from bzrlib.hooks import Hooks
26from bzrlib import (26from bzrlib import (
27 errors,27 errors,
28 trace,28 trace,
@@ -239,21 +239,21 @@
239 These are all empty initially, because by default nothing should get239 These are all empty initially, because by default nothing should get
240 notified.240 notified.
241 """241 """
242 Hooks.__init__(self)242 Hooks.__init__(self, "bzrlib.smart.server", "SmartTCPServer.hooks")
243 self.create_hook(HookPoint('server_started',243 self.add_hook('server_started',
244 "Called by the bzr server when it starts serving a directory. "244 "Called by the bzr server when it starts serving a directory. "
245 "server_started is called with (backing urls, public url), "245 "server_started is called with (backing urls, public url), "
246 "where backing_url is a list of URLs giving the "246 "where backing_url is a list of URLs giving the "
247 "server-specific directory locations, and public_url is the "247 "server-specific directory locations, and public_url is the "
248 "public URL for the directory being served.", (0, 16), None))248 "public URL for the directory being served.", (0, 16))
249 self.create_hook(HookPoint('server_started_ex',249 self.add_hook('server_started_ex',
250 "Called by the bzr server when it starts serving a directory. "250 "Called by the bzr server when it starts serving a directory. "
251 "server_started is called with (backing_urls, server_obj).",251 "server_started is called with (backing_urls, server_obj).",
252 (1, 17), None))252 (1, 17))
253 self.create_hook(HookPoint('server_stopped',253 self.add_hook('server_stopped',
254 "Called by the bzr server when it stops serving a directory. "254 "Called by the bzr server when it stops serving a directory. "
255 "server_stopped is called with the same parameters as the "255 "server_stopped is called with the same parameters as the "
256 "server_started hook: (backing_urls, public_url).", (0, 16), None))256 "server_started hook: (backing_urls, public_url).", (0, 16))
257257
258SmartTCPServer.hooks = SmartServerHooks()258SmartTCPServer.hooks = SmartServerHooks()
259259
260260
=== modified file 'bzrlib/status.py'
--- bzrlib/status.py 2011-01-31 22:09:46 +0000
+++ bzrlib/status.py 2011-03-31 15:13:30 +0000
@@ -379,23 +379,23 @@
379 These are all empty initially, because by default nothing should get379 These are all empty initially, because by default nothing should get
380 notified.380 notified.
381 """381 """
382 _mod_hooks.Hooks.__init__(self)382 _mod_hooks.Hooks.__init__(self, "bzrlib.status", "hooks")
383 self.create_hook(_mod_hooks.HookPoint('post_status',383 self.add_hook('post_status',
384 "Called with argument StatusHookParams after Bazaar has "384 "Called with argument StatusHookParams after Bazaar has "
385 "displayed the status. StatusHookParams has the attributes "385 "displayed the status. StatusHookParams has the attributes "
386 "(old_tree, new_tree, to_file, versioned, show_ids, short, "386 "(old_tree, new_tree, to_file, versioned, show_ids, short, "
387 "verbose). The last four arguments correspond to the command "387 "verbose). The last four arguments correspond to the command "
388 "line options specified by the user for the status command. "388 "line options specified by the user for the status command. "
389 "to_file is the output stream for writing.",389 "to_file is the output stream for writing.",
390 (2, 3), None))390 (2, 3))
391 self.create_hook(_mod_hooks.HookPoint('pre_status',391 self.add_hook('pre_status',
392 "Called with argument StatusHookParams before Bazaar "392 "Called with argument StatusHookParams before Bazaar "
393 "displays the status. StatusHookParams has the attributes "393 "displays the status. StatusHookParams has the attributes "
394 "(old_tree, new_tree, to_file, versioned, show_ids, short, "394 "(old_tree, new_tree, to_file, versioned, show_ids, short, "
395 "verbose). The last four arguments correspond to the command "395 "verbose). The last four arguments correspond to the command "
396 "line options specified by the user for the status command. "396 "line options specified by the user for the status command. "
397 "to_file is the output stream for writing.",397 "to_file is the output stream for writing.",
398 (2, 3), None))398 (2, 3))
399399
400400
401class StatusHookParams(object):401class StatusHookParams(object):
402402
=== modified file 'bzrlib/tests/test_hooks.py'
--- bzrlib/tests/test_hooks.py 2011-03-30 12:24:06 +0000
+++ bzrlib/tests/test_hooks.py 2011-03-31 15:13:30 +0000
@@ -39,39 +39,38 @@
39class TestHooks(tests.TestCase):39class TestHooks(tests.TestCase):
4040
41 def test_create_hook_first(self):41 def test_create_hook_first(self):
42 hooks = Hooks()42 hooks = Hooks("bzrlib.tests.test_hooks", "some_hooks")
43 doc = ("Invoked after changing the tip of a branch object. Called with"43 doc = ("Invoked after changing the tip of a branch object. Called with"
44 "a bzrlib.branch.PostChangeBranchTipParams object")44 "a bzrlib.branch.PostChangeBranchTipParams object")
45 hook = HookPoint("post_tip_change", doc, (0, 15), None)45 hook = HookPoint("post_tip_change", doc, (0, 15), None)
46 hooks.create_hook(hook)46 self.applyDeprecated(deprecated_in((2, 4)), hooks.create_hook, hook)
47 self.assertEqual(hook, hooks['post_tip_change'])47 self.assertEqual(hook, hooks['post_tip_change'])
4848
49 def test_create_hook_name_collision_errors(self):49 def test_create_hook_name_collision_errors(self):
50 hooks = Hooks()50 hooks = Hooks("bzrlib.tests.test_hooks", "some_hooks")
51 doc = ("Invoked after changing the tip of a branch object. Called with"51 doc = ("Invoked after changing the tip of a branch object. Called with"
52 "a bzrlib.branch.PostChangeBranchTipParams object")52 "a bzrlib.branch.PostChangeBranchTipParams object")
53 hook = HookPoint("post_tip_change", doc, (0, 15), None)53 hook = HookPoint("post_tip_change", doc, (0, 15), None)
54 hook2 = HookPoint("post_tip_change", None, None, None)54 hook2 = HookPoint("post_tip_change", None, None, None)
55 hooks.create_hook(hook)55 self.applyDeprecated(deprecated_in((2, 4)), hooks.create_hook, hook)
56 self.assertRaises(errors.DuplicateKey, hooks.create_hook, hook2)56 self.assertRaises(errors.DuplicateKey, self.applyDeprecated,
57 deprecated_in((2, 4, 0)), hooks.create_hook, hook2)
57 self.assertEqual(hook, hooks['post_tip_change'])58 self.assertEqual(hook, hooks['post_tip_change'])
5859
59 def test_docs(self):60 def test_docs(self):
60 """docs() should return something reasonable about the Hooks."""61 """docs() should return something reasonable about the Hooks."""
61 class MyHooks(Hooks):62 class MyHooks(Hooks):
62 pass63 pass
63 hooks = MyHooks()64 hooks = MyHooks("bzrlib.tests.test_hooks", "some_hooks")
64 hooks['legacy'] = []65 hooks['legacy'] = []
65 hook1 = HookPoint('post_tip_change',66 hooks.add_hook('post_tip_change',
66 "Invoked after the tip of a branch changes. Called with "67 "Invoked after the tip of a branch changes. Called with "
67 "a ChangeBranchTipParams object.", (1, 4), None)68 "a ChangeBranchTipParams object.", (1, 4))
68 hook2 = HookPoint('pre_tip_change',69 hooks.add_hook('pre_tip_change',
69 "Invoked before the tip of a branch changes. Called with "70 "Invoked before the tip of a branch changes. Called with "
70 "a ChangeBranchTipParams object. Hooks should raise "71 "a ChangeBranchTipParams object. Hooks should raise "
71 "TipChangeRejected to signal that a tip change is not permitted.",72 "TipChangeRejected to signal that a tip change is not permitted.",
72 (1, 6), None)73 (1, 6), None)
73 hooks.create_hook(hook1)
74 hooks.create_hook(hook2)
75 self.assertEqualDiff(74 self.assertEqualDiff(
76 "MyHooks\n"75 "MyHooks\n"
77 "-------\n"76 "-------\n"
@@ -99,18 +98,18 @@
99 "signal that a tip change is not permitted.\n", hooks.docs())98 "signal that a tip change is not permitted.\n", hooks.docs())
10099
101 def test_install_named_hook_raises_unknown_hook(self):100 def test_install_named_hook_raises_unknown_hook(self):
102 hooks = Hooks()101 hooks = Hooks("bzrlib.tests.test_hooks", "some_hooks")
103 self.assertRaises(errors.UnknownHook, hooks.install_named_hook, 'silly',102 self.assertRaises(errors.UnknownHook, hooks.install_named_hook, 'silly',
104 None, "")103 None, "")
105104
106 def test_install_named_hook_appends_known_hook(self):105 def test_install_named_hook_appends_known_hook(self):
107 hooks = Hooks()106 hooks = Hooks("bzrlib.tests.test_hooks", "some_hooks")
108 hooks['set_rh'] = []107 hooks['set_rh'] = []
109 hooks.install_named_hook('set_rh', None, "demo")108 hooks.install_named_hook('set_rh', None, "demo")
110 self.assertEqual(hooks['set_rh'], [None])109 self.assertEqual(hooks['set_rh'], [None])
111110
112 def test_install_named_hook_and_retrieve_name(self):111 def test_install_named_hook_and_retrieve_name(self):
113 hooks = Hooks()112 hooks = Hooks("bzrlib.tests.test_hooks", "somehooks")
114 hooks['set_rh'] = []113 hooks['set_rh'] = []
115 hooks.install_named_hook('set_rh', None, "demo")114 hooks.install_named_hook('set_rh', None, "demo")
116 self.assertEqual("demo", hooks.get_hook_name(None))115 self.assertEqual("demo", hooks.get_hook_name(None))
@@ -134,7 +133,7 @@
134 set_rh = lambda: None133 set_rh = lambda: None
135134
136 def test_install_named_hook_lazy(self):135 def test_install_named_hook_lazy(self):
137 hooks = Hooks()136 hooks = Hooks("bzrlib.tests.hooks", "some_hooks")
138 hooks['set_rh'] = HookPoint("set_rh", "doc", (0, 15), None)137 hooks['set_rh'] = HookPoint("set_rh", "doc", (0, 15), None)
139 hooks.install_named_hook_lazy('set_rh', 'bzrlib.tests.test_hooks',138 hooks.install_named_hook_lazy('set_rh', 'bzrlib.tests.test_hooks',
140 'TestHooks.set_rh', "demo")139 'TestHooks.set_rh', "demo")
@@ -143,7 +142,7 @@
143 def test_install_named_hook_lazy_old(self):142 def test_install_named_hook_lazy_old(self):
144 # An exception is raised if a lazy hook is raised for143 # An exception is raised if a lazy hook is raised for
145 # an old style hook point.144 # an old style hook point.
146 hooks = Hooks()145 hooks = Hooks("bzrlib.tests.hooks", "some_hooks")
147 hooks['set_rh'] = []146 hooks['set_rh'] = []
148 self.assertRaises(errors.UnsupportedOperation,147 self.assertRaises(errors.UnsupportedOperation,
149 hooks.install_named_hook_lazy,148 hooks.install_named_hook_lazy,
150149
=== modified file 'bzrlib/tests/test_selftest.py'
--- bzrlib/tests/test_selftest.py 2011-03-29 04:30:03 +0000
+++ bzrlib/tests/test_selftest.py 2011-03-31 15:13:30 +0000
@@ -1437,12 +1437,12 @@
1437 # Note this test won't fail with hooks that the core library doesn't1437 # Note this test won't fail with hooks that the core library doesn't
1438 # use - but it trigger with a plugin that adds hooks, so its still a1438 # use - but it trigger with a plugin that adds hooks, so its still a
1439 # useful warning in that case.1439 # useful warning in that case.
1440 self.assertEqual(bzrlib.branch.BranchHooks(),1440 self.assertEqual(bzrlib.branch.BranchHooks(), bzrlib.branch.Branch.hooks)
1441 bzrlib.branch.Branch.hooks)1441 self.assertEqual(
1442 self.assertEqual(bzrlib.smart.server.SmartServerHooks(),1442 bzrlib.smart.server.SmartServerHooks(),
1443 bzrlib.smart.server.SmartTCPServer.hooks)1443 bzrlib.smart.server.SmartTCPServer.hooks)
1444 self.assertEqual(bzrlib.commands.CommandHooks(),1444 self.assertEqual(
1445 bzrlib.commands.Command.hooks)1445 bzrlib.commands.CommandHooks(), bzrlib.commands.Command.hooks)
14461446
1447 def test__gather_lsprof_in_benchmarks(self):1447 def test__gather_lsprof_in_benchmarks(self):
1448 """When _gather_lsprof_in_benchmarks is on, accumulate profile data.1448 """When _gather_lsprof_in_benchmarks is on, accumulate profile data.
14491449
=== modified file 'bzrlib/tests/transport_util.py'
--- bzrlib/tests/transport_util.py 2011-01-26 19:34:58 +0000
+++ bzrlib/tests/transport_util.py 2011-03-31 15:13:30 +0000
@@ -47,7 +47,8 @@
47 """Dict-mapping hook name to a list of callables for transport hooks"""47 """Dict-mapping hook name to a list of callables for transport hooks"""
4848
49 def __init__(self):49 def __init__(self):
50 super(TransportHooks, self).__init__()50 super(TransportHooks, self).__init__("bzrlib.tests.transport_util",
51 "InstrumentedTransport.hooks")
51 # Invoked when the transport has just created a new connection.52 # Invoked when the transport has just created a new connection.
52 # The api signature is (transport, connection, credentials)53 # The api signature is (transport, connection, credentials)
53 self['_set_connection'] = []54 self['_set_connection'] = []
5455
=== modified file 'bzrlib/version_info_formats/format_rio.py'
--- bzrlib/version_info_formats/format_rio.py 2011-02-18 19:01:43 +0000
+++ bzrlib/version_info_formats/format_rio.py 2011-03-31 15:13:30 +0000
@@ -89,7 +89,7 @@
89 self.add_hook('revision',89 self.add_hook('revision',
90 "Invoked when adding information about a revision to the"90 "Invoked when adding information about a revision to the"
91 " RIO stanza that is printed. revision is called with a"91 " RIO stanza that is printed. revision is called with a"
92 " revision object and a RIO stanza.", (1, 15), None)92 " revision object and a RIO stanza.", (1, 15))
9393
9494
95RioVersionInfoBuilder.hooks = RioVersionInfoBuilderHooks()95RioVersionInfoBuilder.hooks = RioVersionInfoBuilderHooks()
9696
=== modified file 'doc/en/release-notes/bzr-2.4.txt'
--- doc/en/release-notes/bzr-2.4.txt 2011-03-30 10:54:24 +0000
+++ doc/en/release-notes/bzr-2.4.txt 2011-03-31 15:13:30 +0000
@@ -56,6 +56,9 @@
56.. Changes that may require updates in plugins or other code that uses56.. Changes that may require updates in plugins or other code that uses
57 bzrlib.57 bzrlib.
5858
59* ``Hooks.create_hook`` is now deprecated in favour of ``Hooks.add_hook``.
60 (Jelmer Vernooij)
61
59Internals62Internals
60*********63*********
6164