[インデックス 12013] ファイルの概要
このコミットは、Go言語のドキュメンテーションツールである godoc
コマンドの挙動に関する修正です。具体的には、go doc foo
のようにコマンドとして godoc
を実行した際に、不必要なサジェスチョンが表示される問題を解決しています。この修正は、godoc
がパスを処理する方法を改善し、特に go
コマンドが絶対パスで godoc
を呼び出す場合の挙動を調整することで実現されています。
コミット
- コミットハッシュ:
6cdf0a1eab8c038b439543f45aff2bcf660b0eac
- Author: Robert Griesemer gri@golang.org
- Date: Fri Feb 17 11:01:16 2012 -0800
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6cdf0a1eab8c038b439543f45aff2bcf660b0eac
元コミット内容
godoc: don't print spurious suggestion when running "go doc foo"
Fixes #3041.
R=rsc
CC=golang-dev
https://golang.org/cl/5671087
変更の背景
godoc
はGo言語のパッケージやコマンドのドキュメンテーションを表示するためのツールです。通常、godoc <package_path>
のようにパッケージのドキュメントを表示したり、godoc <symbol>
のように特定のシンボルのドキュメントを表示したりします。また、go doc <command_name>
のように go
コマンドのサブコマンドとして実行されることもあります。
このコミットが修正しようとしている問題は、go doc foo
のように godoc
がコマンドとして実行された際に、godoc
が不必要な「サジェスチョン」を表示してしまうというものでした。これは、godoc
が入力された foo
をパッケージパスとしても解釈しようとし、その結果、存在しないパッケージに対する「もしかしてこれですか?」のような誤った提案を出してしまうことが原因と考えられます。
特に、go
コマンドが godoc
を呼び出す際には、内部的に絶対パスを使用して godoc
に引数を渡すことがあります。この場合、godoc
はその絶対パスを「コマンド」としてではなく、「パッケージパス」として処理しようとし、結果として誤った挙動を引き起こしていました。コミットメッセージにある Fixes #3041
は、この問題がGoの内部的な課題追跡システムで管理されていたことを示唆しています。ただし、現在のGitHubリポジトリでは直接このIssueを見つけることはできませんでした。
この変更の目的は、godoc
がコマンド引数をより適切に解釈し、特に go
コマンドからの呼び出しにおいて、不必要なサジェスチョンや誤ったドキュメント表示を防ぐことにあります。
前提知識の解説
このコミットを理解するためには、以下のGo言語および godoc
に関する基本的な知識が必要です。
godoc
コマンド: Go言語のソースコードからドキュメンテーションを生成し、表示するためのツールです。パッケージ、関数、型、変数などのドキュメントを表示できます。また、HTTPサーバーとしてドキュメントを提供することも可能です。go doc
コマンド:go
コマンドのサブコマンドの一つで、godoc
ツールを呼び出してドキュメントを表示します。例えば、go doc fmt
はfmt
パッケージのドキュメントを表示します。filepath.IsAbs(path string) bool
: Go言語のpath/filepath
パッケージにある関数で、与えられたパスが絶対パスであるかどうかを判定します。絶対パスは、ファイルシステムのルートからの完全なパスを指します(例:/usr/local/bin/go
)。abspath
(absolute path): 絶対パスの略。ファイルシステム上の特定のリソースへの完全なパス。relpath
(relative path): 相対パスの略。現在の作業ディレクトリからの相対的なパス。PageInfo
:godoc
内部で使用される構造体で、表示するドキュメントページの情報を保持します。これには、ドキュメントの内容、タイトル、関連情報などが含まれます。cmdHandler
とpkgHandler
:godoc
内部で、それぞれコマンドのドキュメントとパッケージのドキュメントを処理するためのハンドラ(ロジックの塊)です。godoc
は、与えられた引数がコマンド名なのか、それともパッケージパスなのかを判断し、適切なハンドラを使ってドキュメントを検索・表示します。getPageInfo(abspath, relpath, query string, mode PageInfoMode)
:cmdHandler
やpkgHandler
が持つメソッドで、指定されたパスやクエリに基づいてPageInfo
オブジェクトを取得します。
godoc
は、与えられた引数をまずパッケージパスとして解釈しようとし、次にコマンド名として解釈しようとする、という優先順位で動作していました。このコミットは、この解釈ロジックに filepath.IsAbs
を用いた条件を追加することで、go
コマンドからの呼び出し(絶対パスが渡される場合)の挙動を改善しています。
技術的詳細
このコミットの技術的な核心は、godoc
がコマンド引数を処理する際のロジックに、パスが絶対パスであるかどうかのチェックを追加した点にあります。
修正前の godoc/main.go
の関連部分では、まず pkgHandler.getPageInfo
を使って引数をパッケージとして解釈しようとします。その後、cinfo := cmdHandler.getPageInfo(abspath, relpath, "", mode)
の行で、無条件に引数をコマンドとして解釈しようとしていました。ここで abspath
は、pkgHandler
がパッケージとして解釈しようとした際に生成された絶対パスがそのまま使われていました。
問題は、go
コマンドが godoc
を呼び出す際に、例えば go doc foo
の foo
が内部的に /path/to/go/bin/foo
のような絶対パスとして godoc
に渡される場合です。この場合、godoc
は foo
をパッケージとしても、コマンドとしても解釈しようとします。しかし、foo
が実際にはコマンド名であるにもかかわらず、godoc
がそれを絶対パスとして受け取ると、cmdHandler.getPageInfo
がその絶対パスを「コマンドの絶対パス」として処理しようとします。もしその絶対パスに該当するコマンドが存在しない場合、godoc
は「もしかしてこれですか?」のような不必要なサジェスチョンを出力してしまうことがありました。
このコミットでは、cmdHandler.getPageInfo
を呼び出す前に if !filepath.IsAbs(path)
という条件を追加しています。
path
はgodoc
に渡された元の引数です。filepath.IsAbs(path)
は、その引数が絶対パスであるかどうかを判定します。
この条件が true
(つまり、path
が相対パスである) の場合にのみ、cmdHandler.getPageInfo
を呼び出して引数をコマンドとして解釈しようとします。
これにより、go
コマンドが godoc
を絶対パスで呼び出した場合(例: go doc /usr/local/bin/go
のような内部的な呼び出し)、filepath.IsAbs(path)
が true
となり、!filepath.IsAbs(path)
は false
になるため、cmdHandler.getPageInfo
の呼び出しがスキップされます。これにより、godoc
は絶対パスをコマンドとして誤って解釈しようとすることがなくなり、不必要なサジェスチョンの表示が抑制されます。
また、var cinfo PageInfo
が追加され、cinfo
の宣言が if
ブロックの外に出されています。これは、cinfo
が if
ブロックのスコープ外でも利用されるため、Goのスコープ規則に合わせた変更です。
コアとなるコードの変更箇所
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -417,11 +417,13 @@ func main() {
info = pkgHandler.getPageInfo(abspath, relpath, "", mode)
}
- // second, try as command
+ // second, try as command unless the path is absolute
+ // (the go command invokes godoc w/ absolute paths; don't override)
+ var cinfo PageInfo
if !filepath.IsAbs(path) {
abspath = absolutePath(path, cmdHandler.fsRoot)
+ cinfo = cmdHandler.getPageInfo(abspath, relpath, "", mode)
}
- cinfo := cmdHandler.getPageInfo(abspath, relpath, "", mode)
// determine what to use
if info.IsEmpty() {
コアとなるコードの解説
変更の中心は、src/cmd/godoc/main.go
ファイルの main
関数内の、コマンドとして引数を解釈しようとする部分です。
元のコード:
// second, try as command
cinfo := cmdHandler.getPageInfo(abspath, relpath, "", mode)
この行は、godoc
に渡された引数を無条件にコマンドとして解釈しようとしていました。abspath
は、その時点での絶対パス(パッケージとして解釈しようとした結果のパス)が使われていました。
変更後のコード:
// second, try as command unless the path is absolute
// (the go command invokes godoc w/ absolute paths; don't override)
var cinfo PageInfo
if !filepath.IsAbs(path) {
abspath = absolutePath(path, cmdHandler.fsRoot)
cinfo = cmdHandler.getPageInfo(abspath, relpath, "", mode)
}
この変更により、以下の点が改善されました。
var cinfo PageInfo
の追加:cinfo
変数がif
ブロックの外で宣言されるようになりました。これにより、if
ブロックの条件が満たされない場合でもcinfo
が定義され、その後のif info.IsEmpty() { ... }
のロジックでcinfo
を参照できるようになります。Goの言語仕様では、:=
を使った短い変数宣言は、その変数が宣言されたブロック内でのみ有効です。この変更は、cinfo
のスコープを適切に広げるためのものです。if !filepath.IsAbs(path)
条件の追加: これが最も重要な変更です。path
はgodoc
コマンドに最初に渡された生の引数です。filepath.IsAbs(path)
は、そのpath
が絶対パスであるかどうかをチェックします。!
は論理否定なので、!filepath.IsAbs(path)
は「path
が絶対パスではない場合(つまり相対パスの場合)」という条件になります。- この条件が
true
の場合にのみ、godoc
は引数をコマンドとして解釈しようとします。
このロジックにより、go
コマンドが godoc
を呼び出す際に、内部的に絶対パス(例: /usr/local/bin/go
)を引数として渡した場合、filepath.IsAbs(path)
が true
となり、if
ブロック内の cmdHandler.getPageInfo
の呼び出しはスキップされます。これにより、godoc
は絶対パスを誤ってコマンド名として解釈しようとすることがなくなり、不必要なサジェスチョンが表示される問題が解決されます。
要するに、この修正は godoc
が引数を「コマンド名」として解釈する前に、その引数が「相対パス」であるかどうかを確認するようになった、ということです。これにより、go
コマンドのような上位のツールが godoc
を絶対パスで呼び出す際の挙動がより適切に制御されるようになりました。
関連リンク
- Go CL (Change List) へのリンク: https://golang.org/cl/5671087
参考にした情報源リンク
path/filepath
パッケージのドキュメント: https://pkg.go.dev/path/filepathgodoc
コマンドに関する一般的な情報 (Go公式ドキュメントなど): https://go.dev/blog/godoc- Go言語のスコープに関する情報 (Go公式ドキュメントなど): https://go.dev/ref/spec#Declarations_and_scope
- Issue #3041 については、直接的なGitHub上の情報は見つかりませんでした。これは、Goプロジェクトが内部的な課題追跡システムを使用していた時期のIssueであるか、または別のリポジトリのIssueである可能性があります。