[インデックス 11422] ファイルの概要
このコミットは、Goコマンドラインツールのdoc.go
ファイルを、go help
コマンドの出力から自動生成されるテキストで更新することを目的としています。これにより、Goコマンドのヘルプドキュメントが常に最新かつ正確に保たれるようになります。
コミット
commit 29dbd988b83e3cb43ca034916e52d030f150c7e1
Author: Andrew Gerrand <adg@golang.org>
Date: Fri Jan 27 08:19:43 2012 +1100
cmd/go: update doc.go with text generated from the usage strings
Fixes #2783.
R=bsiegert, rsc
CC=golang-dev
https://golang.org/cl/5570069
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/29dbd988b83e3cb43ca034916e52d030f150c7e1
元コミット内容
cmd/go: update doc.go with text generated from the usage strings
このコミットは、go
コマンドのdoc.go
ファイルを、各コマンドの利用方法(usage strings)から生成されたテキストで更新します。これにより、手動での更新作業を減らし、ドキュメントの正確性を向上させます。
Fixes #2783.
このコミットは、GoプロジェクトのIssue #2783を修正します。
変更の背景
Go言語のコマンドラインツール(go
コマンド)は、go build
, go run
, go test
など、多くのサブコマンドを提供しています。これらのサブコマンドにはそれぞれ詳細なヘルプドキュメントが存在し、go help <command>
で参照できます。
このコミット以前は、src/cmd/go/doc.go
ファイルにGoコマンド全体の概要と各サブコマンドの簡単な説明が手動で記述されていました。しかし、各サブコマンドのヘルプテキストはsrc/cmd/go/main.go
内のCommand
構造体に定義されたUsageLine
やLong
フィールドから生成されていました。
この状況では、サブコマンドの機能やオプションが変更された際に、main.go
内の定義とdoc.go
内の説明の両方を手動で更新する必要があり、ドキュメントの不整合や陳腐化のリスクがありました。特に、go help
コマンドの出力とdoc.go
の内容が一致しないという問題(Issue #2783)が発生していました。
このコミットの背景にあるのは、ドキュメントの自動生成と一貫性の確保です。go help
コマンドが生成する詳細なヘルプテキストを直接doc.go
に書き込むことで、ドキュメントのメンテナンスコストを削減し、常に最新の正確な情報を提供できるようにすることが目的です。
前提知識の解説
- Goコマンド (cmd/go): Go言語のビルド、テスト、パッケージ管理などを行うための主要なコマンドラインツールです。
go build
,go run
,go test
,go get
などのサブコマンドを持ちます。 doc.go
ファイル: Goパッケージのドキュメントを記述するための慣習的なファイルです。パッケージレベルのコメントや、パッケージ内の主要な型、関数、変数などの概要を記述します。godoc
ツールによって解析され、ドキュメントとして表示されます。このコミットでは、cmd/go
パッケージのdoc.go
が対象です。go help
コマンド:go
コマンドのヘルプ情報を表示するためのコマンドです。go help
でコマンド一覧と概要を、go help <command>
で特定のサブコマンドの詳細なヘルプを表示します。text/template
パッケージ: Go言語の標準ライブラリで提供されるテキストテンプレートエンジンです。プレースホルダーを含むテキストを定義し、データ構造を渡すことで動的にテキストを生成できます。go
コマンドのヘルプ出力もこのテンプレートエンジンを使用して生成されています。gofmt
: Go言語のコードフォーマッタです。Goの標準的なコーディングスタイルに沿ってコードを自動的に整形します。このコミットでは、生成されたdoc.go
ファイルを整形するために使用されます。mkdoc.sh
: シェルスクリプトで、このコミットで新しく追加されます。go help documentation
コマンドを実行し、その出力をdoc.go
にリダイレクトし、さらにgofmt
で整形する役割を担います。- Issue #2783: GoプロジェクトのIssueトラッカーで報告された問題です。具体的には、「
go help
の出力とdoc.go
の内容が一致しない」というドキュメントの不整合に関する問題でした。
技術的詳細
このコミットの主要な技術的変更点は、go help documentation
という新しい内部コマンドを導入し、そのコマンドがgo
コマンド全体のヘルプドキュメントを生成するようにしたことです。
-
documentationTemplate
の導入:src/cmd/go/main.go
にdocumentationTemplate
という新しいtext/template
が追加されました。このテンプレートは、go
コマンドの各サブコマンドのShort
(短い説明)とLong
(詳細な説明)フィールドを整形し、doc.go
ファイルの形式に合うように出力します。特に、Short
フィールドの最初の文字を大文字にするcapitalize
関数がテンプレート関数として追加されています。 -
go help documentation
コマンドの追加:src/cmd/go/main.go
のhelp
関数内に、引数が"documentation"
の場合の特別な処理が追加されました。この処理では、まずprintUsage
関数を呼び出してgo
コマンド全体の概要(コマンド一覧など)をバッファに書き込みます。次に、この概要と既存のcommands
スライス(各サブコマンドの定義)をdocumentationTemplate
に渡し、その結果を標準出力に出力します。 -
mkdoc.sh
スクリプトの追加:src/cmd/go/mkdoc.sh
という新しいシェルスクリプトが追加されました。このスクリプトは以下の2つのコマンドを実行します。go help documentation > doc.go
:go help documentation
コマンドの出力をsrc/cmd/go/doc.go
ファイルにリダイレクトします。これにより、doc.go
の内容が自動生成されます。gofmt -w doc.go
: 生成されたdoc.go
ファイルをgofmt
で整形し、Goの標準的なコーディングスタイルに準拠させます。
これらの変更により、doc.go
ファイルは手動で編集されるのではなく、mkdoc.sh
スクリプトを実行することで、main.go
内のCommand
構造体の定義に基づいて自動的に生成されるようになりました。これにより、go help
コマンドの出力とdoc.go
の内容の同期が保証され、ドキュメントのメンテナンス性が大幅に向上しました。
また、src/cmd/go/doc.go
の既存の内容は、この自動生成された内容に置き換えられています。変更前は手動で記述されていた各コマンドの簡単な説明が、main.go
で定義されている詳細なヘルプテキストから抽出されてdoc.go
に反映される形になります。
コアとなるコードの変更箇所
src/cmd/go/doc.go
このファイルは、手動で記述されていたGoコマンドの概要と各サブコマンドの説明が、自動生成される内容に完全に置き換えられています。変更前は簡潔な説明だったものが、go help
コマンドが提供する詳細な説明文に置き換わっています。
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -9,13 +9,14 @@ Usage: go command [arguments]
The commands are:
- build compile and install packages and dependencies
- clean remove intermediate objects
+ build compile packages and dependencies
+ doc run godoc on package sources
fix run gofix on packages
- fmt run gofmt -w on packages
+ fmt run gofmt on package sources
get download and install packages and dependencies
- install install packages and dependencies
+ install compile and install packages and dependencies
list list packages
+ run compile and run Go program
test test packages
version print Go version
vet run govet on packages
@@ -27,8 +28,573 @@ Additional help topics:
gopath GOPATH environment variable
importpath description of import paths
remote remote import path syntax
+ testflag description of testing flags
+ testfunc description of testing functions
Use "go help [topic]" for more information about that topic.
+\n+\n+Compile packages and dependencies
+... (以下、各コマンドの詳細なヘルプテキストが続く)
src/cmd/go/main.go
このファイルには、documentationTemplate
の定義、capitalize
ヘルパー関数、そしてgo help documentation
コマンドの処理ロジックが追加されています。
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -5,6 +5,7 @@
package main
import (
+\t"bytes"
\t"flag"
\t"fmt"
\t"go/build"
@@ -17,6 +18,8 @@ import (
\t"regexp"
\t"strings"
\t"text/template"
+\t"unicode"
+\t"unicode/utf8"
)
// A Command is an implementation of a go command
@@ -141,16 +144,44 @@ var helpTemplate = `{{if .Run}}usage: go {{.UsageLine}}\n
{{end}}{{.Long | trim}}\n
`
+var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+\n/*
+{{range .}}{{if .Short}}{{.Short | capitalize}}
+\n{{end}}{{if .Run}}Usage:
+\n\tgo {{.UsageLine}}
+\n{{end}}{{.Long | trim}}
+\n\n
+{{end}}*/
+package documentation
+\n// NOTE: cmdDoc is in fmt.go.
+`
+\n // tmpl executes the given template text on data, writing the result to w.\n func tmpl(w io.Writer, text string, data interface{}) {\n \tt := template.New("top")\n-\tt.Funcs(template.FuncMap{"trim": strings.TrimSpace})\n+\tt.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})\n \ttemplate.Must(t.Parse(text))\n \tif err := t.Execute(w, data); err != nil {\n \t\tpanic(err)\n \t}\n }\n \n+func capitalize(s string) string {\n+\tif s == "" {\n+\t\treturn s\n+\t}\n+\tr, n := utf8.DecodeRuneInString(s)\n+\treturn string(unicode.ToTitle(r)) + s[n:]\n+}\n+\n func printUsage(w io.Writer) {\n \ttmpl(w, usageTemplate, commands)\n }\n@@ -173,6 +204,16 @@ func help(args []string) {\n \t}\n \n \targ := args[0]\n+\n+\t// 'go help documentation' generates doc.go.\n+\tif arg == "documentation" {\n+\t\tbuf := new(bytes.Buffer)\n+\t\tprintUsage(buf)\n+\t\tusage := &Command{Long: buf.String()}\n+\t\ttmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))\n+\t\treturn\n+\t}\n+\n \tfor _, cmd := range commands {\n \t\tif cmd.Name() == arg {\n \t\t\ttmpl(os.Stdout, helpTemplate, cmd)\n```
### `src/cmd/go/mkdoc.sh`
この新しいシェルスクリプトは、`doc.go`を自動生成するためのビルドステップを定義しています。
```diff
--- /dev/null
+++ b/src/cmd/go/mkdoc.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.\n
+go help documentation > doc.go
+gofmt -w doc.go
+\n
コアとなるコードの解説
-
documentationTemplate
: このtext/template
は、doc.go
ファイルの内容を生成するための「設計図」です。Goのソースコードコメントブロック(/* ... */
)内に、各Goコマンドの短い説明(Short
)と長い説明(Long
)を整形して埋め込みます。{{range .}}
で渡されたコマンドのリストをイテレートし、それぞれのコマンドに対してShort
とLong
フィールドを処理します。{{.Short | capitalize}}
の部分では、Short
フィールドの最初の文字を大文字に変換するcapitalize
関数が適用されます。これは、doc.go
のコメントとして自然な見た目にするためです。 -
capitalize
関数:text/template
内で使用されるカスタム関数です。引数として受け取った文字列の最初のUnicodeルーン(文字)を大文字に変換し、残りの文字列と結合して返します。これにより、Short
フィールドが常に大文字で始まるようになります。 -
help
関数内の"documentation"
引数処理:main.go
のhelp
関数は、go help <topic>
の<topic>
部分を処理します。このコミットでは、<topic>
が"documentation"
の場合に特別なロジックが実行されます。buf := new(bytes.Buffer)
: 出力先となる一時的なバッファを作成します。printUsage(buf)
:go
コマンド全体の基本的な使用方法(コマンド一覧など)をこのバッファに書き込みます。usage := &Command{Long: buf.String()}
:printUsage
で生成されたテキストを、あたかも一つの長いドキュメントであるかのようにCommand
構造体のLong
フィールドに格納します。これは、documentationTemplate
が期待するデータ形式に合わせるためです。tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
:documentationTemplate
を使用して、usage
(全体の概要)とcommands
(各サブコマンドの詳細)を結合したデータから最終的なドキュメントを生成し、標準出力(os.Stdout
)に出力します。この出力がmkdoc.sh
によってdoc.go
にリダイレクトされます。
-
mkdoc.sh
: このシェルスクリプトは、go help documentation
コマンドを実行し、その出力をdoc.go
ファイルに書き込みます。その後、gofmt -w doc.go
を実行して、生成されたdoc.go
ファイルがGoの標準的なフォーマットに準拠するように自動整形します。これは、ビルドプロセスの一部として実行されることを想定しており、開発者が手動でdoc.go
を更新する手間を省きます。
これらの変更により、Goコマンドのヘルプドキュメントは、コード内の定義から自動的に生成されるようになり、ドキュメントの正確性とメンテナンス性が大幅に向上しました。
関連リンク
- Go Issue #2783:
go help
output anddoc.go
are out of sync: https://github.com/golang/go/issues/2783 - Go Code Review 5570069:
cmd/go: update doc.go with text generated from the usage strings
: https://golang.org/cl/5570069
参考にした情報源リンク
- Go言語公式ドキュメント: https://go.dev/doc/
text/template
パッケージドキュメント: https://pkg.go.dev/text/templategodoc
コマンドについて: https://go.dev/blog/godoc-documenting-go-code- Go Modules (GOPATHの概念を含む): https://go.dev/blog/using-go-modules (GOPATHは古い概念ですが、このコミット当時のGoの環境設定の基礎でした)
- Goのテストについて (
go test
,testing
パッケージ): https://go.dev/blog/testing-is-easy gofmt
について: https://go.dev/blog/gofmt- UnicodeとGoの文字列処理: https://go.dev/blog/strings (特に
unicode
とutf8
パッケージの関連)