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

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

このコミットは、Go言語のコマンドラインツール(cmd/go)における詳細表示(verbose command displaying)の不具合を修正するものです。具体的には、goコマンドが実行する内部コマンドのパス表示において、ルートディレクトリ(/)が不適切に省略される問題を解決しています。

コミット

commit e8c970e5f7d5fa720a38da00a31870fc0b1c2b0f
Author: Gustavo Niemeyer <gustavo@niemeyer.net>
Date:   Thu Mar 1 20:14:21 2012 -0300

    cmd/go: fix verbose command displaying

    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5715050

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

https://github.com/golang/go/commit/e8c970e5f7d5fa720a38da00a31870fc0b1c2b0f

元コミット内容

cmd/go: fix verbose command displaying

このコミットは、goコマンドの詳細表示における不具合を修正します。

変更の背景

Go言語のgoコマンドは、ビルドやテストなどの操作を行う際に、内部で様々なサブコマンドや外部ツールを実行します。-xオプションなどを付けて詳細表示を有効にすると、これらの内部で実行されるコマンドの具体的な内容が表示されます。

このコミット以前のバージョンでは、goコマンドが内部で実行するコマンドのパスを表示する際に、現在の作業ディレクトリがルートディレクトリ(/)である場合に、そのパスが不適切に省略されてしまうという問題がありました。例えば、/go buildを実行した際に、本来表示されるべきコマンドパスが正しく表示されない、あるいは意図しない形で省略されてしまうことが考えられます。これは、デバッグや問題の特定を行う際に、ユーザーが正確な情報を得られないという点で不便でした。

この修正は、このような表示上の不具合を解消し、どのようなディレクトリでgoコマンドを実行しても、内部コマンドのパスが正確に表示されるようにすることを目的としています。

前提知識の解説

  • cmd/go: Go言語の公式ツールチェーンに含まれるコマンドラインツールです。go build, go run, go test, go getなど、Goプロジェクトの管理と操作を行うための主要なコマンドを提供します。
  • Verbose Command Displaying: goコマンドに-xオプションなどを付与することで有効になる、詳細なコマンド実行ログの表示機能です。これにより、goコマンドが内部でどのようなシェルコマンドを実行しているかを確認できます。これは、ビルドプロセスの理解やデバッグに非常に役立ちます。
  • src/cmd/go/build.go: Goツールチェーンのソースコードの一部で、go buildコマンドのロジックや、ビルドプロセスに関連するユーティリティ関数が定義されています。
  • fmt.Sprintf: Go言語の標準ライブラリfmtパッケージに含まれる関数で、フォーマット文字列と引数を受け取り、フォーマットされた文字列を返します。C言語のsprintfに似ています。
  • strings.Replace: Go言語の標準ライブラリstringsパッケージに含まれる関数で、文字列内の指定された部分文字列を別の文字列に置換します。
  • builder構造体とfmtcmdメソッド: cmd/goの内部で、ビルドプロセス中に実行されるコマンドを整形・表示するためのロジックをカプセル化したものです。fmtcmdメソッドは、実行されるコマンドの文字列を生成し、必要に応じてパスの整形などを行います。

技術的詳細

このコミットの技術的な核心は、src/cmd/go/build.goファイル内のbuilder構造体のfmtcmdメソッドにおける条件式の変更です。

fmtcmdメソッドは、内部で実行されるコマンドの文字列を整形する役割を担っています。このメソッドは、コマンドが実行されるディレクトリ(dir引数)を受け取り、そのディレクトリが現在の作業ディレクトリと異なる場合に、コマンドパスを相対パス(.)に置き換える処理を行っていました。

元のコードでは、このパス置換の条件がif dir != ""となっていました。これは、「ディレクトリが空文字列でなければ」という条件です。しかし、Unix系システムにおいてルートディレクトリは""ではなく/で表現されます。このため、現在の作業ディレクトリがルートディレクトリ(/)である場合でも、dir != ""の条件は真となり、strings.Replaceによるパスの置換処理が実行されてしまっていました。

具体的には、strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]という行で、コマンド文字列中の絶対パスを相対パスの.に置き換える処理が行われます。ルートディレクトリの場合、例えば/usr/bin/goのようなコマンドが/usr/bin/.のように不適切に置換されてしまう可能性がありました。

この修正では、条件式をif dir != "" && dir != "/"に変更しています。これにより、「ディレクトリが空文字列ではなく、かつルートディレクトリでもない場合」にのみパスの置換処理が実行されるようになります。結果として、ルートディレクトリでgoコマンドを実行した場合でも、内部コマンドのパスが正しく絶対パスのまま表示されるようになり、詳細表示の正確性が向上しました。

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

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -902,7 +902,7 @@ func isObject(s string) bool {
 //
 func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string {
 	cmd := fmt.Sprintf(format, args...)
-	if dir != "" {
+	if dir != "" && dir != "/" {
 		cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]
 		if b.scriptDir != dir {
 			b.scriptDir = dir

コアとなるコードの解説

変更された行は以下の通りです。

-	if dir != "" {
+	if dir != "" && dir != "/" {
  • 変更前 (-の行): if dir != ""
    • この条件は、dir(コマンドが実行されるディレクトリ)が空文字列でない場合に真となります。ルートディレクトリ(/)は空文字列ではないため、この条件に合致し、続くパス置換ロジックが実行されていました。
  • 変更後 (+の行): if dir != "" && dir != "/"
    • この新しい条件は、dirが空文字列でなく、かつルートディレクトリ(/)でもない場合にのみ真となります。
    • これにより、dirがルートディレクトリである場合には、このifブロック内のパス置換処理がスキップされるようになります。
    • 結果として、ルートディレクトリで実行されるコマンドのパスは、不適切に相対パスの.に置換されることなく、元の絶対パスのまま詳細表示されるようになります。

この小さな変更により、goコマンドの詳細表示機能が、ルートディレクトリでの実行時にも正確な情報を提供するようになりました。

関連リンク

  • Gerrit Change-Id: https://golang.org/cl/5715050

参考にした情報源リンク