[インデックス 11250] ファイルの概要
このコミットは、Go言語のコマンドラインツール(cmd/go
)におけるパッケージスキャン処理の改善を目的としています。具体的には、パッケージの検索時に、名前にアンダースコア(_
)で始まるディレクトリ(例: _obj
)をスキップするように変更が加えられました。これにより、ビルドアーティファクトなどが含まれる不要なディレクトリがスキャン対象から除外され、パッケージ検索の効率化と正確性の向上が図られています。
コミット
commit f47807a57f9dacab74ebf7e9d86f3dc0dcb933b0
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Wed Jan 18 19:27:16 2012 -0800
cmd/go: skip _obj directories in package scans
Fixes #2693
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5557057
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f47807a57f9dacab74ebf7e9d86f3dc0dcb933b0
元コミット内容
cmd/go: skip _obj directories in package scans
Fixes #2693
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5557057
変更の背景
Go言語のビルドシステムでは、コンパイル済みオブジェクトファイルやその他のビルドアーティファクトを格納するために、慣習的にアンダースコアで始まるディレクトリ(例: _obj
)が使用されることがあります。cmd/go
ツールがパッケージをスキャンする際、これらのディレクトリも対象に含まれてしまうと、以下のような問題が発生する可能性がありました。
- パフォーマンスの低下: 不要なディレクトリを走査することで、パッケージスキャンにかかる時間が増加します。特に大規模なプロジェクトや多数のビルドアーティファクトが存在する場合、この影響は顕著になります。
- 誤ったパッケージの検出:
_obj
ディレクトリ内に、意図しない形でGoのソースファイルやパッケージとして解釈されうるファイルが存在した場合、cmd/go
がそれらを誤ってパッケージとして認識してしまう可能性があります。これはビルドエラーや予期せぬ動作の原因となり得ます。 - ビルドシステムの整合性:
_obj
のようなディレクトリは、通常、一時的なビルド成果物であり、ユーザーが直接操作するパッケージソースとは区別されるべきものです。これらをスキップすることで、cmd/go
のパッケージ検索がより「クリーン」なソースコードのみを対象とするようになり、ビルドシステムの整合性が保たれます。
コミットメッセージにある「Fixes #2693」は、この変更が特定の課題(Issue 2693)を解決したことを示しています。ただし、現在の公開されているGoのIssueトラッカーでは、この番号に直接関連する詳細な情報を見つけることは困難でした。これは、コミットが2012年と古いため、当時の内部的なIssue管理システムや、現在ではクローズされているか番号が変更されている可能性が考えられます。しかし、変更内容から推測するに、上記のような問題が実際に発生し、それを解決するためにこのコミットが作成されたと考えるのが妥当です。
前提知識の解説
このコミットを理解するためには、以下のGo言語およびファイルシステム関連の概念を理解しておく必要があります。
- Goパッケージスキャン:
go build
やgo install
などのコマンドを実行する際、Goツールは指定されたパスや現在のディレクトリからGoのソースコード(パッケージ)を検索します。この検索プロセスは、ファイルシステムを再帰的に走査して行われます。 filepath.Split
: Go標準ライブラリのpath/filepath
パッケージに含まれる関数です。与えられたパス文字列をディレクトリ部分とファイル名(または最後のディレクトリ名)部分に分割します。例えば、filepath.Split("/a/b/c.go")
は("/a/b/", "c.go")
を返します。このコミットでは、ディレクトリのパスからそのディレクトリ自身の名前(elem
)を取得するために使用されています。strings.HasPrefix
: Go標準ライブラリのstrings
パッケージに含まれる関数です。ある文字列が特定のプレフィックス(接頭辞)で始まるかどうかを判定します。このコミットでは、ディレクトリ名が.
(ドット)や_
(アンダースコア)で始まるかどうかをチェックするために使用されています。filepath.SkipDir
:path/filepath
パッケージのWalkFunc
(filepath.Walk
関数に渡されるコールバック関数)が返すエラー値の一つです。WalkFunc
がfilepath.SkipDir
を返すと、filepath.Walk
はそのディレクトリのサブディレクトリへの再帰的な走査をスキップします。これにより、特定の条件に合致するディレクトリツリー全体を効率的に無視することができます。.foo
ディレクトリ: Unix系システムでは、ファイル名やディレクトリ名が.
で始まるものは隠しファイル/ディレクトリとして扱われる慣習があります。Goのパッケージスキャンにおいても、これらの隠しディレクトリは通常、パッケージソースを含まないためスキップされます。testdata
ディレクトリ: Goのテストコードにおいて、テスト用のデータファイルを格納するために慣習的に使用されるディレクトリです。このディレクトリ内のファイルはGoのソースコードとしてコンパイルされるべきではないため、パッケージスキャンから除外されます。_obj
ディレクトリ: 過去のGoのビルドシステムや一部のプロジェクトでは、コンパイル済みオブジェクトファイルや中間生成物を_obj
のようなアンダースコアで始まるディレクトリに格納する慣習がありました。これらはソースコードではないため、パッケージスキャンから除外されるべきです。
技術的詳細
このコミットの変更は、src/cmd/go/main.go
ファイル内のallPackages
関数とallPackagesInFS
関数の2箇所に適用されています。これらの関数は、Goのパッケージを検索し、そのパスのリストを返す役割を担っています。
両関数内では、filepath.Walk
関数を使用してファイルシステムを再帰的に走査しています。filepath.Walk
は、走査中にディレクトリやファイルが見つかるたびに、引数として渡されたWalkFunc
コールバック関数を呼び出します。このWalkFunc
内で、特定の条件に基づいてディレクトリをスキップするかどうかの判断が行われます。
変更前のコードでは、ディレクトリ名が.
で始まる(隠しディレクトリ)か、またはtestdata
という名前である場合に、filepath.SkipDir
を返してそのディレクトリの走査をスキップしていました。
// 変更前
if strings.HasPrefix(elem, ".") || elem == "testdata" {
return filepath.SkipDir
}
このコミットでは、この条件にstrings.HasPrefix(elem, "_")
が追加されました。
// 変更後
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
これにより、ディレクトリ名がアンダースコア(_
)で始まる場合も、そのディレクトリとそのサブディレクトリがパッケージスキャンの対象から除外されるようになりました。この変更は、特に_obj
のようなビルドアーティファクトを格納するディレクトリを効率的に無視するために重要です。
allPackages
関数は、GOPATH環境変数で指定されたパスやGoの標準ライブラリパスなど、Goのビルドシステムが認識するすべてのパッケージパスを検索します。一方、allPackagesInFS
関数は、特定のファイルシステムパス内でのパッケージ検索に特化しています。どちらの関数も同様のディレクトリスキップロジックを共有しているため、両方に同じ変更が適用されています。
この変更は、Goツールがパッケージを検出する際の基本的な振る舞いを改善し、不要なファイルやディレクトリを無視することで、より堅牢で効率的なビルドプロセスに貢献しています。
コアとなるコードの変更箇所
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 8ef6395f4f..fdea80916f 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -327,9 +327,9 @@ func allPackages(pattern string) []string {
return nil
}
- // Avoid .foo and testdata directory trees.
+ // Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
- if strings.HasPrefix(elem, ".") || elem == "testdata" {
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
@@ -394,9 +394,9 @@ func allPackagesInFS(pattern string) []string {
return nil
}
- // Avoid .foo and testdata directory trees.
+ // Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
- if strings.HasPrefix(elem, ".") || elem == "testdata" {
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
コアとなるコードの解説
上記のdiff
は、src/cmd/go/main.go
ファイル内の2つの関数、allPackages
とallPackagesInFS
における変更を示しています。
-
コメントの変更:
- // Avoid .foo and testdata directory trees. + // Avoid .foo, _foo, and testdata directory trees.
これはコードの振る舞いを説明するコメントの更新です。以前は
.
で始まるディレクトリとtestdata
ディレクトリを避けることを示していましたが、変更後は_
で始まるディレクトリも避けるようになったことを明示しています。これはコードの意図を正確に反映するための重要な変更です。 -
条件式の変更:
- if strings.HasPrefix(elem, ".") || elem == "testdata" { + if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
これがこのコミットの核心的な変更です。
elem
は、filepath.Split(path)
によって取得された現在のディレクトリ名(またはファイル名)です。- 変更前は、
elem
が.
で始まる(strings.HasPrefix(elem, ".")
)か、またはelem
が厳密に"testdata"
である場合に、そのディレクトリをスキップしていました。 - 変更後は、この条件に
|| strings.HasPrefix(elem, "_")
が追加されました。これにより、elem
がアンダースコア(_
)で始まる場合も、ディレクトリがスキップされるようになりました。
この変更は、allPackages
とallPackagesInFS
の両方の関数内のfilepath.Walk
コールバック関数内で適用されています。filepath.Walk
はファイルシステムを再帰的に走査する際に、各ディレクトリに対してこの条件を評価します。条件が真(true)になった場合、filepath.SkipDir
が返され、filepath.Walk
はそのディレクトリのサブディレクトリへの再帰的な走査を停止し、次の兄弟ディレクトリへと進みます。
これにより、_obj
のようなビルドアーティファクトを格納するディレクトリがGoのパッケージスキャンから除外され、スキャンプロセスの効率化と、誤ったパッケージ検出の防止に貢献しています。
関連リンク
- Go CL (Change List) 5557057: https://golang.org/cl/5557057
参考にした情報源リンク
- Go言語の
path/filepath
パッケージドキュメント: https://pkg.go.dev/path/filepath - Go言語の
strings
パッケージドキュメント: https://pkg.go.dev/strings - Go言語のIssueトラッカー(一般的な情報源として。Issue 2693の直接的な情報は見つからず): https://github.com/golang/go/issues
- Go言語のビルドシステムに関する一般的な情報(
_obj
ディレクトリの慣習など)