[インデックス 17216] ファイルの概要
このコミットは、Go言語のgo get
コマンドに-t
フラグを追加し、指定されたパッケージのテストに必要な依存関係もダウンロードできるようにするものです。これにより、開発者がテスト環境をより簡単にセットアップできるようになります。
コミット
commit 5dde7ccecf22a345535721c78a34879755de1fc0
Author: Andrew Gerrand <adg@golang.org>
Date: Wed Aug 14 11:01:17 2013 +1000
cmd/go: add -t flag to 'go get' to download test dependencies
Fixes #5126.
R=golang-dev, dsymonds, bradfitz, r, rsc, rogpeppe
CC=golang-dev
https://golang.org/cl/12566046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5dde7ccecf22a345535721c78a34879755de1fc0
元コミット内容
cmd/go: add -t flag to 'go get' to download test dependencies
このコミットは、go get
コマンドに-t
フラグを追加し、テストの依存関係もダウンロードするようにします。
関連するIssue: #5126
変更の背景
Go言語のプロジェクトでは、通常、アプリケーションのビルドに必要な依存関係はgo get
コマンドによって自動的に解決され、ダウンロードされます。しかし、これまでのgo get
は、パッケージのテストコードが依存するパッケージ(テスト依存関係)を自動的にダウンロードする機能を持っていませんでした。
開発者がGoパッケージをクローンし、そのパッケージのテストを実行しようとした場合、テストコードが外部パッケージに依存していると、それらの依存関係が不足しているためにテストが失敗するという問題がありました。これは、特にCI/CD環境や、新しい開発者がプロジェクトに参加する際に、手動でテスト依存関係を解決する必要があるという手間を生んでいました。
このコミットは、この問題を解決するために、go get
コマンドに-t
フラグを導入しました。-t
フラグを使用することで、go get
は通常のビルド依存関係に加えて、テストに必要な依存関係も自動的にダウンロードするようになります。これにより、開発者はよりスムーズにプロジェクトのテスト環境を構築できるようになり、開発体験が向上します。
関連するIssueである#5126
は、この機能の必要性を示唆していたものと考えられます。
前提知識の解説
Go Modulesと依存関係管理 (コミット当時の状況)
このコミットが行われた2013年時点では、Go Modulesはまだ存在せず、Goの依存関係管理は主にGOPATH
とgo get
コマンドに依存していました。
- GOPATH: Goのワークスペースのルートディレクトリを指す環境変数です。すべてのGoのソースコード、コンパイル済みバイナリ、パッケージは
GOPATH
内に配置されます。 go get
コマンド: 指定されたインポートパスのパッケージとその依存関係をダウンロードし、GOPATH
内の適切な場所に配置するコマンドです。通常、ダウンロードされたパッケージは自動的にビルドされ、インストールされます。- パッケージのインポート: Goのソースコードでは、
import "path/to/package"
のように記述することで、他のパッケージの機能を利用できます。go get
はこのインポートパスを解析して依存関係を解決します。 - テストパッケージとテスト依存関係: Goでは、通常のパッケージコードとは別に、テストコードを記述するための慣習があります。
- 内部テスト: 同じパッケージ内のテストは、
_test.go
ファイルに記述され、同じパッケージ名を使用します。これらのテストは、パッケージの内部要素にアクセスできます。 - 外部テスト: テストコードがテスト対象のパッケージとは異なるパッケージとして扱われる場合、パッケージ名の末尾に
_test
を付けます(例:package mypackage_test
)。これにより、テストコードはテスト対象パッケージのエクスポートされた要素のみにアクセスできます。外部テストは、テスト対象パッケージの公開APIのみをテストする際に有用です。 - テスト依存関係: テストコード(
_test.go
ファイル内)が、通常のアプリケーションコードでは使用しないが、テストの実行にのみ必要な外部パッケージをインポートすることがあります。これらが「テスト依存関係」です。例えば、モックライブラリやテストユーティリティなどがこれに該当します。
- 内部テスト: 同じパッケージ内のテストは、
このコミット以前のgo get
は、通常のビルド依存関係は解決しましたが、_test.go
ファイル内でインポートされているテスト依存関係は考慮していませんでした。
技術的詳細
このコミットの技術的な核心は、go get
コマンドの内部ロジックを変更し、-t
フラグが指定された場合にテスト依存関係もダウンロードの対象に含めるようにした点です。
Goのパッケージは、go/build
パッケージ(またはその内部的な機能)によって解析され、そのパッケージが依存する他のパッケージのインポートパスが特定されます。このインポートパスには、通常のコードがインポートするパッケージ(p.Deps
)と、テストコードがインポートするパッケージ(p.TestImports
およびp.XTestImports
)が含まれます。
変更前は、go get
のdownload
関数は主にp.Deps
のみを再帰的にダウンロードしていました。このコミットでは、download
関数にgetTestDeps
という新しいブール引数を追加し、この引数がtrue
の場合にp.TestImports
とp.XTestImports
もダウンロードするように拡張しました。
重要なのは、テスト依存関係をダウンロードする際の再帰的な呼び出しです。download(path, stk, false)
のように、テスト依存関係のさらにその先のテスト依存関係はダウンロードしないように制御されています。これは、テスト依存関係の依存関係まで深く追跡すると、ダウンロードされるパッケージの数が膨大になり、不必要に多くのリソースを消費する可能性があるためです。通常、テストのテスト依存関係までを自動的に解決する必要性は低いと判断されたため、この制限が設けられています。
この変更により、go get -t
を実行すると、指定されたパッケージのビルドに必要なすべての依存関係と、そのパッケージのテストを実行するために必要なすべての依存関係が、自動的にGOPATH
にダウンロードされるようになります。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルは以下の2つです。
src/cmd/go/doc.go
:go get
コマンドのヘルプドキュメントを更新し、-t
フラグとその説明を追加しています。src/cmd/go/get.go
:go get
コマンドの実際のロジックが実装されているファイルです。
src/cmd/go/doc.go
の変更
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -236,7 +236,7 @@ Download and install packages and dependencies
Usage:
- go get [-d] [-fix] [-u] [build flags] [packages]
+ go get [-d] [-fix] [-t] [-u] [build flags] [packages]
Get downloads and installs the packages named by the import paths,
along with their dependencies.
@@ -247,6 +247,9 @@ it instructs get not to install the packages.
The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.
+The -t flag instructs get to also download the packages required to build
+the tests for the specified packages.
+
The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
src/cmd/go/get.go
の変更
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -18,7 +18,7 @@ import (
)
var cmdGet = &Command{
- UsageLine: "get [-d] [-fix] [-u] [build flags] [packages]",
+ UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
Short: "download and install packages and dependencies",
Long: `
Get downloads and installs the packages named by the import paths,
@@ -30,6 +30,9 @@ it instructs get not to install the packages.
The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.
+The -t flag instructs get to also download the packages required to build
+the tests for the specified packages.
+
The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
@@ -53,6 +56,7 @@ See also: go build, go install, go clean.
}
var getD = cmdGet.Flag.Bool("d", false, "")
+var getT = cmdGet.Flag.Bool("t", false, "")
var getU = cmdGet.Flag.Bool("u", false, "")
var getFix = cmdGet.Flag.Bool("fix", false, "")
@@ -65,7 +69,7 @@ func runGet(cmd *Command, args []string) {
// Phase 1. Download/update.
var stk importStack
for _, arg := range downloadPaths(args) {
-\t\tdownload(arg, &stk)\n+\t\tdownload(arg, &stk, *getT)\n \t}\n \texitIfErrors()\n \n@@ -137,7 +141,7 @@ var downloadRootCache = map[string]bool{}\n \n // download runs the download half of the get command
// for the package named by the argument.\n-func download(arg string, stk *importStack) {\n+func download(arg string, stk *importStack, getTestDeps bool) {\n \tp := loadPackage(arg, stk)\n \n \t// There\'s nothing to do if this is a package in the standard library.\n@@ -216,7 +220,18 @@ func download(arg string, stk *importStack) {\n \n \t\t// Process dependencies, now that we know what they are.\n \t\tfor _, dep := range p.deps {\n-\t\t\tdownload(dep.ImportPath, stk)\n+\t\t\tdownload(dep.ImportPath, stk, false)\n+\t\t}\n+\t\tif getTestDeps {\n+\t\t\t// Process test dependencies when -t is specified.\n+\t\t\t// (Don\'t get test dependencies for test dependencies.)\n+\t\t\tfor _, path := range p.TestImports {\n+\t\t\t\tdownload(path, stk, false)\n+\t\t\t}\n+\t\t\tfor _, path := range p.XTestImports {\n+\t\t\t\tdownload(path, stk, false)\n+\t\t\t}\n \t\t}\n \t}\n }\n```
## コアとなるコードの解説
### `src/cmd/go/doc.go` の変更点
* `UsageLine`の更新: `go get`コマンドの利用方法を示す行に`-t`フラグが追加されました。
* `-t`フラグの説明の追加: `go get`のヘルプテキストに、`-t`フラグが「指定されたパッケージのテストをビルドするために必要なパッケージもダウンロードする」という説明が追加されました。これはユーザーがコマンドの機能を理解するために不可欠なドキュメントの更新です。
### `src/cmd/go/get.go` の変更点
1. **`UsageLine`の更新**: `doc.go`と同様に、`cmdGet`構造体の`UsageLine`フィールドに`-t`フラグが追加されています。
2. **`-t`フラグの定義**:
```go
var getT = cmdGet.Flag.Bool("t", false, "")
```
`getT`という名前のブール型フラグが定義されました。これはコマンドラインで`-t`が指定された場合に`true`になります。`cmdGet.Flag.Bool`は、Goの`flag`パッケージの機能を利用してコマンドライン引数を解析するためのものです。
3. **`runGet`関数内の`download`呼び出しの変更**:
```diff
-\t\tdownload(arg, &stk)\n+\t\tdownload(arg, &stk, *getT)\n ```
`runGet`関数は`go get`コマンドのエントリポイントの一つで、各引数(パッケージパス)に対して`download`関数を呼び出します。この変更により、`download`関数に新しく定義された`getT`フラグの値(ポインタをデリファレンスしてブール値)が渡されるようになりました。これにより、`download`関数内で`-t`フラグが指定されたかどうかを判断できるようになります。
4. **`download`関数のシグネチャ変更**:
```diff
-func download(arg string, stk *importStack) {
+func download(arg string, stk *importStack, getTestDeps bool) {
```
`download`関数は、パッケージのダウンロードと依存関係の解決を行う主要な関数です。この変更により、`getTestDeps`という新しいブール型引数を受け取るようになりました。この引数は、現在のダウンロード操作がテスト依存関係のダウンロードを考慮すべきかどうかを示します。
5. **`download`関数内のテスト依存関係の処理ロジック**:
```go
// Process dependencies, now that we know what they are.
for _, dep := range p.deps {
download(dep.ImportPath, stk, false) // 通常の依存関係はテスト依存関係を再帰的にダウンロードしない
}
if getTestDeps {
// Process test dependencies when -t is specified.
// (Don't get test dependencies for test dependencies.)
for _, path := range p.TestImports {
download(path, stk, false) // テスト依存関係も再帰的にダウンロードしない
}
for _, path := range p.XTestImports {
download(path, stk, false) // テスト依存関係も再帰的にダウンロードしない
}
}
```
これがこのコミットの最も重要な変更点です。
* まず、通常の依存関係(`p.deps`)はこれまで通り再帰的に`download`されますが、その際の`getTestDeps`引数は`false`に設定されています。これは、通常の依存関係のダウンロードではテスト依存関係を追跡しないことを意味します。
* 次に、`if getTestDeps`ブロックが追加されました。これは、`go get -t`が実行された場合にのみ実行されます。
* このブロック内で、`p.TestImports`と`p.XTestImports`(それぞれGoパッケージの内部テストと外部テストがインポートするパッケージのリスト)がループ処理されます。
* これらのテスト依存関係に対しても`download`関数が呼び出されますが、ここでも`getTestDeps`引数は`false`に設定されています。この設計は、テスト依存関係のさらにその先のテスト依存関係(「テストのテスト依存関係」)はダウンロードしないというポリシーを反映しています。これにより、不必要なダウンロードの連鎖を防ぎ、`go get -t`のスコープを適切に限定しています。
これらの変更により、`go get -t`は、指定されたパッケージのビルド依存関係と、そのパッケージのテストに必要な依存関係の両方を効率的かつ適切にダウンロードできるようになりました。
## 関連リンク
* Go Issue #5126: `go get` should download test dependencies: [https://github.com/golang/go/issues/5126](https://github.com/golang/go/issues/5126)
* Gerrit Change-Id: `12566046` (Goのコードレビューシステム): [https://golang.org/cl/12566046](https://golang.org/cl/12566046)
## 参考にした情報源リンク
* Go言語の公式ドキュメント (当時の`go get`に関する情報): [https://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies](https://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies) (これは現在のドキュメントであり、コミット当時の正確なスナップショットではない可能性がありますが、基本的な概念は共通しています。)
* Go Modulesに関する情報 (参考として、このコミット後のGoの依存関係管理の進化): [https://go.dev/blog/using-go-modules](https://go.dev/blog/using-go-modules)
* Goのテストに関する公式ドキュメント: [https://go.dev/doc/code#Testing](https://go.dev/doc/code#Testing) (これも現在のドキュメントですが、テストの概念は共通しています。)