The Go Blog
Go 1.16 での新しいモジュール変更点
Go 1.16 を楽しんでいただけていることを願っています!このリリースには、特にモジュールに関して多くの新機能があります。リリースノートではこれらの変更点を簡単に説明していますが、いくつか深く掘り下げてみましょう。
デフォルトでモジュールが有効に
go コマンドは、go.mod が存在しない場合でも、デフォルトでモジュール対応モードでパッケージをビルドするようになりました。これは、すべてのプロジェクトでモジュールを使用するための大きな一歩です。
GO111MODULE 環境変数を off に設定することで、GOPATH モードでパッケージをビルドすることも可能です。また、GO111MODULE を auto に設定すると、現在のディレクトリまたは親ディレクトリに go.mod ファイルが存在する場合にのみモジュール対応モードを有効にできます。これは以前のデフォルトでした。GO111MODULE やその他の変数を go env -w で永続的に設定できることに注意してください。
go env -w GO111MODULE=auto
Go 1.17 では GOPATH モードのサポートを廃止する予定です。つまり、Go 1.17 は GO111MODULE を無視します。モジュール対応モードでビルドできないプロジェクトがある場合は、今が移行する時です。移行を妨げる問題がある場合は、issue または 体験レポート を提出することを検討してください。
go.mod と go.sum の自動変更なし
以前は、go コマンドが go.mod や go.sum に問題 (require ディレクティブの欠落や checksum の欠落など) を見つけると、自動的に問題を修正しようとしました。この動作が、特に副作用を通常持たない go list のようなコマンドにとって驚くべきものであるという多くのフィードバックを受けました。自動修正は常に望ましいものではありませんでした。インポートされたパッケージがいずれの必須モジュールでも提供されていない場合、go コマンドは新しい依存関係を追加し、共通の依存関係のアップグレードを引き起こす可能性がありました。スペルミスのあるインポートパスでさえ、(失敗した) ネットワーク検索につながりました。
Go 1.16 では、モジュール対応コマンドは、go.mod または go.sum に問題を発見した後、自動的に問題を修正しようとせずにエラーを報告します。ほとんどの場合、エラーメッセージは問題を修正するためのコマンドを推奨します。
$ go build
example.go:3:8: no required module provides package golang.org/x/net/html; to add it:
go get golang.org/x/net/html
$ go get golang.org/x/net/html
$ go build
以前と同様に、go コマンドは vendor ディレクトリが存在する場合にそれを使用できます (詳細はベンダーリングを参照)。go get や go mod tidy のようなコマンドは、主な目的が依存関係の管理であるため、引き続き go.mod および go.sum を変更します。
特定のバージョンの実行可能ファイルのインストール
go install コマンドは、@version サフィックスを指定することで、特定のバージョンの実行可能ファイルをインストールできるようになりました。
go install golang.org/x/tools/gopls@v0.6.5
この構文を使用する場合、go install は現在のディレクトリおよび親ディレクトリにある go.mod ファイルを無視して、その正確なモジュールバージョンからコマンドをインストールします。(@version サフィックスがない場合、go install は常にそうであったように動作し続け、現在のモジュールの go.mod に記載されているバージョン要件と置換を使用してプログラムをビルドします)。
以前は実行可能ファイルをインストールするために go get -u program を推奨していましたが、この使用法は go.mod でモジュールバージョンの要件を追加または変更するための go get の意味との混乱が多すぎました。そして、誤って go.mod を変更するのを避けるために、人々は次のようなより複雑なコマンドを提案し始めました。
cd $HOME; GO111MODULE=on go get program@latest
今では、代わりに go install program@latest を使用できます。詳細については、go install を参照してください。
どのバージョンが使用されるかについての曖昧さを排除するために、このインストール構文を使用する際には、プログラムの go.mod ファイルに存在できるディレクティブにはいくつかの制限があります。特に、replace および exclude ディレクティブは、少なくとも現時点では許可されていません。長期的には、新しい go install program@version が十分なユースケースでうまく機能するようになったら、go get がコマンドバイナリのインストールを停止するようにする予定です。詳細については、issue 43684 を参照してください。
モジュールの撤回
準備ができていないうちに誤ってモジュールバージョンを公開してしまったことはありませんか?または、バージョン公開直後にすぐに修正が必要な問題を発見したことはありませんか?公開されたバージョンの間違いを修正するのは困難です。モジュールのビルドを確定的に保つために、バージョンは公開後に変更することはできません。たとえバージョンタグを削除したり変更したりしても、proxy.golang.org や他のプロキシは元のバージョンをすでにキャッシュしている可能性が高いです。
モジュールの作者は、go.mod の retract ディレクティブを使用してモジュールバージョンを撤回できるようになりました。撤回されたバージョンは依然として存在し、ダウンロードできます (そのため、それに依存するビルドは壊れません) が、go コマンドは @latest のようなバージョンを解決する際にそれを自動的に選択しません。go get および go list -m -u は、既存の使用法について警告を表示します。
たとえば、人気のあるライブラリ example.com/lib の作者が v1.0.5 をリリースし、新しいセキュリティ問題を発見したとします。彼らは、以下のようなディレクティブを go.mod ファイルに追加できます。
// Remote-triggered crash in package foo. See CVE-2021-01234.
retract v1.0.5
次に、作者はバージョン v1.0.6 をタグ付けしてプッシュできます。これは新しい最高のバージョンです。その後、すでに v1.0.5 に依存しているユーザーは、更新をチェックしたり、依存パッケージをアップグレードしたりする際に、撤回通知を受け取ります。通知メッセージには、retract ディレクティブの上のコメントからのテキストが含まれる場合があります。
$ go list -m -u all
example.com/lib v1.0.0 (retracted)
$ go get .
go: warning: example.com/lib@v1.0.5: retracted by module author:
Remote-triggered crash in package foo. See CVE-2021-01234.
go: to switch to the latest unretracted version, run:
go get example.com/lib@latest
インタラクティブなブラウザベースのガイドについては、play-with-go.dev のモジュールバージョンの撤回をご覧ください。構文の詳細については、retract ディレクティブのドキュメントを参照してください。
GOVCS によるバージョン管理ツールの制御
go コマンドは、proxy.golang.org のようなミラーから、または git、hg、svn、bzr、fossil を使用してバージョン管理リポジトリから直接、モジュールソースコードをダウンロードできます。直接バージョン管理アクセスは重要であり、特にプロキシで利用できないプライベートモジュールの場合に重要ですが、潜在的なセキュリティ問題でもあります。バージョン管理ツールのバグが、悪意のあるサーバーによって意図しないコードの実行に悪用される可能性があります。
Go 1.16 では、新しい構成変数 GOVCS が導入され、ユーザーが特定のバージョン管理ツールを使用できるモジュールを指定できるようになりました。GOVCS は、pattern:vcslist ルールのコンマ区切りリストを受け入れます。pattern は、モジュールパスの1つ以上の先頭要素に一致する path.Match パターンです。特殊なパターン public と private は、パブリックモジュールとプライベートモジュールに一致します (private は GOPRIVATE のパターンに一致するモジュールとして定義され、public はそれ以外のすべてです)。vcslist は、許可されるバージョン管理コマンドのパイプ区切りリスト、またはキーワード all もしくは off です。
例
GOVCS=github.com:git,evil.com:off,*:git|hg
この設定により、github.com 上のパスを持つモジュールは git を使用してダウンロードでき、evil.com 上のパスはどのバージョン管理コマンドも使用してダウンロードできず、他のすべてのパス (* はすべてに一致) は git または hg を使用してダウンロードできます。
GOVCS が設定されていない場合、またはモジュールがいずれのパターンにも一致しない場合、go コマンドは次のデフォルトを使用します: パブリックモジュールには git と hg が許可され、プライベートモジュールにはすべてのツールが許可されます。Git と Mercurial のみを許可する理由の背景には、これら2つのシステムが、信頼できないサーバーのクライアントとして実行されることの問題に最も注意を払ってきたということがあります。対照的に、Bazaar、Fossil、Subversion は主に信頼できる認証された環境で使用されており、攻撃対象領域としての精査が十分ではありません。つまり、デフォルト設定は次のとおりです。
GOVCS=public:git|hg,private:all
詳細については、GOVCS によるバージョン管理ツールの制御を参照してください。
次は何ですか?
これらの機能がお役に立つことを願っています。Go 1.17 の次のモジュール機能、特にモジュールのロードプロセスを高速かつ安定させるはずの遅延モジュールロードにすでに取り組んでいます。いつものように、新しいバグに遭遇した場合は、issue tracker でお知らせください。Happy coding!
次の記事: コンテキストと構造体
前の記事: Go 1.16 がリリースされました
ブログインデックス