Mercurial は、リポジトリに発生したイベントに応じて、自動的な処理を実行する強力な仕組みを提供しています。幾つかの状況では、イベントに対する Mercurial の応答結果を制御することもできます。
Mercurial が利用するこれらの処理は、フック(hook)と呼ばれています。構成管理システムによってはフックを “トリガ” と呼ぶこともありますが、これらは共に同じ考え方を指します。
Mercurial が提供するフックの簡単なリストを示します。これらのフックに関する詳細は10.8 節で説明します。
“制御用” と書かれているフックは、処理の継続性の可否を判定する機能を持っています。フックの実行が成功した場合、フックに対応する処理は継続されますが、フックの実行が失敗した場合、対応する処理は許可されないか実行しなかったことになります(どちらに なるかはフックに応じて決まります)。
リポジトリにおいて Mercurial のコマンドを実行し、そのコマンドがフックを起動することになった場合、コマンド実行者のシステム 上において、コマンド実行者のユーザアカウントにより、コマンド実行者の権限レベルで実行されます。フックは任意の実行コードです から、十分な配慮を持って扱う必要があります。誰が作成して何をするフックなのかを熟知している確信無しに、フックをインストール しないでください。
時には、自分でインストールしたのではないフックに晒されるかもしれません。馴染みの無いシステム上で Mercurial を使用する際 には、 Mercurial がシステム共通のhgrc ファイルで定義されたフックを実行するかもしれません。
他のユーザが所有するリポジトリで作業する場合、 Mercurial はそのユーザのリポジトリで定義されたフックを実行できますが、そ れは “あなたの” 権限で実行されます。例えば、あるリポジトリから“hg pull” した際に、そのリポジトリの.hg/hgrc ファイル がoutgoing フックを定義していた場合、リモートリポジトリの所有者で無かったとしても、フックはあなたのアカウントで実行されま す。
リポジトリにおけるフックの定義状況を見るには、“hg showconfig hooks” コマンドが利用できます。あるリポジトリで作業中に、自分 の所有していない別なリポジトリとの連携(例: “hg pull” ないし“hg incoming”)が必要になった場合、リポジトリのフック定義状況を確 認すべきです1 。
Mercurial では、フック設定の構成管理は行われないため、リポジトリの clone ないし pull の際に、フック設定は伝播しません。その 理由は簡単で、フックは完全に任意の実行コードだからです。フックは、コマンド実行者のマシン上において、コマンド実行者のユーザ アカウントにより、コマンド実行者の権限レベルで実行されます。
フックの構成管理の実装は、構成管理システム利用者のアカウントを弱体化させる上で、容易に悪用可能な方法を提供してしまうた め、あらゆる分散構成管理システムにとって極めて無謀と言えます。
Mercurial はフックを伝播しないため、共通のプロジェクトでの他のメンバーとの連携の際には、彼らが自分と同じ Mercurial の フックを利用していることや、彼らがフックを正しく設定していることを仮定してはいけません。彼らにフックの使用を期待するのであ れば、それを文書化すべきです。
企業のイントラネットの場合、例えば Mercurial の “標準的な” インストールを NFS 上で行い、組織で共通のhgrc ファイルで全 てのユーザが使用すべきフックを定義する、といったことが可能であるため、フックの管理は幾分容易になります。しかし、それでも後 述するような制限が生じます。
Mercurial は、再定義によるフックの上書きを許しています。フック指定に空文字列を設定することでフック設定を無効にすることもで きますし、希望通りに振る舞いを変えることもできます。
幾つかのフックを定義した、マシンないし組織共通のhgrc ファイルを配備したとしても、利用者によるフックの無効化や上書きが 行われる可能性があることを、理解しておく必要があります。
他のメンバーに実施して欲しくない事柄について纏めた方針を、強制したいことも時にはあるかもしれません。例えば、全てのチェンジセットには必ず厳密なテスト一式に通っていて欲しい、と思うかもしれません。この要望を実現するために、組織共通の hgrc ファイルでフックを定義したとしても、モバイル PC からアクセスする遠隔ユーザ等には機能しませんし、勿論ローカルユーザにとってもフックの上書きによって無効化が可能です。
(プロジェクトにおける) Mercurial の利用方針として、メンバーが変更伝播する際には、関門の機能を果たすように適切に 設定された周知の “正規” サーバを通す、と策定することで、フックによる利用方針の強制を代替することが可能で す。
実現方法の一つとして、ソーシャルエンジニアリングと技術の組み合わせによるものがあります。アクセス制限付きアカウントを用 意し、当該アカウントで管理されたリポジトリに、各メンバーはネットワーク経由で変更を push できるようにしますが、そのアカウン トでログインしたり、通常のシェルコマンドを実行したりできないようにします。このままでは、メンバーは「ゴミ」を含むようなチェ ンジセットのコミットも可能です。
メンバーが pull するサーバーへと誰かがチェンジセットを push した場合、そのチェンジセットが永続化される前にサーバーはテストを 実施2 し、 テスト一式に通らなければそのチェンジセットを拒否します。メンバーがこのフィルタサーバからしかチェンジセットの pull をしないのであれば、メンバーが pull する全てのチェンジセットは、自動的に点検されていることが保証されま す。
多くの人により共有されているリポジトリに対して、フックによる自動実行を設定する場合、実施方式には注意が必要で す。
Mercurial がリポジトリにロックを掛けるのは、リポジトリに書き込みを行う時だけであり、且つロックに対して注意を払うのは、 Mercurial の書き込み処理の部分的な箇所だけです。書き込みロックは、複数の処理の同時書き込みによるリポジトリ破損を防ぐこと で、お互いの書き込み内容を保護します。
Mercurial はデータの読み込み書き出し順序に注意を払っていますから、リポジトリからのデータ読み込みの際にロックは必要あり ません。 Mercurial がリポジトリからデータを読み込む際には、ロックに対して注意を払いません。ロックを必要としないこの仕組み は、性能と平行性を大きく向上させています。
しかしながら、「ロックされない」ということは、それを知らないと、大きな性能向上と引き換えにトラブル発生の潜 在的な危険性を持っています。この危険性について説明するには、リポジトリへのチェンジセットの追加、およびそ れらチェンジセットの読み出しを、 Mercurial がどういった手順で行うかについて、幾分詳細な知識が必要となりま す。
Mercurial がメタデータを書き出す際には、対象ファイルにメタデータを直接書き出します。最初に filelog にメタデータを書き出 し、次に manifest のデータ(これには、 filelog に書き出した新しいデータへのポインタが含まれます)、そして changelog のデータ (これには、 manifest に書き出した新しいデータへのポインタが含まれます)が書き出されます。個々のファイルへの最初の書き出し の前に、 Mercurial は個々のファイルの終端位置情報をトランザクションログに記録します。 Mercurial によりト ランザクションが巻き戻される際には、トランザクション開始時点のサイズにまで個々のファイルが切り詰められま す。
Mercurial がメタデータを読み込む際には、 changelog を読み込んだ後でその他のファイルの読み込みを行います。データ読み込み の際には、先に読み込んだ changelog から到達可能な manifest や filelog の部分にしかアクセスしないので、不十分な書き出し中の データを読むことはありません。
幾つかの制御用フックの(pretxncommit やpretxnchangegroup)は、トランザクションの完了直前に実行されます。この時点で 全てのメタデータは書き出し済みですが、 Mercurial はトランザクションを巻き戻すことで、新たに書き出されたデータを破棄するこ とができます。
トランザクション完了前のチェンジセットは永続性が確定しておらず、そのため “本当に存在する” とみなすことができないことか ら、トランザクション完了前に実行される制御用フックが終了までに長時間を要する場合、永続性が確定していないチェンジセットのメ タデータが、平行して動作している他の処理により読み出される時間帯が発生します。フックの実行時間が長くなる程、この時間帯が長 くなります。
原則的にpretxnchangegroup フックは、集約用リポジトリでの受け入れ前に、新規チェンジセットのビルドやテストを自動化するの に適しています。この用法は “ビルドを失敗させる” 変更が集約用リポジトリに反映されないことを保証します。しか し、 pretxnchangegroup フックによるテスト途上の変更を、他の利用者が pull できてしまうようでは、テストの有用性が無くなってしまいます。リポジトリ内容の整合性に疑いを持たない利用者は、ビルドを失敗させる潜在的な可能性を持つテスト未実施の変更を、自 身のリポジトリへと反映してしまうからです。
このような難題への最も安全な技術的解法は、 “門番” リポジトリの利用を単方向に限定してしまうことです。門番リポジトリは、 外部からのチェンジセットの push は許しても、 pull はできないようにします(preoutgoing フックでそのような行為を禁止しま す)。新しいチェンジセットにおけるビルドないしテストが成功したならば、そのチェンジセットを別なリポジトリへ と push するようにchangegroup フックを設定し、利用者はそちらのリポジトリから pull できるようにしましょ う。
実際問題、このような集約されたボトルネックを設けることは、あまり良いアイディアではなく (XXXX ?)、 In practice, putting a centralised bottleneck like this in place is not often a good idea トランザクションの漏 洩3 は問題 になりません。チェンジセットを取り扱う時間よりもそれをテストするのに時間を要する状況では、プロジェクトの大きさ — およびビ ルド・テストに要する時間 — が増加するほど、 “購入前の試用” 手法により壁の内側に素早く走りこめます。 XXXXX ???? As the size of a project—and the time it takes to build and test—grows, you rapidly run into a wall with this “try before you buy” approach, where you have more changesets to test than time in which to deal with them. 避けられない結果は、すべてが巻き込ま れた部分におけるフラストレーションです。 XXXXXXX ???? The inevitable result is frustration on the part of all involved.
より大規模化可能な手法は、 push 前に各自でビルド・テストを実施してもらい、 push の後に中央で自動的にビルド・テストを行 うことで、全てのチェンジセットが良好であることを確認する、というものです。この手法の利点は、リポジトリにおけるチェンジセッ トの受理進度に関して、制限が課されることが無い点にあります。
Mercurial のフックは簡単に書けます。“hg commit” が完了した際に実行され、作成したばかりのチェンジセットのハッシュ値を表示 するだけの、簡単なフックを書いてみましょう。
全てのフックは、10.1 の例における形式を踏襲します。hgrc ファイルの[hooks] セクションにエントリを追加します。左辺は実行契機になるイベントの名前で、右辺は実行される処理です。見てわかるように、フックにおいては任意のシェルコマンドを実行で きます。環境変数(例におけるHG_NODE を参照してください)を用いて、 Mercurial はフックに付加情報を渡しま す。
10.4.1 の例に示すような、特定の種類のイベントに対して1つ以上のフックを定義したい状況が、しばしば発生することでしょう。 Mercurial では、フック名の末尾に拡張子を付与することで、同一イベントへの複数フックの定義が可能になります。拡張子の付与は、 フック名に、ピリオド(“.” 文字)と任意に選んだ文字列を続けることで行います。例えば、commit が発生した場合、 Mercurial はcommit.foo およびcommit.bar フックを実行します。
1 $ echo ’commit.when = echo -n "date of commit: "; date’ >> .hg/hgrc
2 $ echo a >> a 3 $ hg commit -m ’i have two hooks’ 4 committed 8c33eeeac40ef9219a93dc3ea3da7bd3fa55896f 5 date of commit: Mon Jul 20 21:48:17 GMT 2009
|
あるイベントに複数のフックが定義されている際に、その実行順序を明確に定義するために、 Mercurial はフックを拡張子で整列させ、フックコマンドをこの整列された順序で実行します。上記の例では、 commit.fooの前にcommit.bar を、これらの前にcommit を実行します。
新しいフックを定義する際に、何らかの説明的な拡張子を使用するのは良いアイディアです。そうすることで、そのフックが何をす るためのものかを思い出しやすくなります。フックの実行が失敗した場合、フック名と拡張子を含むエラーメッセージが表示されますか ら、フックが失敗した理由に関して、説明的な拡張子から即製のヒントを得ることができます(例に関しては、10.4.2 節を参照してく ださい)。
先の例では、コミット操作が完了した後で実行されるcommit フックを使用しました。このフックは、操作が完了した 後で実行される Mercurial のフックの1つです。これらのフックは、操作そのものに影響を及ぼすことはありませ ん。
Mercurial では、操作が開始される前や、操作が完了するまでの間に発生するイベントが定義されています。これらのイベントの際 に起動されるフックは、操作を継続可能か中断すべきかを判断することができます。
pretxncommit フックは、コミット操作が概ね終了した後、コミットが完了する前の段階で起動されます。言い換えるなら、チェン ジセットを表すメタデータがディスクに書き込まれてはいるものの、トランザクションが未だ完了していない状況で起動されま す。pretxncommit フックは、トランザクションを完了させるのか、あるいは巻き戻すべきかを決定することができま す。
pretxncommit フックが終了状態値として0を返却した場合、トランザクションは完了し、コミット操作は終了しますの で、commit フックが実行されます。pretxncommit フックが終了状態として非0を返却した場合、トランザクションは巻き戻され、 チェンジセットを表すメタデータは削除され、commit フックは実行されません。
1 $ cat check_bug_id
2 #!/bin/sh 3 # check that a commit comment mentions a numeric bug id 4 hg log -r $1 --template {desc} | grep -q "∖<bug *[0-9]" 5 $ echo ’pretxncommit.bug_id_required = ./check_bug_id $HG_NODE’ >> .hg/hgrc 6 $ echo a >> a 7 $ hg commit -m ’i am not mentioning a bug id’ 8 transaction abort! 9 rollback completed 10 abort: pretxncommit.bug_id_required hook exited with status 1 11 $ hg commit -m ’i refer you to bug 666’ 12 committed 940df882cbfe637969eb2c546c0de01f814b8849 13 date of commit: Mon Jul 20 21:48:18 GMT 2009
|
例 10.4.2 中のフックは、コミット時のコメントがバグ ID を含んでいることを確認しています。コメントがバグ ID を含んでいる場合、コミットは完了します。そうでなければ、コミット操作は巻き戻されます。
-v オプション付き、あるいはverbose 設定項目を “true” にして Mercurial を実行するのが、フック実装の際には有用であることに気 付くかもしれません。このようにして Mercurial を実行することで、それぞれのフックを起動する際に事前にメッセージを表示しま す。
フックを実装する際には、通常のプログラム — 典型的にはシェルスクリプト — としても実装できますが、 Python 関数としても実装 でき、その場合は Mercurial プロセス内で実行されます。
外部プログラムとしてフックを実装する利点は、 Mercurial の内部事情に関して知る必要が無い点にあります。付加的な情報の取得のため に、通常の Mercurial コマンドを起動することもできます。その利点と引き換えに、外部(プログラムとしての)フックは、プロセス内フック よりも低速4 で す。
Python 関数によるプロセス内フックは、全ての Mercurial API にアクセスでき、他のプロセスを “生成” する必要はありませんの で、基本的に外部フックよりも高速です。フックが必要とする多くの情報の入手も、 Mercurial コマンドから得るよりも、 Mercurial API から得る方が容易です。
Python の利用が苦にならないか、高い実行性能が要求される場合、 Python でのフック実装を選択すべきです。しかしながら、簡 単なフックで、性能を気にする必要が無い(おそらく多くのフックがそうです)のであれば、シェルスクリプトでの実装で十分で す。
Mercurial がフックを起動する際には、明確に定義されたパラメータがフックに渡されます。 Python でのフック実装の場合、パラメー タはキーワード引数としてフック関数に渡されます。外部プログラムでのフック実装の場合、パラメータは環境変数として渡されま す。
フック実装が Python ・シェルスクリプトのいずれであるかで、フック固有のパラメータ名とその値が決まりま す5 真偽値 パラメータは、 Python フックでは真偽値型として表現されますが、外部フックに対しては “1” (“true” 値として)ないし “0” (“false” 値として)を持つ環境変数で表現されます。フックパラメータが foo という名前である場合、 Python フックのキーワード引 数の名前も foo ですが、外部フックの環境変数名は HG_FOO となります。
実行が成功したフックは、外部フックの場合は終了コード0で、プロセス内フックの場合は真偽値 “False” で終了しなければなりませ ん6 。フッ クの実行失敗は、外部フックの場合は非0の終了コードで、プロセス内フックの場合は真偽値 “true” で表されます。プロセス内ふっく が例外を浮揚した場合、フック実行は失敗したと見做されます。
操作の継続性を制御できるフックの場合、0/ false は継続の “許可” を、非0/ true /例外は “拒否” を意味します。
hgrc ファイルに外部フックを記述した場合、hgrc ファイルに記述したフックの内容は、シェルプロセスに渡され、そのシェルプロ セスによって解釈されます。これは、フック記述の本体に、通常のシェルコマンドラインと同様の構造を用いることができる、というこ とを意味しています。
実行可能なフックは、常にリポジトリのルートディレクトリ直下で実行されます。
個々のフックパラメータは環境変数経由で渡されますが、環境変数名には、大文字化され、接頭辞として “HG_” が付与された名前が 用いられます。
フックパラメータを例外とすれば、 Mercurial はフック実行時に環境変数の改変を行いません。それぞれに異なる環境変数設定をし ている多くのユーザによって実行される、組織全体で共用されるフックを実装する際には、この知識が役に立つでしょう。複数ユーザに より実行される状況下では、フックの試験環境で設定されていた環境変数が、実行時に設定されていることを期待してはいけませ ん。
プロセス内フックを hgrc ファイルで設定する際の文法は、実行可能フッ ク7 設定の 際のそれとは少々異なりますフック設定は、接頭辞 “python:” に続き、フックとして使用する呼び出し可能オブジェク ト8 の完全 修飾された名前が記述されていなければなりません。
フック定義が存在するモジュールは、フック実行時に自動的に import されます。モジュール名とPYTHONPATH 設定が正しければ、きっと動 作する筈です9 。
以下に示すhgrc ファイルの引用例は、前述した表記に関する文法と意味を例示しています。
Mercurial が commit.example フックを起動する際には、mymodule.submodule を import し、myhook という名前の呼び出し可 能オブジェクトを探し出して起動します。
以下に示す最も単純なプロセス内フックは、フックとしては何もしませんが、フック API の基本的な概要を例示できま す。
Python フック10 の最初の引数は、常に mercurial.ui.ui オブジェクトです。第2引数はリポジトリオブジェクトですが、現在の Mercurial の実装では、そ のインスタンスは常にmercurial.localrepo.localrepository です。これらに続くその他の引数はキーワード引数として渡されま す。渡される内容は起動されるフック(の種類)に依存しますが、上記例における **kwargs のように、キーワード引数辞書に落とし 込む11 こ とで、興味の無い引数を無視することができます。
有用なコミットメッセージが非常に短い、という状況は想像し難いものがあります。図 10.4 に示す単純なpretxncommit フックは、1 0バイトよりも短いメッセージでのチェンジセットのコミットを妨げます。
1 $ cat .hg/hgrc
2 [hooks] 3 pretxncommit.msglen = test ‘hg tip --template {desc} | wc -c‘ -ge 10 4 $ echo a > a 5 $ hg add a 6 $ hg commit -A -m ’too short’ 7 transaction abort! 8 rollback completed 9 abort: pretxncommit.msglen hook exited with status 1 10 $ hg commit -A -m ’long enough’
|
コミットに関する興味深いフックの利用は、綺麗なコードでの実装を補助するというものです。簡単な “綺麗なコード” の例としては、 変更が追加する新しい行には “末尾空白” が含まれていてはならない、という格言があります。末尾空白とは、空白文字およびタブ (tab)文字の連続が行末にあることを意味します。多くの場合、末尾空白は必要の無い不可視の雑音みたいなものですが、時には問題 を含むことから、それらが取り除かれることを望みます。
precommit とpretxncommit のいずれのフックでも、末尾空白問題を通知することが可能です。precommit フックを使用した場 合、フックはコミット対象ファイルを知ることができないので、リポジトリ中の変更されたファイル全てに対して末尾空白を確認してし まいます。そうすると、ファイル foo の変更のみをコミットしたい場合でも、bar ファイルが末尾空白を含んでいたな ら、precommit フックでのチェックは、bar の問題を理由に foo のコミットを妨げてしまいます。これではいけませ ん。
pretxncommit フックで実現する場合、コミットのトランザクションが完了する直前までチェックが行われません。このため、末尾空白問題 の確認を、厳密にコミット対象のファイルだけに行うことができます。しかし、コミットメッセージを対話的に入力した後であっても、フック の実行が失敗12 し た場合、トランザクションは巻き戻されてしまいますので、末尾空白を取り除いた後で再び“hg commit” コマンド実行した際には、も う一度コミットメッセージを入力する必要があります。
1 $ cat .hg/hgrc
2 [hooks] 3 pretxncommit.whitespace = hg export tip | (! egrep -q ’^∖+.*[ ∖t]$’) 4 $ echo ’a ’ > a 5 $ hg commit -A -m ’test with trailing whitespace’ 6 adding a 7 transaction abort! 8 rollback completed 9 abort: pretxncommit.whitespace hook exited with status 1 10 $ echo ’a’ > a 11 $ hg commit -A -m ’drop trailing whitespace and try again’
|
図 10.5 では、末尾空白をチェックする簡単なpretxncommit フックを紹介しています。このフックは短いですが、非常に有用です。変更により何れかのファイルに対して末尾空白を含む行が追加された場合、こ のフックはエラーステータスで終了しますが、不愉快なファイルや行の特定を補助する情報を何ら表示しませ ん13 。こ のフックは、改変されていない行には注意を払わず、末尾空白問題を持ち込む行にのみ注意を払う、という優れた特質も持っていま す。
1 $ cat .hg/hgrc
2 [hooks] 3 pretxncommit.whitespace = .hg/check_whitespace.py 4 $ echo ’a ’ >> a 5 $ hg commit -A -m ’add new line with trailing whitespace’ 6 a, line 2: trailing whitespace added 7 commit message saved to .hg/commit.save 8 transaction abort! 9 rollback completed 10 abort: pretxncommit.whitespace hook exited with status 1 11 $ sed -i ’s, *$,,’ a 12 $ hg commit -A -m ’trimmed trailing whitespace’ 13 a, line 2: trailing whitespace added 14 commit message saved to .hg/commit.save 15 transaction abort! 16 rollback completed 17 abort: pretxncommit.whitespace hook exited with status 1
|
図 10.6 は先の例よりは複雑ですが、より有用なフックの例を示していま す14 。こ のフックは unified diff 形式を解析して、末尾空白を追加する行の有無を判定し、そのようなファイルの名前と行番号を表示します。そ れに加えてこのフックは、チェンジセットが末尾空白を追加することを検知した場合、実行を終了して Mercurial にトランザ クションの巻き戻しを伝える前に、コミットメッセージを保存してそのファイル名を表示しますので、問題点を修正 した後のコミットの際には、“hg commit -l filename ” を使ってコミットメッセージを再利用することができま す。
図 10.6ファイルから末尾空白を取り除くperl の一行記述の用法を示します。この方法はここに再掲するに足るだけの、簡潔さと有用性を 持っています15 。
Mercurial の配布版には、幾つかのフックが添付されています。添付フックは Mercurial ソースツリーのhgext ディレクトリに格納さ れています。 Mercurial のバイナリ配布版を使用している場合には、パッケージのインストーラーが Mercurial をインストールした位 置にあるhgext ディレクトリに格納されています。
acl 拡張により、ネットワーク上のサーバに対してチェンジセットを push 可能な遠隔ユーザを制限することができます。リポジトリの 一部(勿論全体も)を保護することができますので、特定のユーザに対しては、保護された部分に影響を及ぼさないチェンジセットのみ の push が可能です。
この拡張は push 対象のチェンジセットをコミットしたユーザではなく、 push を実施するユーザの身元情報を元にアクセス制 御を行います。遠隔ユーザを認証する監禁(lock-downed)サーバが存在する環境で、特定のユーザだけが監禁サー バへのチェンジセットの push が許されることを確実にしたい場合でなければ、このフックの使用は意味がありませ ん。
持ち込まれるチェンジセットを管理するために、acl フックはpretxnchangegroup フックとして用います。pretxnchangegroup フックとして用いられることで、外来のチェンジセットにより変更されるファイルを知ることができるため、 “禁止されている” ファイ ルへの変更を行うチェンジセット群に対しては、トランザクションの巻き戻しが行われます。
[acl] セクションには、フックが注意を払うべき外来チェンジセットの出所を列挙するsources エントリだけが記述されます。通 常はこのセクションを設定する必要はありません。
[acl.allow] セクションは、リポジトリへのチェンジセット追加を許可されているユーザを決定します。このセクションが存在し ない場合、明示的に禁止されていないユーザは、誰でもチェンジセットの追加をできます。このセクションが存在する場合、明示的に許 可されていないユーザは、誰もチェンジセットの追加ができません(ですので、このセクションを空にした場合、全てのユーザがチェン ジセットの追加を禁止されます)。
[acl.deny] セクションは、リポジトリへのチェンジセット追加を禁止されているユーザを決定 します。このセクションが記述されない場合、全てのユーザはチェンジセットの追加を許可されま す16 。
[acl.allow] および[acl.deny]セクションの文法は同一です。各エントリの左辺は、リポジトリルート相対でのファイルないし ディレクトリのマッチングパターンで、右辺はユーザ名となっています。
以下の例では、ユーザ docwriter がリポジトリのdocs 配下に対する変更の push のみが許可されている一方 で、ユーザ intern はsource/sensitive以外の任意のディレクトリ・ファイルに対する変更を push 可能で す17 。
acl フックを試してみたい場合、 Mercurial のデバッグ出力を有効にして実行しましょう。--debug オプションを指定し難い(あるい は不可能な)サーバ上で実行することもあるでしょうから、サーバ側のhgrcファイルでデバッグ出力を有効化できることをお忘れな く。
これを有効にすることで、当該ユーザによる push を許可・禁止する理由を判断するに足る情報を表示することでしょ う。
bugzilla 拡張は、コミットメッセージにバグ ID を検知した際に Bugzilla バグへのコメント追加を行います。このフッ クを共有サーバに設定することで、このサーバへのリモートからの変更伝播の際には、常にこのフックが実行されま す。
このフックは Bugzilla バグに、以下のようなコメントを追加します(方法は後述しますが、コメント内容は変更できま す)。
このフックの価値は、チェンジセット(のコミットメッセージ)がバグを参照している際に、バグ情報を更新する手順を自動化する 点にあります。フックの設定を適切に行うことで、 Bugzilla バグから参照元チェンジセットへと、一直線に到達することが容易になり ます。
このフックの実装を足掛りにして、より高度な Bugzilla との統合を図ることも可能です。例えば:
bugzilla フックは、サーバ側のhgrc 中でincoming フックとして設定しなければなりません。
機能特化されたフックの性質と、 Bugzilla が元々この種の統合を念頭に置いていないことから、このフックの設定は何かと複雑にな ります。
フックの設定に先立って、フックが実行されるホスト(群)に対して、 MySQL の Python バインディングをインス トールしてください。対象ホストにおいてバイナリパッケージが見当たらない場合、[Dus] からダウンロードできま す。
フックの設定は、hgrc ファイルの[bugzilla] セクションに記述されます。
Bugzilla の processmail プログラムは、バグ ID (フックにより “%s” がバグ ID に置換されます)と、電子メールアドレス を必要とします。このプログラムは、実行時ディレクトリへのファイル書き出しの権限も必要とします。 Bugzilla とフックが同 じサーバ上にインストールされていない場合、 Bugzilla がインストールされているサーバ上でprocessmail を起動する方法を見 つけ出す必要があります。
既定状態のbugzilla フックは、チェンジセットをコミットしたユーザの電子メールアドレスを、バグの更新を行う Bugzilla ユーザ名として使用することを試みます。この挙動が状況に即さない場合、[usermap] セクションを使用 して、チェンジセットをコミットしたユーザの電子メールアドレスを Bugzilla のユーザ名に変換することができま す。
[usermap] セクションの個々の要素は、左辺に電子メールアドレス、右辺に Bugzilla ユーザ名を保持します。
通常のhgrcファイルに[usermap] データを直接保持することもできますが、bugzilla フックに外部のusermap ファイルから情報 を読み込むように指示することもできます。後者の場合、例えば usermap データそのものを、利用者が改変可能なリポジトリに格納す ることもできます。そうすることで、利用者自身がusermap 中の各自の要素を保守することができます。この場合のhgrc ファイルは 以下のように記述されます。
usermap が参照するファイルの内容は、以下のようになります。
Mercurial のテンプレート形式で記述することで、bugzilla フックが追加するコメントの内容を設定することが可能です。幾つかの ([bugzilla] セクションにおける) hgrc 要素により、(テンプレートの?)振る舞いを制御することができま す。
これらに加えて、hgrc ファイルの[web] セクションにbaseurl 項目を追加することができます。 Bugzilla コメントからのチェ ンジセット参照に使用するリンクの URL を構築する際の基底文字列としてbugzilla フックはテンプレート展開の際にこの値を使用し ます。例えば:
bugzillaフックの設定例を以下に示します18 。
bugzilla フック設定において最も良くある問題は、 Bugzilla の processmail スクリプト実行に関するものと、コミットユーザ名か ら Bugzilla ユーザ名への変換に関するものです。
先の10.7.2 節からの説明で述べたように、 Mercurial プロセスをサーバで実行するユーザが、processmail スクリプトを実行す るユーザでもあります。processmail スクリプトは Bugzilla が設定ディレクトリ中のファイルに何らかの情報を書き 出す契機となるため、通常 Bugzilla の設定ファイルは Bugzilla が動作するウェブサーバの実行者の権限下にありま す。
processmail 実行の際には、sudo コマンドを利用するなどして適切なユーザ権限で実行しましょう。sudoers フィルの設定例を 以下に示します。
この例では、hg_user ユーザは、processmail-wrapper プログラムをhttpd_user ユーザの権限下で実行することができま す。
processmail プログラムは Bugzilla をインストールしたディレクトリ直下での実行が必要ですが、sudoers ファイルにはそのよう な制約を記述することができないので、このような間接実行のためのラッパースクリプトが必要となります。ラッパースクリプトの内容 は以下のように簡単なものです。
processmailに指定する電子メールアドレスは、どのようなものでも構いません。
[usermap] が正しく設定されていない場合、チェンジセットをサーバに push した際にbugzilla フックによりエラーメッセージが 表示されます。エラーメッセージは以下のようなものです。
このメッセージは、コミットしたユーザの電子メールアドレスjohn.q.public@example.comが有効な Bugzilla ユーザ名ではない か、john.q.public@example.comを有効な Bugzilla ユーザ名に変換するエントリが rcsectionusermap に記述されていないことを意 味します。
Mercurial の組み込みウェブサーバにより、全てのリポジトリに対してチェンジセット情報の RSS 配信機能が提供されますが、電子 メールによる変更通知が選択される場合が多いです。notify フックは、購読者が興味を持つ新たなチェンジセットごとに、電子メール アドレス(群)に宛てて通知を行います。
notify はテンプレート駆動型のフックですので、bugzilla フックと同様に、送信される通知の内容をカスタマイズすることがで きます。
既定状態では notify フックはチェンジセットごとの差分情報を取り込みますが、差分情報の量を制限したり、この機能を完全に停止することもできます。購読者による変更の即時レビューを想定する場合、指定された URL をクリックするよりも、差分情報を取り込むほうが有用です。
notify フックは、新たなチェンジセットごとに1通の電子メールを送信することもできれば、(単独の“hg pull” ないし“hg push” によりリポジトリに追加される)新たなチェンジセット群ごとに送信することもできます。
このフックの設定情報は、hgrc ファイルの[notify] セクションに記述されます。
[web] セクションでbaseurl 項目を設定している場合、テンプレート中で webroot として使用することができま す。
notify 設定情報の一式を以下に示します。
この設定により、以下のようなメッセージが生成されます。
既定値のままではnotify 拡張は一切のメールを送信しませんので、test 項目を明示的にfalse で設定することを忘れないでくださ い。この設定を行うまでは、notify 拡張は送信するであろうメッセージを表示します。
プロセス内フックは、以下の引数形式で起動されます。
ui引数はmercurial.ui.ui オブジェクト、repo 引数はmercurial.localrepo.localrepository オブジェクト です。**kwargs パラメータの持つ名前と値は、起動されるフックの種類に依存し、以下の共通の特徴を持っていま す。
プロセス内フックは、(外部フックがリポジトリ直下で実行されるのと違い)プロセスの作業ディレクトリを変更せずに起動されま す。プロセスの作業ディレクトリを移動させると、 Mercurial API の呼び出しが失敗する要因と成りえますので、プロセス内フックは 作業ディレクトリを変更してはいけません。
(プロセス内)フックが真偽値 “false” を返却した場合、フック呼び出しは成功したものとみなされます。真偽値 “true” が返却さ れるか、例外が浮揚された場合、フック呼び出しは失敗したものとみなされます。起動の慣習を理解するには、 “失敗したか否かを通知 する” と覚えるのが良いでしょう。
チェンジセット ID は、 Mercurial API が常用しているバイナリハッシュ形式ではなく、 Python フックに 16 進文字列の形式で渡 される点に注意してください。 16 進ハッシュ値をバイナリハッシュ値形式に変換するには、mercurial.node.bin 関数を使用してく ださい。
プロセス外フック(の起動文字列)は、 Mercurial を実行しているシェルに渡されます。そのため、変数置換やコマンド出力のリダイ レクトといった、シェルの機能が利用可能です。プロセス外フックは、(プロセス内フックが Mercurial が起動されたディレクトリで 実行されるのと違い)リポジトリルート直下で実行されます。
フック引数は、環境変数を経由して渡されます。個々の環境変数の名前は、大文字で且つ “HG_” 接頭辞が付与され た形式に変換されます。例えば、引数名が “node” の場合、当該引数を表す環境変数の名前は “HG_NODE” となりま す。
真偽値引数は、 “true” が文字列 “1” で、 “false” が文字列 “0” で表されます。環境変数HG_NODE、HG_PARENT1 ないし HG_PARENT2 は、チェンジセット ID を 16 進文字列で保持します。 “空のチェンジセット ID” は、 “0” の連続ではなく空の文字 列として表現されます。環境変数HG_URL は、それが特定可能な場合に限り、遠隔リポジトリの URL を保持しま す。
プロセス外フックが終了コード 0 で終了した場合、フックの実行は成功したものとみなされます。終了コードが 0 以外の場合、フッ クの実行は失敗したものとみなされます。
ローカルリポジトリと他のリポジトリの間のチェンジセットの転送に関わるフックは、 “向こう側” の情報を知ることができる場合があ ります。 Mercurial は、チェンジセットがどのようにして転送されたのかと、多くの場合、どのリポジトリとの間でチェンジセットが 転送されるのかも知っています。
Mercurial はリポジトリ間でチェンジセットを転送する意図を、フックに対して事前(ないし事後に)通知します。この情報は、 Python によるプロセス内フックの場合は source という名前の引数で、外部フックの場合はHG_SOURCE という名前の環境変数で、 Mercurial からフックに渡されます。
Mercurial は、リポジトリ間でのチェンジセット転送処理における “向こう側” の位置を、可能であればフックに知らせます。この情報 は、 Python によるプロセス内フックの場合は url という名前の引数で、外部フックの場合はHG_URL という名前の環境変数で、 Mercurial からフックに渡されます。
この情報は常にわかるというわけではありません。 http ないし ssh 経由でサービスを提供しているリポジトリにお いてフックが起動された場合、 Mercurial は遠隔リポジトリを特定することはできませんが、クライアントがどのア ドレスから接続しているのかは特定することができます。このような場合、 URL は以下のいずれかの形式になりま す。
このフックは、例えば“hg pull” ないし“hg unbundle” によって、あらかじめ存在しているチェンジセットの一群が、リポジトリに追加された後に実行されます。これらの操作は任意個のチェンジセットを追加できますが、このフックは各操作毎に1回づつ実行されま す。このことは、チェンジセットがまとまって追加されるか否かに関わらず、incoming フックの実行がチェンジセット毎に実行されるのと対照的です。
追加されたチェンジセットに対する自動化されたビルド・テストの開始契機としたり、バグデータベースの更新、リポジトリが 新たなチェンジセットを取り込んだことの購読者への通知、といったものが、このフックに想定される用途の一部で す。
このフックに渡されるパラメータは:
要別途参照: incoming (10.9.3 節)、prechangegroup (10.9.5 節)、pretxnchangegroup (10.9.9 節)
このフックは、新しいチェンジセットが作成された後で実行されます。
このフックに渡されるパラメータは:
要別途参照: precommit (10.9.6 節)、pretxncommit (10.9.10 節)
このフックは、例えば“hg push” によって、あらかじめ存在しているチェンジセットが、リポジトリに追加された後に実行されます。 複数のチェンジセットが単一の操作で追加された場合でも、このフックは追加された個々のチェンジセット毎に実行されま す。
このフックをchangegroup フック(10.9.1 節参照)と同様の目的に使用することができます。一群のチェンジセット毎のフック 起動の方が便利な場合もありますが、時にはチェンジセットごとのフック起動も便利です。
このフックに渡されるパラメータは:
要別途参照: changegroup (10.9.1 節)、prechangegroup (10.9.5 節)、pretxnchangegroup (10.9.9 節)
このフックは、例えば“hg push” ないし“hg bundle” によって、他のリポジトリへとチェンジセットの一群が伝播した後に実行され ます。
チェンジセットが外部に伝播したことの管理者への通知などは、このフックに想定される用途の1つです。
このフックに渡されるパラメータは:
要別途参照:preoutgoing (10.9.7 節)
この制御用フックは、他のリポジトリからのチェンジセット群の追加が Mercurial により開始される直前に実行されま す。
このフックはチェンジセット群の転送開始が許可される前に実行されるため、フック自体は追加されるチェンジ セットに関する情報を得ることができません。このフックの実行が失敗した場合、チェンジセット群は転送されませ ん。
このフックの用途の一つに、リポジトリに対する外部からのチェンジセット追加の禁止があります。例えば、ローカルホスト上の管 理者がリポジトリを変更できる一方で、利用者がサーバ経由で変更を“hg push” できないように、一時的ないし永久に “凍結” するこ ともできます。
このフックに渡されるパラメータは:
要別途参照:changegroup (10.9.1 節)、incoming (10.9.3 節)、pretxnchangegroup (10.9.9 節)
このフックは、 Mercurial が新たなチェンジセットをコミットする前に実行されます。コミットされるファイル、コミットメッセージ ないし日付といった、コミットに関するメタデータを Mercurial が揃える前に実行されます。
このフックの用途の一つに、チェンジセットの受け入れを許す一方での、新たなチェンジセットのコミットの禁止があります。他の 用途ととしては、ビルドやテストを実施し、それらが成功した場合にのみコミットを許可する、というものもありま す。
このフックに渡されるパラメータは:
コミットが進行した場合、作業領域ディレクトリの(両)親が、新たなチェンジセットの親となります。
要別途参照:commit (10.9.2 節)、pretxncommit (10.9.10 節)
このフックは、 Mercurial が外部に転送されるチェンジセットを特定する直前に実行されます。
チェンジセットが他のリポジトリへ転送されるのを防ぐことは、このフックに想定される用途の1うです。
このフックに渡されるパラメータは:
要別途参照: outgoing (10.9.4 節)
この制御フックは、タグが生成される前に実行されます。フックの実行が成功した場合、タグの生成は継続され、フックの実行が失敗し た場合、タグは生成されません。
このフックに渡されるパラメータは:
生成されるタグが構成管理対象となる場合、 precommit (10.9.2 節)およびpretxncommit (10.9.10 節)フックも実行されます。
要別途参照:tag (10.9.12 節)
この制御フックは、トランザクション — このトランザクションは、他のリポジトリからの一群のチェンジセットの追加を管理します — が完了する前に実行されます。フックの実行が成功した場合、トランザクションは完了し、全てのチェンジセットがリポジトリにおいて 永続化されます。フックの実行が失敗した場合、トランザクションは巻き戻され、チェンジセットに関するデータは破棄されま す。
このフックは、「ほぼ追加された」チェンジセットに関するメタデータにアクセスできますが、永続化されるような操 作21 をこ れらのデータに基づいて行うべきではありません作業ディレクトリも変更すべきではありません。
このフックの実行中に、他の Mercurial プロセスが同じリポジトリにアクセスしてきた場合、このプロセスからは、「ほぼ追加され た」チェンジセットが永続化されたもののように見えます。この状況を回避する手順を踏まないと、競合状態になりかねませ ん。
このフックは、チェンジセット群に対する診断に利用可能です。フックの実行が失敗した場合、トランザクションが巻き戻され、全 てのチェンジセットが “拒否” されます。
このフックに渡されるパラメータは:
要別途参照:changegroup (10.9.1)、incoming (10.9.3)、prechangegroup (10.9.5)
この制御フックは、トランザクション — このトランザクションは、新たなチェンジセットのコミットを管理します — が完了する前に 実行されます。フックの実行が成功した場合、トランザクションは完了し、チェンジセットがリポジトリにおいて永続 化されます。フックの実行が失敗した場合、トランザクションは巻き戻され、コミットに関するデータは破棄されま す。
このフックは、「ほぼ新規作成された」チェンジセットに関するメタデータにアクセスできますが、永続化されるような操作をこれ らのデータに基づいて行うべきではありません作業ディレクトリも変更すべきではありません。
このフックの実行中に、他の Mercurial プロセスが同じリポジトリにアクセスしてきた場合、このプロセスからは、「ほぼ新規作成 された」チェンジセットが永続化されたもののように見えます。この状況を回避する手順を踏まないと、競合状態になりかねませ ん。
このフックに渡されるパラメータは:
要別途参照:precommit (10.9.6 節)
この制御フックは、作業領域ディレクトリにおける“hg update” ないし“hg merge” の実施前に実行されます。このフックは、 Mercurial の“hg update” 実施前確認が“hg update” ないし“hg merge” を実行可能と判断した場合にしか実行されません。フック の実行が成功した場合、“hg update” ないし“hg merge” の実行は継続されますが、フックの実行が失敗した場合、“hg update” な いし “hg merge” は実行されません。
このフックに渡されるパラメータは:
要別途参照:update (10.9.13 節)
このフックは、タグが生成された後で実行されます。
このフックに渡されるパラメータは:
生成されるタグが構成管理対象となる場合、このフックの実行に先立ってcommit フック(10.9.2 節)が実行されま す。
要別途参照:pretag (10.9.8 節)
このフックは、作業領域ディレクトリにおける“hg update” ないし“hg merge” が完了した際に実行されます。“hg merge” は失敗 し得る(外部コマンドのhgmergeが各ファイルにおける衝突の解消に失敗した場合)ので、このフックには“hg update” ないし“hg merge” の成否が伝えられます。
要別途参照:preupdate (10.9.11節)