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

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

このコミットは、Go言語の公式ドキュメンテーションツールであるgodocにおいて、ソースコード内の特定のコメント(通称「Notes」)の表示方法を改善し、より汎用的な仕組みに移行するものです。具体的には、これまでPackage.Bugsフィールドで特別に扱われていたBUGコメントを、より一般的なPackage.Notesフィールドに統合し、TODOSECBUGといった他の種類のNotesもgodocで表示できるように拡張しています。

コミット

commit d6a057c90ed0746ae394efc0345b53f97d781b64
Author: Cosmos Nicolaou <cnicolaou@google.com>
Date:   Mon Feb 25 20:34:09 2013 -0800

    cmd/godoc: add support for display Notes parsed by pkg/go/doc
    pkg/go/doc: move BUG notes from Package.Bugs to the general Package.Notes field.
    Removing .Bugs would break existing code so it's left in for now.

    R=gri, gri, gary.burd, dsymonds, rsc, kevlar
    CC=golang-dev
    https://golang.org/cl/7341053

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

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

元コミット内容

cmd/godoc: pkg/go/docによってパースされたNotesの表示をサポート pkg/go/doc: BUGノートをPackage.Bugsから一般的なPackage.Notesフィールドに移動。 .Bugsを削除すると既存のコードが壊れるため、当面は残しておく。

変更の背景

Go言語のソースコードでは、開発者がコードに関する特定の情報やタスクをコメントとして残す慣習があります。これらは通常、BUG(userid):TODO(userid):FIXME(userid):SECBUG(userid):といった特定のマーカーで始まります。これらは「Notes」と呼ばれ、コードの改善点、未解決の問題、セキュリティ上の懸念などを開発者に伝えるために使用されます。

このコミット以前は、godocツールはBUGコメントのみを特別に扱い、pkg/go/docパッケージのPackage構造体内のBugsフィールドに格納していました。しかし、他の種類のNotes(TODOSECBUGなど)はgodocの出力に表示されず、開発者がこれらの重要な情報を見落とす可能性がありました。

この変更の背景には、以下の目的があります。

  1. 汎用性の向上: BUGコメントだけでなく、あらゆる種類のNotesをgodocで表示できるようにすることで、ドキュメンテーションの網羅性を高める。
  2. 情報の可視化: 開発者がコードベース全体に散らばるTODOSECBUGなどの重要なNotesを、godocを通じて一元的に確認できるようにする。
  3. コードとドキュメントの一貫性: ソースコード内のNotesが、生成されるドキュメントにも適切に反映されるようにする。
  4. 将来的な拡張性: 新しい種類のNotesが導入された場合でも、既存のメカニズムを大きく変更することなく対応できるようにする。

Package.Bugsフィールドは既存のコードとの互換性を保つために残されましたが、将来的にはPackage.Notesへの完全な移行が意図されています。

前提知識の解説

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

  1. godoc:

    • godocはGo言語の公式ドキュメンテーションツールです。Goのソースコードからドキュメントを生成し、Webサーバーとして提供したり、コマンドラインで表示したりできます。
    • Goのパッケージ、関数、型、変数などの定義に付随するコメントを解析し、整形されたドキュメントとして出力します。
    • 開発者はgodoc -http=:6060のように実行することで、ローカルでGoの標準ライブラリや自分のプロジェクトのドキュメントをブラウザで閲覧できます。
  2. pkg/go/docパッケージ:

    • pkg/go/docは、Goのソースコードからドキュメンテーションを抽出・解析するための標準ライブラリパッケージです。
    • godocツールはこのパッケージを利用して、GoのAST(抽象構文木)を解析し、ドキュメンテーションコメントやコード構造からdoc.Packageなどの構造体を構築します。
    • doc.Package構造体は、パッケージ全体のドキュメント、インポートパス、ファイル名、そしてこのコミットで焦点となるNotes(以前はBugs)などの情報を含んでいます。
  3. GoのコメントにおけるNotes(マーカー):

    • Goのソースコードでは、特定の形式のコメントが特別な意味を持つことがあります。これらは通常、MARKER(userid): comment textの形式を取ります。
    • BUG(userid):: 既知のバグや問題点を示すために使用されます。
    • TODO(userid):: 将来的に実装すべき機能や改善点を示すために使用されます。
    • FIXME(userid):: 修正が必要なコード部分を示すために使用されます。
    • SECBUG(userid):: セキュリティ上の懸念や脆弱性を示すために使用されます。
    • useridは通常、コメントを追加した開発者のイニシャルやIDです。
    • これらのNotesは、コードレビューやプロジェクト管理において重要な役割を果たします。
  4. Goのtext/templateおよびhtml/templateパッケージ:

    • Goの標準ライブラリには、テンプレートエンジンを提供するtext/templatehtml/templateパッケージがあります。
    • godocはこれらのパッケージを使用して、解析したドキュメントデータをHTMLやプレーンテキスト形式でレンダリングします。
    • テンプレートファイル(例: lib/godoc/package.html)は、Goのテンプレート構文({{.Field}}, {{range .Slice}}, {{if .Condition}}など)を使用して、動的にコンテンツを生成します。
    • FuncMapは、テンプレート内で呼び出すことができるカスタム関数を登録するために使用されます。

これらの前提知識を理解することで、コミットがgodocの動作、pkg/go/docのデータ構造、そしてGoのコメント慣習にどのように影響を与えるかを深く把握できます。

技術的詳細

このコミットの技術的な核心は、pkg/go/docパッケージがコメントからNotesを解析する方法と、cmd/godocがそれらのNotesをWebページやテキスト出力で表示する方法の変更にあります。

  1. pkg/go/docにおけるNotesの汎用化:

    • 以前は、pkg/go/doc.Package構造体にはBugs []stringというフィールドがあり、BUGコメントのみがここに収集されていました。
    • このコミットでは、Package構造体にNotes map[string][]stringという新しいフィールドが追加されました。これは、マーカー(例: "BUG", "TODO", "SECBUG")をキーとし、そのマーカーに属するコメントテキストのリストを値とするマップです。
    • src/pkg/go/doc/doc.goでは、BugsフィールドがDEPRECATEDとマークされ、新しいコードではNotesを使用するよう促されています。ただし、既存のコードとの互換性のため、Bugsフィールドは引き続きBUGコメントで埋められます。
    • src/pkg/go/doc/reader.goreadFile関数内で、コメントを解析してNotesを収集するロジックが変更されました。readNote関数がコメントからマーカーとテキストを抽出し、その結果をr.notes[marker]に格納するように統一されました。以前はBUGマーカーの場合のみr.bugsにも追加する特殊な処理がありましたが、これが簡素化され、すべてのNotesがr.notesマップに格納されるようになりました。
  2. cmd/godocにおけるNotesの表示サポート:

    • src/cmd/godoc/godoc.goPageInfo構造体に、Notes map[string][]stringフィールドが追加されました。これは、pkg/go/doc.Packageから取得したNotesをgodocのテンプレートに渡すための中間構造体です。
    • getPageInfo関数内で、pkg.Notesから特定のNotes(デフォルトではBUG)をinfo.Notesにコピーするロジックが追加されました。これにより、表示したいNotesをフィルタリングできます。
    • src/cmd/godoc/main.goでは、新しいコマンドラインフラグ-notesが追加されました。これにより、ユーザーはgodocがどのNotesマーカー(例: -notes="BUG,TODO,SECBUG")を表示するかをカンマ区切りで指定できるようになりました。デフォルトではBUGのみが表示されます。
    • src/cmd/godoc/godoc.goには、noteTitleという新しいテンプレート関数が追加されました。この関数は、Notesマーカー(例: "BUG")を受け取り、それを整形されたタイトル(例: "Bugs")に変換します。これは、HTMLやテキスト出力でNotesのセクション見出しを生成するために使用されます。
    • lib/godoc/package.htmllib/godoc/package.txtのテンプレートファイルが更新され、$.Notesフィールドをイテレートして、各Notesマーカーとその内容を表示するようになりました。これにより、BUGだけでなく、指定されたすべてのNotesが表示されるようになります。また、noteTitle関数を使用して見出しが生成されます。
  3. テストデータの更新:

    • src/pkg/go/doc/testdata/a.0.goldena.1.goldena.2.goldentemplate.txtといったテスト出力ファイルが更新され、新しいNotesの表示形式(例: BUGSからBUGS .Bugs is now deprecated, please use .Notes insteadSECBUGからSECBUGSTODOからTODOS)を反映しています。これは、godocがNotesを複数形で見出しとして表示するようになったことを示しています。

この変更により、godocはより柔軟にソースコード内のNotesをドキュメントとして表示できるようになり、開発者にとってコードベースの重要な情報へのアクセスが容易になりました。

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

このコミットにおける主要なコード変更は以下のファイルに集中しています。

  1. src/pkg/go/doc/doc.go:

    • Package構造体からBugs []stringフィールドが削除され、代わりにNotes map[string][]stringが追加されました。
    • Bugsフィールドは互換性のために残され、DEPRECATEDコメントが追加されました。
    --- a/src/pkg/go/doc/doc.go
    +++ b/src/pkg/go/doc/doc.go
    @@ -17,7 +17,10 @@ type Package struct {
     	ImportPath string
     	Imports    []string
     	Filenames  []string
    -	Bugs       []string
    +	// DEPRECATED. For backward compatibility Bugs is still populated,
    +	// but all new code should use Notes instead.
    +	Bugs []string
    +
     	// Notes such as TODO(userid): or SECURITY(userid):
     	// along the lines of BUG(userid). Any marker with 2 or more upper
     	// case [A-Z] letters is recognised.
    
  2. src/pkg/go/doc/reader.go:

    • readFile関数内で、コメントからNotesを収集するロジックが変更されました。以前はBUGとそれ以外のNotesで処理が分かれていましたが、すべてのNotesがr.notesマップに格納されるように統一されました。BUGの場合のみ、互換性のためにr.bugsにも追加されます。
    --- a/src/pkg/go/doc/reader.go
    +++ b/src/pkg/go/doc/reader.go
    @@ -487,12 +486,9 @@ func (r *reader) readFile(src *ast.File) {
     	// collect MARKER(...): annotations
     	for _, c := range src.Comments {
     	\tif marker, text := readNote(c); marker != "" {
    -\t\t\t// Remove r.bugs in a separate CL along with
    -\t\t\t// any necessary changes to client code.
    +\t\t\tr.notes[marker] = append(r.notes[marker], text)
     \t\t\tif marker == "BUG" {
     \t\t\t\tr.bugs = append(r.bugs, text)
    -\t\t\t} else {
    -\t\t\t\tr.notes[marker] = append(r.notes[marker], text)
     \t\t\t}
     \t\t}
     	}
    
  3. src/cmd/godoc/godoc.go:

    • PageInfo構造体にNotes map[string][]stringフィールドが追加されました。
    • getPageInfo関数内で、pkg.Notesから表示対象のNotesをinfo.Notesに収集するロジックが追加されました。
    • noteTitleという新しいテンプレートヘルパー関数が追加され、fmap(テンプレート関数マップ)に登録されました。
    --- a/src/cmd/godoc/godoc.go
    +++ b/src/cmd/godoc/godoc.go
    @@ -446,6 +446,10 @@ func example_suffixFunc(name string) string {
     	return suffix
     }
    
    +func noteTitle(note string) string {
    +	return strings.Title(strings.ToLower(note))
    +}
    +
     func splitExampleName(s string) (name, suffix string) {
     	i := strings.LastIndex(s, "_")
     	if 0 <= i && i < len(s)-1 && !startsWithUppercase(s[i+1:]) {
    @@ -539,6 +543,9 @@ var fmap = template.FuncMap{
     	"example_text":   example_textFunc,
     	"example_name":   example_nameFunc,
     	"example_suffix": example_suffixFunc,
    +
    +	// formatting of Notes
    +	"noteTitle": noteTitle,
     }
    
     func readTemplate(name string) *template.Template {
    @@ -897,11 +904,12 @@ type PageInfo struct {
     	Err     error  // error or nil
    
     	// package info
    -	FSet     *token.FileSet // nil if no package documentation
    -	PDoc     *doc.Package   // nil if no package documentation
    -	Examples []*doc.Example // nil if no example code
    -	PAst     *ast.File      // nil if no AST with package exports
    -	IsMain   bool           // true for package main
    +	FSet     *token.FileSet      // nil if no package documentation
    +	PDoc     *doc.Package        // nil if no package documentation
    +	Examples []*doc.Example      // nil if no example code
    +	Notes    map[string][]string // nil if no package Notes
    +	PAst     *ast.File           // nil if no AST with package exports
    +	IsMain   bool                // true for package main
    
     	// directory info
     	Dirs    *DirList  // nil if no directory information
    @@ -1082,6 +1090,17 @@ func (h *docServer) getPageInfo(abspath, relpath string, mode PageInfoMode) (inf
     			log.Println("parsing examples:", err)
     		}
     		info.Examples = collectExamples(pkg, files)
    +
    +		// collect any notes that we want to show
    +		if info.PDoc.Notes != nil {
    +			info.Notes = make(map[string][]string)
    +			for _, m := range notesToShow {
    +				if n := info.PDoc.Notes[m]; n != nil {
    +					info.Notes[m] = n
    +				}
    +			}
    +		}
    +
     	} else {
     		// show source code
     		// TODO(gri) Consider eliminating export filtering in this mode,
    
  4. src/cmd/godoc/main.go:

    • -notesという新しいコマンドラインフラグが追加され、表示するNotesマーカーを指定できるようになりました。
    --- a/src/cmd/godoc/main.go
    +++ b/src/cmd/godoc/main.go
    @@ -71,6 +71,11 @@ var (
    
     	// command-line searches
     	query = flag.Bool("q", false, "arguments are considered search queries")
    +
    +	// which code 'Notes' to show.
    +	notes = flag.String("notes", "BUG", "comma separated list of Note markers as per pkg:go/doc")
    +	// vector of 'Notes' to show.
    +	notesToShow []string
     )
    
     func serveError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
    @@ -157,6 +162,8 @@ func main() {
     	flag.Usage = usage
     	flag.Parse()
    
    +	notesToShow = strings.Split(*notes, ",")
    +
     	// Check usage: either server and no args, command line and args, or index creation mode
     	if (*httpAddr != "" || *urlFlag != "") != (flag.NArg() == 0) && !*writeIndex {
     		usage()
    
  5. lib/godoc/package.html および lib/godoc/package.txt:

    • Bugsフィールドの代わりにNotesフィールドをイテレートし、noteTitle関数を使用して見出しを生成するようにテンプレートが変更されました。
    --- a/lib/godoc/package.html
    +++ b/lib/godoc/package.html
    @@ -70,12 +70,9 @@
     				<dd>&nbsp; &nbsp; <a href="#{{$tname_html}}.{{$name_html}}">{{node_html .Decl $.FSet}}</a></dd>
     				{{end}}
     			{{end}}
    -			{{if .Bugs}}
    -				<dd><a href="#pkg-bugs">Bugs</a></dd>
    -			{{end}}
    -			{{if .Notes}}
    -                                {{range $marker, $item := .Notes}}
    -				<dd><a href="#pkg-{{$marker}}">{{$marker}}</a></dd>
    +			{{if $.Notes}}
    +                                {{range $marker, $item := $.Notes}}
    +				<dd><a href="#pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</a></dd>
                                  {{end}}
     			{{end}}
     			</dl>
    @@ -167,15 +164,9 @@
     		{{comment_html .Doc}}
     	{{end}}
    
    -	{{with .Bugs}}
    -		<h2 id="pkg-bugs">Bugs</h2>
    -		{{range .}}
    -		{{comment_html .}}
    -		{{end}}
    -	{{end}}
    -	{{with .Notes}}
    +	{{with $.Notes}}
                 {{range $marker, $content := .}}
    -		    <h2 id="pkg-{{$marker}}">{{$marker}}</h2>
    +		    <h2 id="pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</h2>
     		    {{range .}}
     		    {{comment_html .}}
                     {{end}}
    

コアとなるコードの解説

このコミットの主要な変更は、Goのドキュメンテーション生成プロセスにおける「Notes」の扱いを、特定の「Bugs」から汎用的なメカニズムへと進化させた点にあります。

  1. pkg/go/docの変更 (src/pkg/go/doc/doc.go, src/pkg/go/doc/reader.go):

    • Package.BugsからPackage.Notesへの移行: 以前はdoc.Package構造体にBugs []stringというフィールドがあり、BUGコメントのみがここに格納されていました。このコミットでは、より汎用的なNotes map[string][]stringが導入されました。これは、TODOSECBUGなど、任意のマーカーを持つコメントをキーと値のペアで格納できるマップです。
    • 互換性の維持: BugsフィールドはDEPRECATEDとマークされましたが、既存のコードが壊れないように、BUGコメントは引き続きBugsフィールドにも追加されます。これは、段階的な移行を可能にするための重要な設計判断です。
    • 解析ロジックの統一: reader.goreadFile関数内のコメント解析ロジックが簡素化されました。すべてのNotes(BUGを含む)はまずr.notesマップに格納されます。その後、BUGマーカーの場合にのみ、互換性のためにr.bugsにも追加されるという形になりました。これにより、Notesの収集メカニズムがより一貫性を持つようになりました。
  2. cmd/godocの変更 (src/cmd/godoc/godoc.go, src/cmd/godoc/main.go):

    • PageInfo構造体の拡張: godocがドキュメントをレンダリングする際に使用するPageInfo構造体に、Notes map[string][]stringフィールドが追加されました。これにより、pkg/go/docから取得したNotesデータをテンプレートに渡す準備が整いました。
    • Notesのフィルタリングと収集: getPageInfo関数内で、pkg.Notesから、コマンドラインで指定された(またはデフォルトの)Notesマーカーに対応するNotesのみをinfo.Notesに収集するロジックが追加されました。これにより、ユーザーはgodocの出力に表示されるNotesの種類を制御できます。
    • 新しいコマンドラインフラグ-notes: main.goで導入された-notesフラグは、ユーザーがgodocに表示させたいNotesマーカーをカンマ区切りで指定できるようにします(例: godoc -notes="BUG,TODO")。これにより、ドキュメントのカスタマイズ性が向上しました。
    • noteTitleテンプレート関数: godoc.goに追加されたnoteTitle関数は、Notesマーカー(例: "BUG")を、ドキュメントの見出しに適した形式(例: "Bugs")に変換します。これは、strings.Title(strings.ToLower(note))というシンプルなロジックで実現されており、汎用的なタイトル生成を可能にしています。この関数はgodocのテンプレートエンジンに登録され、HTMLやテキストのレンダリング時に利用されます。
  3. テンプレートの変更 (lib/godoc/package.html, lib/godoc/package.txt):

    • HTMLおよびテキストテンプレートは、$.Notesマップをイテレートするように変更されました。これにより、BUGだけでなく、TODOSECBUGなど、すべての指定されたNotesがそれぞれ独立したセクションとして表示されるようになりました。
    • noteTitle関数が使用され、各Notesセクションの見出しが動的に生成されます(例: <h2>Bugs</h2>, <h2>Todos</h2>)。これにより、ドキュメントの可読性と構造が向上しました。

これらの変更により、godocはGoソースコード内のNotesをより包括的かつ柔軟にドキュメントとして表示できるようになり、開発者がコードベースの重要な情報にアクセスしやすくなりました。

関連リンク

参考にした情報源リンク

これらのリンクは、コミットの背景、実装の詳細、およびGoコミュニティにおける関連する議論をさらに深く理解するのに役立ちます。