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

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

このコミットは、Go言語の標準ライブラリ path/filepath パッケージのテストファイルである src/pkg/path/filepath/path_test.go に関連するものです。このファイルは、ファイルパスの操作、特にシンボリックリンクの評価やパスの結合など、様々なシナリオにおける path/filepath パッケージの機能が正しく動作するかを検証するための単体テストを含んでいます。

コミット

path/filepath パッケージのテストを修正し、シンボリックリンクされた GOROOT 環境下でもテストが正常に実行できるようにしました。

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

https://github.com/golang/go/commit/24075d33a502889a54ae25195c3f9ae6bceb6628

元コミット内容

path/filepath: fix test

Make it possible to run test over symlinked GOROOT.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6268046

変更の背景

この変更の背景には、Go言語の開発環境において GOROOT 環境変数がシンボリックリンクを指している場合に、一部のテストが失敗するという問題がありました。具体的には、TestBug3486 というテストケースが、GOROOT の実際のパスではなくシンボリックリンクのパスをそのまま使用しようとしたため、期待されるファイルパスの解決に失敗していました。

Goのビルドシステムやテストフレームワークは、GOROOT をGoの標準ライブラリやツールがインストールされているルートディレクトリとして参照します。しかし、開発者が柔軟な環境設定のために GOROOT をシンボリックリンクとして設定することがあります。例えば、異なるバージョンのGoを切り替えるために GOROOT をシンボリックリンクで管理するケースなどが考えられます。

このような環境で path/filepath パッケージのテストを実行すると、テスト内部で os.Getenv("GOROOT") を使って取得したパスがシンボリックリンクのパスのままであり、その後のパス操作(filepath.Joinなど)が期待通りの結果を返さないことがありました。このコミットは、この問題を解決し、シンボリックリンクされた GOROOT 環境でもテストが堅牢に動作するようにするためのものです。

前提知識の解説

  • GOROOT: Go言語の環境変数の一つで、Goのインストールディレクトリのルートパスを指定します。Goのコンパイラ、標準ライブラリ、ツールなどがこのディレクトリ以下に配置されています。Goのプログラムをビルド・実行する際に、この GOROOT を参照して必要なリソースを見つけます。
  • シンボリックリンク (Symbolic Link / Symlink): ファイルシステムにおける特殊なファイルの一種で、他のファイルやディレクトリへの参照(ポインタ)として機能します。シンボリックリンク自体はデータを含まず、参照先のパス情報のみを持ちます。これにより、実際のファイルやディレクトリが別の場所に存在していても、シンボリックリンクを介してアクセスできるようになります。UNIX系OSでは ln -s コマンドで作成されます。
  • os.Getenv(key string) string: Go言語の os パッケージに含まれる関数で、指定された環境変数の値を取得します。この関数は、環境変数が設定されていない場合は空文字列を返します。
  • filepath.EvalSymlinks(path string) (string, error): Go言語の path/filepath パッケージに含まれる関数で、指定されたパスに含まれるすべてのシンボリックリンクを評価し、最終的な物理パスを返します。例えば、/usr/local/go/opt/go1.18 へのシンボリックリンクである場合、filepath.EvalSymlinks("/usr/local/go")/opt/go1.18 を返します。シンボリックリンクが存在しない場合は、元のパスがそのまま返されます。エラーが発生した場合は error を返します。
  • t.Fatal(args ...interface{}): Go言語のテストフレームワーク (testing パッケージ) で使用されるメソッドです。このメソッドが呼び出されると、テストは失敗とマークされ、現在のテスト関数は直ちに実行を停止します。通常、致命的なエラーが発生した場合にテストを中断するために使用されます。

技術的詳細

このコミットの技術的な核心は、GOROOT 環境変数の値がシンボリックリンクである場合に、そのシンボリックリンクを解決して実際の物理パスを取得することにあります。

元のコードでは、TestBug3486 テスト内で root := os.Getenv("GOROOT") を使用して GOROOT の値を取得していました。この root 変数は、GOROOT がシンボリックリンクである場合、シンボリックリンク自体のパス(例: /usr/local/go)を保持していました。その後の処理で filepath.Join(root, "lib")filepath.Join(root, "src") のようにパスを結合すると、シンボリックリンクのパスを基点とした相対パスが生成されます。

しかし、TestBug3486 は、Goのソースツリー内の特定のファイルやディレクトリ(例: GOROOT/src)の存在を検証するテストであり、シンボリックリンクを解決した後の物理パスに基づいてこれらのファイルが存在することを期待していました。シンボリックリンクのパスをそのまま使用すると、テストが期待する物理パスと一致せず、ファイルが見つからないなどの理由でテストが失敗していました。

この問題を解決するため、変更後のコードでは root, err := filepath.EvalSymlinks(os.Getenv("GOROOT")) を導入しました。これにより、os.Getenv("GOROOT") で取得したシンボリックリンクのパスが filepath.EvalSymlinks によって物理パスに解決されます。例えば、GOROOT/usr/local/go で、それが /opt/go1.18 へのシンボリックリンクである場合、root 変数には /opt/go1.18 が格納されるようになります。

また、filepath.EvalSymlinks はエラーを返す可能性があるため、if err != nil { t.Fatal(err) } というエラーハンドリングが追加されました。これにより、シンボリックリンクの解決に失敗した場合(例えば、参照先のファイルやディレクトリが存在しない場合など)には、テストが適切に失敗し、その原因が報告されるようになります。

この修正により、TestBug3486GOROOT がシンボリックリンクであっても、常にGoの実際のインストールディレクトリを基点としてパスを解決できるようになり、テストの堅牢性が向上しました。

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

--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -876,7 +876,10 @@ func TestDriveLetterInEvalSymlinks(t *testing.T) {
 }
 
 func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
-	root := os.Getenv("GOROOT")
+	root, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
+	if err != nil {
+		t.Fatal(err)
+	}
 	lib := filepath.Join(root, "lib")
 	src := filepath.Join(root, "src")
 	seenSrc := false

コアとなるコードの解説

変更は src/pkg/path/filepath/path_test.go ファイル内の TestBug3486 関数に集中しています。

  1. 変更前:

    root := os.Getenv("GOROOT")
    

    この行では、GOROOT 環境変数の値を直接取得し、それを root 変数に代入していました。GOROOT がシンボリックリンクの場合、root にはシンボリックリンクのパスがそのまま格納されていました。

  2. 変更後:

    root, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
    if err != nil {
    	t.Fatal(err)
    }
    
    • os.Getenv("GOROOT")GOROOT 環境変数の値を取得します。
    • 取得した値を filepath.EvalSymlinks() 関数に渡します。この関数は、パスに含まれるシンボリックリンクを解決し、最終的な物理パスを返します。
    • filepath.EvalSymlinks() は、解決されたパスとエラーの2つの値を返します。これらはそれぞれ rooterr 変数に代入されます。
    • if err != nil { t.Fatal(err) } のブロックは、filepath.EvalSymlinks() の実行中にエラーが発生した場合(例: シンボリックリンクの解決に失敗した場合)に、テストを即座に失敗させるためのエラーハンドリングです。これにより、テストの実行が中断され、エラーの詳細が報告されます。

この変更により、root 変数には常に GOROOT の物理パスが格納されるようになり、その後の filepath.Join などのパス操作が、シンボリックリンクの有無にかかわらず、常に正しい物理パスを基点として行われるようになりました。これにより、TestBug3486 がシンボリックリンクされた GOROOT 環境でも期待通りに動作するようになります。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語の標準ライブラリ path/filepath パッケージのテストファイルである src/pkg/path/filepath/path_test.go に関連するものです。このファイルは、ファイルパスの操作、特にシンボリックリンクの評価やパスの結合など、様々なシナリオにおける path/filepath パッケージの機能が正しく動作するかを検証するための単体テストを含んでいます。

コミット

path/filepath パッケージのテストを修正し、シンボリックリンクされた GOROOT 環境下でもテストが正常に実行できるようにしました。

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

https://github.com/golang/go/commit/24075d33a502889a54ae25195c3f9ae6bceb6628

元コミット内容

path/filepath: fix test

Make it possible to run test over symlinked GOROOT.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6268046

変更の背景

この変更の背景には、Go言語の開発環境において GOROOT 環境変数がシンボリックリンクを指している場合に、一部のテストが失敗するという問題がありました。具体的には、TestBug3486 というテストケースが、GOROOT の実際のパスではなくシンボリックリンクのパスをそのまま使用しようとしたため、期待されるファイルパスの解決に失敗していました。

Goのビルドシステムやテストフレームワークは、GOROOT をGoの標準ライブラリやツールがインストールされているルートディレクトリとして参照します。しかし、開発者が柔軟な環境設定のために GOROOT をシンボリックリンクとして設定することがあります。例えば、異なるバージョンのGoを切り替えるために GOROOT をシンボリックリンクで管理するケースなどが考えられます。

このような環境で path/filepath パッケージのテストを実行すると、テスト内部で os.Getenv("GOROOT") を使って取得したパスがシンボリックリンクのパスのままであり、その後のパス操作(filepath.Joinなど)が期待通りの結果を返さないことがありました。このコミットは、この問題を解決し、シンボリックリンクされた GOROOT 環境でもテストが堅牢に動作するようにするためのものです。

前提知識の解説

  • GOROOT: Go言語の環境変数の一つで、Goのインストールディレクトリのルートパスを指定します。Goのコンパイラ、標準ライブラリ、ツールなどがこのディレクトリ以下に配置されています。Goのプログラムをビルド・実行する際に、この GOROOT を参照して必要なリソースを見つけます。
  • シンボリックリンク (Symbolic Link / Symlink): ファイルシステムにおける特殊なファイルの一種で、他のファイルやディレクトリへの参照(ポインタ)として機能します。シンボリックリンク自体はデータを含まず、参照先のパス情報のみを持ちます。これにより、実際のファイルやディレクトリが別の場所に存在していても、シンボリックリンクを介してアクセスできるようになります。UNIX系OSでは ln -s コマンドで作成されます。
  • os.Getenv(key string) string: Go言語の os パッケージに含まれる関数で、指定された環境変数の値を取得します。この関数は、環境変数が設定されていない場合は空文字列を返します。
  • filepath.EvalSymlinks(path string) (string, error): Go言語の path/filepath パッケージに含まれる関数で、指定されたパスに含まれるすべてのシンボリックリンクを評価し、最終的な物理パスを返します。例えば、/usr/local/go/opt/go1.18 へのシンボリックリンクである場合、filepath.EvalSymlinks("/usr/local/go")/opt/go1.18 を返します。シンボリックリンクが存在しない場合は、元のパスがそのまま返されます。エラーが発生した場合は error を返します。
  • t.Fatal(args ...interface{}): Go言語のテストフレームワーク (testing パッケージ) で使用されるメソッドです。このメソッドが呼び出されると、テストは失敗とマークされ、現在のテスト関数は直ちに実行を停止します。通常、致命的なエラーが発生した場合にテストを中断するために使用されます。

技術的詳細

このコミットの技術的な核心は、GOROOT 環境変数の値がシンボリックリンクである場合に、そのシンボリックリンクを解決して実際の物理パスを取得することにあります。

元のコードでは、TestBug3486 テスト内で root := os.Getenv("GOROOT") を使用して GOROOT の値を取得していました。この root 変数は、GOROOT がシンボリックリンクである場合、シンボリックリンク自体のパス(例: /usr/local/go)を保持していました。その後の処理で filepath.Join(root, "lib")filepath.Join(root, "src") のようにパスを結合すると、シンボリックリンクのパスを基点とした相対パスが生成されます。

しかし、TestBug3486 は、Goのソースツリー内の特定のファイルやディレクトリ(例: GOROOT/src)の存在を検証するテストであり、シンボリックリンクを解決した後の物理パスに基づいてこれらのファイルが存在することを期待していました。シンボリックリンクのパスをそのまま使用すると、テストが期待する物理パスと一致せず、ファイルが見つからないなどの理由でテストが失敗していました。

この問題を解決するため、変更後のコードでは root, err := filepath.EvalSymlinks(os.Getenv("GOROOT")) を導入しました。これにより、os.Getenv("GOROOT") で取得したシンボリックリンクのパスが filepath.EvalSymlinks によって物理パスに解決されます。例えば、GOROOT/usr/local/go で、それが /opt/go1.18 へのシンボリックリンクである場合、root 変数には /opt/go1.18 が格納されるようになります。

また、filepath.EvalSymlinks はエラーを返す可能性があるため、if err != nil { t.Fatal(err) } というエラーハンドリングが追加されました。これにより、シンボリックリンクの解決に失敗した場合(例えば、参照先のファイルやディレクトリが存在しない場合など)には、テストが適切に失敗し、その原因が報告されるようになります。

この修正により、TestBug3486GOROOT がシンボリックリンクであっても、常にGoの実際のインストールディレクトリを基点としてパスを解決できるようになり、テストの堅牢性が向上しました。

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

--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -876,7 +876,10 @@ func TestDriveLetterInEvalSymlinks(t *testing.T) {
 }
 
 func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
-	root := os.Getenv("GOROOT")
+	root, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
+	if err != nil {
+		t.Fatal(err)
+	}
 	lib := filepath.Join(root, "lib")
 	src := filepath.Join(root, "src")
 	seenSrc := false

コアとなるコードの解説

変更は src/pkg/path/filepath/path_test.go ファイル内の TestBug3486 関数に集中しています。

  1. 変更前:

    root := os.Getenv("GOROOT")
    

    この行では、GOROOT 環境変数の値を直接取得し、それを root 変数に代入していました。GOROOT がシンボリックリンクの場合、root にはシンボリックリンクのパスがそのまま格納されていました。

  2. 変更後:

    root, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
    if err != nil {
    	t.Fatal(err)
    }
    
    • os.Getenv("GOROOT")GOROOT 環境変数の値を取得します。
    • 取得した値を filepath.EvalSymlinks() 関数に渡します。この関数は、パスに含まれるシンボリックリンクを解決し、最終的な物理パスを返します。
    • filepath.EvalSymlinks() は、解決されたパスとエラーの2つの値を返します。これらはそれぞれ rooterr 変数に代入されます。
    • if err != nil { t.Fatal(err) } のブロックは、filepath.EvalSymlinks() の実行中にエラーが発生した場合(例: シンボリックリンクの解決に失敗した場合)に、テストを即座に失敗させるためのエラーハンドリングです。これにより、テストの実行が中断され、エラーの詳細が報告されます。

この変更により、root 変数には常に GOROOT の物理パスが格納されるようになり、その後の filepath.Join などのパス操作が、シンボリックリンクの有無にかかわらず、常に正しい物理パスを基点として行われるようになりました。これにより、TestBug3486 がシンボリックリンクされた GOROOT 環境でも期待通りに動作するようになります。

関連リンク

参考にした情報源リンク