[インデックス 1539] ファイルの概要
このコミットは、Go言語の初期のテストツールである gotest
の機能拡張に関するものです。具体的には、テストソースファイル内に特別なコメント形式で記述されたコマンドを、コンパイル前に実行できるようにする変更が導入されています。これにより、テスト専用の依存関係のビルドなど、コンパイル前に必要な前処理を柔軟に行えるようになりました。
コミット
commit d9abca81c087448e305e4992d3056407a217f2cf
Author: Russ Cox <rsc@golang.org>
Date: Thu Jan 22 14:23:50 2009 -0800
let test sources specify commands to run
before their compilation.
R=r
OCL=23300
CL=23300
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d9abca81c087448e305e4992d3056407a217f2cf
元コミット内容
let test sources specify commands to run
before their compilation.
R=r
OCL=23300
CL=23300
変更の背景
Go言語の初期段階において、テストの実行環境は現在のような go test
コマンドとして統合されておらず、src/cmd/gotest/gotest
のようなシェルスクリプトがその役割を担っていました。この時期のテストプロセスでは、テスト対象のコードだけでなく、テスト自体が依存する特別なファイルやライブラリが存在する場合があります。例えば、テスト専用のモックオブジェクトやヘルパー関数が別のGoファイルとして定義されており、これらもテスト本体がコンパイルされる前にビルドされている必要がありました。
このコミット以前は、このようなテスト専用の依存関係を処理するための標準的なメカニズムが gotest
には存在しなかったと考えられます。そのため、開発者はテストを実行する際に手動でこれらの依存関係をビルドするか、gotest
スクリプト自体を直接変更する必要がありました。これは非効率的であり、テストのポータビリティを損なう問題でした。
この変更の背景には、テストの柔軟性と自動化を向上させ、テストコード内で必要な前処理を宣言的に指定できるようにするという意図があります。これにより、テストのセットアップがより簡単になり、テストの独立性が高まります。
前提知識の解説
このコミットを理解するためには、以下のGo言語およびUnix系ツールの初期の状況に関する知識が必要です。
-
Go言語の初期のビルドシステム:
6g
: 2009年当時のGo言語のコンパイラの一つです。Go言語は当初、Plan 9アーキテクチャに由来するツールチェイン(6g
for amd64,8g
for 386,5g
for ARMなど)を使用していました。これらは現在のgo build
コマンドが内部的に呼び出すコンパイラとは異なり、より低レベルな操作を直接行っていました。6g foo.go
はfoo.go
をコンパイルし、オブジェクトファイル(通常は.6
拡張子)を生成します。gotest
: このコミットが変更しているsrc/cmd/gotest/gotest
は、当時のGo言語のテストランナーのシェルスクリプトです。現在のgo test
コマンドのような統合されたツールではなく、テストファイルのコンパイル、リンク、実行を制御するシンプルなスクリプトでした。
-
Unix系コマンドラインツール:
sed
: Stream EDitor の略で、テキストの変換を行うコマンドラインツールです。このコミットでは、入力ストリームから特定のパターンにマッチする行を抽出し、その一部を置換するために使用されています。sed -n 's/^\/\/ gotest: //p'
の意味:-n
: デフォルトの出力を抑制します。s/^\/\/ gotest: //
: 行頭が// gotest:
で始まるパターンを検索し、そのパターンを空文字列に置換します。つまり、// gotest:
の部分を削除します。p
: 置換が成功した行のみを出力します。
- これにより、Goソースファイル内の
// gotest: <command>
という形式のコメントから<command>
の部分だけを抽出できます。
sh
: Bourne Shell またはその互換シェル(Bashなど)を指します。Unix系システムでコマンドを実行するためのインタプリタです。| sh
のようにパイプで渡された入力は、sh
によってコマンドとして解釈され実行されます。
-
Go言語のコメント:
- Go言語では
//
で始まる行は単一行コメントとして扱われます。このコミットでは、このコメント形式を特別な指示(ディレクティブ)を埋め込むために利用しています。
- Go言語では
技術的詳細
このコミットは、src/cmd/gotest/gotest
シェルスクリプトに以下の機能を追加します。
- ディレクティブの検出: テスト対象のGoソースファイル (
$gofiles
変数に含まれるファイル群) を走査し、// gotest:
で始まる行を検出します。 - コマンドの抽出:
sed
コマンドを使用して、検出された行から// gotest:
プレフィックスを取り除き、残りの部分(つまり、実行すべきコマンド)を抽出します。 - コマンドの実行: 抽出されたコマンドはパイプ (
|
) を通じてsh
に渡され、テストファイルのコンパイル (6g $i
) が行われる前に実行されます。
このメカニズムにより、例えば test.go
というテストファイルに以下のような行が含まれている場合:
// gotest: 6g my_test_dependency.go
package main
import "testing"
func TestSomething(t *testing.T) {
// ...
}
gotest
スクリプトは、TestSomething
のコンパイルを開始する前に 6g my_test_dependency.go
というコマンドを実行します。これにより、my_test_dependency.go
が事前にコンパイルされ、その結果が TestSomething
のコンパイル時に利用可能になります。
このアプローチは、現在の go generate
や go:build
タグ、あるいは go test
が提供するより洗練されたビルド・テスト統合機能の萌芽とも言えるものです。初期のGoツールチェインがまだ発展途上であった時期に、テストプロセスに柔軟性をもたらすための実用的なハックとして導入されました。
コアとなるコードの変更箇所
変更は src/cmd/gotest/gotest
ファイルの1箇所のみです。
--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -33,6 +33,11 @@ esac
ofiles=$(echo $gofiles | sed 's/\.go/.6/g')
files=$(echo $gofiles | sed 's/\.go//g')
+# Run any commands given in sources, like
+# // gotest: 6g foo.go
+# to build any test-only dependencies.
+sed -n 's/^\/\/ gotest: //p' $gofiles | sh
+
for i in $gofiles
do
6g $i
コアとなるコードの解説
追加された5行のコードは、gotest
スクリプトの主要な処理ループ(for i in $gofiles
で始まる部分)の直前に挿入されています。
# Run any commands given in sources, like
# // gotest: 6g foo.go
# to build any test-only dependencies.
sed -n 's/^\/\/ gotest: //p' $gofiles | sh
- コメント行: 最初の3行は、このコードブロックの目的を説明するコメントです。テストソースファイル内で
// gotest: 6g foo.go
のような形式でコマンドを指定できること、そしてそれがテスト専用の依存関係をビルドするために使われることを示しています。 sed -n 's/^\/\/ gotest: //p' $gofiles
:$gofiles
: これはgotest
スクリプトが処理するGoソースファイル(テストファイル)のリストを含むシェル変数です。sed -n 's/^\/\/ gotest: //p'
: このsed
コマンドは、$gofiles
内の各ファイルの内容を読み込みます。そして、各行が// gotest:
で始まる場合に、そのプレフィックスを削除した残りの部分を標準出力に出力します。-n
オプションは、パターンマッチングに成功した行(p
フラグで指定された行)のみを出力することを意味します。- 結果として、この部分のコマンドは、すべてのテストファイルから抽出された
gotest:
ディレクティブに続くコマンド群を、改行区切りで出力します。
| sh
:- パイプ (
|
) は、左側のコマンドの標準出力を右側のコマンドの標準入力に渡します。 sh
:sed
からの出力をシェルスクリプトとして実行します。つまり、sed
が抽出した各コマンド(例:6g my_test_dependency.go
)が、それぞれ独立したシェルコマンドとして実行されます。
- パイプ (
この一連の処理により、gotest
はテストファイルのコンパイルを開始する前に、テストファイル自体に埋め込まれた前処理コマンドを自動的に実行できるようになります。これは、当時のGoのビルドシステムにおける依存関係管理の柔軟性を高めるための、シンプルかつ効果的な解決策でした。
関連リンク
- Go言語の初期の歴史に関する情報: Go言語の公式ブログや初期の設計ドキュメントなどが参考になります。
sed
コマンドのドキュメント:man sed
やオンラインのUnixコマンドリファレンス。sh
(シェル) の基本的な使い方: シェルスクリプトの入門書やオンラインチュートリアル。
参考にした情報源リンク
- Go言語の公式リポジトリ (GitHub): https://github.com/golang/go
- Go言語の初期のコミット履歴: GitHubのコミット履歴を遡ることで、当時の開発状況やツールの進化を追うことができます。
- Go言語の初期のツールチェインに関する議論やドキュメント(もし公開されていれば)。
- Unix系コマンドラインツールの一般的なリファレンス。
- Go言語の歴史に関する記事やブログポスト。
- 特に、
6g
のような初期のコンパイラについては、Go言語の歴史を解説する記事や、Goのソースコードリポジトリ内のsrc/cmd
ディレクトリの初期のコミットが参考になります。 - Russ Cox氏のブログや発表資料(Go言語の設計や歴史に関するもの)。
- Go言語のメーリングリストアーカイブ(初期の議論が含まれている可能性)。```markdown
[インデックス 1539] ファイルの概要
このコミットは、Go言語の初期のテストツールである gotest
の機能拡張に関するものです。具体的には、テストソースファイル内に特別なコメント形式で記述されたコマンドを、コンパイル前に実行できるようにする変更が導入されています。これにより、テスト専用の依存関係のビルドなど、コンパイル前に必要な前処理を柔軟に行えるようになりました。
コミット
commit d9abca81c087448e305e4992d3056407a217f2cf
Author: Russ Cox <rsc@golang.org>
Date: Thu Jan 22 14:23:50 2009 -0800
let test sources specify commands to run
before their compilation.
R=r
OCL=23300
CL=23300
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d9abca81c087448e305e4992d3056407a217f2cf
元コミット内容
let test sources specify commands to run
before their compilation.
R=r
OCL=23300
CL=23300
変更の背景
Go言語の初期段階において、テストの実行環境は現在のような go test
コマンドとして統合されておらず、src/cmd/gotest/gotest
のようなシェルスクリプトがその役割を担っていました。この時期のテストプロセスでは、テスト対象のコードだけでなく、テスト自体が依存する特別なファイルやライブラリが存在する場合があります。例えば、テスト専用のモックオブジェクトやヘルパー関数が別のGoファイルとして定義されており、これらもテスト本体がコンパイルされる前にビルドされている必要がありました。
このコミット以前は、このようなテスト専用の依存関係を処理するための標準的なメカニズムが gotest
には存在しなかったと考えられます。そのため、開発者はテストを実行する際に手動でこれらの依存関係をビルドするか、gotest
スクリプト自体を直接変更する必要がありました。これは非効率的であり、テストのポータビリティを損なう問題でした。
この変更の背景には、テストの柔軟性と自動化を向上させ、テストコード内で必要な前処理を宣言的に指定できるようにするという意図があります。これにより、テストのセットアップがより簡単になり、テストの独立性が高まります。
前提知識の解説
このコミットを理解するためには、以下のGo言語およびUnix系ツールの初期の状況に関する知識が必要です。
-
Go言語の初期のビルドシステム:
6g
: 2009年当時のGo言語のコンパイラの一つです。Go言語は当初、Plan 9アーキテクチャに由来するツールチェイン(6g
for amd64,8g
for 386,5g
for ARMなど)を使用していました。これらは現在のgo build
コマンドが内部的に呼び出すコンパイラとは異なり、より低レベルな操作を直接行っていました。6g foo.go
はfoo.go
をコンパイルし、オブジェクトファイル(通常は.6
拡張子)を生成します。gotest
: このコミットが変更しているsrc/cmd/gotest/gotest
は、当時のGo言語のテストランナーのシェルスクリプトです。現在のgo test
コマンドのような統合されたツールではなく、テストファイルのコンパイル、リンク、実行を制御するシンプルなスクリプトでした。
-
Unix系コマンドラインツール:
sed
: Stream EDitor の略で、テキストの変換を行うコマンドラインツールです。このコミットでは、入力ストリームから特定のパターンにマッチする行を抽出し、その一部を置換するために使用されています。sed -n 's/^\/\/ gotest: //p'
の意味:-n
: デフォルトの出力を抑制します。s/^\/\/ gotest: //
: 行頭が// gotest:
で始まるパターンを検索し、そのパターンを空文字列に置換します。つまり、// gotest:
の部分を削除します。p
: 置換が成功した行のみを出力します。
- これにより、Goソースファイル内の
// gotest: <command>
という形式のコメントから<command>
の部分だけを抽出できます。
sh
: Bourne Shell またはその互換シェル(Bashなど)を指します。Unix系システムでコマンドを実行するためのインタプリタです。| sh
のようにパイプで渡された入力は、sh
によってコマンドとして解釈され実行されます。
-
Go言語のコメント:
- Go言語では
//
で始まる行は単一行コメントとして扱われます。このコミットでは、このコメント形式を特別な指示(ディレクティブ)を埋め込むために利用しています。
- Go言語では
技術的詳細
このコミットは、src/cmd/gotest/gotest
シェルスクリプトに以下の機能を追加します。
- ディレクティブの検出: テスト対象のGoソースファイル (
$gofiles
変数に含まれるファイル群) を走査し、// gotest:
で始まる行を検出します。 - コマンドの抽出:
sed
コマンドを使用して、検出された行から// gotest:
プレフィックスを取り除き、残りの部分(つまり、実行すべきコマンド)を抽出します。 - コマンドの実行: 抽出されたコマンドはパイプ (
|
) を通じてsh
に渡され、テストファイルのコンパイル (6g $i
) が行われる前に実行されます。
このメカニズムにより、例えば test.go
というテストファイルに以下のような行が含まれている場合:
// gotest: 6g my_test_dependency.go
package main
import "testing"
func TestSomething(t *testing.T) {
// ...
}
gotest
スクリプトは、TestSomething
のコンパイルを開始する前に 6g my_test_dependency.go
というコマンドを実行します。これにより、my_test_dependency.go
が事前にコンパイルされ、その結果が TestSomething
のコンパイル時に利用可能になります。
このアプローチは、現在の go generate
や go:build
タグ、あるいは go test
が提供するより洗練されたビルド・テスト統合機能の萌芽とも言えるものです。初期のGoツールチェインがまだ発展途上であった時期に、テストプロセスに柔軟性をもたらすための実用的なハックとして導入されました。
コアとなるコードの変更箇所
変更は src/cmd/gotest/gotest
ファイルの1箇所のみです。
--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -33,6 +33,11 @@ esac
ofiles=$(echo $gofiles | sed 's/\.go/.6/g')
files=$(echo $gofiles | sed 's/\.go//g')
+# Run any commands given in sources, like
+# // gotest: 6g foo.go
+# to build any test-only dependencies.
+sed -n 's/^\/\/ gotest: //p' $gofiles | sh
+
for i in $gofiles
do
6g $i
コアとなるコードの解説
追加された5行のコードは、gotest
スクリプトの主要な処理ループ(for i in $gofiles
で始まる部分)の直前に挿入されています。
# Run any commands given in sources, like
# // gotest: 6g foo.go
# to build any test-only dependencies.
sed -n 's/^\/\/ gotest: //p' $gofiles | sh
- コメント行: 最初の3行は、このコードブロックの目的を説明するコメントです。テストソースファイル内で
// gotest: 6g foo.go
のような形式でコマンドを指定できること、そしてそれがテスト専用の依存関係をビルドするために使われることを示しています。 sed -n 's/^\/\/ gotest: //p' $gofiles
:$gofiles
: これはgotest
スクリプトが処理するGoソースファイル(テストファイル)のリストを含むシェル変数です。sed -n 's/^\/\/ gotest: //p'
: このsed
コマンドは、$gofiles
内の各ファイルの内容を読み込みます。そして、各行が// gotest:
で始まる場合に、そのプレフィックスを削除した残りの部分を標準出力に出力します。-n
オプションは、パターンマッチングに成功した行(p
フラグで指定された行)のみを出力することを意味します。- 結果として、この部分のコマンドは、すべてのテストファイルから抽出された
gotest:
ディレクティブに続くコマンド群を、改行区切りで出力します。
| sh
:- パイプ (
|
) は、左側のコマンドの標準出力を右側のコマンドの標準入力に渡します。 sh
:sed
からの出力をシェルスクリプトとして実行します。つまり、sed
が抽出した各コマンド(例:6g my_test_dependency.go
)が、それぞれ独立したシェルコマンドとして実行されます。
- パイプ (
この一連の処理により、gotest
はテストファイルのコンパイルを開始する前に、テストファイル自体に埋め込まれた前処理コマンドを自動的に実行できるようになります。これは、当時のGoのビルドシステムにおける依存関係管理の柔軟性を高めるための、シンプルかつ効果的な解決策でした。
関連リンク
- Go言語の初期の歴史に関する情報: Go言語の公式ブログや初期の設計ドキュメントなどが参考になります。
sed
コマンドのドキュメント:man sed
やオンラインのUnixコマンドリファレンス。sh
(シェル) の基本的な使い方: シェルスクリプトの入門書やオンラインチュートリアル。
参考にした情報源リンク
- Go言語の公式リポジトリ (GitHub): https://github.com/golang/go
- Go言語の初期のコミット履歴: GitHubのコミット履歴を遡ることで、当時の開発状況やツールの進化を追うことができます。
- Go言語の初期のツールチェインに関する議論やドキュメント(もし公開されていれば)。
- Unix系コマンドラインツールの一般的なリファレンス。
- Go言語の歴史に関する記事やブログポスト。
- 特に、
6g
のような初期のコンパイラについては、Go言語の歴史を解説する記事や、Goのソースコードリポジトリ内のsrc/cmd
ディレクトリの初期のコミットが参考になります。 - Russ Cox氏のブログや発表資料(Go言語の設計や歴史に関するもの)。
- Go言語のメーリングリストアーカイブ(初期の議論が含まれている可能性)。