フックを利用する

フックとは?

Bazaarのふるまいをカスタマイズする1つの方法は フック(hook) です。 フックによって特定のBazaarの特定のオペレーションの前後でアクションを実行できます。 オペレーションは commit, push, pulluncommit を含みます。 フックとパラメータの完全なリストに関しては、ユーザーリファレンスの フック を参照してください。

大抵のフックはクライアントで実行されますが、サーバーで実行されるものもわずかに あります。 (サーバーサイドのオペレーションの特殊なケースを扱うものは push-and-update plugin も参照。)

フックを使用する

フックを使用するには、 プラグインを書きます 。 新しいコマンドを作成する代わりに、このプラグインはフックを定義してインストールします。例です:

from bzrlib import branch


def post_push_hook(push_result):
    print "The new revno is %d" % push_result.new_revno


branch.Branch.hooks.install_named_hook('post_push', post_push_hook,
                                 'My post_push hook')

この例を使用するには、 push_hook.py という名前のファイルを作り plugins サブディレクトリに設置します。 (プラグインをインストールしていなければ、 plugins ディレクトリを作る必要があります)。

以上です!次回にpushすると、”The new revno is…”が表示されます。 もちろん、Pythonのフルパワーを思いとおりにできるので、フックはこれよりもはるかに手が込んでいます。 これでフックの使い方を理解したので、それらで何をするかはあなたしだいです。

プラグインのコードは2つのことを行います。 最初に、これは push が完了した後に実行する関数を定義します。 (代わりにインスタンスメソッドもしくは呼び出し可能なオブジェクトを使用することもできます。) すべてのpushフックは単独の引数 push_result をとります。

2番目に、プラグインはフックをインストールします。 最初の引数 'post_push' はフックがインストールされている場所を特定します。 2番目の引数はフック自身です。3番目の引数は 'My post_push hook' という名前で、 これは進行メッセージとエラーメッセージで使用されます。

To reduce the start-up time of Bazaar it is also possible to “lazily” install hooks, using the bzrlib.hooks.install_lazy_named_hook function. This removes the need to load the module that contains the hook point just to install the hook. Here’s lazy version of the example above:

Bazaar のスタートアップ時間を短縮するために、フックを “遅延” インストールすることができます。 遅延インストールには bzrlib.hooks.install_lazy_named_hook 関数を使います。 遅延インストールを使えば、フックをインストールするためだけにフックポイントを含むモジュールを ロードする必要がなくなります。 次の例は、上の例の遅延バージョンです。

from bzrlib import hooks

def post_push_hook(push_result):
    print "The new revno is %d" % push_result.new_revno


hooks.install_lazy_named_hook('bzrlib.branch', 'Branch.hooks',
    'post_push', post_push_hook, 'My post_push hook')

フックをデバッグする

インストールされたフックの一覧 (と、利用可能なフックポイントの一覧) を表示するには、 隠しコマンドである hooks コマンドを使います:

bzr hooks

例: マージプラグイン

次の例は Merger.merge_file_content フックのデモのための、完全なプラグインです。 このプラグインは、 *.xml の名前のファイルに対する全てのマージに着いて、 Bazaar がそのマージがクリーンだと判断しても必ず「衝突」状態にします。

merge_xml.py:

"""Custom 'merge' logic for *.xml files.

Always conflicts if both branches have changed the file.
"""

from bzrlib.merge import PerFileMerger, Merger

def merge_xml_files_hook(merger):
    """Hook to merge *.xml files"""
    return AlwaysConflictXMLMerger(merger)

class AlwaysConflictXMLMerger(PerFileMerger):

    def file_matches(self, params):
        filename = self.get_filename(params, self.merger.this_tree)
        return filename.endswith('.xml')

    def merge_matching(self, params):
        return 'conflicted', params.this_lines

Merger.hooks.install_named_hook(
    'merge_file_content', merge_xml_files_hook, '*.xml file merge')

merge_file_content hooks are executed for each file to be merged. For a more a complex example look at the news_merge plugin that’s bundled with Bazaar in the bzrlib/plugins directory.

merge_file_content フックは各ファイルがマージされるたびに呼ばれます。 もっと複雑な例として、 Bazaar の bzrlib/plugins ディレクトリに同梱されている news_merge プラグインも参照してください。