Goブログ

Go 1.16 での新しいモジュール変更

Jay Conrod
2021年2月18日

Go 1.16 を楽しんでいただければ幸いです!このリリースには、特にモジュールに関して多くの新機能があります。 リリースノートでこれらの変更について簡単に説明していますが、いくつか詳しく見ていきましょう。

モジュールがデフォルトで有効

go コマンドは、go.mod が存在しない場合でも、デフォルトでモジュール認識モードでパッケージをビルドするようになりました。これは、すべてのプロジェクトでモジュールを使用するための大きな一歩です。

GO111MODULE 環境変数を off に設定することで、GOPATH モードでパッケージをビルドすることも引き続き可能です。また、GO111MODULEauto に設定して、現在のディレクトリまたは親ディレクトリに 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 ディレクティブや不足している sum などの問題を発見した場合、自動的に問題を修正しようとしていました。特に通常は副作用のない 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 getgo mod tidy などのコマンドは、主な目的が依存関係を管理することであるため、go.modgo.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.modretract ディレクティブを使用してモジュールバージョンを取り消すことができるようになりました。取り消されたバージョンは引き続き存在し、ダウンロードできます (したがって、それに依存するビルドは壊れません) が、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 のようなミラーから、または githgsvnbzr、または fossil を使用してバージョン管理リポジトリから直接モジュールソースコードをダウンロードできます。特にプロキシで利用できないプライベートモジュールの場合、直接バージョン管理アクセスは重要ですが、セキュリティ上の問題になる可能性もあります。バージョン管理ツールのバグは、悪意のあるサーバーによって意図しないコードを実行するために悪用される可能性があります。

Go 1.16 では、新しい構成変数である GOVCS が導入されました。これにより、ユーザーは特定のバージョン管理ツールを使用できるモジュールを指定できます。GOVCS は、pattern:vcslist ルールのコンマ区切りリストを受け入れます。pattern は、モジュールパスの1つ以上の先頭要素に一致する path.Match パターンです。特別なパターン public および private は、パブリックおよびプライベートモジュールに一致します (privateGOPRIVATE のパターンに一致するモジュールとして定義され、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 でお知らせください。ハッピーコーディング!

次の記事:コンテキストと構造体
前の記事:Go 1.16 がリリースされました
ブログインデックス