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

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

このコミットは、Go言語のコマンドラインツールcmd/goにおけるgo test -iコマンドの挙動を修正するものです。具体的には、相対パスで指定されたテストパッケージの依存関係を処理する際に、ローカルインポートではないパスのみを対象とするように変更が加えられています。これにより、go test -i ./...のようなコマンド実行時に、ローカルのテストデータディレクトリなどが誤ってインストール対象に含まれてしまう問題を解決しています。

変更されたファイルは以下の2つです。

  • src/cmd/go/test.bash: go test -iコマンドの相対パスでのテストケースを追加しています。
  • src/cmd/go/test.go: go test -iコマンドの内部ロジックを修正し、ローカルインポートではないパスのみを依存関係として追加するように変更しています。

コミット

commit 34976b985a9e2d29c594daa2dfa4dd21ee4c4bf1
Author: Francisco Souza <franciscossouza@gmail.com>
Date:   Wed Aug 15 07:32:49 2012 -0700

    cmd/go: skipping relative paths on go test -i ./...
    
    Fixes #3896.
    
    R=rsc, rogpeppe, r
    CC=golang-dev
    https://golang.org/cl/6457075

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

https://github.com/golang/go/commit/34976b985a9e2d29c594daa2dfa4dd21ee4c4bf1

元コミット内容

diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index fe186d4bbc..587bcfc1f9 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -76,6 +76,12 @@ if ! ./testgo test ./testdata/testimport; then
  \tok=false
  fi
  
 +# Test installation with relative imports.
 +if ! ./testgo test -i ./testdata/testimport; then
 +    echo "go test -i ./testdata/testimport failed"
 +    ok=false
 +fi
 +
  # Test tests with relative imports in packages synthesized
  # from Go files named on the command line.
  if ! ./testgo test ./testdata/testimport/*.go; then
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 5f40bd64c0..cd9b411e9d 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -276,7 +276,9 @@ func runTest(cmd *Command, args []string) {
  
  	\tall := []string{}
  	\tfor path := range deps {\n-\t\t\tall = append(all, path)\n+\t\t\tif !build.IsLocalImport(path) {\n+\t\t\t\tall = append(all, path)\n+\t\t\t}\n  \t\t}\n  \t\tsort.Strings(all)\n  

変更の背景

この変更は、Go言語のIssue #3896「cmd/go: go test -i doesn't work if there are no Go files in the current directory.」を修正するために行われました。

元の問題は、go test -iコマンドが、カレントディレクトリにGoファイルが存在しない場合に正しく機能しないというものでした。特に、go test -i ./...のように相対パスとワイルドカードを組み合わせて使用した場合、テスト対象ではないローカルのディレクトリ(例えばテストデータが置かれたtestdataディレクトリなど)が誤って依存関係として認識され、インストール対象に含まれてしまうことがありました。これは、go test -iがテストパッケージとその依存関係をインストールしようとする際に、相対パスで指定されたディレクトリを適切にフィルタリングできていなかったためです。

このコミットは、go test -iがテストパッケージの依存関係を収集する際に、ローカルインポート(相対パスで指定されたパッケージ)をスキップすることで、この問題を解決しています。これにより、go test -iが意図しないディレクトリをインストールしようとすることを防ぎ、コマンドの正確な挙動を保証します。

前提知識の解説

go test -i コマンド

go testコマンドはGo言語のテストを実行するための主要なツールです。-iフラグは「install」を意味し、テストを実行する前にテストパッケージとその依存関係をインストールすることを指示します。これにより、テストの実行環境がクリーンな状態に保たれ、依存関係の解決が確実に行われることが期待されます。通常、go testはテストを実行するだけで依存関係のインストールは行いませんが、-iフラグを使用することで、テストの実行前に必要なパッケージがビルドされ、GOPATHのpkgディレクトリにインストールされます。

相対パスとパッケージのインポート

Go言語では、パッケージのインポートパスは通常、GOPATHまたはGo Modulesのルートからの絶対パスで指定されます(例: github.com/user/repo/package)。しかし、同じモジュール内やローカルのファイルシステム上にあるパッケージを参照する際には、相対パスを使用することも可能です(例: ./subpackage)。

build.IsLocalImport(path)

Go言語のgo/buildパッケージには、パッケージのインポートパスがローカルインポートであるかどうかを判定するためのIsLocalImport関数が存在します。この関数は、与えられたパスが...で始まる相対パスである場合にtrueを返します。この関数は、Goツールがパッケージの依存関係を解析し、ビルドやテストの際に適切な処理を行うために利用されます。

技術的詳細

このコミットの技術的な核心は、go test -iコマンドがテストパッケージの依存関係を収集するロジックにbuild.IsLocalImport関数を導入した点にあります。

go test -iは、テスト対象のパッケージが依存するすべてのパッケージを特定し、それらをインストールしようとします。この「すべてのパッケージ」には、標準ライブラリのパッケージ、サードパーティのパッケージ、そして同じプロジェクト内の他のローカルパッケージが含まれます。

問題は、./...のようなワイルドカードを含む相対パスが指定された場合、testdataのようなテストデータが格納されているディレクトリもパッケージとして認識され、そのパスが依存関係のリストdepsに含まれてしまうことでした。testdataディレクトリは通常、Goのソースファイルを含まないため、パッケージとしてビルド・インストールされるべきではありません。しかし、相対パスとして認識されるため、従来のロジックではこれをフィルタリングできませんでした。

この修正では、depsマップから取得した各pathに対してbuild.IsLocalImport(path)を呼び出し、その結果がfalse(つまり、ローカルインポートではない)の場合にのみ、そのパスをallスライスに追加するように変更しました。これにより、./testdata/testimportのようなローカルの相対パスはインストール対象から除外され、go test -iが意図しないディレクトリを処理しようとする問題が解決されました。

test.bashの変更は、この修正が正しく機能することを確認するためのテストケースの追加です。go test -i ./testdata/testimportというコマンドを実行し、それが成功することを確認しています。これは、修正によってローカルのテストデータディレクトリが正しくスキップされることを検証するものです。

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

src/cmd/go/test.bash

--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -76,6 +76,12 @@ if ! ./testgo test ./testdata/testimport; then
  \tok=false
  fi
  
 +# Test installation with relative imports.
 +if ! ./testgo test -i ./testdata/testimport; then
 +    echo "go test -i ./testdata/testimport failed"
 +    ok=false
 +fi
 +
  # Test tests with relative imports in packages synthesized
  # from Go files named on the command line.
  if ! ./testgo test ./testdata/testimport/*.go; then

src/cmd/go/test.go

--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -276,7 +276,9 @@ func runTest(cmd *Command, args []string) {
  
  	\tall := []string{}
  	\tfor path := range deps {\n-\t\t\tall = append(all, path)\n+\t\t\tif !build.IsLocalImport(path) {\n+\t\t\t\tall = append(all, path)\n+\t\t\t}\n  \t\t}\n  \t\tsort.Strings(all)\n  

コアとなるコードの解説

src/cmd/go/test.bash の変更

このファイルは、goコマンドのテストスクリプトです。追加された部分は、go test -iコマンドが相対パスで指定されたテストデータディレクトリに対して正しく動作するかどうかを検証するための新しいテストケースです。

+if ! ./testgo test -i ./testdata/testimport; then
+    echo "go test -i ./testdata/testimport failed"
+    ok=false
+fi

このコードは、./testgo test -i ./testdata/testimportというコマンドを実行しています。./testdata/testimportは、Goのパッケージとしては無効な、単なるテストデータが格納されたディレクトリを想定しています。修正前は、このコマンドがエラーになったり、意図しない動作をしたりする可能性がありました。修正後は、go test -iがこの相対パスをローカルインポートとして認識し、インストール対象からスキップするため、コマンドはエラーなく(または期待されるエラーで)終了するはずです。このテストケースの追加により、修正が意図通りに機能していることが自動的に検証されます。

src/cmd/go/test.go の変更

このファイルは、go testコマンドの主要なロジックを実装しています。変更された部分は、テストパッケージの依存関係を収集するループ内です。

 	all := []string{}
 	for path := range deps {
-		all = append(all, path)
+		if !build.IsLocalImport(path) {
+			all = append(all, path)
+		}
 	}
 	sort.Strings(all)

元のコードでは、depsマップ(テストパッケージの依存関係のパスがキーとして格納されている)から取得したすべてのpathを無条件にallスライスに追加していました。このallスライスは、その後、インストール対象のパッケージリストとして使用されます。

修正後のコードでは、all = append(all, path)の行がif !build.IsLocalImport(path) { all = append(all, path) }という条件文で囲まれています。

  • build.IsLocalImport(path): この関数は、path...で始まる相対パスである場合にtrueを返します。
  • !build.IsLocalImport(path): この条件は、「pathがローカルインポートではない場合」を意味します。

したがって、この変更により、depsに含まれるパスのうち、ローカルインポートではない(つまり、GOPATHやGo Modulesのルートからの絶対パスで指定されるような)パッケージのみがallスライスに追加されるようになりました。これにより、./testdata/testimportのようなローカルの相対パスは、go test -iのインストール対象から除外され、問題が解決されます。

関連リンク

参考にした情報源リンク