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

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

このコミットは、Go言語のcmd/fixツールに、非推奨となったパッケージ(expolddeletedに分類されるパッケージ)の使用に対して警告を発する機能を追加するものです。これにより、Go 1のリリースに伴うパッケージの整理と移行を開発者がよりスムーズに行えるよう支援します。

コミット

commit 878153682ecac3fb00bdad50ff8dcc296e30a701
Author: Russ Cox <rsc@golang.org>
Date:   Sun Feb 12 23:55:33 2012 -0500

    cmd/fix: warn about exp, old, deleted packages
    
    Fixes #2776.
    
    There was a previous attempt at CL 5592043 but that
    seems to have stalled.  This one is simpler, and more up to date
    (correct handling of spdy, for example).
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5645091

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

https://github.com/golang/go/commit/878153682ecac3fb00bdad50ff8dcc296e30a701

元コミット内容

cmd/fix: expolddeletedパッケージについて警告する

Issue #2776 を修正。

以前にCL 5592043で試みられたが、それは停滞しているようだ。 今回のものはよりシンプルで、より最新の状態に対応している(例えば、spdyの正しい扱いなど)。

R=golang-dev, r CC=golang-dev https://golang.org/cl/5645091

変更の背景

このコミットは、Go言語の最初の安定版リリースであるGo 1の準備段階で行われました。Go 1では、標準ライブラリのAPI安定化と整理が重要な目標の一つでした。これに伴い、一部のパッケージは標準ライブラリから削除されたり、別のリポジトリに移動されたり、あるいは実験的な(exp)状態のまま残されたりしました。

このような変更は、既存のGoプログラムがGo 1に移行する際に、互換性の問題を引き起こす可能性があります。特に、削除されたパッケージや移動されたパッケージを使用しているコードは、手動での修正が必要になります。go fixツールは、Goのバージョンアップに伴うコードの自動修正を支援するために設計されていますが、Go 1のリリース時点では、これらの非推奨パッケージの使用に対する警告機能が不足していました。

コミットメッセージにある「Fixes #2776」は、この問題がGoのIssueトラッカーで追跡されていたことを示しています。Issue #2776は、go fixが削除されたパッケージやexpパッケージの使用について警告すべきであるという要望でした。このコミットは、その要望に応える形で、開発者がGo 1への移行時に自身のコードベースで非推奨パッケージの使用箇所を特定し、修正するのを助けることを目的としています。

以前にも同様の試み(CL 5592043)があったものの、それが停滞していたため、よりシンプルで最新の状況(特にspdyパッケージの扱い)に対応した新しい実装が提案されました。

前提知識の解説

Go言語のgo fixコマンド

go fixコマンドは、Go言語のツールチェーンの一部であり、Goの新しいバージョンへの移行に伴うコードの自動修正を支援するために使用されます。Go言語は後方互換性を重視していますが、言語仕様や標準ライブラリの変更によって、古いコードが新しいバージョンでコンパイルできなくなったり、意図しない動作をしたりする場合があります。go fixは、このような互換性の問題を自動的に検出し、修正する機能を提供します。例えば、パッケージ名の変更やAPIの変更に対応するために、インポートパスや関数呼び出しを自動的に書き換えることができます。

Go 1リリースとパッケージの整理

Go 1は、Go言語の最初の安定版リリースであり、言語仕様と標準ライブラリのAPIが安定化されました。これにより、Go 1で書かれたプログラムは、将来のGoのバージョンでも動作することが保証されるようになりました。この安定化の過程で、標準ライブラリに含まれていた一部のパッケージが整理されました。

  • expパッケージ: exp(experimental)は、実験的なパッケージを含むディレクトリです。これらのパッケージは、将来的に標準ライブラリに取り込まれる可能性がありますが、APIが安定しておらず、変更される可能性があります。Go 1の時点では、exp内のパッケージは標準ライブラリの一部とは見なされず、使用は推奨されませんでした。
  • oldパッケージ: oldは、Goの初期バージョンで存在したが、Go 1で非推奨または削除されたパッケージを含むディレクトリです。これらのパッケージは、Go 1では使用すべきではありません。
  • deletedパッケージ: Go 1で完全に削除されたパッケージです。これらのパッケージは、もはやGoの標準配布物には含まれていません。

これらのパッケージの整理は、標準ライブラリの品質と保守性を向上させるための重要なステップでしたが、既存のコードベースを持つ開発者にとっては移行の課題となりました。

GoのIssueトラッカーとChange List (CL)

  • Issueトラッカー: Goプロジェクトは、バグ報告や機能要望を追跡するためにIssueトラッカー(当時はGoogle CodeのIssueトラッカー、現在はGitHub Issues)を使用しています。Issue #2776は、go fixが非推奨パッケージについて警告すべきであるという具体的な要望でした。
  • Change List (CL): Goプロジェクトでは、コード変更はChange List (CL) として提出され、レビュープロセスを経てマージされます。コミットメッセージにあるCL 5592043CL 5645091は、これらの変更提案を指します。

技術的詳細

このコミットの主要な技術的変更は、src/cmd/fix/go1pkgrename.goファイルに集中しています。このファイルは、Go 1への移行に伴うパッケージのリネームを処理するgo fixのロジックを含んでいます。

変更の核心は、go1PackageRenamesという構造体スライスに、expolddeletedに分類されるパッケージのエントリを追加したことです。

  • expパッケージの追加: ebnfgo/typesといったパッケージがexp/ebnfexp/typesとしてリストに追加されました。これらの新しいパスは、exp/プレフィックスを持つことで、実験的なパッケージであることを示します。
  • deletedパッケージの追加: container/vectorexp/datafmtgo/typecheckerold/netchanold/regexpold/templatetryといったパッケージが、新しいパスが空文字列("")としてリストに追加されました。これは、これらのパッケージが完全に削除されたことを示します。

go1pkgrename関数内のロジックが修正され、これらの新しいエントリを処理するようになりました。

  1. インポートのチェック: importSpec関数(既存のimports関数の代わりに導入された、より詳細な情報を提供する関数)を使用して、ファイルが特定の古いパッケージをインポートしているかどうかをチェックします。
  2. 削除されたパッケージの警告: rename.newが空文字列("")の場合、そのパッケージがGo 1で削除されたことを意味します。この場合、warn関数が呼び出され、「package %q has been deleted in Go 1」(パッケージ %q はGo 1で削除されました)という警告メッセージが表示されます。
  3. expパッケージの警告: rename.newexp/で始まる場合、そのパッケージがGo 1の一部ではないことを意味します。この場合も、warn関数が呼び出され、「package %q is not part of Go 1」(パッケージ %q はGo 1の一部ではありません)という警告メッセージが表示されます。
  4. パッケージのリネーム: 削除されたパッケージやexpパッケージでない場合、既存のrewriteImport関数が呼び出され、パッケージのインポートパスが新しいパスに書き換えられます。

この変更により、go fixは単にパッケージをリネームするだけでなく、非推奨または削除されたパッケージの使用を検出し、開発者に適切な警告を出すことができるようになりました。これにより、開発者はGo 1への移行時に、自身のコードベースで修正が必要な箇所をより簡単に特定できるようになります。

また、doc/go1.htmldoc/go1.tmplから、以前の「TODO: go fix should warn about deletions.」のようなコメントが削除されています。これは、このコミットによってそのTODOが完了したことを示しています。

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

src/cmd/fix/go1pkgrename.go

このファイルは、go fixコマンドがGo 1のパッケージリネームを処理するためのロジックを含んでいます。

--- a/src/cmd/fix/go1pkgrename.go
+++ b/src/cmd/fix/go1pkgrename.go
@@ -6,6 +6,7 @@ package main
 
 import (
 	"go/ast"
+	"strings"
 )
 
 func init() {
@@ -76,10 +77,24 @@ var go1PackageRenames = []struct{ old, new string }{\
 	{"net/dict", "code.google.com/p/go.net/dict"},
 	{"net/websocket", "code.google.com/p/go.net/websocket"},
 	{"exp/spdy", "code.google.com/p/go.net/spdy"},
+	{"http/spdy", "code.google.com/p/go.net/spdy"},
 
 	// go.codereview sub-repository
 	{"encoding/git85", "code.google.com/p/go.codereview/git85"},
 	{"patch", "code.google.com/p/go.codereview/patch"},
+
+	// exp
+	{"ebnf", "exp/ebnf"},
+	{"go/types", "exp/types"},
+
+	// deleted
+	{"container/vector", ""},
+	{"exp/datafmt", ""},
+	{"go/typechecker", ""},
+	{"old/netchan", ""},
+	{"old/regexp", ""},
+	{"old/template", ""},
+	{"try", ""},
 }
 
 var go1PackageNameRenames = []struct{ newPath, old, new string }{
@@ -92,12 +107,20 @@ func go1pkgrename(f *ast.File) bool {
 
 	// First update the imports.
 	for _, rename := range go1PackageRenames {
-		if !imports(f, rename.old) {
+		spec := importSpec(f, rename.old)
+		if spec == nil {
 			continue
 		}
+		if rename.new == "" {
+			warn(spec.Pos(), "package %q has been deleted in Go 1", rename.old)
+			continue
+		}
 		if rewriteImport(f, rename.old, rename.new) {
 			fixed = true
 		}
+		if strings.HasPrefix(rename.new, "exp/") {
+			warn(spec.Pos(), "package %q is not part of Go 1", rename.new)
+		}
 	}
 	if !fixed {
 		return false

src/cmd/fix/go1pkgrename_test.go

このファイルは、go1pkgrename関数のテストケースを含んでいます。

--- a/src/cmd/fix/go1pkgrename_test.go
+++ b/src/cmd/fix/go1pkgrename_test.go
@@ -87,6 +87,11 @@ import (
 import "cmath"
 import poot "exp/template/html"
 
+import (
+	"ebnf"
+	"old/regexp"
+)
+
 var _ = cmath.Sin
 var _ = poot.Poot
 `,
@@ -95,6 +100,11 @@ var _ = poot.Poot
 import "math/cmplx"
 import poot "html/template"
 
+import (
+	"exp/ebnf"
+	"old/regexp"
+)
+
 var _ = cmplx.Sin
 var _ = poot.Poot
 `,

doc/go1.html および doc/go1.tmpl

これらのファイルはGo 1のリリースノートのドキュメントであり、go fixが非推奨パッケージについて警告すべきであるというTODOコメントが削除されています。

--- a/doc/go1.html
+++ b/doc/go1.html
@@ -539,8 +539,6 @@ Running <code>go fix</code> will update all imports and package renames for pack
 remain inside the standard repository.  Programs that import packages
 that are no longer in the standard repository will need to be edited
 by hand.
-<br>
-<font color="red">TODO: go fix should warn about deletions.</font>
 </p>
 
 <h3 id="exp">The package tree exp</h3>
@@ -581,8 +579,6 @@ If they are installed, they now reside in <code>$GOROOT/bin/tool</code>.
 Code that uses packages in <code>exp</code> will need to be updated by hand,
 or else compiled from an installation that has <code>exp</code> available.
 The go fix tool or the compiler will complain about such uses.
-<br>
-<font color="red">TODO: go fix should warn about such uses.</font>
 </p>
 
 <h3 id="old">The package tree old</h3>
@@ -608,8 +604,6 @@ The packages in their new locations are:
 Code that uses packages now in <code>old</code> will need to be updated by hand,
 or else compiled from an installation that has <code>old</code> available.
 The go fix tool will warn about such uses.
-<br>
-<font color="red">TODO: go fix should warn about such uses.</font>
 </p>
 
 <h3 id="deleted">Deleted packages</h3>
@@ -636,8 +630,6 @@ slices directly.  See
 <a href="http://code.google.com/p/go-wiki/wiki/SliceTricks">the Go
 Language Community Wiki</a> for some suggestions.
 Code that uses the other packages (there should be almost zero) will need to be rethought.
-<br>
-<font color="red">TODO: go fix should warn such uses.</font>
 </p>
 
 <h3 id="subrepo">Packages moving to subrepositories</h3>

コアとなるコードの解説

go1pkgrename.goの変更点

  1. import "strings"の追加: strings.HasPrefix関数を使用するために、stringsパッケージがインポートされました。これは、exp/プレフィックスを持つパッケージを識別するために使用されます。

  2. go1PackageRenames構造体スライスの拡張: このスライスは、Go 1で変更されたパッケージのマッピングを定義します。

    • expパッケージ(例: ebnf -> exp/ebnf)と、新しいパスがexp/で始まるエントリが追加されました。
    • deletedパッケージ(例: container/vector -> "")と、新しいパスが空文字列のエントリが追加されました。空文字列は、そのパッケージが削除されたことを示すマーカーとして機能します。
    • http/spdyからcode.google.com/p/go.net/spdyへのリネームも追加されており、これはコミットメッセージにある「correct handling of spdy」に対応します。
  3. go1pkgrename関数のロジック変更:

    • imports(f, rename.old)の代わりにspec := importSpec(f, rename.old)が使用されるようになりました。importSpecは、単にインポートが存在するかどうかをチェックするだけでなく、そのインポートのASTノード(*ast.ImportSpec)を返します。これにより、警告メッセージで正確な位置情報(spec.Pos())を提供できるようになります。
    • 削除されたパッケージの警告ロジック:
      if rename.new == "" {
          warn(spec.Pos(), "package %q has been deleted in Go 1", rename.old)
          continue
      }
      
      go1PackageRenamesnewフィールドが空文字列に設定されている場合、そのパッケージはGo 1で削除されたと見なされます。go fixは、そのインポートが存在するコード行に対して、「package %q has been deleted in Go 1」という警告を出力します。continueにより、このインポートに対するさらなる処理(リネームなど)はスキップされます。
    • expパッケージの警告ロジック:
      if strings.HasPrefix(rename.new, "exp/") {
          warn(spec.Pos(), "package %q is not part of Go 1", rename.new)
      }
      
      go1PackageRenamesnewフィールドがexp/で始まる場合、そのパッケージはGo 1の標準ライブラリの一部ではないと見なされます。go fixは、そのインポートが存在するコード行に対して、「package %q is not part of Go 1」という警告を出力します。この警告は、パッケージがリネームされた後(rewriteImportが実行された後)に表示されるため、開発者は新しいexp/パスを使用しているにもかかわらず、それが実験的なパッケージであることを認識できます。

go1pkgrename_test.goの変更点

テストファイルには、ebnfold/regexpのインポートを含む新しいテストケースが追加されました。これにより、go fixがこれらの非推奨パッケージを正しく検出し、警告を生成するかどうかを確認できます。テストの期待される出力には、これらのパッケージがそれぞれexp/ebnfold/regexpにリネームされることが含まれていますが、同時に警告も発生することが暗黙的にテストされます。

ドキュメントファイルの変更点

doc/go1.htmldoc/go1.tmplから、go fixが削除されたパッケージやexpパッケージについて警告すべきであるというTODOコメントが削除されました。これは、このコミットによってこれらの機能が実装され、TODOが完了したことを示しています。

これらの変更により、go fixはGo 1への移行プロセスにおいて、開発者にとってより強力で役立つツールとなりました。

関連リンク

参考にした情報源リンク