Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 1934] ファイルの概要

このコミットは、Go言語のテストツールであるgotestスクリプトの挙動に関するものです。gotestは、Goのテストファイルをコンパイルし、実行するためのシェルスクリプトであり、この変更はコンパイルエラーが発生した場合のスクリプトの終了挙動を改善することを目的としています。具体的には、テストファイルのコンパイルが失敗した場合に、gotestが即座に終了するように修正されています。

コミット

Bail out of gotest immediately if compiling fails.

R=rsc APPROVED=rsc DELTA=4 (2 added, 2 deleted, 0 changed) OCL=26978 CL=26978

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/c025cf64dcf0f4a95fae5340eafd9e7ab352944c

元コミット内容

Bail out of gotest immediately if compiling fails.

R=rsc APPROVED=rsc DELTA=4 (2 added, 2 deleted, 0 changed) OCL=26978 CL=26978

変更の背景

この変更の背景には、gotestスクリプトが複数のGoテストファイルをコンパイルする際に、コンパイルエラーが発生した場合の挙動の改善があります。元のスクリプトでは、set -eコマンドがコンパイルループのに配置されていました。これにより、もし複数のテストファイルのうち最初のいくつかのファイルのコンパイルが失敗しても、スクリプトは残りのファイルのコンパイルを試み続け、最終的にエラーで終了するまでに不必要な処理を実行していました。

開発者は、コンパイルエラーが発生した時点で即座にスクリプトの実行を停止し、エラーを報告することを望んでいました。これは、開発サイクルにおいてフィードバックを早め、無駄な計算資源の消費を防ぐ上で重要です。このコミットは、この「早期終了(fail-fast)」の原則をgotestスクリプトに適用するために行われました。

前提知識の解説

set -e (シェルスクリプト)

set -eは、シェルスクリプトにおいて非常に重要なコマンドです。このコマンドが有効になっている場合、スクリプト内の任意のコマンドが非ゼロの終了ステータス(エラーを示す)を返すと、シェルは即座にスクリプトの実行を終了します。これにより、エラーが発生したにもかかわらずスクリプトが後続の処理を続行してしまうことを防ぎ、予期せぬ副作用や誤った結果を防ぐことができます。

例えば、ファイルが存在しない状態でそのファイルを処理しようとするコマンドが失敗した場合、set -eがなければスクリプトは次の行に進んでしまう可能性がありますが、set -eがあればその時点でスクリプトは停止します。

gotest (Go言語の初期のテストランナー)

gotestは、Go言語の初期のバージョンで使用されていたテスト実行ツールです。現在のGoではgo testコマンドが標準的なテストランナーとして機能していますが、このコミットが作成された2009年当時は、gotestのようなシェルスクリプトがテストのコンパイルと実行を管理していました。

gotestスクリプトの主な役割は以下の通りです。

  1. テスト対象のGoソースファイル(*.go)を特定する。
  2. これらのファイルをコンパイルする。
  3. コンパイルされたテストバイナリを実行し、テスト結果を収集する。
  4. 一時ファイルをクリーンアップする。

Go言語のコンパイルプロセス

Go言語のソースコードは、go buildコマンド(またはGCコンパイラを直接使用)によって機械語にコンパイルされます。コンパイル中に構文エラーや型エラーなどの問題が検出された場合、コンパイラは非ゼロの終了ステータスを返して失敗します。これは、コンパイルが成功した場合にはゼロの終了ステータスを返すというUnix/Linuxの一般的な慣習に従っています。

技術的詳細

このコミットの技術的な核心は、シェルスクリプトにおけるset -eコマンドの配置が、スクリプトの制御フローに与える影響です。

元のgotestスクリプトでは、テストファイルのコンパイルは以下のようなループで行われていました。

for i in $gofiles
do
	$GC $i
done
set -e # <-- ここにset -eがあった

この配置では、forループ内で$GC $i(Goコンパイラによるコンパイルコマンド)が実行され、もしコンパイルが失敗して$GCが非ゼロの終了ステータスを返しても、set -eがまだ有効になっていないため、シェルはループの次のイテレーションに進んでしまいます。つまり、すべてのファイルがコンパイルされるまで、エラーが発生してもスクリプトは停止しませんでした。スクリプトはループが完了したset -eに到達し、その時点で初めて、それ以前に発生したエラーによってスクリプトが終了する可能性がありました。しかし、これは「早期終了」ではありません。

変更後、set -eはコンパイルループの直前に移動されました。

set -e # <-- ここにset -eが移動した
for i in $gofiles
do
	$GC $i
done

この新しい配置により、set -eforループが開始される前に有効になります。したがって、ループ内で$GC $iコマンドが実行され、もしコンパイルが失敗して非ゼロの終了ステータスを返した場合、set -eの作用により、その時点でスクリプト全体の実行が即座に停止します。これにより、コンパイルエラーが発生した直後にgotestスクリプトが終了し、開発者は問題を迅速に特定できるようになります。

この変更は、わずか2行の追加と2行の削除という小さなものですが、スクリプトの堅牢性とユーザーエクスペリエンスを大幅に向上させる効果があります。

コアとなるコードの変更箇所

--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -50,13 +50,13 @@ files=$(echo $gofiles | sed 's/\.go//g')
 # to build any test-only dependencies.
 sed -n 's/^\/\/ gotest: //p' $gofiles | sh
 
+set -e
+
 for i in $gofiles
 do
 	$GC $i
 done
 
-set -e
-
 # They all compile; now generate the code to call them.
 trap "rm -f _testmain.go _testmain.6" 0 1 2 3 14 15
 {

コアとなるコードの解説

この変更は、src/cmd/gotest/gotestシェルスクリプト内のset -eコマンドの位置を移動したものです。

  • 削除された行 (-set -e): コンパイルループ(for i in $gofiles ... done)の直後にあったset -eが削除されました。この位置では、ループ内で発生したコンパイルエラーが即座にスクリプトを終了させることはありませんでした。ループ内の各コンパイルコマンドが失敗しても、スクリプトは次のファイルのコンパイルを試み続け、ループが完了した後に初めてエラーが検出される可能性がありました。

  • 追加された行 (+set -e): コンパイルループの直前set -eが追加されました。この新しい位置により、set -eはコンパイルループが開始される前に有効になります。その結果、ループ内で$GC $iコマンド(Goコンパイラを実行するコマンド)が非ゼロの終了ステータス(コンパイルエラーを示す)を返した場合、シェルスクリプトはset -eの指示に従って、その時点で即座に実行を停止します。

この変更により、gotestスクリプトはコンパイルエラーをより迅速に検出し、不必要な後続のコンパイル処理をスキップして、開発者に早期にフィードバックを提供するようになりました。これは、テスト実行の効率性とエラーハンドリングの改善に貢献します。

関連リンク

参考にした情報源リンク

  • Go言語のソースコードリポジトリ: https://github.com/golang/go
  • シェルスクリプトの一般的な慣習とベストプラクティスに関する資料。
  • Unix/Linuxコマンドの終了ステータスに関する一般的な知識。I have generated the detailed technical explanation in Markdown format, adhering to all the specified requirements, including the chapter structure and detailed explanations. The output is printed to standard output as requested.