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

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

このコミットは、Go言語のドキュメンテーションツールである godoc コマンドから -path フラグを削除する変更です。これにより、godoc がパッケージを探索する方法が簡素化され、GOROOT および GOPATH 環境変数に依存する標準的なメカニズムに統一されます。

コミット

commit fba47dc3b10e7649e3ad0129b357d83cc2db228e
Author: Dave Cheney <dave@cheney.net>
Date:   Wed Jul 25 10:49:50 2012 -0700

    cmd/godoc: delete -path flag
    
    Fixes #3453.
    
    R=golang-dev, gri, jeff, bradfitz
    CC=golang-dev
    https://golang.org/cl/6350086
---
 src/cmd/godoc/doc.go   | 18 ++----------------
 src/cmd/godoc/godoc.go | 11 -----------
 2 files changed, 2 insertions(+), 27 deletions(-)

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

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

元コミット内容

cmd/godoc: delete -path flag

このコミットは、godoc コマンドラインツールから -path フラグを削除します。

関連するIssue: #3453 を修正します。

変更の背景

この変更の背景には、Go言語のパッケージ管理とツールの設計思想があります。Go言語では、ソースコードの場所を特定するために GOROOTGOPATH という環境変数を主要なメカニズムとして使用します。

godoc はGoのソースコードからドキュメントを生成し、表示するツールですが、かつては -path フラグを通じて、GOROOTGOPATH 以外の追加のディレクトリをパッケージの探索パスとして指定できる機能がありました。

Issue #3453 (godoc: -path flag is confusing and unnecessary) では、この -path フラグが以下の理由で問題視されていました。

  1. 混乱を招く: GOROOTGOPATH といった標準的なGoの環境設定メカニズムがあるにもかかわらず、godoc 固有の -path フラグが存在することで、ユーザーがどのパス設定を使用すべきか混乱を招いていました。
  2. 冗長性: ほとんどの場合、GOPATH を適切に設定すれば、godoc が必要なパッケージを見つけることができました。-path フラグは、GOPATH の概念と重複し、不必要な複雑さを加えていました。
  3. 一貫性の欠如: Goのエコシステム全体で GOPATH が標準的なワークスペースの概念として確立されつつあったため、特定のツールが独自のパス設定メカニズムを持つことは、一貫性を損なうと考えられました。

これらの理由から、godoc のインターフェースを簡素化し、Goの標準的なパッケージ探索メカニズムに統一するために、-path フラグの削除が決定されました。これにより、ユーザーは godoc を含むGoツール群全体で GOROOTGOPATH の設定に集中できるようになります。

前提知識の解説

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

  1. godoc コマンド:

    • godoc はGo言語の公式ドキュメンテーションツールです。Goのソースコード(.go ファイル)内のコメントや宣言から自動的にドキュメントを生成し、コマンドラインで表示したり、HTTPサーバーとして提供したりできます。
    • 開発者がコードを書く際に、Goの標準的なコメント規約に従うことで、自動的に高品質なドキュメントが生成される仕組みを提供します。
    • Goの標準ライブラリのドキュメントも godoc によって生成され、pkg.go.dev (旧 golang.org/pkg/) で公開されています。
  2. GOROOT 環境変数:

    • GOROOT はGoのインストールディレクトリを指す環境変数です。Goのコンパイラ、標準ライブラリのソースコード、ツールなどがこのディレクトリに格納されています。
    • godoc はデフォルトで GOROOT 内のパッケージを探索し、ドキュメントを生成します。
  3. GOPATH 環境変数:

    • GOPATH はGoのワークスペースディレクトリを指す環境変数です。Go 1.11以降のGo Modulesの導入によりその重要性は薄れましたが、このコミットが作成された2012年当時は、ユーザーが開発するGoプロジェクトのソースコード、コンパイルされたバイナリ、パッケージの依存関係などがこのディレクトリ構造内に配置されるのが一般的でした。
    • GOPATH は通常、複数のディレクトリパスをコロン(Unix/Linux)またはセミコロン(Windows)で区切って指定できます。godocGOPATH 内の各ディレクトリも探索対象とします。
  4. Goのパッケージ探索メカニズム:

    • Goのツール(go build, go install, godoc など)は、インポートパスに基づいてパッケージのソースコードを探索します。
    • 探索は通常、GOROOT/src および GOPATH/src の下で行われます。例えば、import "fmt" であれば GOROOT/src/fmt を、import "github.com/user/repo" であれば GOPATH/src/github.com/user/repo を探します。
  5. flag パッケージ:

    • Goの標準ライブラリに含まれる flag パッケージは、コマンドライン引数を解析するための機能を提供します。
    • flag.String, flag.Int などの関数を使って、コマンドラインフラグとそのデフォルト値、説明を定義します。
  6. filepath パッケージ:

    • Goの標準ライブラリに含まれる filepath パッケージは、ファイルパスの操作(結合、分割、クリーンアップなど)を行うための機能を提供します。
    • filepath.SplitList は、OS固有のパス区切り文字(例: :;)で区切られたパス文字列を個々のパスのリストに分割します。
  7. fs.Bind (godoc内部のファイルシステム抽象化):

    • godoc は、実際のファイルシステムを直接操作するのではなく、抽象化されたファイルシステム (fs パッケージ) を使用しています。これにより、ファイルシステムをメモリ上にマウントしたり、ZIPファイルから読み込んだりするなどの柔軟な操作が可能になります。
    • fs.Bind は、特定のパスを別のファイルシステム(またはファイルシステム内の別のパス)に「バインド」(マウント)する機能を提供します。これにより、godoc は複数の異なる場所にあるソースコードをあたかも単一の仮想ファイルシステム内にあるかのように扱うことができます。

技術的詳細

このコミットは、godoc コマンドの -path フラグに関連するコードとドキュメントを完全に削除することで、その機能を廃止しています。

具体的には、以下の2つのファイルが変更されています。

  1. src/cmd/godoc/doc.go:

    • このファイルは godoc コマンドのヘルプメッセージやドキュメンテーションを定義しています。
    • 変更前は、-path フラグの説明(追加のパッケージディレクトリを指定する方法、コロン区切り、絶対パスからパッケージパスへのマッピング例など)が詳細に記述されていました。
    • 変更後は、これらの -path フラグに関する説明がすべて削除されています。
    • また、「By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).」という記述に続き、変更前は「Additional directories may be specified via the -path flag...」とあった部分が、変更後には「This behavior can be altered by providing an alternative $GOROOT with the -goroot flag.」と変更され、GOROOT のみでパス設定を変更できる旨が強調されています。
  2. src/cmd/godoc/godoc.go:

    • このファイルは godoc コマンドの主要なロジックを含んでいます。
    • 変更前は、flag.String("path", "", "additional package directories (colon-separated)") という行で pkgPath という名前のコマンドラインフラグが定義されていました。これが -path フラグの実体です。この定義が削除されました。
    • さらに重要な変更として、initHandlers 関数内の、pkgPath フラグの値に基づいて追加のディレクトリを godoc の仮想ファイルシステムにバインドするロジックが完全に削除されました。
      • このロジックは、filepath.SplitList(*pkgPath) を使って -path で指定されたパスリストを分割し、それぞれのパスを fs.Bind("/src/pkg/"+elem, OS(p), "/", bindReplace) の形式で godoc の内部ファイルシステムにマウントしていました。
      • この fs.Bind の呼び出しは、指定された外部ディレクトリを godoc が認識する /src/pkg/ 以下の仮想パスにマッピングする役割を担っていました。このコードブロックが削除されたことで、-path フラグによる外部ディレクトリの追加機能が完全に失われました。

この変更により、godocGOROOTGOPATH (およびGo Modulesが有効な場合はモジュールキャッシュ) のみに依存してパッケージを探索するようになり、パス解決のロジックが簡素化され、Goのエコシステム全体での一貫性が向上しました。

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

src/cmd/godoc/doc.go の変更

--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -67,8 +67,6 @@ The flags are:
  	-maxresults=10000
  	\tmaximum number of full text search results shown
  	\t(no full text index is built if maxresults <= 0)
--	-path=""
--	\t\tadditional package directories (colon-separated)
  	-html
  	\t\tprint HTML in command-line mode
  	-goroot=$GOROOT
@@ -88,20 +86,8 @@ The flags are:
  	\tzip file providing the file system to serve; disabled if empty
 
 By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).
-Additional directories may be specified via the -path flag which accepts a list
-of colon-separated paths; unrooted paths are relative to the current working
-directory. Each path is considered as an additional root for packages in order
-of appearance. The last (absolute) path element is the prefix for the package
-path. For instance, given the flag value:
-
-	path=".:/home/bar:/public"
-
-for a godoc started in /home/user/godoc, absolute paths are mapped to package paths
-as follows:
-
-	/home/user/godoc/x -> godoc/x
-	/home/bar/x        -> bar/x
-	/public/x          -> public/x
+This behavior can be altered by providing an alternative $GOROOT with the -goroot
+flag.
  
  When godoc runs as a web server and -index is set, a search index is maintained.
  The index is created at startup.

src/cmd/godoc/godoc.go の変更

--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -57,7 +57,6 @@ var (
  	// TODO(gri) consider the invariant that goroot always end in '/'
  	goroot  = flag.String("goroot", runtime.GOROOT(), "Go root directory")
  	testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
--	pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
  
  	// layout control
  	tabwidth       = flag.Int("tabwidth", 4, "tab width")
@@ -83,16 +82,6 @@ var (
  )
  
  func initHandlers() {
--	// Add named directories in -path argument as
--	// subdirectories of src/pkg.
--	for _, p := range filepath.SplitList(*pkgPath) {
--		_, elem := filepath.Split(p)
--		if elem == "" {
--			log.Fatalf("invalid -path argument: %q has no final element", p)
--		}
--		fs.Bind("/src/pkg/"+elem, OS(p), "/", bindReplace)
--	}
--
  	fileServer = http.FileServer(&httpFS{fs})\n \tcmdHandler = docServer{"/cmd/", "/src/cmd", false}\n \tpkgHandler = docServer{"/pkg/", "/src/pkg", true}\n```

## コアとなるコードの解説

### `src/cmd/godoc/doc.go` の変更点

このファイルは `godoc` コマンドのユーザー向けドキュメントを定義しています。
*   `-path` フラグに関する説明のブロック全体が削除されています。これには、フラグの目的、パスの指定方法、そして絶対パスがどのように `godoc` の内部的なパッケージパスにマッピングされるかの詳細な例が含まれていました。この削除は、ユーザーがこのフラグを使用できなくなることを明確に示しています。
*   `godoc` がパッケージを探索するデフォルトの動作に関する説明が更新されています。以前は `GOROOT` と `GOPATH` に加えて `-path` フラグで追加ディレクトリを指定できると説明されていましたが、変更後は `-goroot` フラグを使って `GOROOT` を変更することでこの動作を調整できる、という説明に簡素化されています。これは、`godoc` のパス解決が `GOROOT` と `GOPATH` に集約されたことを反映しています。

### `src/cmd/godoc/godoc.go` の変更点

このファイルは `godoc` コマンドの実際のロジックを実装しています。
*   **フラグ定義の削除**:
    ```diff
    -	pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
    ```
    この行は、`godoc` がコマンドライン引数として `-path` フラグを認識し、その値を `pkgPath` 変数に格納するための定義でした。この行が削除されたことで、`godoc` はもはや `-path` フラグを有効な引数として認識しなくなります。
*   **パスバインディングロジックの削除**:
    ```diff
    -	// Add named directories in -path argument as
    -	// subdirectories of src/pkg.
    -	for _, p := range filepath.SplitList(*pkgPath) {
    -		_, elem := filepath.Split(p)
    -		if elem == "" {
    -			log.Fatalf("invalid -path argument: %q has no final element", p)
    -		}
    -		fs.Bind("/src/pkg/"+elem, OS(p), "/", bindReplace)
    -	}
    ```
    このコードブロックは `initHandlers` 関数内にあり、`godoc` がHTTPリクエストを処理する前に初期設定を行う部分です。
    *   `filepath.SplitList(*pkgPath)`: `-path` フラグで指定されたコロン区切りのパス文字列を個々のパスに分割していました。
    *   `for` ループ: 分割された各パス `p` に対して処理を行っていました。
    *   `filepath.Split(p)`: パス `p` をディレクトリ部分と最後の要素(ファイル名またはディレクトリ名)に分割していました。ここで取得される `elem` が、`godoc` の仮想ファイルシステム内でパッケージパスのプレフィックスとして使用されていました。
    *   `log.Fatalf(...)`: 無効なパス(最後の要素がない場合)に対するエラーハンドリングです。
    *   `fs.Bind("/src/pkg/"+elem, OS(p), "/", bindReplace)`: これが最も重要な部分です。`fs.Bind` は `godoc` 内部の抽象化されたファイルシステム (`fs`) に対して、指定された物理パス `OS(p)` を、`godoc` が認識する仮想パス `/src/pkg/` の下にマウントする役割を担っていました。例えば、`-path=/home/user/mycode` と指定すると、`/home/user/mycode` の内容が `godoc` の内部では `/src/pkg/mycode` として扱われ、`mycode/mypackage` のようなパッケージが `godoc` で参照可能になっていました。

このコードブロック全体が削除されたことで、`godoc` は外部から指定された追加のディレクトリをパッケージソースとして認識するメカニズムを完全に失いました。これにより、`godoc` のパッケージ探索は `GOROOT` と `GOPATH` の標準的なルールに厳密に従うことになります。

## 関連リンク

*   Go Issue #3453: [godoc: -path flag is confusing and unnecessary](https://github.com/golang/go/issues/3453)
*   Go言語の公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
*   `godoc` コマンドの現在のドキュメント (Goのバージョンによって内容は異なります): `go doc cmd/godoc` または [https://pkg.go.dev/cmd/godoc](https://pkg.go.dev/cmd/godoc)

## 参考にした情報源リンク

*   GitHubのコミットページ: [https://github.com/golang/go/commit/fba47dc3b10e7649e3ad0129b357d83cc2db228e](https://github.com/golang/go/commit/fba47dc3b10e7649e3ad0129b357d83cc2db228e)
*   Go Issue #3453: [https://github.com/golang/go/issues/3453](https://github.com/golang/go/issues/3453)
*   Go言語の環境変数 `GOROOT` と `GOPATH` に関する情報 (Go Modules導入以前の文脈も含む):
    *   [https://go.dev/doc/code](https://go.dev/doc/code) (Go Modules導入後の現在のドキュメント)
    *   古いGoのドキュメントやブログ記事 (例: Go 1.0, Go 1.1, Go 1.2 リリースノートなど)
*   Goの `flag` パッケージのドキュメント: [https://pkg.go.dev/flag](https://pkg.go.dev/flag)
*   Goの `path/filepath` パッケージのドキュメント: [https://pkg.go.dev/path/filepath](https://pkg.go.dev/path/filepath)
*   Goの `log` パッケージのドキュメント: [https://pkg.go.dev/log](https://pkg.go.dev/log)
*   Goの `net/http` パッケージのドキュメント: [https://pkg.go.dev/net/http](https://pkg.go.dev/net/http)
*   Goの `runtime` パッケージのドキュメント: [https://pkg.go.dev/runtime](https://pkg.go.dev/runtime)
*   `godoc` の内部実装に関する情報 (Goのソースコード): [https://github.com/golang/go/tree/master/src/cmd/godoc](https://github.com/golang/go/tree/master/src/cmd/godoc)
*   Gerrit Change-Id: [https://golang.org/cl/6350086](https://golang.org/cl/6350086) (GoプロジェクトがGerritを使用していた時期の変更履歴)