[インデックス 12570] ファイルの概要
このコミットは、Mercurial バージョン 2.1 で導入された変更に対応するため、Go プロジェクトのコードレビューツール (lib/codereview/codereview.py
) を修正するものです。Mercurial 2.1 以降、コマンドの終了コードが整数である必要があるという新しい要件が課せられたため、既存のコマンドが正しく動作するように、Python のデコレータを使用してこれらのコマンドの戻り値を調整しています。
コミット
- コミットハッシュ:
bd71072eee41cdf7966805a33e509831bfccc7d9
- 作者: Russ Cox rsc@golang.org
- 日付: Mon Mar 12 14:39:44 2012 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/bd71072eee41cdf7966805a33e509831bfccc7d9
元コミット内容
codereview: fix for Mercurial 2.1
Mercurial: the Python of version control systems.
Python: the Mercurial of programming languages.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5777066
変更の背景
この変更は、バージョン管理システムである Mercurial がバージョン 2.1 にアップデートされたことに起因します。Mercurial の以前のバージョンでは、拡張機能によって定義されたコマンドがエラーを示すために任意の文字列を返すことが許容されていました。しかし、Mercurial 2.1 からは、コマンドは必ず整数の終了コードを返すことが義務付けられるようになりました。
Go プロジェクトのコードレビューシステムは、Mercurial の拡張機能として実装されており、そのコマンドは以前のバージョンの Mercurial の仕様に合わせて文字列を返す可能性がありました。Mercurial 2.1 にアップグレードすると、これらのコマンドが文字列を返した場合に TypeError
が発生し、Mercurial がクラッシュするという問題が発生しました。このコミットは、この互換性の問題を解決し、Mercurial 2.1 以降でもコードレビューツールが正常に機能するようにするために行われました。
コミットメッセージにある「Mercurial: the Python of version control systems. Python: the Mercurial of programming languages.」という記述は、Mercurial が Python で書かれていること、そして両者が柔軟性と拡張性において似た特性を持つことを示唆するユーモラスな表現です。
前提知識の解説
Mercurial (Hg)
Mercurial は、分散型バージョン管理システム(DVCS)の一つで、Git と同様にソースコードの変更履歴を管理するために使用されます。Python で書かれており、拡張性が高いことが特徴です。ユーザーは独自のコマンドや機能を Python で記述し、Mercurial の動作をカスタマイズできます。
Mercurial 拡張機能
Mercurial は、~/.hgrc
ファイルなどで設定を記述することで、Python で書かれたカスタムコマンドやフックを追加できます。これらの拡張機能は、Mercurial の内部 API を利用して、リポジトリの操作や情報の取得などを行います。
コマンドの終了コード (Exit Code)
Unix/Linux システムでは、プログラムやコマンドが実行を終了する際に、その結果を示す整数値を返します。これを終了コード(または終了ステータス)と呼びます。
0
: 通常、成功を示します。0以外
: エラーや異常終了を示します。具体的な値はエラーの種類によって異なります。 Mercurial 2.1 では、拡張機能のコマンドもこの標準的な終了コードの規約に従うことが求められるようになりました。
Python デコレータ (Decorator)
Python のデコレータは、関数やメソッドの定義をラップし、その動作を変更または拡張するための構文です。@decorator_name
の形式で関数定義の直前に記述します。デコレータは、元の関数を引数として受け取り、新しい関数(または元の関数をラップした関数)を返します。これにより、既存のコードを変更せずに機能を追加したり、共通の処理を適用したりすることができます。
このコミットでは、Mercurial コマンドの戻り値を正規化するためにデコレータが使用されています。
技術的詳細
Mercurial 2.1 での変更は、Mercurial のコマンドディスパッチメカニズムが、拡張機能から返される値の型チェックを厳格化したことにあります。以前は、コマンド関数がエラーメッセージとして文字列を返しても許容されていましたが、2.1 以降は、コマンド関数が整数(終了コード)を返すことを期待するようになりました。文字列が返された場合、Mercurial の内部で型エラー(TypeError
)が発生し、プログラムが異常終了する原因となっていました。
この問題を解決するために、hgcommand
という新しい Python デコレータが導入されました。このデコレータの主な役割は以下の通りです。
- 戻り値の正規化: デコレータは、元の Mercurial コマンド関数が返す値をインターセプトします。
- 型チェックと変換:
- もし元の関数が整数を返した場合、それはそのまま終了コードとして返されます。
- もし元の関数が
None
または空の文字列(""
)を返した場合、これは成功と見なされ、終了コード0
が返されます。 - もし元の関数が
None
でも空文字列でもない文字列を返した場合、これはエラーメッセージと見なされ、hg_util.Abort
例外を発生させます。hg_util.Abort
は Mercurial のユーティリティ関数で、指定されたメッセージとともに Mercurial の実行を中断するために使用されます。これにより、Mercurial はエラーメッセージを適切に表示し、非ゼロの終了コードで終了できます。
このデコレータを既存のすべての Mercurial コマンド関数に適用することで、各コマンド関数が個別に終了コードの規約に対応する必要がなくなり、コードの重複を避け、保守性を高めています。
コアとなるコードの変更箇所
変更は lib/codereview/codereview.py
ファイルに集中しています。
-
hgcommand
デコレータの追加:def hgcommand(f): def wrapped(ui, repo, *pats, **opts): err = f(ui, repo, *pats, **opts) if type(err) is int: return err if not err: return 0 raise hg_util.Abort(err) return wrapped
このデコレータは、元の関数
f
をラップし、その戻り値err
の型をチェックします。整数であればそのまま返し、None
や空文字列であれば0
を返し、それ以外の文字列であればhg_util.Abort
例外を発生させます。 -
既存のコマンド関数へのデコレータの適用: 以下の Mercurial コマンド関数に
@hgcommand
デコレータが追加されました。change
code_login
clpatch
undo
release_apply
download
file
gofmt
mail
ps
pq
pending
submit
sync
upload
例:
@hgcommand def change(ui, repo, *pats, **opts): """create, edit or delete a change list ...
コアとなるコードの解説
hgcommand
デコレータは、Mercurial のコマンド関数が呼び出される際に、その戻り値を統一的な形式(整数の終了コード)に変換する役割を担っています。
-
def hgcommand(f):
これはデコレータの定義です。引数f
はデコレートされる元の関数(Mercurial コマンド関数)です。 -
def wrapped(ui, repo, *pats, **opts):
これはデコレータが返す「ラッパー関数」です。Mercurial コマンド関数は通常、ui
(ユーザーインターフェースオブジェクト)、repo
(リポジトリオブジェクト)、可変長の引数*pats
、およびキーワード引数**opts
を受け取ります。ラッパー関数はこれらの引数をそのまま元の関数f
に渡します。 -
err = f(ui, repo, *pats, **opts)
ここで元の Mercurial コマンド関数が実行され、その戻り値がerr
変数に格納されます。 -
if type(err) is int:
もしerr
が整数型であれば、それはすでに適切な終了コードであるため、そのままreturn err
で返されます。 -
if not err:
もしerr
がNone
または空の文字列(Python ではこれらはFalse
と評価されます)であれば、これは成功と見なされます。したがって、標準的な成功を示す終了コード0
が返されます。 -
raise hg_util.Abort(err)
上記のどの条件にも当てはまらず、err
が文字列(かつ空ではない)である場合、これはエラーメッセージと見なされます。この場合、hg_util.Abort(err)
例外が送出されます。hg_util.Abort
は Mercurial の内部で定義されている例外クラスで、この例外が捕捉されると、Mercurial はerr
の内容をエラーメッセージとして表示し、非ゼロの終了コードで終了します。これにより、Mercurial 2.1 の新しい要件を満たしつつ、以前のバージョンで文字列を返していたコマンドの動作をエミュレートしています。
このデコレータを各コマンド関数に適用することで、Mercurial 2.1 の厳格な終了コード要件に、最小限のコード変更で対応しています。
関連リンク
- Mercurial 公式サイト: https://www.mercurial-scm.org/
- Go プロジェクトの Gerrit コードレビューリンク: https://golang.org/cl/5777066
参考にした情報源リンク
- Mercurial 2.1 リリースノート (具体的な変更点に関する公式ドキュメント):
- https://www.mercurial-scm.org/wiki/WhatsNew2.1 (このコミットの背景にある変更について言及されている可能性があります)
- Python デコレータに関するドキュメント:
- Unix/Linux の終了コードに関する一般的な情報:
- Mercurial 拡張機能の開発に関する情報 (Mercurial の公式ドキュメントやチュートリアル):
hg_util.Abort
の使用例や定義に関する情報 (Mercurial のソースコード):- Mercurial のソースコードリポジトリ内で
hg_util.py
やabort
を検索することで、より詳細な情報を得られます。# [インデックス 12570] ファイルの概要
- Mercurial のソースコードリポジトリ内で
このコミットは、Mercurial バージョン 2.1 で導入された変更に対応するため、Go プロジェクトのコードレビューツール (lib/codereview/codereview.py
) を修正するものです。Mercurial 2.1 以降、コマンドの終了コードが整数である必要があるという新しい要件が課せられたため、既存のコマンドが正しく動作するように、Python のデコレータを使用してこれらのコマンドの戻り値を調整しています。
コミット
- コミットハッシュ:
bd71072eee41cdf7966805a33e509831bfccc7d9
- 作者: Russ Cox rsc@golang.org
- 日付: Mon Mar 12 14:39:44 2012 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/bd71072eee41cdf7966805a33e509831bfccc7d9
元コミット内容
codereview: fix for Mercurial 2.1
Mercurial: the Python of version control systems.
Python: the Mercurial of programming languages.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5777066
変更の背景
この変更は、バージョン管理システムである Mercurial がバージョン 2.1 にアップデートされたことに起因します。Mercurial の以前のバージョンでは、拡張機能によって定義されたコマンドがエラーを示すために任意の文字列を返すことが許容されていました。しかし、Mercurial 2.1 からは、コマンドは必ず整数の終了コードを返すことが義務付けられるようになりました。
Go プロジェクトのコードレビューシステムは、Mercurial の拡張機能として実装されており、そのコマンドは以前のバージョンの Mercurial の仕様に合わせて文字列を返す可能性がありました。Mercurial 2.1 にアップグレードすると、これらのコマンドが文字列を返した場合に TypeError
が発生し、Mercurial がクラッシュするという問題が発生しました。このコミットは、この互換性の問題を解決し、Mercurial 2.1 以降でもコードレビューツールが正常に機能するようにするために行われました。
コミットメッセージにある「Mercurial: the Python of version control systems. Python: the Mercurial of programming languages.」という記述は、Mercurial が Python で書かれていること、そして両者が柔軟性と拡張性において似た特性を持つことを示唆するユーモラスな表現です。
前提知識の解説
Mercurial (Hg)
Mercurial は、分散型バージョン管理システム(DVCS)の一つで、Git と同様にソースコードの変更履歴を管理するために使用されます。Python で書かれており、拡張性が高いことが特徴です。ユーザーは独自のコマンドや機能を Python で記述し、Mercurial の動作をカスタマイズできます。
Mercurial 拡張機能
Mercurial は、~/.hgrc
ファイルなどで設定を記述することで、Python で書かれたカスタムコマンドやフックを追加できます。これらの拡張機能は、Mercurial の内部 API を利用して、リポジトリの操作や情報の取得などを行います。
コマンドの終了コード (Exit Code)
Unix/Linux システムでは、プログラムやコマンドが実行を終了する際に、その結果を示す整数値を返します。これを終了コード(または終了ステータス)と呼びます。
0
: 通常、成功を示します。0以外
: エラーや異常終了を示します。具体的な値はエラーの種類によって異なります。 Mercurial 2.1 では、拡張機能のコマンドもこの標準的な終了コードの規約に従うことが求められるようになりました。
Python デコレータ (Decorator)
Python のデコレータは、関数やメソッドの定義をラップし、その動作を変更または拡張するための構文です。@decorator_name
の形式で関数定義の直前に記述します。デコレータは、元の関数を引数として受け取り、新しい関数(または元の関数をラップした関数)を返します。これにより、既存のコードを変更せずに機能を追加したり、共通の処理を適用したりすることができます。
このコミットでは、Mercurial コマンドの戻り値を正規化するためにデコレータが使用されています。
技術的詳細
Mercurial 2.1 での変更は、Mercurial のコマンドディスパッチメカニズムが、拡張機能から返される値の型チェックを厳格化したことにあります。以前は、コマンド関数がエラーメッセージとして文字列を返しても許容されていましたが、2.1 以降は、コマンド関数が整数(終了コード)を返すことを期待するようになりました。文字列が返された場合、Mercurial の内部で型エラー(TypeError
)が発生し、プログラムが異常終了する原因となっていました。
この問題を解決するために、hgcommand
という新しい Python デコレータが導入されました。このデコレータの主な役割は以下の通りです。
- 戻り値の正規化: デコレータは、元の Mercurial コマンド関数が返す値をインターセプトします。
- 型チェックと変換:
- もし元の関数が整数を返した場合、それはそのまま終了コードとして返されます。
- もし元の関数が
None
または空の文字列(""
)を返した場合、これは成功と見なされ、終了コード0
が返されます。 - もし元の関数が
None
でも空文字列でもない文字列を返した場合、これはエラーメッセージと見なされ、hg_util.Abort
例外を発生させます。hg_util.Abort
は Mercurial のユーティリティ関数で、指定されたメッセージとともに Mercurial の実行を中断するために使用されます。これにより、Mercurial はエラーメッセージを適切に表示し、非ゼロの終了コードで終了できます。
このデコレータを既存のすべての Mercurial コマンド関数に適用することで、各コマンド関数が個別に終了コードの規約に対応する必要がなくなり、コードの重複を避け、保守性を高めています。
コアとなるコードの変更箇所
変更は lib/codereview/codereview.py
ファイルに集中しています。
-
hgcommand
デコレータの追加:def hgcommand(f): def wrapped(ui, repo, *pats, **opts): err = f(ui, repo, *pats, **opts) if type(err) is int: return err if not err: return 0 raise hg_util.Abort(err) return wrapped
このデコレータは、元の関数
f
をラップし、その戻り値err
の型をチェックします。整数であればそのまま返し、None
や空文字列であれば0
を返し、それ以外の文字列であればhg_util.Abort
例外を発生させます。 -
既存のコマンド関数へのデコレータの適用: 以下の Mercurial コマンド関数に
@hgcommand
デコレータが追加されました。change
code_login
clpatch
undo
release_apply
download
file
gofmt
mail
ps
pq
pending
submit
sync
upload
例:
@hgcommand def change(ui, repo, *pats, **opts): """create, edit or delete a change list ...
コアとなるコードの解説
hgcommand
デコレータは、Mercurial のコマンド関数が呼び出される際に、その戻り値を統一的な形式(整数の終了コード)に変換する役割を担っています。
-
def hgcommand(f):
これはデコレータの定義です。引数f
はデコレートされる元の関数(Mercurial コマンド関数)です。 -
def wrapped(ui, repo, *pats, **opts):
これはデコレータが返す「ラッパー関数」です。Mercurial コマンド関数は通常、ui
(ユーザーインターフェースオブジェクト)、repo
(リポジトリオブジェクト)、可変長の引数*pats
、およびキーワード引数**opts
を受け取ります。ラッパー関数はこれらの引数をそのまま元の関数f
に渡します。 -
err = f(ui, repo, *pats, **opts)
ここで元の Mercurial コマンド関数が実行され、その戻り値がerr
変数に格納されます。 -
if type(err) is int:
もしerr
が整数型であれば、それはすでに適切な終了コードであるため、そのままreturn err
で返されます。 -
if not err:
もしerr
がNone
または空の文字列(Python ではこれらはFalse
と評価されます)であれば、これは成功と見なされます。したがって、標準的な成功を示す終了コード0
が返されます。 -
raise hg_util.Abort(err)
上記のどの条件にも当てはまらず、err
が文字列(かつ空ではない)である場合、これはエラーメッセージと見なされます。この場合、hg_util.Abort(err)
例外が送出されます。hg_util.Abort
は Mercurial の内部で定義されている例外クラスで、この例外が捕捉されると、Mercurial はerr
の内容をエラーメッセージとして表示し、非ゼロの終了コードで終了します。これにより、Mercurial 2.1 の新しい要件を満たしつつ、以前のバージョンで文字列を返していたコマンドの動作をエミュレートしています。
このデコレータを各コマンド関数に適用することで、Mercurial 2.1 の厳格な終了コード要件に、最小限のコード変更で対応しています。
関連リンク
- Mercurial 公式サイト: https://www.mercurial-scm.org/
- Go プロジェクトの Gerrit コードレビューリンク: https://golang.org/cl/5777066
参考にした情報源リンク
- Mercurial 2.1 リリースノート (具体的な変更点に関する公式ドキュメント):
- https://www.mercurial-scm.org/wiki/WhatsNew2.1 (このコミットの背景にある変更について言及されている可能性があります)
- Python デコレータに関するドキュメント:
- Unix/Linux の終了コードに関する一般的な情報:
- Mercurial 拡張機能の開発に関する情報 (Mercurial の公式ドキュメントやチュートリアル):
hg_util.Abort
の使用例や定義に関する情報 (Mercurial のソースコード):- Mercurial のソースコードリポジトリ内で
hg_util.py
やabort
を検索することで、より詳細な情報を得られます。
- Mercurial のソースコードリポジトリ内で