Rev 4121: Migrate existing hooks over to the new HookPoint infrastructure. in http://people.ubuntu.com/~robertc/baz2.0/pending/Hooks.docs

Robert Collins robertc at robertcollins.net
Thu Mar 12 06:24:47 GMT 2009


At http://people.ubuntu.com/~robertc/baz2.0/pending/Hooks.docs

------------------------------------------------------------
revno: 4121
revision-id: robertc at robertcollins.net-20090312062439-gigl7rnor6t2cbcz
parent: robertc at robertcollins.net-20090312024346-jx3vpibkrwo1qxar
committer: Robert Collins <robertc at robertcollins.net>
branch nick: Hooks.docs
timestamp: Thu 2009-03-12 17:24:39 +1100
message:
  Migrate existing hooks over to the new HookPoint infrastructure.
=== modified file 'NEWS'
--- a/NEWS	2009-03-12 02:43:46 +0000
+++ b/NEWS	2009-03-12 06:24:39 +0000
@@ -54,7 +54,10 @@
       ``bzrlib.hooks.known_hooks``. This removes the separate list from
       ``bzrlib.tests`` and ensures that all hooks registered there are
       correctly isolated by the test suite (previously
-      ``MutableTreeHooks`` were not being isolated correctly).
+      ``MutableTreeHooks`` were not being isolated correctly). Further, 
+      documentation for hooks is now dynamically generated from the
+      present HookPoints. ``bzr hooks`` will now also report on all the
+      hooks present in the ``bzrlib.hooks.known_hooks`` registry.
       (Robert Collins)
 
     * ``bzr add`` no longer prints ``add completed`` on success. Failure

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2009-03-06 04:38:56 +0000
+++ b/bzrlib/branch.py	2009-03-12 06:24:39 +0000
@@ -44,7 +44,7 @@
 """)
 
 from bzrlib.decorators import needs_read_lock, needs_write_lock
-from bzrlib.hooks import Hooks
+from bzrlib.hooks import HookPoint, Hooks
 from bzrlib.inter import InterObject
 from bzrlib import registry
 from bzrlib.symbol_versioning import (
@@ -1372,75 +1372,66 @@
         notified.
         """
         Hooks.__init__(self)
-        # Introduced in 0.15:
-        # 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.
-        self['set_rh'] = []
-        # Invoked after a branch is opened. The api signature is (branch).
-        self['open'] = []
-        # invoked after a push operation completes.
-        # the api signature is
-        # (push_result)
-        # containing the members
-        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
-        # where local is the local target branch or None, master is the target
-        # master branch, and the rest should be self explanatory. The source
-        # is read locked and the target branches write locked. Source will
-        # be the local low-latency branch.
-        self['post_push'] = []
-        # invoked after a pull operation completes.
-        # the api signature is
-        # (pull_result)
-        # containing the members
-        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
-        # where local is the local branch or None, master is the target
-        # master branch, and the rest should be self explanatory. The source
-        # is read locked and the target branches write locked. The local
-        # branch is the low-latency branch.
-        self['post_pull'] = []
-        # invoked before a commit operation takes place.
-        # the api signature is
-        # (local, master, old_revno, old_revid, future_revno, future_revid,
-        #  tree_delta, future_tree).
-        # old_revid is NULL_REVISION for the first commit to a branch
-        # tree_delta is a TreeDelta object describing changes from the basis
-        # revision, hooks MUST NOT modify this delta
-        # future_tree is an in-memory tree obtained from
-        # CommitBuilder.revision_tree() and hooks MUST NOT modify this tree
-        self['pre_commit'] = []
-        # invoked after a commit operation completes.
-        # the api signature is
-        # (local, master, old_revno, old_revid, new_revno, new_revid)
-        # old_revid is NULL_REVISION for the first commit to a branch.
-        self['post_commit'] = []
-        # invoked after a uncommit operation completes.
-        # the api signature is
-        # (local, master, old_revno, old_revid, new_revno, new_revid) where
-        # local is the local branch or None, master is the target branch,
-        # and an empty branch recieves new_revno of 0, new_revid of None.
-        self['post_uncommit'] = []
-        # Introduced in 1.6
-        # Invoked before the tip of a branch changes.
-        # the api signature is
-        # (params) where params is a ChangeBranchTipParams with the members
-        # (branch, old_revno, new_revno, old_revid, new_revid)
-        self['pre_change_branch_tip'] = []
-        # Introduced in 1.4
-        # Invoked after the tip of a branch changes.
-        # the api signature is
-        # (params) where params is a ChangeBranchTipParams with the members
-        # (branch, old_revno, new_revno, old_revid, new_revid)
-        self['post_change_branch_tip'] = []
-        # Introduced in 1.9
-        # Invoked when a stacked branch activates its fallback locations and
-        # allows the transformation of the url of said location.
-        # the api signature is
-        # (branch, url) where branch is the branch having its fallback
-        # location activated and url is the url for the fallback location.
-        # The hook should return a url.
-        self['transform_fallback_location'] = []
+        self.create_hook(HookPoint('set_rh',
+            "Invoked whenever the revision history has been set via "
+            "set_revision_history. The api signature is (branch, "
+            "revision_history), and the branch will be write-locked. "
+            "The set_rh hook can be expensive for bzr to trigger, a better "
+            "hook to use is Branch.post_change_branch_tip.", (0, 15), None))
+        self.create_hook(HookPoint('open',
+            "Called with the Branch object that has been opened after a "
+            "branch is opened.", (1, 8), None))
+        self.create_hook(HookPoint('post_push',
+            "Called after a push operation completes. post_push is called "
+            "with a bzrlib.branch.PushResult object and only runs in the "
+            "bzr client.", (0, 15), None))
+        self.create_hook(HookPoint('post_pull',
+            "Called after a pull operation completes. post_pull is called "
+            "with a bzrlib.branch.PullResult object and only runs in the "
+            "bzr client.", (0, 15), None))
+        self.create_hook(HookPoint('pre_commit',
+            "Called after a commit is calculated but before it is is "
+            "completed. pre_commit is called with (local, master, old_revno, "
+            "old_revid, future_revno, future_revid, tree_delta, future_tree"
+            "). old_revid is NULL_REVISION for the first commit to a branch, "
+            "tree_delta is a TreeDelta object describing changes from the "
+            "basis revision. hooks MUST NOT modify this delta. "
+            " future_tree is an in-memory tree obtained from "
+            "CommitBuilder.revision_tree() and hooks MUST NOT modify this "
+            "tree.", (0,91), None))
+        self.create_hook(HookPoint('post_commit',
+            "Called in the bzr client after a commit has completed. "
+            "post_commit is called with (local, master, old_revno, old_revid, "
+            "new_revno, new_revid). old_revid is NULL_REVISION for the first "
+            "commit to a branch.", (0, 15), None))
+        self.create_hook(HookPoint('post_uncommit',
+            "Called in the bzr client after an uncommit completes. "
+            "post_uncommit is called with (local, master, old_revno, "
+            "old_revid, new_revno, new_revid) where local is the local branch "
+            "or None, master is the target branch, and an empty branch "
+            "recieves new_revno of 0, new_revid of None.", (0, 15), None))
+        self.create_hook(HookPoint('pre_change_branch_tip',
+            "Called in bzr client and server before a change to the tip of a "
+            "branch is made. pre_change_branch_tip is called with a "
+            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
+            "commit, uncommit will all trigger this hook.", (1, 6), None))
+        self.create_hook(HookPoint('post_change_branch_tip',
+            "Called in bzr client and server after a change to the tip of a "
+            "branch is made. post_change_branch_tip is called with a "
+            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
+            "commit, uncommit will all trigger this hook.", (1, 4), None))
+        self.create_hook(HookPoint('transform_fallback_location',
+            "Called when a stacked branch is activating its fallback "
+            "locations. transform_fallback_location is called with (branch, "
+            "url), and should return a new url. Returning the same url "
+            "allows it to be used as-is, returning a different one can be "
+            "used to cause the branch to stack on a closer copy of that "
+            "fallback_location. Note that the branch cannot have history "
+            "accessing methods called on it during this hook because the "
+            "fallback locations have not been activated. When there are "
+            "multiple hooks installed for transform_fallback_location, "
+            "all are called with the url returned from the previous hook."
+            "The order is however undefined.", (1, 9), None))
 
 
 # install the default hooks into the Branch class.
@@ -2625,11 +2616,11 @@
     :ivar new_revno: Revision number after pull.
     :ivar old_revid: Tip revision id before pull.
     :ivar new_revid: Tip revision id after pull.
-    :ivar source_branch: Source (local) branch object.
+    :ivar source_branch: Source (local) branch object. (read locked)
     :ivar master_branch: Master branch of the target, or the target if no
         Master
     :ivar local_branch: target branch if there is a Master, else None
-    :ivar target_branch: Target/destination branch object.
+    :ivar target_branch: Target/destination branch object. (write locked)
     :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
     """
 
@@ -2649,13 +2640,20 @@
 class PushResult(_Result):
     """Result of a Branch.push operation.
 
-    :ivar old_revno: Revision number before push.
-    :ivar new_revno: Revision number after push.
-    :ivar old_revid: Tip revision id before push.
-    :ivar new_revid: Tip revision id after push.
-    :ivar source_branch: Source branch object.
-    :ivar master_branch: Master branch of the target, or None.
-    :ivar target_branch: Target/destination branch object.
+    :ivar old_revno: Revision number (eg 10) of the target before push.
+    :ivar new_revno: Revision number (eg 12) of the target after push.
+    :ivar old_revid: Tip revision id (eg joe at foo.com-1234234-aoeua34) of target
+        before the push.
+    :ivar new_revid: Tip revision id (eg joe at foo.com-5676566-boa234a) of target
+        after the push.
+    :ivar source_branch: Source branch object that the push was from. This is
+        read locked, and generally is a local (and thus low latency) branch.
+    :ivar master_branch: If target is a bound branch, the master branch of
+        target, or target itself. Always write locked.
+    :ivar target_branch: The direct Branch where data is being sent (write
+        locked).
+    :ivar local_branch: If the target is a bound branch this will be the
+        target, otherwise it will be None.
     """
 
     def __int__(self):

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2009-03-10 23:39:48 +0000
+++ b/bzrlib/builtins.py	2009-03-12 06:24:39 +0000
@@ -35,6 +35,7 @@
     config,
     errors,
     globbing,
+    hooks,
     log,
     merge as _mod_merge,
     merge_directive,
@@ -5340,25 +5341,23 @@
 
 
 class cmd_hooks(Command):
-    """Show a branch's currently registered hooks.
-    """
+    """Show hooks."""
 
     hidden = True
-    takes_args = ['path?']
 
-    def run(self, path=None):
-        if path is None:
-            path = '.'
-        branch_hooks = Branch.open(path).hooks
-        for hook_type in branch_hooks:
-            hooks = branch_hooks[hook_type]
-            self.outf.write("%s:\n" % (hook_type,))
-            if hooks:
-                for hook in hooks:
-                    self.outf.write("  %s\n" %
-                                    (branch_hooks.get_hook_name(hook),))
-            else:
-                self.outf.write("  <no hooks installed>\n")
+    def run(self):
+        for hook_key in sorted(hooks.known_hooks.keys()):
+            some_hooks = hooks.known_hooks_key_to_object(hook_key)
+            self.outf.write("%s:\n" % type(some_hooks).__name__)
+            for hook_name, hook_point in sorted(some_hooks.items()):
+                self.outf.write("  %s:\n" % (hook_name,))
+                found_hooks = list(hook_point)
+                if found_hooks:
+                    for hook in found_hooks:
+                        self.outf.write("    %s\n" %
+                                        (some_hooks.get_hook_name(hook),))
+                else:
+                    self.outf.write("    <no hooks installed>\n")
 
 
 class cmd_shelve(Command):

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2009-03-10 01:51:46 +0000
+++ b/bzrlib/commands.py	2009-03-12 06:24:39 +0000
@@ -50,7 +50,7 @@
 
 from bzrlib import registry
 # Compatibility
-from bzrlib.hooks import Hooks
+from bzrlib.hooks import HookPoint, Hooks
 from bzrlib.option import Option
 
 
@@ -591,11 +591,10 @@
         notified.
         """
         Hooks.__init__(self)
-        # Introduced in 1.13:
-        # invoked after creating a command object to allow modifications such
-        # as adding or removing options, docs etc. Invoked with the command
-        # object.
-        self['extend_command'] = []
+        self.create_hook(HookPoint('extend_command',
+            "Called after creating a command object to allow modifications "
+            "such as adding or removing options, docs etc. Called with the "
+            "new bzrlib.commands.Command object.", (1, 13), None))
 
 Command.hooks = CommandHooks()
 

=== modified file 'bzrlib/help_topics/__init__.py'
--- a/bzrlib/help_topics/__init__.py	2009-03-03 05:02:36 +0000
+++ b/bzrlib/help_topics/__init__.py	2009-03-12 06:24:39 +0000
@@ -736,16 +736,18 @@
                         'Environment variable names and values')
 topic_registry.register('files', _files,
                         'Information on configuration and log files')
+topic_registry.register_lazy('hooks', 'bzrlib.hooks', 'hooks_help_text',
+                        'Points at which custom processing can be added')
 
-# Load some of the help topics from files
+# Load some of the help topics from files. Note that topics which reproduce API
+# details will tend to skew (quickly usually!) so please seek other solutions
+# for such things.
 topic_registry.register('authentication', _load_from_file,
                         'Information on configuring authentication')
 topic_registry.register('configuration', _load_from_file,
                         'Details on the configuration settings available')
 topic_registry.register('conflicts', _load_from_file,
                         'Types of conflicts and what to do about them')
-topic_registry.register('hooks', _load_from_file,
-                        'Points at which custom processing can be added')
 topic_registry.register('log-formats', _load_from_file,
                         'Details on the logging formats available')
 

=== removed file 'bzrlib/help_topics/en/hooks.txt'
--- a/bzrlib/help_topics/en/hooks.txt	2009-02-11 12:49:50 +0000
+++ b/bzrlib/help_topics/en/hooks.txt	1970-01-01 00:00:00 +0000
@@ -1,291 +0,0 @@
-Hooks
-=====
-
-Introduction
-------------
-
-A hook of type *xxx* of class *yyy* needs to be registered using::
-
-  yyy.hooks.install_named_hook("xxx", ...)
-
-See `Using hooks`_ in the User Guide for examples.
-
-.. _Using hooks: ../user-guide/index.html#using-hooks
-
-The class that contains each hook is given in parentheses immediately
-after each hook type below.
-
-Each description also indicates whether the hook runs on the client (the
-machine where bzr was invoked) or the server (the machine addressed by
-the branch URL).  These may be, but are not necessarily, the same machine.
-
-Plugins (including hooks) are run on the server if any of these is true:
-
-  * The remote branch is on the same machine as the client, and the client
-    has plugins enabled.
-
-  * The connection is via a smart server (accessed with a URL starting with
-    "bzr://", "bzr+ssh://" or "bzr+http://", or accessed via a "http://"
-    URL when a smart server is available via HTTP), and that server has
-    plugins enabled.
-
-
-open (Branch)
--------------
-
-Called after a Branch object is opened, with the Branch object.
-Runs on the client and on the server.
-
-
-post_push (Branch)
-------------------
-
-Run after ``push`` has completed.
-Runs on the client.
-
-The hook signature is (push_result), containing the members
-
-  source_branch
-    Where the data is being pushed from (read locked).
-    This should be the lowest latency branch.
-
-  target_branch
-    The direct location where data is being sent (write locked).
-
-  master_branch
-    Either target_branch, or if the target is a bound branch, it
-    will be the master location (write locked).
-
-  local_branch
-    If the target is a bound branch, this will be the target
-    branch, else it will be None.
-
-  old_revno
-    The revision number (eg 10) of the branch before the push.
-
-  old_revid
-    The revision id (eg joe at foo.com-1234234-aoeua34) before the push.
-
-  new_revno
-    The revision number (eg 12) of the branch after the push.
-
-  new_revid
-    The revision id (eg joe at foo.com-5676566-boa234a) after the push.
-
-
-post_pull (Branch)
-------------------
-
-Run after ``pull`` has completed.
-Runs on the client.
-
-The hook signature is (push_result) containing the members
-(source, local, master, old_revno, old_revid, new_revno, new_revid)
-where local is the local target branch or None, master is the target 
-master branch, and the rest should be self explanatory. The source
-is read-locked and the target branches are write-locked. Source will
-be the local low-latency branch.
-
-
-start_commit (MutableTree)
---------------------------
-
-Run on the working tree before ``commit`` starts processing it.
-Runs on the client.
-
-Unlike the ``pre_commit`` hook (see below), the ``start_commit`` hook
-can safely change the working tree.
-
-The hook signature is (tree) where tree is a MutableTree object.
-
-
-pre_commit (Branch)
--------------------
-
-Run before ``commit`` has completed.
-Runs on the client.
-
-The hook signature is (local, master, old_revno, old_revid, future_revno,
-future_revid, tree_delta, future_tree) where old_revno is NULL_REVISION for
-the first commit to a branch, tree_delta is a TreeDelta object describing
-changes from the basis revision, and future_tree is an in-memory tree
-obtained from CommitBuilder.revision_tree(). Hooks MUST NOT modify tree_delta
-and future_tree.
-
-
-post_commit (Branch)
---------------------
-
-Run after ``commit`` has completed.
-Runs on the client.
-
-The hook signature is (local, master, old_revno, old_revid, new_revno,
-new_revid) old_revid is NULL_REVISION for the first commit to a branch.
-
-
-post_uncommit (Branch)
-----------------------
-
-Run after ``uncommit`` has completed.
-Runs on the client.
-
-The api signature is (local, master, old_revno, old_revid, new_revno,
-new_revid) where local is the local branch or None, master is the target
-branch, and an empty branch receives new_revno of 0, new_revid of None.
-
-
-pre_change_branch_tip (Branch)
--------------------------------
-
-Run before a branch tip has been changed, while the branch is write-locked.
-Runs on the client and on the server.
-Note that push, pull, commit and uncommit all invoke this hook.
-
-The hook signature is (params), where params is an object containing
-the members
-
-  branch
-    The branch whose tip has been changed.
-
-  old_revno
-    The revision number (eg 10) of the branch before the change.
-
-  old_revid
-    The revision id (eg joe at foo.com-1234234-aoeua34) before the change.
-
-  new_revno
-    The revision number (eg 12) of the branch after the change.
-
-  new_revid
-    The revision id (eg joe at foo.com-5676566-boa234a) after the change.
-
-The old_revno and new_revno members are integers, as the head
-revision never has a dotted revision number.
-
-
-post_change_branch_tip (Branch)
--------------------------------
-
-Run after a branch tip has been changed but while the branch is still
-write-locked.
-Runs on the client and on the server.
-Note that push, pull, commit and uncommit all invoke this hook.
-
-The hook signature is (params), where params is an object containing
-the members
-
-  branch
-    The branch whose tip has been changed.
-
-  old_revno
-    The revision number (eg 10) of the branch before the change.
-
-  old_revid
-    The revision id (eg joe at foo.com-1234234-aoeua34) before the change.
-
-  new_revno
-    The revision number (eg 12) of the branch after the change.
-
-  new_revid
-    The revision id (eg joe at foo.com-5676566-boa234a) after the change.
-
-The old_revno and new_revno members are integers, as the head
-revision never has a dotted revision number.
-
-
-set_rh (Branch)
----------------
-
-Note: This hook is now deprecated and will be removed in the near future.
-Please use the ``post_change_branch_tip`` hook instead.
-
-
-transform_fallback_location (Branch)
-------------------------------------
-
-Invoked as a stacked branch activates its fallback locations.
-
-The hook signature is (branch, url) where:
-
-  branch
-    The branch being opened.  Note that as it does not yet have its
-    fallback locations activated, the branch should be treated as
-    half-built.
-
-  url
-    The URL that the branch specified for its fallback location.
-
-The hook must return a URL for the branch containing the fallback
-location. If multiple hooks are registered, the order in which they 
-will be called is undefined and subject to change.
-
-(New in 1.9)
-
-
-server_started (SmartTCPServer)
--------------------------------
-
-Invoked whenever the server starts serving a directory.
-Runs on the server.
-
-The hook signature is (backing urls, public url), where:
-
-  backing_url
-    A list of (string) URLs giving the server-specific directory locations.
-
-  public_url
-    The public URL for the directory.
-
-
-server_stopped (SmartTCPServer)
--------------------------------
-
-Invoked whenever the server stops serving a directory.
-Runs on the server.
-
-The hook signature is the same as ``server_started``.
-
-
-lock_acquired (LockDir)
-----------------------------
-
-Called with a LockResult object when a lock has been successfully acquired.
-Runs on the client and on the server.
-
-(New in 1.8.)
-
-lock_released (LockDir)
-----------------------------
-
-Called with a LockResult object when a lock has been successfully released.
-Runs on the client.
-
-(New in 1.8.)
-
-commit_message_template (msgeditor)
------------------------------------
-
-Invoked by commit to generate a commit message template.
-Each hook can modify the commit message template.
-The hook signature is (commit, start_message), where:
-
-  commit
-    A commit object, for the commit in progress
-
-  start_message
-    The original commit message, None initially.
-
-The hook should return a new commit message template.
-
-(New in 1.10.)
-
-extend_command (Commands)
--------------------------
-
-Invoked by the command line interface when constructing a command object, this
-hook permits the object to be altered after construction - for instance, to add
-options, hook into callbacks that that command offers or more.
-
-The hook signature is hook(cmd) -> None. 
-
-This hook was added in 1.13.

=== modified file 'bzrlib/hooks.py'
--- a/bzrlib/hooks.py	2009-03-12 02:43:46 +0000
+++ b/bzrlib/hooks.py	2009-03-12 06:24:39 +0000
@@ -26,6 +26,7 @@
         _format_version_tuple,
         errors,
         )
+from bzrlib.help_topics import help_as_plain_text
 """)
 
 
@@ -34,6 +35,8 @@
     'BranchHooks')
 known_hooks.register_lazy(('bzrlib.commands', 'Command.hooks'),
     'bzrlib.commands', 'CommandHooks')
+known_hooks.register_lazy(('bzrlib.lock', 'Lock.hooks'), 'bzrlib.lock',
+    'LockHooks')
 known_hooks.register_lazy(('bzrlib.mutabletree', 'MutableTree.hooks'),
     'bzrlib.mutabletree', 'MutableTreeHooks')
 known_hooks.register_lazy(('bzrlib.smart.client', '_SmartClient.hooks'),
@@ -100,7 +103,7 @@
         hook_docs = []
         name = self.__class__.__name__
         hook_docs.append(name)
-        hook_docs.append("="*len(name))
+        hook_docs.append("-"*len(name))
         hook_docs.append("")
         for hook_name in hook_names:
             hook = self[hook_name]
@@ -110,7 +113,7 @@
                 # legacy hook
                 strings = []
                 strings.append(hook_name)
-                strings.append("-" * len(hook_name))
+                strings.append("~" * len(hook_name))
                 strings.append("")
                 strings.append("An old-style hook. For documentation see the __init__ "
                     "method of '%s'\n" % (name,))
@@ -203,7 +206,7 @@
         """
         strings = []
         strings.append(self.name)
-        strings.append('-'*len(self.name))
+        strings.append('~'*len(self.name))
         strings.append('')
         if self.introduced:
             introduced_string = _format_version_tuple(self.introduced)
@@ -220,6 +223,10 @@
         strings.append('')
         return '\n'.join(strings)
 
+    def __eq__(self, other):
+        return (type(other) == type(self) and 
+            other.__dict__ == self.__dict__)
+
     def hook(self, callback, callback_label):
         """Register a callback to be called when this HookPoint fires.
 
@@ -228,7 +235,8 @@
             processing.
         """
         self._callbacks.append(callback)
-        self._callback_names[callback] = callback_label
+        if callback_label is not None:
+            self._callback_names[callback] = callback_label
 
     def __iter__(self):
         return iter(self._callbacks)
@@ -247,3 +255,46 @@
             strings[-1] = ")"
         strings.append("]>")
         return ''.join(strings)
+
+
+_help_prefix = \
+"""
+Hooks
+=====
+
+Introduction
+------------
+
+A hook of type *xxx* of class *yyy* needs to be registered using::
+
+  yyy.hooks.install_named_hook("xxx", ...)
+
+See `Using hooks`_ in the User Guide for examples.
+
+.. _Using hooks: ../user-guide/index.html#using-hooks
+
+The class that contains each hook is given before the hooks it supplies. For
+instance, BranchHooks as the class is the hooks class for
+`bzrlib.branch.Branch.hooks`.
+
+Each description also indicates whether the hook runs on the client (the
+machine where bzr was invoked) or the server (the machine addressed by
+the branch URL).  These may be, but are not necessarily, the same machine.
+
+Plugins (including hooks) are run on the server if all of these is true:
+
+  * The connection is via a smart server (accessed with a URL starting with
+    "bzr://", "bzr+ssh://" or "bzr+http://", or accessed via a "http://"
+    URL when a smart server is available via HTTP).
+
+  * The hook is either server specific or part of general infrastructure rather
+    than client specific code (such as commit).
+
+"""
+
+def hooks_help_text(topic):
+    segments = [_help_prefix]
+    for hook_key in sorted(known_hooks.keys()):
+        hooks = known_hooks_key_to_object(hook_key)
+        segments.append(hooks.docs())
+    return '\n'.join(segments)

=== modified file 'bzrlib/lock.py'
--- a/bzrlib/lock.py	2009-03-11 06:26:54 +0000
+++ b/bzrlib/lock.py	2009-03-12 06:24:39 +0000
@@ -42,21 +42,19 @@
     osutils,
     trace,
     )
-from bzrlib.hooks import Hooks
+from bzrlib.hooks import HookPoint, Hooks
 
 
 class LockHooks(Hooks):
 
     def __init__(self):
         Hooks.__init__(self)
-
-        # added in 1.8; called with a LockResult when a physical lock is
-        # acquired
-        self['lock_acquired'] = []
-
-        # added in 1.8; called with a LockResult when a physical lock is
-        # acquired
-        self['lock_released'] = []
+        self.create_hook(HookPoint('lock_acquired',
+            "Called with a bzrlib.lock.LockResult when a physical lock is "
+            "acquired.", (1, 8), None))
+        self.create_hook(HookPoint('lock_released',
+            "Called with a bzrlib.lock.LockResult when a physical lock is "
+            "released.", (1, 8), None))
 
 
 class Lock(object):

=== modified file 'bzrlib/lockdir.py'
--- a/bzrlib/lockdir.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/lockdir.py	2009-03-12 06:24:39 +0000
@@ -125,7 +125,6 @@
         ResourceBusy,
         TransportError,
         )
-from bzrlib.hooks import Hooks
 from bzrlib.trace import mutter, note
 from bzrlib.osutils import format_delta, rand_chars, get_host_name
 import bzrlib.ui

=== modified file 'bzrlib/msgeditor.py'
--- a/bzrlib/msgeditor.py	2009-02-23 15:29:35 +0000
+++ b/bzrlib/msgeditor.py	2009-03-12 06:24:39 +0000
@@ -29,7 +29,7 @@
     trace,
     )
 from bzrlib.errors import BzrError, BadCommitMessageEncoding
-from bzrlib.hooks import Hooks
+from bzrlib.hooks import HookPoint, Hooks
 
 
 def _get_editor():
@@ -293,13 +293,15 @@
         These are all empty initially.
         """
         Hooks.__init__(self)
-        # Introduced in 1.10:
-        # Invoked to generate the commit message template shown in the editor
-        # The api signature is:
-        # (commit, message), and the function should return the new message
-        # There is currently no way to modify the order in which
-        # template hooks are invoked
-        self['commit_message_template'] = []
+        self.create_hook(HookPoint('commit_message_template',
+            "Called when a commit message is being generated. "
+            "commit_message_template is called with the bzrlib.commit.Commit "
+            "object and the message that is known so far. "
+            "commit_message_template must return a new message to use (which "
+            "could be the same as it was given. When there are multiple "
+            "hooks registered for commit_message_template, they are chained "
+            "with the result from the first passed into the second, and so "
+            "on.", (1, 10), None))
 
 
 hooks = MessageEditorHooks()

=== modified file 'bzrlib/mutabletree.py'
--- a/bzrlib/mutabletree.py	2009-02-27 15:14:34 +0000
+++ b/bzrlib/mutabletree.py	2009-03-12 06:24:39 +0000
@@ -569,8 +569,11 @@
 
         """
         hooks.Hooks.__init__(self)
-        # Invoked before a commit is done in a tree. New in 1.4
-        self['start_commit'] = []
+        self.create_hook(hooks.HookPoint('start_commit',
+            "Called before a commit is performed on a tree. The start commit "
+            "hook is able to change the tree before the commit takes place. "
+            "start_commit is called with the bzrlib.tree.MutableTree that the "
+            "commit is being performed on.", (1, 4), None))
 
 
 # install the default hooks into the MutableTree class.

=== modified file 'bzrlib/smart/client.py'
--- a/bzrlib/smart/client.py	2009-02-23 15:29:35 +0000
+++ b/bzrlib/smart/client.py	2009-03-12 06:24:39 +0000
@@ -192,7 +192,11 @@
 
     def __init__(self):
         hooks.Hooks.__init__(self)
-        self['call'] = []
+        self.create_hook(hooks.HookPoint('call',
+            "Called when the smart client is submitting a request to the "
+            "smart server. Called with a bzrlib.smart.client.CallHookParams "
+            "object. Streaming request bodies, and responses, are not "
+            "accessible.", None, None))
 
 
 _SmartClient.hooks = SmartClientHooks()

=== modified file 'bzrlib/smart/server.py'
--- a/bzrlib/smart/server.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/smart/server.py	2009-03-12 06:24:39 +0000
@@ -21,7 +21,7 @@
 import sys
 import threading
 
-from bzrlib.hooks import Hooks
+from bzrlib.hooks import HookPoint, Hooks
 from bzrlib import (
     errors,
     trace,
@@ -208,14 +208,16 @@
         notified.
         """
         Hooks.__init__(self)
-        # Introduced in 0.16:
-        # invoked whenever the server starts serving a directory.
-        # The api signature is (backing urls, public url).
-        self['server_started'] = []
-        # Introduced in 0.16:
-        # invoked whenever the server stops serving a directory.
-        # The api signature is (backing urls, public url).
-        self['server_stopped'] = []
+        self.create_hook(HookPoint('server_started',
+            "Called by the bzr server when it starts serving a directory. "
+            "server_started is called with (backing urls, public url), "
+            "where backing_url is a list of URLs giving the "
+            "server-specific directory locations, and public_url is the "
+            "public URL for the directory being served.", (0, 16), None))
+        self.create_hook(HookPoint('server_stopped',
+            "Called by the bzr server when it stops serving a directory. "
+            "server_stopped is called with the same parameters as the "
+            "server_started hook: (backing_urls, public_url).", (0, 16), None))
 
 SmartTCPServer.hooks = SmartServerHooks()
 

=== modified file 'bzrlib/tests/blackbox/test_hooks.py'
--- a/bzrlib/tests/blackbox/test_hooks.py	2008-04-23 09:46:52 +0000
+++ b/bzrlib/tests/blackbox/test_hooks.py	2009-03-12 06:24:39 +0000
@@ -25,7 +25,7 @@
     def _check_hooks_output(self, command_output, hooks):
         for hook_type in Branch.hooks:
             s = "\n  ".join(hooks.get(hook_type, ["<no hooks installed>"]))
-            self.assert_("%s:\n  %s" % (hook_type, s) in command_output)
+            self.assert_("%s:\n    %s" % (hook_type, s) in command_output)
 
     def test_hooks_with_no_hooks(self):
         self.make_branch('.')
@@ -50,4 +50,4 @@
         self._check_hooks_output(out, {'set_rh': [name]})
 
     def test_hooks_no_branch(self):
-        self.run_bzr('hooks', retcode=3)
+        self.run_bzr('hooks')

=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/tests/test_branch.py	2009-03-12 06:24:39 +0000
@@ -424,7 +424,8 @@
     def test_installed_hooks_are_BranchHooks(self):
         """The installed hooks object should be a BranchHooks."""
         # the installed hooks are saved in self._preserved_hooks.
-        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch], BranchHooks)
+        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
+            BranchHooks)
 
 
 class TestPullResult(TestCase):

=== modified file 'bzrlib/tests/test_help.py'
--- a/bzrlib/tests/test_help.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/tests/test_help.py	2009-03-12 06:24:39 +0000
@@ -203,10 +203,10 @@
 
     def test_get_help_text_loaded_from_file(self):
         # Pick a known topic stored in an external file
-        topic = help_topics.RegisteredTopic('hooks')
+        topic = help_topics.RegisteredTopic('authentication')
         self.assertStartsWith(topic.get_help_text(),
-            'Hooks\n'
-            '=====\n'
+            'Authentication Settings\n'
+            '=======================\n'
             '\n')
 
     def test_get_help_topic(self):

=== modified file 'bzrlib/tests/test_hooks.py'
--- a/bzrlib/tests/test_hooks.py	2009-03-12 02:43:46 +0000
+++ b/bzrlib/tests/test_hooks.py	2009-03-12 06:24:39 +0000
@@ -70,15 +70,15 @@
         hooks.create_hook(hook2)
         self.assertEqualDiff(
             "MyHooks\n"
-            "=======\n"
+            "-------\n"
             "\n"
             "legacy\n"
-            "------\n"
+            "~~~~~~\n"
             "\n"
             "An old-style hook. For documentation see the __init__ method of 'MyHooks'\n"
             "\n"
             "post_tip_change\n"
-            "---------------\n"
+            "~~~~~~~~~~~~~~~\n"
             "\n"
             "Introduced in: 1.4\n"
             "Deprecated in: Not deprecated\n"
@@ -87,7 +87,7 @@
             "ChangeBranchTipParams object.\n"
             "\n"
             "pre_tip_change\n"
-            "--------------\n"
+            "~~~~~~~~~~~~~~\n"
             "\n"
             "Introduced in: 1.6\n"
             "Deprecated in: Not deprecated\n"
@@ -158,7 +158,7 @@
             " a bzrlib.branch.PostChangeBranchTipParams object")
         hook = HookPoint("post_tip_change", doc, (0, 15), None)
         self.assertEqual("post_tip_change\n"
-            "---------------\n"
+            "~~~~~~~~~~~~~~~\n"
             "\n"
             "Introduced in: 0.15\n"
             "Deprecated in: Not deprecated\n"

=== modified file 'bzrlib/tests/test_mutabletree.py'
--- a/bzrlib/tests/test_mutabletree.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/tests/test_mutabletree.py	2009-03-12 06:24:39 +0000
@@ -34,7 +34,7 @@
     def test_installed_hooks_are_MutableTreeHooks(self):
         """The installed hooks object should be a MutableTreeHooks."""
         # the installed hooks are saved in self._preserved_hooks.
-        self.assertIsInstance(self._preserved_hooks[MutableTree],
+        self.assertIsInstance(self._preserved_hooks[MutableTree][1],
                               MutableTreeHooks)
 
 




More information about the bazaar-commits mailing list