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

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

このコミットは、cmd/godoc ツールにおいて、/doc 以下のファイルがユニオンファイルシステム(union filesystems)に常に含まれるように変更するものです。これにより、Path の書き換えが正しく機能するようになり、メタデータがスキャンされない問題(Issue #3282)が修正されます。

コミット

commit 92d4af301e5c69b066b75475b3fce24e4fa51ab3
Author: Andrew Gerrand <adg@golang.org>
Date:   Mon Mar 12 15:55:39 2012 +1100

    cmd/godoc: always include /doc files in union filesystems
    
    Makes Path rewrites work, as the metadata was never being scanned.
    
    Fixes #3282.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/5783076
---
 src/cmd/godoc/filesystem.go | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/cmd/godoc/filesystem.go b/src/cmd/godoc/filesystem.go
index b1913cdd99..869e23ca25 100644
--- a/src/cmd/godoc/filesystem.go
+++ b/src/cmd/godoc/filesystem.go
@@ -420,11 +420,17 @@ func (ns nameSpace) ReadDir(path string) ([]os.FileInfo, error) {
 			first = dir
 		}
 
+		useFiles := false
+
+		// Always include all files under /doc.
+		if path == "/doc" || strings.HasPrefix(path, "/doc/") {
+			useFiles = true // always include docs
+		}
+
 		// If we don't yet have Go files in 'all' and this directory
 		// has some, add all the files from this directory.
 		// Otherwise, only add subdirectories.
-		useFiles := false
-		if !haveGo {
+		if !useFiles && !haveGo {
 			for _, d := range dir {
 				if strings.HasSuffix(d.Name(), ".go") {
 					useFiles = true

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

https://github.com/golang/go/commit/92d4af301e5c69b066b75475b3fce24e4fa51ab3

元コミット内容

cmd/godoc: ユニオンファイルシステムに常に /doc ファイルを含めるようにする。 これにより、Path の書き換えが機能するようになり、メタデータがスキャンされていなかった問題が修正されます。 Issue #3282 を修正。

変更の背景

このコミットは、Go のドキュメンテーションツールである godoc の動作に関するバグ、具体的には Issue #3282 を修正するために行われました。godoc は、Go のソースコードからドキュメントを生成し、Web サーバーとして提供する機能を持っています。この際、複数のファイルシステム(例えば、Go の標準ライブラリのソースコードと、ユーザーが定義したパッケージのソースコード)を仮想的に結合して一つのファイルシステムとして扱う「ユニオンファイルシステム」の概念が用いられています。

問題は、/doc ディレクトリ以下のファイル(Go のドキュメントやチュートリアルなど)が、このユニオンファイルシステム内で適切に処理されていなかったことにありました。特に、Path の書き換え(URL パスと実際のファイルパスのマッピング)を行う際に、/doc 以下のファイルのメタデータがスキャンされず、結果としてこれらのファイルが正しく提供されない、あるいは期待通りに動作しないという状況が発生していました。このコミットは、/doc 以下のファイルを常にユニオンファイルシステムに含めることで、この問題を解決し、godoc がドキュメントを正しく提供できるようにすることを目的としています。

前提知識の解説

  • cmd/godoc: Go 言語の公式ドキュメンテーションツールです。Go のソースコードからコメントを解析し、HTML 形式のドキュメントを生成したり、Go のパッケージやコマンドに関する情報を表示したりします。また、ローカルでドキュメントサーバーを起動する機能も持っています。
  • ユニオンファイルシステム (Union Filesystem): 複数の異なるファイルシステムやディレクトリを透過的に結合し、あたかも単一のファイルシステムであるかのように見せる技術です。godoc の文脈では、Go の標準ライブラリのソースコードが置かれているディレクトリと、GOPATH で指定されたユーザーのプロジェクトディレクトリなどを結合して、一貫したパスでアクセスできるようにするために利用されます。これにより、godoc は Go のすべてのコードベースを単一のツリーとして扱うことができます。
  • os.FileInfo: Go 言語の os パッケージで定義されているインターフェースで、ファイルやディレクトリのメタデータ(名前、サイズ、パーミッション、最終更新時刻など)を提供します。ReadDir のような関数は、ディレクトリ内のエントリの os.FileInfo スライスを返します。
  • Path rewrites (パスの書き換え): Web サーバーやルーティングの文脈で使われる用語で、リクエストされた URL パスを、内部的なファイルパスやリソースパスに変換する処理を指します。godoc の場合、ユーザーがブラウザでアクセスした URL(例: /doc/effective_go.html)を、実際のファイルシステム上のパス(例: /path/to/go/src/doc/effective_go.html)にマッピングする役割を担います。このマッピングが正しく行われないと、リソースが見つからなかったり、誤ったリソースが提供されたりします。
  • strings.HasPrefix: Go 言語の strings パッケージで提供される関数で、ある文字列が特定のプレフィックス(接頭辞)で始まるかどうかを判定します。このコミットでは、パスが /doc または /doc/ で始まるかどうかをチェックするために使用されています。

技術的詳細

cmd/godocfilesystem.go 内の nameSpace 型の ReadDir メソッドは、ユニオンファイルシステムにおけるディレクトリの内容を読み取る役割を担っています。このメソッドは、複数のソースからディレクトリ情報を集約し、最終的な os.FileInfo のスライスを返します。

変更前のコードでは、ディレクトリ内のファイルを含めるかどうかの判断基準として、主にそのディレクトリに Go のソースファイル(.go 拡張子を持つファイル)が含まれているかどうか、そして haveGo というフラグ(既に Go ファイルが見つかっているかどうかを示す)が使われていました。具体的には、haveGofalse の場合(まだ Go ファイルが見つかっていない場合)に、現在のディレクトリに Go ファイルがあれば useFilestrue に設定し、そのディレクトリ内のすべてのファイルを含める、というロジックでした。それ以外の場合は、サブディレクトリのみを含めるという挙動でした。

このロジックの問題点は、/doc ディレクトリ以下のファイルが Go のソースファイルではないため、上記の条件に合致せず、useFilestrue に設定されない可能性があったことです。結果として、/doc 以下の重要なドキュメントファイルがユニオンファイルシステムから除外され、godoc がそれらを正しく提供できないという問題が発生していました。

このコミットでは、この問題を解決するために、useFiles フラグの決定ロジックに新しい条件を追加しました。具体的には、path/doc と完全に一致するか、または /doc/ で始まる場合に、useFiles を無条件に true に設定するようにしました。これにより、/doc ディレクトリとそのサブディレクトリ内のすべてのファイルが、Go のソースファイルの有無にかかわらず、常にユニオンファイルシステムに含まれるようになります。

この変更により、godoc/doc 以下のドキュメントファイルを常に認識し、Path の書き換えが正しく行われるようになり、Issue #3282 で報告された問題が解決されました。

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

--- a/src/cmd/godoc/filesystem.go
+++ b/src/cmd/godoc/filesystem.go
@@ -420,11 +420,17 @@ func (ns nameSpace) ReadDir(path string) ([]os.FileInfo, error) {
 			first = dir
 		}
 
+		useFiles := false
+
+		// Always include all files under /doc.
+		if path == "/doc" || strings.HasPrefix(path, "/doc/") {
+			useFiles = true // always include docs
+		}
+
 		// If we don't yet have Go files in 'all' and this directory
 		// has some, add all the files from this directory.
 		// Otherwise, only add subdirectories.
-		useFiles := false
-		if !haveGo {
+		if !useFiles && !haveGo {
 			for _, d := range dir {
 				if strings.HasSuffix(d.Name(), ".go") {
 					useFiles = true

コアとなるコードの解説

変更は src/cmd/godoc/filesystem.go ファイルの nameSpace 型の ReadDir メソッド内で行われています。

  1. useFiles := false の初期化: 変更前は、useFiles 変数が if !haveGo { ... } ブロックの直前で初期化されていました。変更後、この初期化がメソッドのより早い段階(first = dir の直後)に移動されました。これは、新しいロジックで useFiles が早期に設定される可能性があるため、そのスコープを適切に設定するためです。

  2. /doc ディレクトリの特別扱い:

    +		useFiles := false
    +
    +		// Always include all files under /doc.
    +		if path == "/doc" || strings.HasPrefix(path, "/doc/") {
    +			useFiles = true // always include docs
    +		}
    

    この部分が新たに追加されたロジックです。

    • useFiles が再度 false で初期化されていますが、これは上記の初期化と合わせて、このブロック内で useFiles の状態を明確にするためのものです。
    • コメント // Always include all files under /doc. が追加され、このコードブロックの意図が明確にされています。
    • if path == "/doc" || strings.HasPrefix(path, "/doc/") という条件が追加されました。これは、現在処理しているディレクトリのパスが /doc そのものであるか、または /doc/ で始まる(つまり、/doc のサブディレクトリである)場合に真となります。
    • この条件が真の場合、useFiles = true が設定されます。これにより、/doc 以下のすべてのファイルが、後続のロジックで無条件にユニオンファイルシステムに含まれるようになります。コメント // always include docs がその理由を補足しています。
  3. 既存のロジックの変更:

    -		useFiles := false
    -		if !haveGo {
    +		if !useFiles && !haveGo {
     			for _, d := range dir {
     				if strings.HasSuffix(d.Name(), ".go") {
     					useFiles = true
    

    変更前の if !haveGo { ... } の条件が if !useFiles && !haveGo { ... } に変更されました。

    • !useFiles という新しい条件が追加されました。これは、もし既に上記の /doc 関連のロジックによって useFilestrue に設定されている場合、このブロック内の Go ファイルの有無をチェックするロジックはスキップされることを意味します。
    • つまり、/doc 以下のファイルは常に含まれるようになり、それ以外のパスでは、これまで通り Go ファイルの有無に基づいてファイルを含めるかどうかが判断される、という優先順位が確立されました。

この変更により、/doc 以下のファイルは常に godoc のユニオンファイルシステムに組み込まれるようになり、Path の書き換えが正しく機能し、ドキュメントが適切に提供されるようになりました。

関連リンク

参考にした情報源リンク

  • Go Issue 3282 の議論内容
  • Go の cmd/godoc のソースコード(特に filesystem.go
  • Go の strings パッケージのドキュメント
  • ユニオンファイルシステムに関する一般的な情報