[インデックス 14990] ファイルの概要
このコミットは、Go言語のコマンドラインツールgoのテストスクリプトであるsrc/cmd/go/test.bashに、不足していたテストケースを追加するものです。具体的には、go getコマンドがGOPATHが設定されていない場合やGOPATHがGOROOTと同じディレクトリを指している場合に、パッケージを$GOROOTにダウンロードしようとしないことを検証するテストが追加されています。
コミット
cmd/go: add missing tests
These changes to test.bash were intended to be submitted with CL 6941058, but were accidentally excluded from the original CL.
R=golang-dev
CC=golang-dev
https://golang.org/cl/7232043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c48f7d6b8af8b1a8ced44453a9970801faeeb9f5
元コミット内容
cmd/go: add missing tests
このコミットは、test.bashへの変更であり、元々はCL 6941058という変更リスト(Change List)と共に提出される予定でしたが、誤って元のCLから除外されてしまったものです。
変更の背景
この変更の背景には、Go言語のツールチェインにおけるgo getコマンドの特定の挙動に関する問題、特にissue 4186が関係しています。go getは、Goのパッケージをダウンロードしてインストールするためのコマンドですが、その動作はGOPATHとGOROOTという2つの重要な環境変数に依存します。
GOPATHはGoのワークスペースのルートディレクトリを指定し、ユーザーが開発するGoのソースコード、パッケージ、実行可能ファイルが配置される場所です。一方、GOROOTはGoのSDK(標準ライブラリやツールチェイン自体)がインストールされているディレクトリを指します。
Goの設計思想として、ユーザーがダウンロードしたサードパーティのパッケージや自身のプロジェクトのコードはGOPATH内に配置されるべきであり、GOROOTはGoの標準ライブラリやツールチェインのコードを保持する場所として予約されています。go getコマンドが誤ってGOROOTにパッケージをダウンロードしようとすると、Goのインストールが破損したり、予期せぬ動作を引き起こす可能性があります。
このコミットで追加されたテストは、go getが以下の2つのシナリオで失敗することを確認するためのものです。
GOPATHが設定されていない場合 (GOPATH=)GOPATHがGOROOTと同じディレクトリを指している場合 (GOPATH=$GOROOT)
これらのシナリオでgo getが失敗することは、go getがGOROOTにパッケージをダウンロードしようとしないという期待される挙動を保証するために重要です。元のCL 6941058でこれらのテストが意図せず除外されたため、このコミットで改めて追加されました。
前提知識の解説
Go言語の環境変数 (GOPATH, GOROOT)
GOROOT: Goのインストールディレクトリを指します。Goの標準ライブラリやコンパイラ、その他のツールがここに格納されています。通常、ユーザーはこのディレクトリの内容を変更しません。GOPATH: Goのワークスペースのルートディレクトリを指します。Go 1.11以降のGo Modulesの導入によりその重要性は薄れましたが、それ以前のバージョンや特定のレガシーなビルドシステムでは依然として重要な役割を果たします。GOPATHは通常、以下の3つのサブディレクトリを持ちます。src: ソースコードが配置されます(例:github.com/user/project)。pkg: コンパイル済みのパッケージオブジェクトがキャッシュされます。bin: コンパイル済みの実行可能ファイルが配置されます。go getコマンドは、デフォルトでパッケージを$GOPATH/src以下にダウンロードします。
go getコマンド
go getは、リモートリポジトリからGoのパッケージをダウンロードし、必要に応じてビルド・インストールするコマンドです。例えば、go get github.com/some/packageと実行すると、指定されたパッケージが$GOPATH/src/github.com/some/packageにダウンロードされます。-dフラグを付けると、ダウンロードのみを行い、ビルド・インストールは行いません。
mktemp -d
mktemp -dは、一時的なユニークなディレクトリを作成するためのシェルコマンドです。テスト環境を隔離するために頻繁に使用されます。このコマンドは作成された一時ディレクトリのパスを標準出力に出力します。
code.google.com/p/go.codereview/cmd/hgpatch
これは、Google CodeでホストされていたGoプロジェクトのコードレビューツールに関連するパッケージのパスです。このパッケージ自体が重要なのではなく、go getがダウンロードを試みる対象として使用されている点が重要です。
src/cmd/go/test.bash
Goプロジェクトのソースツリー内にあるシェルスクリプトで、goコマンドラインツールの様々な機能のテストを実行するために使用されます。Goのビルドシステムやテストフレームワークの一部として機能します。
技術的詳細
このコミットで追加されたテストは、src/cmd/go/test.bashスクリプトの既存のテストスイートに組み込まれています。これらのテストは、go getコマンドがGOPATHの適切な設定なしにGOROOTにパッケージをダウンロードしようとしないという、Goツールチェインの重要なセキュリティおよび整合性ルールを強制します。
テストは以下の手順で実行されます。
- 一時ディレクトリの作成:
d=$(mktemp -d)とmkdir -p $d/src/pkgを使用して、テスト用のクリーンな一時ディレクトリ構造を作成します。これは、テストが既存のGOPATHやGOROOTの設定に影響を与えないようにするためです。 GOPATHが未設定の場合のテスト:GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatchを実行します。ここで、GOPATH=はGOPATHを空に設定し、GOROOT=$dは一時ディレクトリをGOROOTとして設定します。./testgoはテスト対象のgoコマンドのラッパーです。- このコマンドが成功した場合(
if条件が真の場合)、それはgo getがGOPATHが設定されていないにもかかわらずパッケージをダウンロードしてしまったことを意味するため、エラーメッセージを出力し、テストのokフラグをfalseに設定します。
GOPATHがGOROOTと同じ場合(GOPATH=$GOROOT)のテスト:- 同様に一時ディレクトリを作成します。
GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatchを実行します。ここではGOPATHとGOROOTの両方が同じ一時ディレクトリを指しています。- このコマンドが成功した場合、それは
go getがGOPATHがGOROOTと同じであるにもかかわらずパッケージをダウンロードしてしまったことを意味するため、エラーメッセージを出力し、テストのokフラグをfalseに設定します。
- 一時ディレクトリのクリーンアップ: 各テストの後に
rm -rf $dを実行して、作成した一時ディレクトリを削除し、テスト環境をクリーンに保ちます。
これらのテストは、go getがGOPATHの適切な設定なしにGOROOTに書き込みを行わないという、Goツールチェインの堅牢性を保証するために不可欠です。
コアとなるコードの変更箇所
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -181,6 +181,24 @@ if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)\
ok=false
fi
+# issue 4186. go get cannot be used to download packages to $GOROOT
+# Test that without GOPATH set, go get should fail
+d=$(mktemp -d)
+mkdir -p $d/src/pkg
+if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
+ echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'
+ ok=false
+fi
+rm -rf $d
+# Test that with GOPATH=$GOROOT, go get should fail
+d=$(mktemp -d)
+mkdir -p $d/src/pkg
+if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
+ echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
+ ok=false
+fi
+rm -rf $d
+
# clean up
rm -rf testdata/bin testdata/bin1
rm -f testgo
コアとなるコードの解説
追加されたコードブロックは、go getコマンドの特定の挙動をテストするためのものです。
-
# issue 4186. go get cannot be used to download packages to $GOROOT- この行は、このテストがGoのissue 4186に関連していることを示しています。このissueは、
go getが$GOROOTにパッケージをダウンロードできないという期待される挙動に関するものです。
- この行は、このテストがGoのissue 4186に関連していることを示しています。このissueは、
-
# Test that without GOPATH set, go get should fail- 最初のテストケースのコメントです。
GOPATHが設定されていない場合にgo getが失敗することを確認します。
- 最初のテストケースのコメントです。
-
d=$(mktemp -d)- 一時的なディレクトリを作成し、そのパスを変数
dに格納します。これはテストの隔離性を保つためです。
- 一時的なディレクトリを作成し、そのパスを変数
-
mkdir -p $d/src/pkg- 作成した一時ディレクトリ内に、Goのワークスペース構造に必要な
src/pkgディレクトリを作成します。
- 作成した一時ディレクトリ内に、Goのワークスペース構造に必要な
-
if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then- この行がテストの核心です。
GOPATH=:GOPATH環境変数を空に設定します。GOROOT=$d:GOROOT環境変数を先ほど作成した一時ディレクトリ$dに設定します。./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch:testgo(goコマンドのテスト用ラッパー)を使って、hgpatchパッケージをダウンロードしようとします。-dフラグはダウンロードのみを行い、ビルドは行いません。
if ... ; then:このコマンドが成功した場合(つまり、go getが予期せずパッケージをダウンロードしてしまった場合)に続くブロックが実行されます。
- この行がテストの核心です。
-
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'- テストが失敗した場合に表示されるエラーメッセージです。
-
ok=false- テストが失敗したことを示すフラグを設定します。
test.bashスクリプト全体でこのok変数が最終的なテスト結果を決定します。
- テストが失敗したことを示すフラグを設定します。
-
rm -rf $d- 最初のテストケースで使用した一時ディレクトリを削除し、クリーンアップします。
-
# Test that with GOPATH=$GOROOT, go get should fail- 2番目のテストケースのコメントです。
GOPATHがGOROOTと同じディレクトリを指している場合にgo getが失敗することを確認します。
- 2番目のテストケースのコメントです。
-
d=$(mktemp -d)- 2番目のテストケースのために、再度新しい一時ディレクトリを作成します。
-
mkdir -p $d/src/pkg- 新しい一時ディレクトリ内に
src/pkgを作成します。
- 新しい一時ディレクトリ内に
-
if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then- この行もテストの核心です。
GOPATH=$d:GOPATHを一時ディレクトリ$dに設定します。GOROOT=$d:GOROOTも一時ディレクトリ$dに設定します。- これにより、
GOPATHとGOROOTが同じ場所を指す状況をシミュレートします。
- このコマンドが成功した場合に続くブロックが実行されます。
- この行もテストの核心です。
-
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'- 2番目のテストが失敗した場合に表示されるエラーメッセージです。
-
ok=false- テストが失敗したことを示すフラグを設定します。
-
rm -rf $d- 2番目のテストケースで使用した一時ディレクトリを削除し、クリーンアップします。
これらのテストは、go getがGOPATHの適切な設定なしにGOROOTに書き込みを行わないという、Goツールチェインの堅牢性を保証するために不可欠です。
関連リンク
- https://golang.org/cl/7232043 (このコミットに対応するGoの変更リスト)
参考にした情報源リンク
- Go issue 4186: cmd/go: go get cannot be used to download packages to $GOROOT
- Go Modules Reference - The Go Programming Language (GOPATHとGo Modulesの関係について)
- Go Command - The Go Programming Language (
go getコマンドの詳細について) - mktemp man page (mktempコマンドについて)
- Go Code Review - Google Code Archive (hgpatchパッケージの元のホスティング場所)