[インデックス 14016] ファイルの概要
このコミットは、Go言語のAPI互換性チェックツールである cmd/api
に、互換性の例外を定義するための except.txt
ファイルを追加するものです。これにより、特定のAPI要素が変更または削除されても、ビルドが失敗しないように調整されます。特に、text/template/parse
パッケージ内の要素が例外として指定されています。
コミット
commit d87d48895337392c9e0fb455cc9e3b08f7f45ce4
Author: Rob Pike <r@golang.org>
Date: Thu Oct 4 11:35:17 2012 +1000
cmd/api: add exception file
Fixes build.
R=golang-dev, adg, bradfitz, dsymonds, dave
CC=golang-dev
https://golang.org/cl/6586074
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d87d48895337392c9e0fb455cc9e3b08f7f45ce4
元コミット内容
diff --git a/api/README b/api/README
index 6adc55454c..34b86efd99 100644
--- a/api/README
+++ b/api/README
@@ -5,6 +5,9 @@ Each file is a list of of API features, one per line.
go1.txt (and similarly named files) are frozen once a version has been
shipped. Each file adds new lines but does not remove any.
+except.txt lists features that may disappear without breaking
+true compatibility. The only package there is text/template/parse.
+
next.txt is the only file intended to be mutated. It's a list of
features that may be added to the next version. It only affects
warning output from the go api tool.
diff --git a/api/except.txt b/api/except.txt
new file mode 100644
index 0000000000..e9fb24b466
--- /dev/null
+++ b/api/except.txt
@@ -0,0 +1,2 @@
+pkg text/template/parse, type DotNode bool
+pkg text/template/parse, type Node interface { Copy, String, Type }
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 7463e20d6d..391cbe76fa 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -38,11 +38,12 @@ import (
var (
// TODO(bradfitz): once Go 1.1 comes out, allow the -c flag to take a comma-separated
// list of files, rather than just one.
-\tcheckFile = flag.String("c", "", "optional filename to check API against")
-\tallowNew = flag.Bool("allow_new", true, "allow API additions")
-\tnextFile = flag.String("next", "", "optional filename of tentative upcoming API features for the next release. This file can be lazily maintained. It only affects the delta warnings from the -c file printed on success.")
-\tverbose = flag.Bool("v", false, "verbose debugging")
-\tforceCtx = flag.String("contexts", "", "optional comma-separated list of <goos>-<goarch>[-cgo] to override default contexts.")
+\tcheckFile = flag.String("c", "", "optional filename to check API against")
+\tallowNew = flag.Bool("allow_new", true, "allow API additions")
+\texceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool")
+\tnextFile = flag.String("next", "", "optional filename of tentative upcoming API features for the next release. This file can be lazily maintained. It only affects the delta warnings from the -c file printed on success.")
+\tverbose = flag.Bool("v", false, "verbose debugging")
+\tforceCtx = flag.String("contexts", "", "optional comma-separated list of <goos>-<goarch>[-cgo] to override default contexts.")
)
// contexts are the default contexts which are scanned, unless
@@ -198,6 +199,13 @@ func main() {
}
}
+\tvar exception = make(map[string]bool) // exception => true
+\tif *exceptFile != "" {
+\t\tfor _, feature := range fileFeatures(*exceptFile) {
+\t\t\texception[feature] = true
+\t\t}\
+\t}
+\
\ttake := func(sl *[]string) string {\n \t\ts := (*sl)[0]\n \t\t*sl = (*sl)[1:]\n@@ -207,8 +215,13 @@ func main() {\n \tfor len(required) > 0 || len(features) > 0 {\n \t\tswitch {\n \t\tcase len(features) == 0 || required[0] < features[0]:\n-\t\t\tfmt.Fprintf(bw, "-%s\\n", take(&required))\n-\t\t\tfail = true // broke compatibility\n+\t\t\tfeature := take(&required)\n+\t\t\tif exception[feature] {\n+\t\t\t\tfmt.Fprintf(bw, "~%s\\n", feature)\n+\t\t\t} else {\n+\t\t\t\tfmt.Fprintf(bw, "-%s\\n", feature)\n+\t\t\t\tfail = true // broke compatibility\n+\t\t\t}\n \t\tcase len(required) == 0 || required[0] > features[0]:\n \t\t\tnewFeature := take(&features)\n \t\t\tif optional[newFeature] {\ndiff --git a/src/run.bash b/src/run.bash
index f379ff5a70..1859555fb1 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -112,7 +112,7 @@ time go run run.go
echo
echo '# Checking API compatibility.'
-go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt
+go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt -except $GOROOT/api/except.txt
echo
echo ALL TESTS PASSED
変更の背景
Go言語は、その安定したAPI互換性を非常に重視しています。これは、Go 1のリリース以降、既存のGoプログラムが新しいバージョンのGoコンパイラでコンパイルできなくなるような破壊的変更を避けるというGoチームの強いコミットメントに基づいています。この互換性保証は、Goエコシステムの健全性と開発者の信頼を維持するために不可欠です。
cmd/api
ツールは、このAPI互換性を自動的にチェックするために使用されます。このツールは、Goの標準ライブラリのAPI定義を読み込み、以前のバージョン(例えば go1.txt
に定義されているGo 1のAPI)と比較して、互換性のない変更(APIの削除やシグネチャの変更など)がないかを検証します。もし互換性のない変更が検出された場合、ツールはエラーを報告し、ビルドプロセスを失敗させることがあります。
しかし、開発の過程で、特定のパッケージやAPI要素が、互換性保証の対象外として扱われる必要がある場合があります。これは、例えば、内部的な実装の詳細であり、外部のユーザーが直接依存すべきではないAPIや、まだ安定していない実験的なAPIなどが該当します。このようなAPIが変更または削除された場合でも、cmd/api
ツールがエラーを報告してビルドを中断するのを避けたいというニーズが生じます。
このコミットの背景には、text/template/parse
パッケージ内の特定の型(DotNode
と Node
インターフェース)が、API互換性チェックの例外として扱われる必要があったという具体的な問題があります。これらの要素が変更された際にビルドが失敗するのを防ぐため、例外メカニズムを導入する必要がありました。コミットメッセージの「Fixes build.」という記述は、この問題が実際にビルドの失敗を引き起こしていたことを示唆しています。
前提知識の解説
Go言語のAPI互換性
Go言語は「Go 1 Compatibility Promise」という強力な互換性保証を持っています。これは、Go 1.xのリリースにおいて、Go 1で書かれたプログラムがGo 1.xの新しいバージョンでもコンパイルされ、実行されることを保証するものです。この保証は、Goの標準ライブラリの公開APIに適用されます。
cmd/api
ツール
cmd/api
は、Goの標準ライブラリのAPIがGo 1 Compatibility Promiseに準拠しているかを検証するための内部ツールです。このツールは、GoのソースコードからAPI情報を抽出し、既知の安定したAPI定義ファイル(例: api/go1.txt
)と比較します。
api/go1.txt
: Go 1のリリース時に確定されたAPIのリスト。このファイルに記載されているAPIは、将来のGoのバージョンでも変更されないことが保証されます。api/next.txt
: 次のリリースで追加される可能性のあるAPIのリスト。これは開発中のAPIであり、まだ安定性が保証されていません。cmd/api
ツールは、このファイルに記載されたAPIの追加については警告を出しません。
cmd/api
ツールは、APIの削除やシグネチャの変更など、互換性を損なう変更を検出するとエラーを報告します。
text/template/parse
パッケージ
text/template
パッケージは、Go言語でテキストテンプレートを解析・実行するための標準ライブラリです。このパッケージは、WebアプリケーションのHTML生成や、設定ファイルの動的な生成など、様々な用途で利用されます。
text/template/parse
パッケージは、text/template
パッケージの内部実装の一部であり、テンプレートの構文木(AST: Abstract Syntax Tree)を構築するための機能を提供します。通常、このパッケージはGoアプリケーション開発者が直接利用することは少なく、text/template
パッケージを介して間接的に利用されます。そのため、text/template/parse
パッケージの内部的な型やインターフェースは、Go 1 Compatibility Promiseの対象外とされることがあります。
技術的詳細
このコミットの主要な目的は、cmd/api
ツールに「例外」の概念を導入することです。これにより、特定のAPI要素が削除または変更されても、ツールが互換性違反として報告しないように設定できるようになります。
except.txt
ファイルの導入
- 新しく
api/except.txt
ファイルが追加されました。このファイルには、API互換性チェックの例外として扱われるAPI要素が記述されます。 api/README
が更新され、except.txt
の目的が説明されています。「except.txt
は、真の互換性を損なうことなく消滅する可能性のある機能をリストアップします。現在、唯一のパッケージはtext/template/parse
です。」と明記されています。except.txt
の初期内容として、pkg text/template/parse, type DotNode bool
とpkg text/template/parse, type Node interface { Copy, String, Type }
が追加されています。これは、text/template/parse
パッケージ内のDotNode
型とNode
インターフェースが、互換性チェックの例外として扱われることを意味します。
cmd/api
ツールの変更
-
-except
フラグの追加:src/cmd/api/goapi.go
に新しいコマンドラインフラグ-except
が追加されました。このフラグは、例外を定義するファイル(例:api/except.txt
)のパスを指定するために使用されます。exceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool")
-
例外マップの生成:
main
関数内で、exceptFile
フラグで指定されたファイルからAPI要素を読み込み、それらをキーとするmap[string]bool
型のexception
マップが作成されます。このマップは、特定のAPI要素が例外であるかどうかを効率的にチェックするために使用されます。var exception = make(map[string]bool) // exception => true if *exceptFile != "" { for _, feature := range fileFeatures(*exceptFile) { exception[feature] = true } }
-
互換性チェックロジックの変更: API互換性チェックのコアロジックが変更されました。以前は、
required
リスト(Go 1のAPIなど、必須とされるAPI)に存在するがfeatures
リスト(現在のAPI)に存在しないAPI要素が見つかった場合、即座に互換性違反としてエラー (fail = true
) を報告していました。 新しいロジックでは、required
から取り出されたfeature
がexception
マップに存在するかどうかをチェックします。- もし
exception[feature]
がtrue
であれば、そのAPI要素は例外として扱われ、互換性違反とは見なされません。出力には-
の代わりに~
が付加され、互換性違反ではないが変更があったことを示します。 exception[feature]
がfalse
であれば、以前と同様に互換性違反としてエラーが報告され、fail = true
が設定されます。
case len(features) == 0 || required[0] < features[0]: feature := take(&required) if exception[feature] { fmt.Fprintf(bw, "~%s\n", feature) } else { fmt.Fprintf(bw, "-%s\n", feature) fail = true // broke compatibility }
- もし
src/run.bash
の変更
- Goのテストスクリプトである
src/run.bash
が更新され、go tool api
コマンドの実行時に新しく追加された-except
フラグが使用されるようになりました。
これにより、ビルドプロセスの一部としてAPI互換性チェックが実行される際に、-go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt +go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt -except $GOROOT/api/except.txt
api/except.txt
に定義された例外が考慮されるようになります。
これらの変更により、text/template/parse
パッケージ内の特定の型が変更または削除されても、cmd/api
ツールがビルドを失敗させることなく、Goのビルドプロセスが正常に完了するようになりました。
コアとなるコードの変更箇所
api/README
:except.txt
の説明を追加。api/except.txt
: 新規ファイルとして追加。text/template/parse
の例外を定義。src/cmd/api/goapi.go
:-except
コマンドラインフラグを追加。except.txt
から例外を読み込み、exception
マップに格納するロジックを追加。- API互換性チェックロジックにおいて、例外を考慮するように変更。
src/run.bash
:go tool api
コマンドに-except $GOROOT/api/except.txt
を追加。
コアとなるコードの解説
api/README
の変更
api/README
は、api
ディレクトリ内のファイル群の目的を説明するドキュメントです。このコミットでは、except.txt
が追加されたことに伴い、その役割が追記されました。これにより、except.txt
が「真の互換性を損なうことなく消滅する可能性のある機能」をリストアップするものであることが明確に示されています。
api/except.txt
の新規追加
このファイルは、cmd/api
ツールが互換性チェックを行う際に無視すべきAPI要素を明示的に指定するために導入されました。ファイルの内容は以下の通りです。
pkg text/template/parse, type DotNode bool
pkg text/template/parse, type Node interface { Copy, String, Type }
これは、text/template/parse
パッケージ内の DotNode
型と Node
インターフェースが、API互換性チェックの例外として扱われることを意味します。これらの要素がGoの将来のバージョンで変更または削除されても、cmd/api
ツールはエラーを報告しません。
src/cmd/api/goapi.go
の変更
このファイルは cmd/api
ツールの主要なロジックを含んでいます。
-
exceptFile
フラグの追加:exceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool")
flag.String
を使用して、コマンドライン引数-except
を定義しています。これにより、ユーザーは例外ファイルを指定できるようになります。 -
例外マップの初期化と読み込み:
var exception = make(map[string]bool) // exception => true if *exceptFile != "" { for _, feature := range fileFeatures(*exceptFile) { exception[feature] = true } }
exception
という名前のmap[string]bool
を作成し、exceptFile
フラグが指定されている場合に、そのファイルから読み込んだ各API要素をマップのキーとして追加しています。fileFeatures
関数は、指定されたファイルからAPI要素のリストを読み込むユーティリティ関数です。このマップにより、特定のAPI要素が例外であるかをO(1)の計算量で高速にルックアップできるようになります。 -
互換性チェックロジックの修正:
case len(features) == 0 || required[0] < features[0]: feature := take(&required) if exception[feature] { fmt.Fprintf(bw, "~%s\n", feature) } else { fmt.Fprintf(bw, "-%s\n", feature) fail = true // broke compatibility }
この部分が、API互換性チェックの核心です。
required
リストからAPI要素 (feature
) を一つ取り出し、それが現在のAPI (features
) に存在しない場合(つまり、APIが削除された場合)の処理です。if exception[feature]
の条件で、取り出したfeature
が例外マップに存在するかどうかをチェックします。- もし存在すれば、
fmt.Fprintf(bw, "~%s\n", feature)
を実行します。これは、APIが削除されたが、それが例外であるため互換性違反とは見なさないことを示すために、~
プレフィックスを付けて出力します。fail = true
は設定されません。 - 存在しなければ、
fmt.Fprintf(bw, "-%s\n", feature)
を実行し、fail = true
を設定します。これは、APIが削除され、それが互換性違反であることを示すために、-
プレフィックスを付けて出力し、ビルドを失敗させます。
src/run.bash
の変更
src/run.bash
はGoのビルドおよびテストプロセスを自動化するためのシェルスクリプトです。
-go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt
+go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt -except $GOROOT/api/except.txt
この変更により、go tool api
コマンドが実行される際に、$GOROOT/api/except.txt
ファイルが例外リストとして渡されるようになります。これにより、Goの公式ビルドプロセスにおいて、text/template/parse
パッケージの特定のAPI変更が互換性違反として扱われなくなり、ビルドが正常に完了するようになります。
関連リンク
- Go CL 6586074: https://golang.org/cl/6586074
参考にした情報源リンク
- Go 1 Compatibility Promise: https://go.dev/doc/go1compat
text/template
package documentation: https://pkg.go.dev/text/templatetext/template/parse
package documentation: https://pkg.go.dev/text/template/parse- Go issue tracker (for context on build failures related to API changes): https://github.com/golang/go/issues (具体的なissue番号は不明ですが、関連する議論が存在する可能性があります)
[インデックス 14016] ファイルの概要
このコミットは、Go言語のAPI互換性チェックツールである cmd/api
に、互換性の例外を定義するための except.txt
ファイルを追加するものです。これにより、特定のAPI要素が変更または削除されても、ビルドが失敗しないように調整されます。特に、text/template/parse
パッケージ内の要素が例外として指定されています。
コミット
commit d87d48895337392c9e0fb455cc9e3b08f7f45ce4
Author: Rob Pike <r@golang.org>
Date: Thu Oct 4 11:35:17 2012 +1000
cmd/api: add exception file
Fixes build.
R=golang-dev, adg, bradfitz, dsymonds, dave
CC=golang-dev
https://golang.org/cl/6586074
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d87d48895337392c9e0fb455cc9e3b08f7f45ce4
元コミット内容
diff --git a/api/README b/api/README
index 6adc55454c..34b86efd99 100644
--- a/api/README
+++ b/api/README
@@ -5,6 +5,9 @@ Each file is a list of of API features, one per line.
go1.txt (and similarly named files) are frozen once a version has been
shipped. Each file adds new lines but does not remove any.
+except.txt lists features that may disappear without breaking
+true compatibility. The only package there is text/template/parse.
+
next.txt is the only file intended to be mutated. It's a list of
features that may be added to the next version. It only affects
warning output from the go api tool.
diff --git a/api/except.txt b/api/except.txt
new file mode 100644
index 0000000000..e9fb24b466
--- /dev/null
+++ b/api/except.txt
@@ -0,0 +1,2 @@
+pkg text/template/parse, type DotNode bool
+pkg text/template/parse, type Node interface { Copy, String, Type }
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 7463e20d6d..391cbe76fa 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -38,11 +38,12 @@ import (
var (
// TODO(bradfitz): once Go 1.1 comes out, allow the -c flag to take a comma-separated
// list of files, rather than just one.
-\tcheckFile = flag.String("c", "", "optional filename to check API against")
-\tallowNew = flag.Bool("allow_new", true, "allow API additions")
-\tnextFile = flag.String("next", "", "optional filename of tentative upcoming API features for the next release. This file can be lazily maintained. It only affects the delta warnings from the -c file printed on success.")
-\tverbose = flag.Bool("v", false, "verbose debugging")
-\tforceCtx = flag.String("contexts", "", "optional comma-separated list of <goos>-<goarch>[-cgo] to override default contexts.")
+\tcheckFile = flag.String("c", "", "optional filename to check API against")
+\tallowNew = flag.Bool("allow_new", true, "allow API additions")
+\texceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool")
+\tnextFile = flag.String("next", "", "optional filename of tentative upcoming API features for the next release. This file can be lazily maintained. It only affects the delta warnings from the -c file printed on success.")
+\tverbose = flag.Bool("v", false, "verbose debugging")
+\tforceCtx = flag.String("contexts", "", "optional comma-separated list of <goos>-<goarch>[-cgo] to override default contexts.")
)
// contexts are the default contexts which are scanned, unless
@@ -198,6 +199,13 @@ func main() {
}
}
+\tvar exception = make(map[string]bool) // exception => true
+\tif *exceptFile != "" {
+\t\tfor _, feature := range fileFeatures(*exceptFile) {
+\t\t\texception[feature] = true
+\t\t}\
+\t}
+\
\ttake := func(sl *[]string) string {\n \t\ts := (*sl)[0]\n \t\t*sl = (*sl)[1:]\n@@ -207,8 +215,13 @@ func main() {\n \tfor len(required) > 0 || len(features) > 0 {\n \t\tswitch {\n \t\tcase len(features) == 0 || required[0] < features[0]:\n-\t\t\tfmt.Fprintf(bw, "-%s\\n", take(&required))\n-\t\t\tfail = true // broke compatibility\n+\t\t\tfeature := take(&required)\n+\t\t\tif exception[feature] {\n+\t\t\t\tfmt.Fprintf(bw, "~%s\\n", feature)\n+\t\t\t} else {\n+\t\t\t\tfmt.Fprintf(bw, "-%s\\n", feature)\n+\t\t\t\tfail = true // broke compatibility\n+\t\t\t}\n \t\tcase len(required) == 0 || required[0] > features[0]:\n \t\t\tnewFeature := take(&features)\n \t\t\tif optional[newFeature] {\ndiff --git a/src/run.bash b/src/run.bash
index f379ff5a70..1859555fb1 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -112,7 +112,7 @@ time go run run.go
echo
echo '# Checking API compatibility.'
-go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt
+go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt -except $GOROOT/api/except.txt
echo
echo ALL TESTS PASSED
変更の背景
Go言語は、その安定したAPI互換性を非常に重視しています。これは、Go 1のリリース以降、既存のGoプログラムが新しいバージョンのGoコンパイラでコンパイルできなくなるような破壊的変更を避けるというGoチームの強いコミットメントに基づいています。この互換性保証は、Goエコシステムの健全性と開発者の信頼を維持するために不可欠です。
cmd/api
ツールは、このAPI互換性を自動的にチェックするために使用されます。このツールは、Goの標準ライブラリのAPI定義を読み込み、以前のバージョン(例えば go1.txt
に定義されているGo 1のAPI)と比較して、互換性のない変更(APIの削除やシグネチャの変更など)がないかを検証します。もし互換性のない変更が検出された場合、ツールはエラーを報告し、ビルドプロセスを失敗させることがあります。
しかし、開発の過程で、特定のパッケージやAPI要素が、互換性保証の対象外として扱われる必要がある場合があります。これは、例えば、内部的な実装の詳細であり、外部のユーザーが直接依存すべきではないAPIや、まだ安定していない実験的なAPIなどが該当します。このようなAPIが変更または削除された場合でも、cmd/api
ツールがエラーを報告してビルドを中断するのを避けたいというニーズが生じます。
このコミットの背景には、text/template/parse
パッケージ内の特定の型(DotNode
と Node
インターフェース)が、API互換性チェックの例外として扱われる必要があったという具体的な問題があります。これらの要素が変更された際にビルドが失敗するのを防ぐため、例外メカニズムを導入する必要がありました。コミットメッセージの「Fixes build.」という記述は、この問題が実際にビルドの失敗を引き起こしていたことを示唆しています。
前提知識の解説
Go言語のAPI互換性
Go言語は「Go 1 Compatibility Promise」という強力な互換性保証を持っています。これは、Go 1.xのリリースにおいて、Go 1で書かれたプログラムがGo 1.xの新しいバージョンでもコンパイルされ、実行されることを保証するものです。この保証は、Goの標準ライブラリの公開APIに適用されます。
cmd/api
ツール
cmd/api
は、Goの標準ライブラリのAPIがGo 1 Compatibility Promiseに準拠しているかを検証するための内部ツールです。このツールは、GoのソースコードからAPI情報を抽出し、既知の安定したAPI定義ファイル(例: api/go1.txt
)と比較します。
api/go1.txt
: Go 1のリリース時に確定されたAPIのリスト。このファイルに記載されているAPIは、将来のGoのバージョンでも変更されないことが保証されます。api/next.txt
: 次のリリースで追加される可能性のあるAPIのリスト。これは開発中のAPIであり、まだ安定性が保証されていません。cmd/api
ツールは、このファイルに記載されたAPIの追加については警告を出しません。
cmd/api
ツールは、APIの削除やシグネチャの変更など、互換性を損なう変更を検出するとエラーを報告します。
text/template/parse
パッケージ
text/template
パッケージは、Go言語でテキストテンプレートを解析・実行するための標準ライブラリです。このパッケージは、WebアプリケーションのHTML生成や、設定ファイルの動的な生成など、様々な用途で利用されます。
text/template/parse
パッケージは、text/template
パッケージの内部実装の一部であり、テンプレートの構文木(AST: Abstract Syntax Tree)を構築するための機能を提供します。通常、このパッケージはGoアプリケーション開発者が直接利用することは少なく、text/template
パッケージを介して間接的に利用されます。そのため、text/template/parse
パッケージの内部的な型やインターフェースは、Go 1 Compatibility Promiseの対象外とされることがあります。
技術的詳細
このコミットの主要な目的は、cmd/api
ツールに「例外」の概念を導入することです。これにより、特定のAPI要素が削除または変更されても、ツールが互換性違反として報告しないように設定できるようになります。
except.txt
ファイルの導入
- 新しく
api/except.txt
ファイルが追加されました。このファイルには、API互換性チェックの例外として扱われるAPI要素が記述されます。 api/README
が更新され、except.txt
の目的が説明されています。「except.txt
は、真の互換性を損なうことなく消滅する可能性のある機能をリストアップします。現在、唯一のパッケージはtext/template/parse
です。」と明記されています。except.txt
の初期内容として、pkg text/template/parse, type DotNode bool
とpkg text/template/parse, type Node interface { Copy, String, Type }
が追加されています。これは、text/template/parse
パッケージ内のDotNode
型とNode
インターフェースが、互換性チェックの例外として扱われることを意味します。
cmd/api
ツールの変更
-
-except
フラグの追加:src/cmd/api/goapi.go
に新しいコマンドラインフラグ-except
が追加されました。このフラグは、例外を定義するファイル(例:api/except.txt
)のパスを指定するために使用されます。exceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool")
-
例外マップの生成:
main
関数内で、exceptFile
フラグで指定されたファイルからAPI要素を読み込み、それらをキーとするmap[string]bool
型のexception
マップが作成されます。このマップは、特定のAPI要素が例外であるかどうかを効率的にチェックするために使用されます。var exception = make(map[string]bool) // exception => true if *exceptFile != "" { for _, feature := range fileFeatures(*exceptFile) { exception[feature] = true } }
-
互換性チェックロジックの変更: API互換性チェックのコアロジックが変更されました。以前は、
required
リスト(Go 1のAPIなど、必須とされるAPI)に存在するがfeatures
リスト(現在のAPI)に存在しないAPI要素が見つかった場合、即座に互換性違反としてエラー (fail = true
) を報告していました。 新しいロジックでは、required
から取り出されたfeature
がexception
マップに存在するかどうかをチェックします。- もし
exception[feature]
がtrue
であれば、そのAPI要素は例外として扱われ、互換性違反とは見なされません。出力には-
の代わりに~
が付加され、互換性違反ではないが変更があったことを示します。 exception[feature]
がfalse
であれば、以前と同様に互換性違反としてエラーが報告され、fail = true
が設定されます。
case len(features) == 0 || required[0] < features[0]: feature := take(&required) if exception[feature] { fmt.Fprintf(bw, "~%s\n", feature) } else { fmt.Fprintf(bw, "-%s\n", feature) fail = true // broke compatibility }
- もし
src/run.bash
の変更
- Goのテストスクリプトである
src/run.bash
が更新され、go tool api
コマンドの実行時に新しく追加された-except
フラグが使用されるようになりました。
これにより、ビルドプロセスの一部としてAPI互換性チェックが実行される際に、-go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt +go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt -except $GOROOT/api/except.txt
api/except.txt
に定義された例外が考慮されるようになります。
これらの変更により、text/template/parse
パッケージ内の特定の型が変更または削除されても、cmd/api
ツールがビルドを失敗させることなく、Goのビルドプロセスが正常に完了するようになりました。
コアとなるコードの変更箇所
api/README
:except.txt
の説明を追加。api/except.txt
: 新規ファイルとして追加。text/template/parse
の例外を定義。src/cmd/api/goapi.go
:-except
コマンドラインフラグを追加。except.txt
から例外を読み込み、exception
マップに格納するロジックを追加。- API互換性チェックロジックにおいて、例外を考慮するように変更。
src/run.bash
:go tool api
コマンドに-except $GOROOT/api/except.txt
を追加。
コアとなるコードの解説
api/README
の変更
api/README
は、api
ディレクトリ内のファイル群の目的を説明するドキュメントです。このコミットでは、except.txt
が追加されたことに伴い、その役割が追記されました。これにより、except.txt
が「真の互換性を損なうことなく消滅する可能性のある機能」をリストアップするものであることが明確に示されています。
api/except.txt
の新規追加
このファイルは、cmd/api
ツールが互換性チェックを行う際に無視すべきAPI要素を明示的に指定するために導入されました。ファイルの内容は以下の通りです。
pkg text/template/parse, type DotNode bool
pkg text/template/parse, type Node interface { Copy, String, Type }
これは、text/template/parse
パッケージ内の DotNode
型と Node
インターフェースが、API互換性チェックの例外として扱われることを意味します。これらの要素がGoの将来のバージョンで変更または削除されても、cmd/api
ツールはエラーを報告しません。
src/cmd/api/goapi.go
の変更
このファイルは cmd/api
ツールの主要なロジックを含んでいます。
-
exceptFile
フラグの追加:exceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool")
flag.String
を使用して、コマンドライン引数-except
を定義しています。これにより、ユーザーは例外ファイルを指定できるようになります。 -
例外マップの初期化と読み込み:
var exception = make(map[string]bool) // exception => true if *exceptFile != "" { for _, feature := range fileFeatures(*exceptFile) { exception[feature] = true } }
exception
という名前のmap[string]bool
を作成し、exceptFile
フラグが指定されている場合に、そのファイルから読み込んだ各API要素をマップのキーとして追加しています。fileFeatures
関数は、指定されたファイルからAPI要素のリストを読み込むユーティリティ関数です。このマップにより、特定のAPI要素が例外であるかをO(1)の計算量で高速にルックアップできるようになります。 -
互換性チェックロジックの修正:
case len(features) == 0 || required[0] < features[0]: feature := take(&required) if exception[feature] { fmt.Fprintf(bw, "~%s\n", feature) } else { fmt.Fprintf(bw, "-%s\n", feature) fail = true // broke compatibility }
この部分が、API互換性チェックの核心です。
required
リストからAPI要素 (feature
) を一つ取り出し、それが現在のAPI (features
) に存在しない場合(つまり、APIが削除された場合)の処理です。if exception[feature]
の条件で、取り出したfeature
が例外マップに存在するかどうかをチェックします。- もし存在すれば、
fmt.Fprintf(bw, "~%s\n", feature)
を実行します。これは、APIが削除されたが、それが例外であるため互換性違反とは見なさないことを示すために、~
プレフィックスを付けて出力します。fail = true
は設定されません。 - 存在しなければ、
fmt.Fprintf(bw, "-%s\n", feature)
を実行し、fail = true
を設定します。これは、APIが削除され、それが互換性違反であることを示すために、-
プレフィックスを付けて出力し、ビルドを失敗させます。
src/run.bash
の変更
src/run.bash
はGoのビルドおよびテストプロセスを自動化するためのシェルスクリプトです。
-go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt
+go tool api -c $GOROOT/api/go1.txt -next $GOROOT/api/next.txt -except $GOROOT/api/except.txt
この変更により、go tool api
コマンドが実行される際に、$GOROOT/api/except.txt
ファイルが例外リストとして渡されるようになります。これにより、Goの公式ビルドプロセスにおいて、text/template/parse
パッケージの特定のAPI変更が互換性違反として扱われなくなり、ビルドが正常に完了するようになります。
関連リンク
- Go CL 6586074: https://golang.org/cl/6586074
参考にした情報源リンク
- Go 1 Compatibility Promise: https://go.dev/doc/go1compat
text/template
package documentation: https://pkg.go.dev/text/templatetext/template/parse
package documentation: https://pkg.go.dev/text/template/parse- Go issue tracker (for context on build failures related to API changes): https://github.com/golang/go/issues (具体的なissue番号は不明ですが、関連する議論が存在する可能性があります)