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

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

このコミットは、Go言語のビルドシステム (go/build パッケージ) におけるエラーメッセージから、冗長なプレフィックス "go/build:" を削除する変更です。これにより、特に goinstall コマンドを使用する際に表示されるエラーメッセージがより分かりやすくなり、ユーザーの混乱を避けることを目的としています。

コミット

  • コミットハッシュ: 96a5780db882b4bd4a1f4b69e185833e5bedffcb
  • Author: Andrew Gerrand adg@golang.org
  • Date: Sat Dec 17 13:14:18 2011 +1100
  • コミットメッセージ:
    go/build: remove 'go/build' from error messages
    
    This leads to really confusing messages in goinstall.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5495074
    

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

https://github.com/golang/go/commit/96a5780db882b4bd4a1f4b69e185833e5bedffcb

元コミット内容

commit 96a5780db882b4bd4a1f4b69e185833e5bedffcb
Author: Andrew Gerrand <adg@golang.org>
Date:   Sat Dec 17 13:14:18 2011 +1100

    go/build: remove 'go/build' from error messages
    
    This leads to really confusing messages in goinstall.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5495074
---\n src/pkg/go/build/path.go | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/src/pkg/go/build/path.go b/src/pkg/go/build/path.go
index 91d6c430a9..5b4d9243e6 100644
--- a/src/pkg/go/build/path.go
+++ b/src/pkg/go/build/path.go
@@ -85,8 +85,8 @@ func (t *Tree) HasPkg(pkg string) bool {
 }\n \n var (\n-\tErrNotFound     = errors.New(\"go/build: package could not be found locally\")\n-\tErrTreeNotFound = errors.New(\"go/build: no valid GOROOT or GOPATH could be found\")\n+\tErrNotFound     = errors.New(\"package could not be found locally\")\n+\tErrTreeNotFound = errors.New(\"no valid GOROOT or GOPATH could be found\")\n )\n \n // FindTree takes an import or filesystem path and returns the\n@@ -151,7 +151,7 @@ func init() {\n \troot := runtime.GOROOT()\n \tt, err := newTree(root)\n \tif err != nil {\n-\t\tlog.Printf(\"go/build: invalid GOROOT %q: %v\", root, err)\n+\t\tlog.Printf(\"invalid GOROOT %q: %v\", root, err)\n \t} else {\n \t\tt.Goroot = true\n \t\tPath = []*Tree{t}\n@@ -163,7 +163,7 @@ func init() {\n \t\t}\n \t\tt, err := newTree(p)\n \t\tif err != nil {\n-\t\t\tlog.Printf(\"go/build: invalid GOPATH %q: %v\", p, err)\n+\t\t\tlog.Printf(\"invalid GOPATH %q: %v\", p, err)\n \t\t\tcontinue\n \t\t}\n \t\tPath = append(Path, t)\n```

## 変更の背景

この変更の背景には、Go言語の初期のツールチェインにおけるユーザーエクスペリエンスの改善があります。コミットメッセージに「This leads to really confusing messages in goinstall.」とあるように、`goinstall` コマンドが `go/build` パッケージから返されるエラーメッセージをそのまま表示すると、ユーザーにとって非常に分かりにくいメッセージになっていました。

具体的には、エラーメッセージの冒頭に常に `"go/build:"` というプレフィックスが付与されていたため、例えば「`go/build: package could not be found locally`」のようなメッセージが表示されていました。これは、エラーが `go/build` パッケージ内で発生したことを示していますが、エンドユーザーにとっては、どのツールがエラーを出しているのか、あるいはエラーの根本原因が何なのかを理解する上で、このプレフィックスはむしろノイズとなっていました。

`goinstall` は、Goのパッケージをダウンロード、ビルド、インストールするための初期のツールであり、ユーザーがGoのコードを扱う上で頻繁に利用するものでした。そのため、このツールが出力するエラーメッセージの明確さは非常に重要でした。開発者は、エラーメッセージが冗長であることによって、ユーザーが問題解決に余計な時間を費やしたり、誤解したりする可能性を懸念し、この改善を決定しました。

この変更は、Go言語の設計哲学の一つである「シンプルさ」と「実用性」にも合致しています。ユーザーが直面する問題を最小限に抑え、より直感的な開発体験を提供するための、細かながらも重要な改善と言えます。

## 前提知識の解説

このコミットを理解するためには、以下のGo言語の基本的な概念とツールに関する知識が必要です。

### Go言語のパッケージとビルドシステム

Go言語のコードは「パッケージ」という単位で管理されます。パッケージは関連するGoのソースファイル (`.go` ファイル) の集まりであり、他のパッケージからインポートして利用することができます。

Goのビルドシステムは、これらのパッケージをコンパイルし、実行可能なバイナリやライブラリを生成する役割を担っています。

### `go/build` パッケージ

`go/build` パッケージは、Goのソースコードを解析し、パッケージの依存関係を解決し、ビルドに必要な情報を収集するための低レベルなAPIを提供します。このパッケージは、Goの標準ツールチェイン(`go build`, `go install`, `go get` など)の基盤として機能します。

このコミットで変更されている `path.go` ファイルは、`go/build` パッケージの一部であり、Goのソースコードやパッケージがファイルシステム上のどこに存在するかを特定するためのロジックを含んでいます。

### `GOROOT` と `GOPATH`

Goの環境変数である `GOROOT` と `GOPATH` は、Goのビルドシステムがパッケージを見つけるために非常に重要です。

*   **`GOROOT`**: GoのSDK(標準ライブラリ、ツールなど)がインストールされているディレクトリを指します。Goの標準パッケージは `GOROOT` 内に存在します。
*   **`GOPATH`**: ユーザーが開発するGoのプロジェクトや、`go get` コマンドでダウンロードされたサードパーティのパッケージが配置されるワークスペースのルートディレクトリを指します。Go 1.11以降のGo Modulesの導入により、`GOPATH` の役割は変化しましたが、このコミットが作成された2011年当時は、`GOPATH` がGo開発における主要なワークスペースでした。

`go/build` パッケージは、これらの環境変数を参照して、指定されたパッケージのソースコードを検索します。

### `goinstall` コマンド

`goinstall` は、Go言語の初期のバージョンで提供されていたコマンドラインツールです。これは、指定されたGoパッケージをインターネットからダウンロードし、コンパイルし、インストールする機能を持っていました。現在の `go get` コマンドの前身にあたります。

このツールは、Goのパッケージ管理と依存関係解決の初期段階を担っており、ユーザーが新しいライブラリやアプリケーションを簡単に導入できるように設計されていました。

### Goのエラーハンドリング

Go言語では、エラーは戻り値として明示的に扱われます。関数は通常、最後の戻り値として `error` 型の値を返します。エラーが発生しなかった場合は `nil` を返します。

`errors.New()` 関数は、新しいエラー値を生成するために使用されます。このコミットでは、`ErrNotFound` と `ErrTreeNotFound` という2つのエラー変数が `errors.New()` を使って定義されています。

### `log.Printf`

`log` パッケージは、Goの標準ライブラリの一部であり、ログメッセージを出力するための機能を提供します。`log.Printf` は、フォーマット文字列と引数を受け取り、標準エラー出力(または設定された出力先)にログメッセージを出力します。

このコミットでは、`GOROOT` や `GOPATH` が無効な場合にログメッセージを出力するために `log.Printf` が使用されています。

## 技術的詳細

このコミットの技術的な詳細は、Go言語のエラーメッセージの設計と、ユーザーへの情報提供のバランスに関するものです。

### エラーメッセージの冗長性の排除

Go言語のエラーメッセージは、通常、問題の内容を簡潔かつ明確に伝えるべきであるという原則があります。このコミット以前は、`go/build` パッケージが生成するエラーメッセージには、常にそのパッケージ名である `"go/build:"` というプレフィックスが付加されていました。

例えば、パッケージが見つからない場合のエラーは `errors.New("go/build: package could not be found locally")` と定義されていました。これは、エラーが `go/build` パッケージの内部で発生したことを示していますが、この情報がエンドユーザーにとって常に有用であるとは限りません。特に、`goinstall` のような上位レベルのツールがこれらのエラーをそのまま表示する場合、ユーザーは「`goinstall` が `go/build` パッケージを使って何かをしようとしたが、それが失敗した」という間接的な情報を得るだけで、直接的な問題解決には繋がりにくいと感じる可能性がありました。

この変更は、この冗長なプレフィックスを削除することで、エラーメッセージをより直接的で分かりやすいものにすることを目的としています。例えば、「`package could not be found locally`」というメッセージは、ユーザーが探しているパッケージが見つからなかったという事実を直接的に伝えます。これにより、ユーザーはエラーメッセージを解釈する手間が省け、問題の特定と解決に集中できるようになります。

### `errors.New` とログメッセージの変更

コミットの差分を見ると、以下の2種類のエラーメッセージと2種類のログメッセージが変更されています。

1.  **`ErrNotFound` と `ErrTreeNotFound` の定義**:
    これらのエラー変数は、`go/build` パッケージ内で定義されている公開エラーです。以前は `errors.New("go/build: ...")` の形式で定義されていましたが、変更後は `"go/build:"` プレフィックスが削除され、`errors.New("...")` の形式になりました。
    これは、これらのエラーが `go/build` パッケージの外部に公開され、他のパッケージやツールによって捕捉・表示される可能性があるため、その際に冗長なプレフィックスが表示されないようにするためです。

2.  **`log.Printf` で出力されるメッセージ**:
    `init()` 関数内で `GOROOT` や `GOPATH` の設定が不正な場合に `log.Printf` を使ってログメッセージが出力されていました。以前は `log.Printf("go/build: invalid GOROOT %q: %v", ...)` の形式でしたが、これも `"go/build:"` プレフィックスが削除されました。
    ログメッセージの場合も、同様に冗長な情報を排除し、より簡潔に問題の内容を伝えることを目的としています。ログは開発者やシステム管理者が見るものですが、それでもメッセージは明確であるべきです。

### 影響とメリット

この変更による主なメリットは以下の通りです。

*   **ユーザーエクスペリエンスの向上**: `goinstall` などのツールが出力するエラーメッセージがより簡潔になり、ユーザーがエラーの原因を迅速に理解できるようになります。
*   **メッセージの一貫性**: Goのエラーメッセージの一般的な慣習に沿う形となり、他のGoツールやライブラリのエラーメッセージとの一貫性が向上します。
*   **コードの簡潔化**: エラーメッセージの定義がわずかに短くなり、コードの可読性も向上します。

この変更は、Go言語のツールチェインが成熟していく過程で、ユーザーからのフィードバックや開発者の経験に基づいて行われた、細かながらも重要な改善の一例と言えます。

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

変更は `src/pkg/go/build/path.go` ファイルに集中しています。

```diff
--- a/src/pkg/go/build/path.go
+++ b/src/pkg/go/build/path.go
@@ -85,8 +85,8 @@ func (t *Tree) HasPkg(pkg string) bool {
 }
 
 var (
-	ErrNotFound     = errors.New("go/build: package could not be found locally")
-	ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
+	ErrNotFound     = errors.New("package could not be found locally")
+	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
 )
 
 // FindTree takes an import or filesystem path and returns the
@@ -151,7 +151,7 @@ func init() {
 	root := runtime.GOROOT()
 	t, err := newTree(root)
 	if err != nil {
-		log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+		log.Printf("invalid GOROOT %q: %v", root, err)
 	} else {
 		t.Goroot = true
 		Path = []*Tree{t}
@@ -163,7 +163,7 @@ func init() {
 		}
 		t, err := newTree(p)
 		if err != nil {
-			log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+			log.Printf("invalid GOPATH %q: %v", p, err)
 		}
 		Path = append(Path, t)
 	}

具体的には、以下の4箇所が変更されています。

  1. ErrNotFound エラー変数の定義
  2. ErrTreeNotFound エラー変数の定義
  3. init() 関数内の GOROOT 関連の log.Printf 呼び出し
  4. init() 関数内の GOPATH 関連の log.Printf 呼び出し

コアとなるコードの解説

このコミットのコアとなる変更は、エラーメッセージとログメッセージから "go/build:" という文字列プレフィックスを削除することです。

エラー変数の定義変更

// 変更前
var (
	ErrNotFound     = errors.New("go/build: package could not be found locally")
	ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
)

// 変更後
var (
	ErrNotFound     = errors.New("package could not be found locally")
	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
)

ErrNotFound は、指定されたパッケージがローカルのファイルシステム上で見つからなかった場合に返されるエラーです。 ErrTreeNotFound は、有効な GOROOT または GOPATH が見つからなかった場合に返されるエラーです。

これらのエラーは go/build パッケージの外部に公開される可能性があるため、このプレフィックスを削除することで、エラーを受け取った側(例えば goinstall)がそのままメッセージを表示しても、冗長な情報が含まれないようになります。これにより、ユーザーは「パッケージが見つかりません」や「GOROOT/GOPATH が無効です」といった、より直接的なメッセージを受け取ることができます。

log.Printf 呼び出しの変更

// 変更前 (GOROOT関連)
if err != nil {
	log.Printf("go/build: invalid GOROOT %q: %v", root, err)
}

// 変更後 (GOROOT関連)
if err != nil {
	log.Printf("invalid GOROOT %q: %v", root, err)
}

// 変更前 (GOPATH関連)
if err != nil {
	log.Printf("go/build: invalid GOPATH %q: %v", p, err)
	continue
}

// 変更後 (GOPATH関連)
if err != nil {
	log.Printf("invalid GOPATH %q: %v", p, err)
	continue
}

init() 関数は、パッケージが初期化される際に自動的に実行される特別な関数です。この関数内で、GOROOTGOPATH の設定を検証し、もし無効なパスが指定されていれば、log.Printf を使って警告メッセージを出力しています。

ここでも同様に、ログメッセージから "go/build:" プレフィックスが削除されています。ログは通常、開発者やシステム管理者がデバッグや問題診断のために参照するものですが、それでもメッセージは簡潔で分かりやすい方が好ましいです。この変更により、「invalid GOROOT」や「invalid GOPATH」といった、より直接的な警告がログに出力されるようになります。

これらの変更は、Go言語のエラーメッセージとログ出力の品質を向上させ、ユーザーと開発者の双方にとってより良い体験を提供するための、細部にわたる配慮を示しています。

関連リンク

参考にした情報源リンク

  • Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
  • Go Code Review Comments (Effective Go): https://go.dev/doc/effective_go#errors (エラーメッセージに関する一般的なGoの慣習)
  • goinstall の歴史に関する情報 (Goの初期のツールチェインに関するブログ記事やディスカッション):
    • Go 1 Release Notes (goinstallからgo getへの移行に関する言及がある可能性): https://go.dev/doc/go1
    • Goの初期のメーリングリストアーカイブ (golang-nuts, golang-dev): https://groups.google.com/g/golang-nuts (当時の議論を検索することで、goinstall の問題点やエラーメッセージに関する議論が見つかる可能性があります。)
  • Goのソースコード (特に src/cmd/go/ ディレクトリ内の goinstall に関連するコードや、src/pkg/go/build/ ディレクトリ内の他のファイル): https://github.com/golang/go
  • GoのIssue Tracker (当時の関連するIssueや提案): https://github.com/golang/go/issues
  • GoのChange List (CL) 5495074: https://golang.org/cl/5495074 (このコミットの元となったコードレビューのページ。詳細な議論や背景情報が含まれている可能性があります。)

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

このコミットは、Go言語のビルドシステム (go/build パッケージ) におけるエラーメッセージから、冗長なプレフィックス "go/build:" を削除する変更です。これにより、特に goinstall コマンドを使用する際に表示されるエラーメッセージがより分かりやすくなり、ユーザーの混乱を避けることを目的としています。

コミット

  • コミットハッシュ: 96a5780db882b4bd4a1f4b69e185833e5bedffcb
  • Author: Andrew Gerrand adg@golang.org
  • Date: Sat Dec 17 13:14:18 2011 +1100
  • コミットメッセージ:
    go/build: remove 'go/build' from error messages
    
    This leads to really confusing messages in goinstall.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5495074
    

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

https://github.com/golang/go/commit/96a5780db882b4bd4a1f4b69e185833e5bedffcb

元コミット内容

commit 96a5780db882b4bd4a1f4b69e185833e5bedffcb
Author: Andrew Gerrand <adg@golang.org>
Date:   Sat Dec 17 13:14:18 2011 +1100

    go/build: remove 'go/build' from error messages
    
    This leads to really confusing messages in goinstall.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5495074
---
 src/pkg/go/build/path.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/pkg/go/build/path.go b/src/pkg/go/build/path.go
index 91d6c430a9..5b4d9243e6 100644
--- a/src/pkg/go/build/path.go
+++ b/src/pkg/go/build/path.go
@@ -85,8 +85,8 @@ func (t *Tree) HasPkg(pkg string) bool {
 }
 
 var (
-	ErrNotFound     = errors.New("go/build: package could not be found locally")
-	ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
+	ErrNotFound     = errors.New("package could not be found locally")
+	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
 )
 
 // FindTree takes an import or filesystem path and returns the
@@ -151,7 +151,7 @@ func init() {
 	root := runtime.GOROOT()
 	t, err := newTree(root)
 	if err != nil {
-		log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+		log.Printf("invalid GOROOT %q: %v", root, err)
 	} else {
 		t.Goroot = true
 		Path = []*Tree{t}
@@ -163,7 +163,7 @@ func init() {
 		}
 		t, err := newTree(p)
 		if err != nil {
-			log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+			log.Printf("invalid GOPATH %q: %v", p, err)
 		}
 		Path = append(Path, t)
 	}

変更の背景

この変更の背景には、Go言語の初期のツールチェインにおけるユーザーエクスペリエンスの改善があります。コミットメッセージに「This leads to really confusing messages in goinstall.」とあるように、goinstall コマンドが go/build パッケージから返されるエラーメッセージをそのまま表示すると、ユーザーにとって非常に分かりにくいメッセージになっていました。

具体的には、エラーメッセージの冒頭に常に "go/build:" というプレフィックスが付与されていたため、例えば「go/build: package could not be found locally」のようなメッセージが表示されていました。これは、エラーが go/build パッケージ内で発生したことを示していますが、エンドユーザーにとっては、どのツールがエラーを出しているのか、あるいはエラーの根本原因が何なのかを理解する上で、このプレフィックスはむしろノイズとなっていました。

goinstall は、Goのパッケージをダウンロード、ビルド、インストールするための初期のツールであり、ユーザーがGoのコードを扱う上で頻繁に利用するものでした。そのため、このツールが出力するエラーメッセージの明確さは非常に重要でした。開発者は、エラーメッセージが冗長であることによって、ユーザーが問題解決に余計な時間を費やしたり、誤解したりする可能性を懸念し、この改善を決定しました。

この変更は、Go言語の設計哲学の一つである「シンプルさ」と「実用性」にも合致しています。ユーザーが直面する問題を最小限に抑え、より直感的な開発体験を提供するための、細かながらも重要な改善と言えます。

前提知識の解説

このコミットを理解するためには、以下のGo言語の基本的な概念とツールに関する知識が必要です。

Go言語のパッケージとビルドシステム

Go言語のコードは「パッケージ」という単位で管理されます。パッケージは関連するGoのソースファイル (.go ファイル) の集まりであり、他のパッケージからインポートして利用することができます。

Goのビルドシステムは、これらのパッケージをコンパイルし、実行可能なバイナリやライブラリを生成する役割を担っています。

go/build パッケージ

go/build パッケージは、Goのソースコードを解析し、パッケージの依存関係を解決し、ビルドに必要な情報を収集するための低レベルなAPIを提供します。このパッケージは、Goの標準ツールチェイン(go build, go install, go get など)の基盤として機能します。

このコミットで変更されている path.go ファイルは、go/build パッケージの一部であり、Goのソースコードやパッケージがファイルシステム上のどこに存在するかを特定するためのロジックを含んでいます。

GOROOTGOPATH

Goの環境変数である GOROOTGOPATH は、Goのビルドシステムがパッケージを見つけるために非常に重要です。

  • GOROOT: GoのSDK(標準ライブラリ、ツールなど)がインストールされているディレクトリを指します。Goの標準パッケージは GOROOT 内に存在します。
  • GOPATH: ユーザーが開発するGoのプロジェクトや、go get コマンドでダウンロードされたサードパーティのパッケージが配置されるワークスペースのルートディレクトリを指します。Go 1.11以降のGo Modulesの導入により、GOPATH の役割は変化しましたが、このコミットが作成された2011年当時は、GOPATH がGo開発における主要なワークスペースでした。

go/build パッケージは、これらの環境変数を参照して、指定されたパッケージのソースコードを検索します。

goinstall コマンド

goinstall は、Go言語の初期のバージョンで提供されていたコマンドラインツールです。これは、指定されたGoパッケージをインターネットからダウンロードし、コンパイルし、インストールする機能を持っていました。現在の go get コマンドの前身にあたります。

このツールは、Goのパッケージ管理と依存関係解決の初期段階を担っており、ユーザーが新しいライブラリやアプリケーションを簡単に導入できるように設計されていました。

Goのエラーハンドリング

Go言語では、エラーは戻り値として明示的に扱われます。関数は通常、最後の戻り値として error 型の値を返します。エラーが発生しなかった場合は nil を返します。

errors.New() 関数は、新しいエラー値を生成するために使用されます。このコミットでは、ErrNotFoundErrTreeNotFound という2つのエラー変数が errors.New() を使って定義されています。

log.Printf

log パッケージは、Goの標準ライブラリの一部であり、ログメッセージを出力するための機能を提供します。log.Printf は、フォーマット文字列と引数を受け取り、標準エラー出力(または設定された出力先)にログメッセージを出力します。

このコミットでは、GOROOTGOPATH が無効な場合にログメッセージを出力するために log.Printf が使用されています。

技術的詳細

このコミットの技術的な詳細は、Go言語のエラーメッセージの設計と、ユーザーへの情報提供のバランスに関するものです。

エラーメッセージの冗長性の排除

Go言語のエラーメッセージは、通常、問題の内容を簡潔かつ明確に伝えるべきであるという原則があります。このコミット以前は、go/build パッケージが生成するエラーメッセージには、常にそのパッケージ名である "go/build:" というプレフィックスが付加されていました。

例えば、パッケージが見つからない場合のエラーは errors.New("go/build: package could not be found locally") と定義されていました。これは、エラーが go/build パッケージの内部で発生したことを示していますが、この情報がエンドユーザーにとって常に有用であるとは限りません。特に、goinstall のような上位レベルのツールがこれらのエラーをそのまま表示する場合、ユーザーは「goinstallgo/build パッケージを使って何かをしようとしたが、それが失敗した」という間接的な情報を得るだけで、直接的な問題解決には繋がりにくいと感じる可能性がありました。

この変更は、この冗長なプレフィックスを削除することで、エラーメッセージをより直接的で分かりやすいものにすることを目的としています。例えば、「package could not be found locally」というメッセージは、ユーザーが探しているパッケージが見つからなかったという事実を直接的に伝えます。これにより、ユーザーはエラーメッセージを解釈する手間が省け、問題の特定と解決に集中できるようになります。

errors.New とログメッセージの変更

コミットの差分を見ると、以下の2種類のエラーメッセージと2種類のログメッセージが変更されています。

  1. ErrNotFoundErrTreeNotFound の定義: これらのエラー変数は、go/build パッケージ内で定義されている公開エラーです。以前は errors.New("go/build: ...") の形式で定義されていましたが、変更後は "go/build:" プレフィックスが削除され、errors.New("...") の形式になりました。 これは、これらのエラーが go/build パッケージの外部に公開され、他のパッケージやツールによって捕捉・表示される可能性があるため、その際に冗長なプレフィックスが表示されないようにするためです。

  2. log.Printf で出力されるメッセージ: init() 関数内で GOROOTGOPATH の設定が不正な場合に log.Printf を使ってログメッセージが出力されていました。以前は log.Printf("go/build: invalid GOROOT %q: %v", ...) の形式でしたが、これも "go/build:" プレフィックスが削除されました。 ログメッセージの場合も、同様に冗長な情報を排除し、より簡潔に問題の内容を伝えることを目的としています。ログは開発者やシステム管理者が見るものですが、それでもメッセージは明確であるべきです。

影響とメリット

この変更による主なメリットは以下の通りです。

  • ユーザーエクスペリエンスの向上: goinstall などのツールが出力するエラーメッセージがより簡潔になり、ユーザーがエラーの原因を迅速に理解できるようになります。
  • メッセージの一貫性: Goのエラーメッセージの一般的な慣習に沿う形となり、他のGoツールやライブラリのエラーメッセージとの一貫性が向上します。
  • コードの簡潔化: エラーメッセージの定義がわずかに短くなり、コードの可読性も向上します。

この変更は、Go言語のツールチェインが成熟していく過程で、ユーザーからのフィードバックや開発者の経験に基づいて行われた、細かながらも重要な改善の一例と言えます。

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

変更は src/pkg/go/build/path.go ファイルに集中しています。

--- a/src/pkg/go/build/path.go
+++ b/src/pkg/go/build/path.go
@@ -85,8 +85,8 @@ func (t *Tree) HasPkg(pkg string) bool {
 }
 
 var (
-	ErrNotFound     = errors.New("go/build: package could not be found locally")
-	ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
+	ErrNotFound     = errors.New("package could not be found locally")
+	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
 )
 
 // FindTree takes an import or filesystem path and returns the
@@ -151,7 +151,7 @@ func init() {
 	root := runtime.GOROOT()
 	t, err := newTree(root)
 	if err != nil {
-		log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+		log.Printf("invalid GOROOT %q: %v", root, err)
 	} else {
 		t.Goroot = true
 		Path = []*Tree{t}
@@ -163,7 +163,7 @@ func init() {
 		}
 		t, err := newTree(p)
 		if err != nil {
-			log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+			log.Printf("invalid GOPATH %q: %v", p, err)
 		}
 		Path = append(Path, t)
 	}

具体的には、以下の4箇所が変更されています。

  1. ErrNotFound エラー変数の定義
  2. ErrTreeNotFound エラー変数の定義
  3. init() 関数内の GOROOT 関連の log.Printf 呼び出し
  4. init() 関数内の GOPATH 関連の log.Printf 呼び出し

コアとなるコードの解説

このコミットのコアとなる変更は、エラーメッセージとログメッセージから "go/build:" という文字列プレフィックスを削除することです。

エラー変数の定義変更

// 変更前
var (
	ErrNotFound     = errors.New("go/build: package could not be found locally")
	ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
)

// 変更後
var (
	ErrNotFound     = errors.New("package could not be found locally")
	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
)

ErrNotFound は、指定されたパッケージがローカルのファイルシステム上で見つからなかった場合に返されるエラーです。 ErrTreeNotFound は、有効な GOROOT または GOPATH が見つからなかった場合に返されるエラーです。

これらのエラーは go/build パッケージの外部に公開される可能性があるため、このプレフィックスを削除することで、エラーを受け取った側(例えば goinstall)がそのままメッセージを表示しても、冗長な情報が含まれないようになります。これにより、ユーザーは「パッケージが見つかりません」や「GOROOT/GOPATH が無効です」といった、より直接的なメッセージを受け取ることができます。

log.Printf 呼び出しの変更

// 変更前 (GOROOT関連)
if err != nil {
	log.Printf("go/build: invalid GOROOT %q: %v", root, err)
}

// 変更後 (GOROOT関連)
if err != nil {
	log.Printf("invalid GOROOT %q: %v", root, err)
}

// 変更前 (GOPATH関連)
if err != nil {
	log.Printf("go/build: invalid GOPATH %q: %v", p, err)
	continue
}

// 変更後 (GOPATH関連)
if err != nil {
	log.Printf("invalid GOPATH %q: %v", p, err)
	continue
}

init() 関数は、パッケージが初期化される際に自動的に実行される特別な関数です。この関数内で、GOROOTGOPATH の設定を検証し、もし無効なパスが指定されていれば、log.Printf を使って警告メッセージを出力しています。

ここでも同様に、ログメッセージから "go/build:" プレフィックスが削除されています。ログは通常、開発者やシステム管理者がデバッグや問題診断のために参照するものですが、それでもメッセージは簡潔で分かりやすい方が好ましいです。この変更により、「invalid GOROOT」や「invalid GOPATH」といった、より直接的な警告がログに出力されるようになります。

これらの変更は、Go言語のエラーメッセージとログ出力の品質を向上させ、ユーザーと開発者の双方にとってより良い体験を提供するための、細部にわたる配慮を示しています。

関連リンク

参考にした情報源リンク

  • Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
  • Go Code Review Comments (Effective Go): https://go.dev/doc/effective_go#errors (エラーメッセージに関する一般的なGoの慣習)
  • goinstall の歴史に関する情報 (Goの初期のツールチェインに関するブログ記事やディスカッション):
    • Go 1 Release Notes (goinstallからgo getへの移行に関する言及がある可能性): https://go.dev/doc/go1
    • Goの初期のメーリングリストアーカイブ (golang-nuts, golang-dev): https://groups.google.com/g/golang-nuts (当時の議論を検索することで、goinstall の問題点やエラーメッセージに関する議論が見つかる可能性があります。)
  • Goのソースコード (特に src/cmd/go/ ディレクトリ内の goinstall に関連するコードや、src/pkg/go/build/ ディレクトリ内の他のファイル): https://github.com/golang/go
  • GoのIssue Tracker (当時の関連するIssueや提案): https://github.com/golang/go/issues
  • GoのChange List (CL) 5495074: https://golang.org/cl/5495074 (このコミットの元となったコードレビューのページ。詳細な議論や背景情報が含まれている可能性があります。)
  • Web検索結果: "goinstall confusing error messages go/build" (Goのエラーメッセージが混乱を招く原因と、goinstallGOPATH との関連性に関する一般的な情報)