[インデックス 12531] ファイルの概要
このコミットは、Go言語のテストスイートにおいて、ディレクトリ内の隠しファイル(ファイル名の先頭が . で始まるファイル)をスキップするように変更を加えるものです。特に、Xcodeが生成する ._foo.go のようなファイルがテストプロセスに誤って含まれることを防ぐ目的があります。
コミット
commit c978a5a3a94fbd03cfe012fbf1ac556728d7fb41
Author: Russ Cox <rsc@golang.org>
Date: Thu Mar 8 14:03:40 2012 -0500
test: skip . files in directory
Xcode generates ._foo.go files.
R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/5786055
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c978a5a3a94fbd03cfe012fbf1ac556728d7fb41
元コミット内容
test: skip . files in directory
Xcode generates ._foo.go files.
R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/5786055
変更の背景
この変更の背景には、macOS環境で開発を行う際にXcodeなどのツールが特定のファイルを扱う方法があります。macOSのファイルシステム(HFS+やAPFS)では、リソースフォークと呼ばれるメタデータがファイルに付随することがあります。これは、ファイルの作成日、変更日、アイコン、カスタム属性などの情報を格納するために使用されます。
Xcodeのような開発ツールや、Finderなどのシステムユーティリティがファイルをコピーしたり操作したりする際、これらのリソースフォーク情報を保持するために、元のファイル名に ._ をプレフィックスとして付けた隠しファイル(例: ._main.go)を生成することがあります。これらのファイルは、通常、ユーザーからは見えないように設定されていますが、ファイルシステム上には存在します。
Go言語のテストスイートがディレクトリ内の .go ファイルを列挙する際、これらの ._foo.go のような隠しファイルも誤って .go ファイルとして認識し、テスト対象に含めてしまう可能性がありました。しかし、これらのファイルは有効なGoのソースコードではないため、コンパイルエラーや予期せぬテストの失敗を引き起こす原因となります。
この問題を解決し、テストの安定性と信頼性を向上させるために、ファイル名の先頭が . で始まるファイルを明示的にスキップする変更が導入されました。
前提知識の解説
隠しファイル(Dotfiles)
Unix系OS(macOS、Linuxなど)では、ファイル名やディレクトリ名の先頭に . (ドット) を付けることで、そのファイルやディレクトリを「隠しファイル(dotfile)」として扱う慣習があります。これらのファイルは、通常、ファイルマネージャーやコマンドラインツール(例: ls コマンド)のデフォルト設定では表示されません。
隠しファイルは、主に設定ファイル(例: .bashrc, .gitconfig)や、システムが内部的に使用する一時ファイル、メタデータファイルなどに利用されます。今回のケースでは、Xcodeが生成する ._foo.go ファイルがこれに該当します。
Xcodeとリソースフォーク
XcodeはAppleが提供する統合開発環境(IDE)であり、macOS、iOS、watchOS、tvOS向けのアプリケーション開発に広く使用されます。Xcodeがファイルを操作する際に、macOSのファイルシステム特性であるリソースフォークを扱うことがあります。
リソースフォークは、ファイルのデータフォーク(実際のファイル内容)とは別に、ファイルに関する追加のメタデータを格納する仕組みです。古いMac OSの時代から存在し、ファイルのアイコンやカスタムプロパティなどを保存するために使われてきました。
現代のmacOSでは、リソースフォークはあまり直接的に使われることは少なくなりましたが、ファイルシステムレベルでの互換性や、特定のツールがメタデータを扱う際に、._ プレフィックスを持つ隠しファイルとしてリソースフォークの内容を保存することがあります。これは、AppleDoubleフォーマットと呼ばれる形式で、非HFS+ファイルシステム(例: FAT32、NTFS、ネットワーク共有)にファイルをコピーする際に、リソースフォーク情報を別途ファイルとして保存するために用いられます。
Go言語のテスト
Go言語には、標準でテストフレームワークが組み込まれており、go test コマンドを使用してテストを実行します。Goのテストファイルは、通常、テスト対象のソースファイルと同じディレクトリに配置され、ファイル名が _test.go で終わる必要があります。go test コマンドは、指定されたパッケージ内の _test.go ファイルを自動的に探し、テスト関数(TestXxx、BenchmarkXxx、ExampleXxx)を実行します。
このコミットで変更された test/run.go は、Go言語の標準ライブラリやツールのテストスイートの一部であり、go test コマンドが内部的にどのようにファイルを処理するか、あるいはテスト実行環境をどのように準備するかに関連するロジックを含んでいると考えられます。
技術的詳細
このコミットの技術的な変更は非常にシンプルですが、効果的です。test/run.go ファイル内の goFiles 関数が変更されています。この関数は、指定されたディレクトリからGoのソースファイル(.go で終わるファイル)を収集する役割を担っています。
変更前は、ファイル名が .go で終わるかどうかのみをチェックしていました。
// 変更前
if strings.HasSuffix(name, ".go") {
names = append(names, name)
}
変更後は、この条件に加えて、ファイル名が . で始まらないこともチェックするようになりました。
// 変更後
if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") {
names = append(names, name)
}
ここで使用されているGoの標準ライブラリ関数は以下の通りです。
strings.HasPrefix(s, prefix string) bool: 文字列sがprefixで始まる場合にtrueを返します。strings.HasSuffix(s, suffix string) bool: 文字列sがsuffixで終わる場合にtrueを返します。
! 演算子は論理否定を表すため、!strings.HasPrefix(name, ".") は「ファイル名が . で始まらない」という条件を意味します。
この変更により、goFiles 関数は、ファイル名が .go で終わり、かつファイル名が . で始まらないファイルのみを有効なGoソースファイルとして認識し、リストに追加するようになります。これにより、._foo.go のような隠しファイルがテストプロセスに誤って含まれることがなくなります。
コアとなるコードの変更箇所
--- a/test/run.go
+++ b/test/run.go
@@ -147,7 +147,7 @@ func goFiles(dir string) []string {
check(err)
names := []string{}
for _, name := range dirnames {
- if strings.HasSuffix(name, ".go") {
+ if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") {
names = append(names, name)
}
}
コアとなるコードの解説
上記のコードスニペットは、test/run.go ファイル内の goFiles 関数の一部を示しています。
goFiles 関数は、引数 dir で指定されたディレクトリ内のGoソースファイル(.go ファイル)のリストを返すことを目的としています。
dirnamesは、指定されたディレクトリ内のファイルおよびディレクトリの名前のリストを保持しています。for _, name := range dirnamesループは、dirnamesの各エントリ(ファイル名またはディレクトリ名)を反復処理します。- 変更前の
if strings.HasSuffix(name, ".go")は、ファイル名が.goで終わるかどうかだけをチェックしていました。 - 変更後の
if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")は、以下の2つの条件を論理AND (&&) で結合しています。!strings.HasPrefix(name, "."): ファイル名が.で始まらないこと。これにより、._foo.goのような隠しファイルが除外されます。strings.HasSuffix(name, ".go"): ファイル名が.goで終わること。これにより、Goソースファイルのみが対象となります。
- 両方の条件が真である場合のみ、その
nameは有効なGoソースファイルと見なされ、namesスライスに追加されます。
この修正により、Goのテストスイートが、Xcodeなどのツールによって生成された無効な隠しファイルを誤って処理しようとすることを防ぎ、テストの実行がより堅牢になります。
関連リンク
- Go CL 5786055: https://golang.org/cl/5786055
参考にした情報源リンク
- AppleDouble - Wikipedia
- Go言語のテスト - golang.jp
- stringsパッケージ - golang.jp
- Go言語のテスト入門 - Qiita (一般的なGoテストの概念理解のため)
- macOSの隠しファイルとフォルダを表示する方法 - Apple サポート (隠しファイルの一般的な概念理解のため)
- Xcode - Wikipedia (Xcodeの一般的な情報のため)