[インデックス 16964] ファイルの概要
このコミットは、Go言語のツールチェインにおけるgodoc
コマンドのインストールパスと、go doc
コマンドのユーザーエクスペリエンスを改善するものです。具体的には、go.tools/cmd/godoc
が$GOROOT/bin/godoc
にインストールされるように変更し、さらにgo doc
コマンド実行時にgodoc
が見つからない場合に、go get
コマンドを使ったインストール方法をユーザーに提示するように改善しています。
コミット
- コミットハッシュ:
e011ac5420e1bda1feb87bc398a61ebbb52c0332
- 作者: Andrew Gerrand adg@golang.org
- 日付: 2013年8月1日 木曜日 11:17:42 +1000
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e011ac5420e1bda1feb87bc398a61ebbb52c0332
元コミット内容
cmd/go: install go.tools/cmd/godoc to $GOROOT/bin/godoc
Also suggest "go get" if godoc not found when running "go doc".
R=golang-dev, r, rsc
CC=golang-dev
https://golang.org/cl/12214043
変更の背景
Go言語の初期のバージョンでは、godoc
ツールはGoの標準配布物には含まれておらず、別途go get
コマンドを使ってインストールする必要がありました。しかし、godoc
はGoのドキュメントを参照するための非常に重要なツールであり、ユーザーがGoのドキュメントを簡単に利用できるようにすることが望まれていました。
このコミット以前は、godoc
は$GOROOT/pkg/tool
ディレクトリにインストールされる可能性がありました。しかし、godoc
は一般的なコマンドラインツールとして利用されることが多いため、ユーザーのPATH
に含まれる$GOROOT/bin
にインストールされる方が、よりアクセスしやすく、使い勝手が良いと考えられました。
また、go doc
コマンドは内部的にgodoc
ツールを呼び出してドキュメントを表示します。もしユーザーのシステムにgodoc
がインストールされていない場合、go doc
コマンドは単にエラーを返すだけで、ユーザーは何をすべきか分かりませんでした。このユーザーエクスペリエンスを改善するため、godoc
が見つからない場合に、そのインストール方法(go get
コマンドの使用)を具体的に提示することが必要とされました。
この変更は、Goツールのインストールと利用の利便性を向上させ、特に新規ユーザーがGoのエコシステムにスムーズに慣れることを支援することを目的としています。
前提知識の解説
このコミットを理解するためには、以下のGo言語に関する基本的な概念とツールについての知識が必要です。
-
go doc
コマンド:go doc
はGoの標準ツールの一つで、Goのパッケージ、関数、型、メソッドなどのドキュメントを表示するために使用されます。これは内部的にgodoc
ツールを呼び出して機能を提供します。例えば、go doc fmt.Println
と入力すると、fmt
パッケージのPrintln
関数のドキュメントが表示されます。 -
godoc
ツール:godoc
はGoのソースコードからドキュメントを生成し、表示するためのツールです。Goのコードコメントは特定の形式で記述することで、godoc
によって自動的にドキュメントとして抽出されます。godoc
はコマンドラインツールとしてだけでなく、Webサーバーとしても機能し、ブラウザを通じてGoのドキュメントを閲覧することもできます。 -
go get
コマンド:go get
は、Goのパッケージやコマンドをリモートリポジトリ(GitHubなど)からダウンロードし、ビルドしてインストールするためのコマンドです。例えば、go get example.com/some/package
と実行すると、指定されたパッケージが$GOPATH/src
にダウンロードされ、そのパッケージ内のコマンドが$GOPATH/bin
にインストールされます。 -
$GOROOT
:$GOROOT
はGoのインストールディレクトリを指す環境変数です。Goの標準ライブラリやツールチェインのバイナリ(go
コマンド自体など)がこのディレクトリ以下に配置されます。$GOROOT/bin
: Goの標準ツール(go
コマンドなど)の実行可能ファイルが置かれる場所です。$GOROOT/pkg/tool
: Goのビルドプロセスで使用される内部ツールや、特定のプラットフォーム向けのツールが置かれる場所です。通常、ユーザーのPATH
には含まれません。
-
$GOPATH
:$GOPATH
はGoのワークスペースディレクトリを指す環境変数です。ユーザーが開発するGoのプロジェクトや、go get
でダウンロード・インストールされたサードパーティのパッケージやコマンドがこのディレクトリ以下に配置されます。$GOPATH/src
: ソースコードが置かれる場所です。$GOPATH/bin
:go install
やgo get
でインストールされたコマンドの実行可能ファイルが置かれる場所です。
-
Goのツールインストールパス: Goのツールは、その性質によってインストールされる場所が異なります。
- 一般的なコマンドラインツールとしてユーザーが直接実行するものは、通常
$GOPATH/bin
または$GOROOT/bin
にインストールされることが望ましいです。 - Goのビルドシステムや他のツールから内部的に呼び出される補助的なツールは、
$GOROOT/pkg/tool
にインストールされることがあります。
- 一般的なコマンドラインツールとしてユーザーが直接実行するものは、通常
このコミットは、godoc
が後者の「内部ツール」から前者の「一般的なコマンドラインツール」としての位置づけに移行し、よりアクセスしやすい場所にインストールされるように変更するものです。
技術的詳細
このコミットは、主にsrc/cmd/go/fmt.go
とsrc/cmd/go/pkg.go
の2つのファイルを変更しています。
src/cmd/go/fmt.go
の変更
このファイルでは、go doc
コマンドが実行された際にgodoc
ツールが見つからない場合の挙動が変更されています。
os/exec
パッケージのインポート:exec.LookPath
関数を使用するために、os/exec
パッケージがインポートされています。runDoc
関数の変更:exec.LookPath("godoc")
を呼び出して、システムPATH
からgodoc
実行可能ファイルを探します。- もし
godoc
が見つからずエラーが発生した場合(err != nil
)、errorf
関数を使ってユーザーにエラーメッセージを表示します。 - 表示されるエラーメッセージは、「
go doc: can't find godoc; to install:\n\tgo get code.google.com/p/go.tools/cmd/godoc
」という形式で、godoc
が見つからないことと、go get
コマンドを使ったインストール方法を具体的に指示します。 - エラーメッセージを表示した後、関数は
return
して処理を終了します。
この変更により、ユーザーはgodoc
がインストールされていない場合に、その解決策をすぐに知ることができます。
src/cmd/go/pkg.go
の変更
このファイルでは、Goのツールがどこにインストールされるかを決定するロジックが変更されています。
-
isGoTool
変数の削除とtargetDir
型およびgoTools
マップの導入:- 以前は
isGoTool
というmap[string]bool
型の変数があり、$GOROOT/pkg/tool
にインストールされるGoツールのインポートパスを単純にリストアップしていました。 - このコミットでは、
targetDir
という新しい列挙型(iota
を使用)が導入されました。toRoot
: パッケージのルート内のbin
ディレクトリ(デフォルト)toTool
:$GOROOT/pkg/tool
toBin
:$GOROOT/bin
goTools
というmap[string]targetDir
型の新しいマップが導入されました。このマップは、Goツールのインポートパスと、そのツールがインストールされるべきターゲットディレクトリのタイプを関連付けます。- 注目すべきは、
"code.google.com/p/go.tools/cmd/godoc"
のエントリがtoBin
に設定されている点です。これにより、godoc
は$GOROOT/bin
にインストールされるようになります。他のツール(cmd/api
,cmd/cgo
,cmd/fix
,cmd/yacc
,cmd/cover
,cmd/vet
)は引き続きtoTool
に設定されています。
- 以前は
-
Package.load
関数の変更:- パッケージのターゲットパスを決定するロジックが、新しい
goTools
マップとtargetDir
型を使用するように変更されました。 - 以前は
isGoTool[p.ImportPath]
という単純なブール値のチェックに基づいていましたが、新しいswitch
ステートメントが導入されました。 switch goTools[p.ImportPath]
によって、ツールのインポートパスに対応するtargetDir
の値に基づいて、インストールパスが決定されます。toRoot
の場合(デフォルト):p.build.BinDir
(通常は$GOPATH/bin
)にインストールされます。toTool
の場合:filepath.Join(gorootPkg, "tool", full)
、つまり$GOROOT/pkg/tool
にインストールされます。toBin
の場合:filepath.Join(gorootBin, elem)
、つまり$GOROOT/bin
にインストールされます。
- パッケージのターゲットパスを決定するロジックが、新しい
この変更により、godoc
はGoの標準バイナリが置かれる$GOROOT/bin
にインストールされるようになり、ユーザーのPATH
を通じて直接実行できるようになります。これは、godoc
がGoのドキュメント参照において中心的な役割を果たすことを考慮した、論理的な配置変更と言えます。
コアとなるコードの変更箇所
src/cmd/go/fmt.go
--- a/src/cmd/go/fmt.go
+++ b/src/cmd/go/fmt.go
@@ -4,6 +4,8 @@
package main
+import "os/exec"
+
func init() {
addBuildFlagsNX(cmdFmt)
addBuildFlagsNX(cmdDoc)
@@ -59,6 +61,11 @@ See also: go fix, go fmt, go vet.
}
func runDoc(cmd *Command, args []string) {
+ _, err := exec.LookPath("godoc")
+ if err != nil {
+ errorf("go doc: can't find godoc; to install:\n\tgo get code.google.com/p/go.tools/cmd/godoc")
+ return
+ }
for _, pkg := range packages(args) {
if pkg.ImportPath == "command-line arguments" {
errorf("go doc: cannot use package file list")
src/cmd/go/pkg.go
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -283,15 +283,23 @@ func reusePackage(p *Package, stk *importStack) *Package {
return p
}
-// isGoTool is the list of directories for Go programs that are installed in
-// $GOROOT/pkg/tool.
-var isGoTool = map[string]bool{
- "cmd/api": true,
- "cmd/cgo": true,
- "cmd/fix": true,
- "cmd/yacc": true,
- "code.google.com/p/go.tools/cmd/cover": true,
- "code.google.com/p/go.tools/cmd/vet": true,
+type targetDir int
+
+const (
+ toRoot targetDir = iota // to bin dir inside package root (default)
+ toTool // GOROOT/pkg/tool
+ toBin // GOROOT/bin
+)
+
+// goTools is a map of Go program import path to install target directory.
+var goTools = map[string]targetDir{
+ "cmd/api": toTool,
+ "cmd/cgo": toTool,
+ "cmd/fix": toTool,
+ "cmd/yacc": toTool,
+ "code.google.com/p/go.tools/cmd/cover": toTool,
+ "code.google.com/p/go.tools/cmd/godoc": toBin,
+ "code.google.com/p/go.tools/cmd/vet": toTool,
}
// expandScanner expands a scanner.List error into all the errors in the list.
@@ -341,11 +349,15 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}\n- if p.build.BinDir != "" {\n- p.target = filepath.Join(p.build.BinDir, elem)\n- }\n- if isGoTool[p.ImportPath] {\n+ switch goTools[p.ImportPath] {\n+ case toRoot: // default, if p.ImportPath not in goTools
+ if p.build.BinDir != "" {
+ p.target = filepath.Join(p.build.BinDir, elem)
+ }
+ case toTool:
p.target = filepath.Join(gorootPkg, "tool", full)
+ case toBin:
+ p.target = filepath.Join(gorootBin, elem)
}
if p.target != "" && buildContext.GOOS == "windows" {
p.target += ".exe"
コアとなるコードの解説
src/cmd/go/fmt.go
の変更点
runDoc
関数はgo doc
コマンドの実行ロジックを担っています。この変更では、godoc
実行可能ファイルがシステムPATH
上に存在するかどうかをexec.LookPath("godoc")
で確認しています。もしgodoc
が見つからなかった場合(err != nil
)、ユーザーに対して「godoc
が見つからないので、go get code.google.com/p/go.tools/cmd/godoc
でインストールしてください」という具体的な指示を含むエラーメッセージを表示し、処理を中断します。これにより、ユーザーはgodoc
が不足している場合に、その解決策をすぐに理解できるようになります。
src/cmd/go/pkg.go
の変更点
このファイルは、Goパッケージのビルドとインストールに関するロジックを含んでいます。
-
isGoTool
からtargetDir
とgoTools
への移行: 以前はisGoTool
という単純なブールマップで、特定のツールが$GOROOT/pkg/tool
にインストールされるかどうかを管理していました。このコミットでは、より柔軟なインストールパスの指定を可能にするために、targetDir
という列挙型とgoTools
というマップが導入されました。targetDir
は、ツールのインストール先として考えられる3つの主要な場所(toRoot
、toTool
、toBin
)を定義します。goTools
マップは、各Goツールのインポートパスと、そのツールがインストールされるべきtargetDir
のタイプを関連付けます。- 特に重要なのは、
"code.google.com/p/go.tools/cmd/godoc"
がtoBin
に設定されたことです。これは、godoc
が$GOROOT/bin
、つまりGoの主要な実行可能ファイルが置かれるディレクトリにインストールされることを意味します。これにより、godoc
はユーザーのPATH
を通じて直接実行できるようになり、利便性が向上します。
-
Package.load
関数のインストールパス決定ロジックの変更:Package.load
関数内の、パッケージの最終的なインストールターゲットパス(p.target
)を決定する部分が変更されました。以前はisGoTool
のブール値に基づいていましたが、新しいロジックではgoTools[p.ImportPath]
の値(targetDir
型)に基づいてswitch
文で分岐します。toRoot
の場合(デフォルト):p.build.BinDir
(通常は$GOPATH/bin
)にインストールされます。これは、一般的なGoのコマンドやアプリケーションのデフォルトのインストール場所です。toTool
の場合:$GOROOT/pkg/tool
にインストールされます。これは、Goの内部ツールや、他のGoツールから呼び出される補助的なツールに適した場所です。toBin
の場合:$GOROOT/bin
にインストールされます。これは、godoc
のようにGoの標準配布物の一部として提供され、ユーザーが直接実行することを意図したツールに適した場所です。
これらの変更により、godoc
はよりアクセスしやすい$GOROOT/bin
にインストールされるようになり、go doc
コマンドはgodoc
が見つからない場合にユーザーに具体的な解決策を提示することで、Goツールの使いやすさが大幅に向上しました。
関連リンク
- Go言語公式ドキュメント: https://go.dev/doc/
go doc
コマンドのドキュメント: https://go.dev/cmd/go/#hdr-Go_documentationgodoc
ツールのドキュメント: https://go.dev/cmd/godoc/go get
コマンドのドキュメント: https://go.dev/cmd/go/#hdr-Download_and_install_packages_and_dependencies- Goの環境変数(
GOROOT
,GOPATH
など): https://go.dev/doc/code#GOPATH
参考にした情報源リンク
- Go言語の公式ドキュメント (上記「関連リンク」に記載)
- Go言語のソースコード (このコミットが属するリポジトリ)
- Go言語のIssueトラッカーやメーリングリスト (コミットメッセージに記載されているCLリンクなど)
https://golang.org/cl/12214043
(現在はhttps://go.dev/cl/12214043
にリダイレクトされます)
- 一般的なGo言語のチュートリアルや解説記事 (Goのツールチェインや環境変数に関する説明)
os/exec
パッケージのGoドキュメント: https://pkg.go.dev/os/execpath/filepath
パッケージのGoドキュメント: https://pkg.go.dev/path/filepathgo/build
パッケージのGoドキュメント: https://pkg.go.dev/go/buildgo.tools
リポジトリ (現在はgolang.org/x/tools
に移行): https://pkg.go.dev/golang.org/x/toolscode.google.com/p/go.tools
(古いパス、現在はgolang.org/x/tools
に移行)