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

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

このコミットは、Go言語のコマンドラインツールgoのテストスクリプトであるsrc/cmd/go/test.bashに、不足していたテストケースを追加するものです。具体的には、go getコマンドがGOPATHが設定されていない場合やGOPATHGOROOTと同じディレクトリを指している場合に、パッケージを$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のパッケージをダウンロードしてインストールするためのコマンドですが、その動作はGOPATHGOROOTという2つの重要な環境変数に依存します。

GOPATHはGoのワークスペースのルートディレクトリを指定し、ユーザーが開発するGoのソースコード、パッケージ、実行可能ファイルが配置される場所です。一方、GOROOTはGoのSDK(標準ライブラリやツールチェイン自体)がインストールされているディレクトリを指します。

Goの設計思想として、ユーザーがダウンロードしたサードパーティのパッケージや自身のプロジェクトのコードはGOPATH内に配置されるべきであり、GOROOTはGoの標準ライブラリやツールチェインのコードを保持する場所として予約されています。go getコマンドが誤ってGOROOTにパッケージをダウンロードしようとすると、Goのインストールが破損したり、予期せぬ動作を引き起こす可能性があります。

このコミットで追加されたテストは、go getが以下の2つのシナリオで失敗することを確認するためのものです。

  1. GOPATHが設定されていない場合 (GOPATH=)
  2. GOPATHGOROOTと同じディレクトリを指している場合 (GOPATH=$GOROOT)

これらのシナリオでgo getが失敗することは、go getGOROOTにパッケージをダウンロードしようとしないという期待される挙動を保証するために重要です。元の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ツールチェインの重要なセキュリティおよび整合性ルールを強制します。

テストは以下の手順で実行されます。

  1. 一時ディレクトリの作成: d=$(mktemp -d)mkdir -p $d/src/pkgを使用して、テスト用のクリーンな一時ディレクトリ構造を作成します。これは、テストが既存のGOPATHGOROOTの設定に影響を与えないようにするためです。
  2. GOPATHが未設定の場合のテスト:
    • GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatchを実行します。ここで、GOPATH=GOPATHを空に設定し、GOROOT=$dは一時ディレクトリをGOROOTとして設定します。./testgoはテスト対象のgoコマンドのラッパーです。
    • このコマンドが成功した場合(if条件が真の場合)、それはgo getGOPATHが設定されていないにもかかわらずパッケージをダウンロードしてしまったことを意味するため、エラーメッセージを出力し、テストのokフラグをfalseに設定します。
  3. GOPATHGOROOTと同じ場合(GOPATH=$GOROOT)のテスト:
    • 同様に一時ディレクトリを作成します。
    • GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatchを実行します。ここではGOPATHGOROOTの両方が同じ一時ディレクトリを指しています。
    • このコマンドが成功した場合、それはgo getGOPATHGOROOTと同じであるにもかかわらずパッケージをダウンロードしてしまったことを意味するため、エラーメッセージを出力し、テストのokフラグをfalseに設定します。
  4. 一時ディレクトリのクリーンアップ: 各テストの後にrm -rf $dを実行して、作成した一時ディレクトリを削除し、テスト環境をクリーンに保ちます。

これらのテストは、go getGOPATHの適切な設定なしに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コマンドの特定の挙動をテストするためのものです。

  1. # issue 4186. go get cannot be used to download packages to $GOROOT

    • この行は、このテストがGoのissue 4186に関連していることを示しています。このissueは、go get$GOROOTにパッケージをダウンロードできないという期待される挙動に関するものです。
  2. # Test that without GOPATH set, go get should fail

    • 最初のテストケースのコメントです。GOPATHが設定されていない場合にgo getが失敗することを確認します。
  3. d=$(mktemp -d)

    • 一時的なディレクトリを作成し、そのパスを変数dに格納します。これはテストの隔離性を保つためです。
  4. mkdir -p $d/src/pkg

    • 作成した一時ディレクトリ内に、Goのワークスペース構造に必要なsrc/pkgディレクトリを作成します。
  5. if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then

    • この行がテストの核心です。
      • GOPATH=GOPATH環境変数を空に設定します。
      • GOROOT=$dGOROOT環境変数を先ほど作成した一時ディレクトリ$dに設定します。
      • ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatchtestgogoコマンドのテスト用ラッパー)を使って、hgpatchパッケージをダウンロードしようとします。-dフラグはダウンロードのみを行い、ビルドは行いません。
    • if ... ; then:このコマンドが成功した場合(つまり、go getが予期せずパッケージをダウンロードしてしまった場合)に続くブロックが実行されます。
  6. echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'

    • テストが失敗した場合に表示されるエラーメッセージです。
  7. ok=false

    • テストが失敗したことを示すフラグを設定します。test.bashスクリプト全体でこのok変数が最終的なテスト結果を決定します。
  8. rm -rf $d

    • 最初のテストケースで使用した一時ディレクトリを削除し、クリーンアップします。
  9. # Test that with GOPATH=$GOROOT, go get should fail

    • 2番目のテストケースのコメントです。GOPATHGOROOTと同じディレクトリを指している場合にgo getが失敗することを確認します。
  10. d=$(mktemp -d)

    • 2番目のテストケースのために、再度新しい一時ディレクトリを作成します。
  11. mkdir -p $d/src/pkg

    • 新しい一時ディレクトリ内にsrc/pkgを作成します。
  12. if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then

    • この行もテストの核心です。
      • GOPATH=$dGOPATHを一時ディレクトリ$dに設定します。
      • GOROOT=$dGOROOTも一時ディレクトリ$dに設定します。
      • これにより、GOPATHGOROOTが同じ場所を指す状況をシミュレートします。
    • このコマンドが成功した場合に続くブロックが実行されます。
  13. echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'

    • 2番目のテストが失敗した場合に表示されるエラーメッセージです。
  14. ok=false

    • テストが失敗したことを示すフラグを設定します。
  15. rm -rf $d

    • 2番目のテストケースで使用した一時ディレクトリを削除し、クリーンアップします。

これらのテストは、go getGOPATHの適切な設定なしにGOROOTに書き込みを行わないという、Goツールチェインの堅牢性を保証するために不可欠です。

関連リンク

参考にした情報源リンク