[インデックス 13074] ファイルの概要
このコミットは、Goコマンドラインツール(cmd/go
)の機能改善とユーザビリティ向上を目的としています。具体的には、go doc
コマンドがgodoc
ツールを呼び出す際の挙動を改善し、go doc
、go fmt
、go vet
の各コマンドに-n
(実行されるコマンドを表示)と-x
(実行中のコマンドを表示)のデバッグフラグを追加しています。さらに、不明なコマンドが入力された際のエラーメッセージをより簡潔にしています。
コミット
commit 0c8f4694282aebd131fee8400cfc6ca0b0c41775
Author: Russ Cox <rsc@golang.org>
Date: Tue May 15 12:53:57 2012 -0400
cmd/go: invoke godoc with import path when possible
Also add -n -x flags to doc, fmt, vet.
Also shorten unknown command error.
Fixes #3612.
Fixes #3613.
R=golang-dev, bradfitz, r
CC=golang-dev
https://golang.org/cl/6211053
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0c8f4694282aebd131fee8400cfc6ca0b0c41775
元コミット内容
cmd/go: invoke godoc with import path when possible
Also add -n -x flags to doc, fmt, vet.
Also shorten unknown command error.
Fixes #3612.
Fixes #3613.
変更の背景
このコミットは、Goツールの使いやすさとデバッグ能力を向上させるために行われました。
-
go doc
のgodoc
呼び出し改善: 以前のgo doc
コマンドは、godoc
ツールを呼び出す際に、常にパッケージのローカルディレクトリパスを渡していました。しかし、Goのパッケージはインポートパス(例:github.com/user/repo/package
)によって識別されるため、ローカルディレクトリパスだけではgodoc
が正確なドキュメントを特定できない場合がありました。特に、GOPATH外のモジュールや、リモートリポジトリから取得したパッケージのドキュメントを参照する際に問題が生じる可能性がありました。この変更により、可能な場合はインポートパスを使用してgodoc
を呼び出すことで、より堅牢で正確なドキュメント参照が可能になります。 -
-n
および-x
フラグの追加:go
コマンドは、内部で他のGoツール(godoc
,gofmt
,go vet
など)を呼び出して処理を実行します。開発者がこれらの内部的なコマンド呼び出しを理解し、デバッグできるようにするために、-n
(実行されるコマンドを表示するが実行しない)と-x
(実行されるコマンドを表示し、実行する)フラグが導入されました。これは、ビルドシステムやスクリプトのデバッグにおいて非常に一般的な機能であり、Goツールにも同様の機能が求められていました。 -
不明なコマンドエラーメッセージの短縮:
go
コマンドに存在しないサブコマンドが入力された際のエラーメッセージが冗長でした。この変更は、ユーザーエクスペリエンスを向上させ、エラーメッセージをより簡潔で分かりやすくすることを目的としています。
コミットメッセージに記載されているFixes #3612
とFixes #3613
は、このコミットが解決したGoのIssueトラッカー上の問題を指しています。ただし、現在のGoのIssueトラッカー(GitHub)ではこれらの番号のIssueは存在しないか、異なる内容を示しているため、このコミットが作成された2012年当時のGoのIssueトラッカー(Google Codeなど)のIssueを参照している可能性が高いです。
前提知識の解説
このコミットを理解するためには、以下のGoの基本的な概念とツールに関する知識が必要です。
- Goコマンド (
go
): Go言語のビルド、テスト、実行、ドキュメント生成など、様々なタスクを管理するための主要なコマンドラインツールです。go build
,go run
,go test
,go get
などのサブコマンドを持ちます。 godoc
: Goのソースコードからドキュメントを生成・表示するためのツールです。Goのコメント規約に従って書かれたコメントや、エクスポートされた識別子(関数、変数、型など)から自動的にドキュメントを生成します。gofmt
: Goのソースコードを標準的なスタイルに自動整形するためのツールです。Goコミュニティ全体で一貫したコードスタイルを維持するために広く利用されています。go vet
: Goのソースコード内で潜在的なバグや疑わしい構造を検出するための静的解析ツールです。例えば、フォーマット文字列の不一致や、到達不能なコードなどを検出します。- パッケージとインポートパス: Goのコードはパッケージに分割され、他のパッケージから利用する際にはインポートパス(例:
fmt
,net/http
,github.com/user/repo/package
)を指定します。インポートパスは、パッケージのソースコードがどこにあるかを特定するための論理的な識別子です。 - GOPATH: Go 1.11以前のGoのワークスペースの概念で、Goのソースコード、コンパイル済みバイナリ、パッケージが配置されるディレクトリ構造を定義していました。Go Modulesの導入により、GOPATHの重要性は低下しましたが、古いコードベースや特定の環境では依然として関連性があります。
- Go Modules: Go 1.11以降で導入された依存関係管理システムです。プロジェクトのルートディレクトリにある
go.mod
ファイルで依存関係を定義し、GOPATHに依存せずにプロジェクトをビルドできるようになりました。 - コマンドラインフラグ (
-n
,-x
): 多くのコマンドラインツールで一般的に使用されるオプションで、ツールの挙動を制御します。-n
(dry run): 実際にコマンドを実行せずに、実行されるであろうコマンドを表示します。スクリプトのデバッグや、予期せぬ変更を防ぐために有用です。-x
(verbose execution): コマンドが実行される際に、そのコマンド自体を表示します。内部で複数のサブコマンドを呼び出すような複雑なツールで、何が実行されているかを追跡するのに役立ちます。
技術的詳細
このコミットは、主にsrc/cmd/go
ディレクトリ内のGoコマンドのサブコマンド処理ロジックとフラグ処理に影響を与えています。
-
godoc
呼び出しの改善 (src/cmd/go/doc.go
):runDoc
関数内で、godoc
を呼び出す際に渡す引数を変更しています。pkg.local
(パッケージがローカルファイルシステム上にあるかどうかを示すブール値)をチェックし、true
の場合はこれまで通りpkg.Dir
(パッケージのディレクトリパス)をgodoc
に渡します。pkg.local
がfalse
の場合(例: リモートパッケージや標準ライブラリパッケージ)、pkg.ImportPath
(パッケージのインポートパス)をgodoc
に渡すように変更されました。これにより、godoc
はインポートパスに基づいて正確なドキュメントを特定できるようになります。
-
-n
,-x
フラグの追加と処理 (src/cmd/go/build.go
,src/cmd/go/doc.go
,src/cmd/go/fmt.go
,src/cmd/go/vet.go
,src/cmd/go/main.go
):src/cmd/go/build.go
にaddBuildFlagsNX
という新しいヘルパー関数が追加されました。この関数は、Command
構造体に-n
と-x
のブール型フラグを登録します。src/cmd/go/doc.go
,src/cmd/go/fmt.go
,src/cmd/go/vet.go
の各ファイルで、それぞれのCommand
構造体のinit
関数内でaddBuildFlagsNX
が呼び出され、対応するサブコマンドに-n
と-x
フラグが追加されます。- これらのフラグの動作は、
src/cmd/go/main.go
のrun
関数で実装されています。run
関数は、Goコマンドが内部で外部コマンド(godoc
,gofmt
,go vet
など)を実行する際に使用される共通のヘルパー関数です。 run
関数内で、グローバル変数buildN
(-n
フラグが設定されているか)またはbuildV
(-v
フラグ、このコミットでは変更なしだが既存の冗長出力フラグ)がtrue
の場合、実行されるコマンドラインが標準出力にfmt.Printf
で表示されます。- 特に
buildN
がtrue
の場合、コマンドは実際に実行されずにreturn
するため、ドライラン機能が実現されます。
-
不明なコマンドエラーメッセージの短縮 (
src/cmd/go/main.go
):main
関数内で、不明なサブコマンドが入力された際のエラー出力ロジックが変更されました。- 以前の
fmt.Fprintf(os.Stderr, "Unknown command %#q\\n\\n", args[0])
とusage()
の呼び出しが、より簡潔なfmt.Fprintf(os.Stderr, "go: unknown subcommand %#q\\nRun 'go help' for usage.\\n", args[0])
とsetExitStatus(2)
、exit()
に置き換えられました。これにより、エラーメッセージが短くなり、go help
を実行するように促す明確な指示が追加されました。また、終了ステータスが2に設定されることで、スクリプトなどからのエラーハンドリングが容易になります。
コアとなるコードの変更箇所
src/cmd/go/build.go
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -152,6 +152,11 @@ func addBuildFlags(cmd *Command) {
cmd.Flag.Var(buildCompiler{}, "compiler", "")
}
+func addBuildFlagsNX(cmd *Command) {
+ cmd.Flag.BoolVar(&buildN, "n", false, "")
+ cmd.Flag.BoolVar(&buildX, "x", false, "")
+}
+
type stringsFlag []string
func (v *stringsFlag) Set(s string) error {
src/cmd/go/doc.go
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -145,7 +145,7 @@ Run godoc on package sources
Usage:
-\tgo doc [packages]
+\tgo doc [-n] [-x] [packages]
Doc runs the godoc command on the packages named by the
import paths.
@@ -153,6 +153,9 @@ import paths.
For more about godoc, see 'godoc godoc'.
For more about specifying packages, see 'go help packages'.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
To run godoc with specific options, run godoc itself.
See also: go fix, go fmt, go vet.
@@ -414,7 +420,7 @@ Run go tool vet on packages
Usage:
-\tgo vet [packages]
+\tgo vet [-n] [-x] [packages]
Vet runs the Go vet command on the packages named by the import paths.
@@ -423,6 +429,9 @@ For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
See also: go fmt, go fix.
src/cmd/go/fmt.go
--- a/src/cmd/go/fmt.go
+++ b/src/cmd/go/fmt.go
@@ -4,9 +4,14 @@
package main
+func init() {
+ addBuildFlagsNX(cmdFmt)
+ addBuildFlagsNX(cmdDoc)
+}
+
var cmdFmt = &Command{
Run: runFmt,
-\tUsageLine: "fmt [packages]",
+\tUsageLine: "fmt [-n] [-x] [packages]",
Short: "run gofmt on package sources",
Long: `
Fmt runs the command 'gofmt -l -w' on the packages named
@@ -15,6 +20,9 @@ by the import paths. It prints the names of the files that are modified.\n For more about gofmt, see 'godoc gofmt'.\n For more about specifying packages, see 'go help packages'.\n \n+The -n flag prints commands that would be executed.\n+The -x flag prints commands as they are executed.\n+\n To run gofmt with specific options, run gofmt itself.\n \n See also: go doc, go fix, go vet.\n@@ -32,7 +40,7 @@ func runFmt(cmd *Command, args []string) {\n \n var cmdDoc = &Command{\n Run: runDoc,\n-\tUsageLine: "doc [packages]",
+\tUsageLine: "doc [-n] [-x] [packages]",
Short: "run godoc on package sources",
Long: `
Doc runs the godoc command on the packages named by the
@@ -41,6 +49,9 @@ import paths.\n For more about godoc, see 'godoc godoc'.\n For more about specifying packages, see 'go help packages'.\n \n+The -n flag prints commands that would be executed.\n+The -x flag prints commands as they are executed.\n+\n To run godoc with specific options, run godoc itself.\n \n See also: go fix, go fmt, go vet.\n@@ -53,6 +64,10 @@ func runDoc(cmd *Command, args []string) {\n \t\t\terrorf("go doc: cannot use package file list")\n \t\t\tcontinue\n \t\t}\n-\t\trun("godoc", pkg.Dir)\n+\t\tif pkg.local {\n+\t\t\trun("godoc", pkg.Dir)\n+\t\t} else {\n+\t\t\trun("godoc", pkg.ImportPath)\n+\t\t}\n \t}\n }\n```
### `src/cmd/go/main.go`
```diff
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -144,8 +144,9 @@ func main() {
}
}
-\tfmt.Fprintf(os.Stderr, "Unknown command %#q\\n\\n", args[0])
-\tusage()
+\tfmt.Fprintf(os.Stderr, "go: unknown subcommand %#q\\nRun 'go help' for usage.\\n", args[0])
+\tsetExitStatus(2)
+\texit()
}
var usageTemplate = `Go is a tool for managing Go source code.
@@ -339,6 +340,13 @@ func exitIfErrors() {
func run(cmdargs ...interface{}) {
cmdline := stringList(cmdargs...)
+\tif buildN || buildV {
+\t\tfmt.Printf("%s\\n", strings.Join(cmdline, " "))
+\t\tif buildN {
+\t\t\treturn
+\t\t}\n+\t}\n+\n cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
src/cmd/go/vet.go
--- a/src/cmd/go/vet.go
+++ b/src/cmd/go/vet.go
@@ -4,9 +4,13 @@
package main
+func init() {
+ addBuildFlagsNX(cmdVet)
+}
+
var cmdVet = &Command{
Run: runVet,
-\tUsageLine: "vet [packages]",
+\tUsageLine: "vet [-n] [-x] [packages]",
Short: "run go tool vet on packages",
Long: `
Vet runs the Go vet command on the packages named by the import paths.
@@ -16,6 +20,9 @@ For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
See also: go fmt, go fix.
`,
}
コアとなるコードの解説
src/cmd/go/build.go
の変更
addBuildFlagsNX
関数が新しく追加されました。この関数は、Command
構造体(Goコマンドのサブコマンドを表す)を受け取り、そのFlag
セットに-n
と-x
という2つのブール型フラグを登録します。これらのフラグはそれぞれグローバル変数buildN
とbuildX
にバインドされ、コマンドラインでこれらのフラグが指定された場合にtrue
になります。これにより、Goコマンドの各サブコマンドが共通の方法でこれらのデバッグフラグをサポートできるようになります。
src/cmd/go/doc.go
, src/cmd/go/fmt.go
, src/cmd/go/vet.go
の変更
- UsageLineの更新: 各コマンドの
UsageLine
フィールドが更新され、新しく追加された-n
と-x
フラグが使用法に明示的に含まれるようになりました。これにより、ユーザーはgo help doc
などのコマンドを実行した際に、これらの新しいフラグの存在を知ることができます。 - Long説明の追加: 各コマンドの
Long
フィールド(詳細な説明)に、-n
と-x
フラグの機能に関する説明が追加されました。 init
関数でのフラグ登録:cmdFmt
,cmdDoc
,cmdVet
の各Command
構造体に対応するinit
関数内で、addBuildFlagsNX
が呼び出されるようになりました。これにより、Goプログラムの初期化時に、これらのサブコマンドに-n
と-x
フラグが自動的に登録されます。runDoc
関数の変更 (src/cmd/go/fmt.go
内のcmdDoc
のRun
フィールド):runDoc
関数は、go doc
コマンドが実行されたときに実際にgodoc
ツールを呼び出すロジックを含んでいます。この変更の最も重要な部分は、godoc
を呼び出す際の引数の選択ロジックです。
このコードは、処理中のパッケージif pkg.local { run("godoc", pkg.Dir) } else { run("godoc", pkg.ImportPath) }
pkg
がローカルファイルシステム上に存在するかどうか(pkg.local
)をチェックします。- もし
pkg.local
がtrue
であれば、godoc
はパッケージの物理的なディレクトリパス(pkg.Dir
)を引数として実行されます。これは、ローカルで開発中のパッケージや、GOPATH内のパッケージに対して適切です。 - もし
pkg.local
がfalse
であれば(例: 標準ライブラリのパッケージや、Go Modulesで管理されているリモートパッケージ)、godoc
はパッケージのインポートパス(pkg.ImportPath
)を引数として実行されます。これにより、godoc
はインポートパスに基づいてパッケージを正確に解決し、適切なドキュメントを表示できるようになります。この変更は、go doc
の堅牢性と汎用性を大幅に向上させました。
- もし
src/cmd/go/main.go
の変更
- 不明なコマンドエラーメッセージの改善:
main
関数内で、Goコマンドに認識されないサブコマンドが渡された場合のエラー処理が変更されました。
以前は「Unknown command」というメッセージと、Goコマンド全体の- fmt.Fprintf(os.Stderr, "Unknown command %#q\\n\\n", args[0]) - usage() + fmt.Fprintf(os.Stderr, "go: unknown subcommand %#q\\nRun 'go help' for usage.\\n", args[0]) + setExitStatus(2) + exit()
usage
(使用法)が表示されていましたが、新しいメッセージは「go: unknown subcommand」とより具体的になり、go help
を実行するように促す簡潔な指示に変わりました。また、setExitStatus(2)
とexit()
が追加され、プログラムがエラー終了コード2で終了するようになりました。これは、スクリプトなどからGoコマンドの実行結果を判断する際に役立ちます。 run
関数の変更:run
関数は、Goコマンドが内部で他の外部コマンドを実行する際の共通のエントリーポイントです。
このコードブロックが追加され、if buildN || buildV { fmt.Printf("%s\\n", strings.Join(cmdline, " ")) if buildN { return } }
-n
または-x
フラグ(buildN
またはbuildX
がtrue
の場合、buildV
は既存の冗長フラグ)が設定されている場合に、実行されるコマンドライン(cmdline
)が標準出力に表示されるようになりました。buildN
がtrue
の場合(-n
フラグが指定された場合)、コマンドラインが表示された後、return
によって実際のコマンド実行がスキップされます。これがドライラン機能の実装です。buildX
がtrue
の場合(-x
フラグが指定された場合)、コマンドラインが表示された後、通常のコマンド実行が続行されます。これにより、実行中のコマンドをリアルタイムで追跡できます。
これらの変更により、Goコマンドはよりデバッグしやすく、ユーザーフレンドリーなツールへと進化しました。
関連リンク
- Go言語公式ウェブサイト: https://go.dev/
godoc
コマンドのドキュメント:go doc godoc
または https://pkg.go.dev/cmd/godocgofmt
コマンドのドキュメント:go doc gofmt
または https://pkg.go.dev/cmd/gofmtgo vet
コマンドのドキュメント:go doc govet
または https://pkg.go.dev/cmd/vet- Go Modulesに関する情報: https://go.dev/blog/using-go-modules
参考にした情報源リンク
- Goのソースコードリポジトリ: https://github.com/golang/go
- Goのコードレビューシステム (Gerrit): https://go.dev/cl/6211053 (コミットメッセージに記載されているChange-ID)
- GoのIssueトラッカー: https://go.dev/issue (ただし、このコミットが修正したIssue番号は古いトラッカーのものと思われる)