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

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

このコミットは、Go言語のツールチェインの一部であるcmd/packのテストコードにおけるバグ修正を目的としています。具体的には、TestHelloというテスト関数内で使用されている正規表現が、Plan 9オペレーティングシステム上でのビルド時に問題を引き起こすため、その正規表現を修正しています。この修正により、Plan 9環境でのGoのビルドの堅牢性が向上します。

コミット

commit 00b76713a7ba9182e9dfc29dcc37e94d000703b8
Author: Rob Pike <r@golang.org>
Date:   Wed Feb 19 16:12:05 2014 -0800

    cmd/pack: another attempt to fix the build for TestHello
    Plan 9 uses single quotes, not double quotes. I should have known.
    
    LGTM=bradfitz
    R=bradfitz
    CC=golang-codereviews
    https://golang.org/cl/66240043

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

https://github.com/golang/go/commit/00b76713a7ba9182e9dfc29dcc37e94d000703b8

元コミット内容

cmd/pack: TestHelloのビルドを修正する別の試み Plan 9はダブルクォートではなくシングルクォートを使用する。知っておくべきだった。

LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/66240043

変更の背景

このコミットの背景には、Go言語のビルドシステムが様々なオペレーティングシステム(OS)に対応する必要があるという課題があります。特に、Go言語の初期開発に深く関わったRob Pike氏が言及しているように、Plan 9というOS環境での互換性が問題となっていました。

TestHelloというテストは、go envコマンドの出力を解析し、GOCHARという環境変数の値を抽出しています。このGOCHARの値は、Goのコンパイラがターゲットとするアーキテクチャを示す文字(例: 8 for amd64, 6 for 386)であり、ビルドプロセスにおいて重要な役割を果たします。

問題は、go envコマンドが環境変数の値を引用符で囲んで出力する際に、OSによって使用する引用符の種類が異なる点にありました。一般的なUnix系システム(Linux, macOSなど)ではダブルクォート(")が使われることが多いのに対し、Plan 9ではシングルクォート(')が使われるという特性がありました。

元の正規表現はダブルクォートのみを想定していたため、Plan 9環境でgo envの出力がシングルクォートで囲まれている場合、正規表現がマッチせず、テストが失敗していました。このコミットは、このOS間の引用符の違いを吸収し、Plan 9上でもテストが正しく動作するようにするための修正です。Rob Pike氏のコメント「知っておくべきだった」は、Plan 9のこの特性がGo開発者にとっては既知であるべきだったという自戒の念を示しています。

前提知識の解説

cmd/pack

cmd/packは、Go言語の初期のツールチェインの一部であり、主にアーカイブファイル(.aファイル)を操作するためのコマンドでした。Goのビルドプロセスにおいて、コンパイルされたオブジェクトファイルやライブラリをまとめるために使用されていました。しかし、Go 1.5以降、ビルドシステムが変更され、cmd/packgo tool packとして内部的に利用される形になり、最終的にはGo 1.10で削除されました。このコミットが行われた2014年時点では、まだGoの標準ツールとして存在していました。

go envコマンド

go envコマンドは、Goの環境変数の値を表示するために使用されます。例えば、GOPATHGOROOTGOOS(オペレーティングシステム)、GOARCH(アーキテクチャ)などのGo関連の環境設定を確認できます。このコマンドの出力は、スクリプトやツールがGoのビルド環境をプログラム的に理解するために利用されることがあります。

正規表現 (Regular Expressions)

正規表現は、文字列のパターンを記述するための強力なツールです。このコミットでは、Goのregexpパッケージが使用されており、特定の文字列パターン(この場合はGOCHAR環境変数の出力形式)を検索・抽出するために利用されています。正規表現の構文には、特定の文字(例: .は任意の一文字、*は直前の文字の0回以上の繰り返し、?は直前の文字の0回または1回の繰り返し)や、文字クラス(例: \sは空白文字、\wは単語文字)などがあります。

Plan 9

Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワークサービスなど)をファイルシステムとして表現するという特徴を持っています。Go言語の開発者の一部(Rob Pike氏、Ken Thompson氏など)はPlan 9の開発にも深く関わっており、Go言語の設計思想にもPlan 9の影響が見られます。Plan 9は、その独特な設計と哲学から、特定の引用符の扱いなど、一般的なUnix系OSとは異なる挙動を示すことがあります。

技術的詳細

このコミットの技術的な核心は、正規表現の修正にあります。

元の正規表現: `\s*GOCHAR=\"?(\w)\"?` 修正後の正規表現: `\s*GOCHAR=[\'\"]?(\w)[\'\"]?`

この変更のポイントは、GOCHARの値が囲まれている引用符を、ダブルクォート(")だけでなくシングルクォート(')も許容するようにした点です。

  • \"? から [\'\"]? への変更:
    • 元の正規表現では、GOCHAR=の後に続く引用符として、エスケープされたダブルクォート\"が0回または1回出現すること(?)を期待していました。
    • 修正後の正規表現では、[\'\"]という文字クラスが導入されています。これは「シングルクォート(')またはダブルクォート(")のいずれか」を意味します。この文字クラスの後に?が付くことで、「シングルクォートまたはダブルクォートのいずれかが0回または1回出現する」というパターンにマッチするようになります。

これにより、go envの出力がGOCHAR="8"のような形式でも、GOCHAR='8'のような形式でも、正規表現が正しく8という文字をキャプチャできるようになりました。この修正は、異なるOS環境(特にPlan 9)での互換性を確保するために不可欠でした。

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

--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -193,7 +193,7 @@ func TestHello(t *testing.T) {
 	}\n 
 	out := run("go", "env")
-	re, err := regexp.Compile(`\s*GOCHAR=\"?(\w)\"?`)
+	re, err := regexp.Compile(`\s*GOCHAR=[\'\"]?(\w)[\'\"]?`)
 	if err != nil {
 		t.Fatal(err)
 	}

コアとなるコードの解説

変更はsrc/cmd/pack/pack_test.goファイルのTestHello関数内の一行に限定されています。

TestHello関数は、Goのビルド環境をテストするために、go envコマンドを実行し、その出力からGOCHAR環境変数の値を抽出しています。

元のコード:

re, err := regexp.Compile(`\s*GOCHAR=\"?(\w)\"?`)

この行では、regexp.Compile関数を使って正規表現をコンパイルしています。この正規表現は、行頭の空白文字(\s*)に続き、GOCHAR=という文字列、そしてオプションのダブルクォート(\"?)があり、その後に単語文字(\w)が1つ(これがキャプチャグループ(\w))、そして再びオプションのダブルクォート(\"?)が続くパターンにマッチします。

修正後のコード:

re, err := regexp.Compile(`\s*GOCHAR=[\'\"]?(\w)[\'\"]?`)

この修正では、正規表現の\"?の部分が[\'\"]?に置き換えられました。

  • []は文字クラスを定義します。
  • \'はシングルクォート文字そのものを表します(正規表現リテラル内ではエスケープ不要ですが、Goの文字列リテラル内ではエスケープが必要な場合があります。ここではバッククォート文字列なので不要ですが、慣例的にエスケープされている可能性もあります)。
  • \"はダブルクォート文字そのものを表します。

したがって、[\'\"]は「シングルクォートまたはダブルクォートのいずれか」にマッチします。この変更により、GOCHARの値がシングルクォートで囲まれていても、ダブルクォートで囲まれていても、正規表現が正しくマッチし、GOCHARの値((\w)でキャプチャされる部分)を抽出できるようになりました。これにより、Plan 9環境でのテストの失敗が解消されました。

関連リンク

参考にした情報源リンク