ワークスペースに慣れよう

Get familiar with workspaces by Beth Brown, for the Go team

Go 1.18ではワークスペースモードが追加され、複数のモジュールを同時に扱いながら作業できるようになりました。

Go 1.18はダウンロードページから入手できます。すべての変更点の詳細は リリースノートを参照してください。

ワークスペース

Go 1.18のワークスペースを使うと、モジュールごとに go.mod ファイルを編集することなく、複数のモジュールを同時に扱いながら作業できます。ワークスペース内の各モジュールは、 依存関係を解決する際にメインモジュールとして扱われます。

これまでは、あるモジュールに機能を追加して別のモジュールで使うには、最初のモジュールへの変更を公開するか、 あるいは依存先モジュールの go.mod ファイルを編集して、 ローカルの未公開のモジュール変更に対する replace ディレクティブを追加する必要がありました。エラーなく 公開するためには、最初のモジュールへのローカルの変更を公開した後に、依存先モジュールの go.mod ファイルから replace ディレクティブを削除しなければなりませんでした。

Goワークスペースを使うと、ワークスペースディレクトリのルートにある go.work ファイルによって、 すべての依存関係を制御できます。 go.work ファイルには、個々の go.mod ファイルを上書きする use ディレクティブと replace ディレクティブがあるため、 go.mod ファイルをそれぞれ個別に編集する必要はありません。

ワークスペースを作成するには、モジュールのディレクトリのリストをスペース区切りの引数として go work init を実行します。ワークスペース自体がその作業対象のモジュールを含んでいる必要はありません。 init コマンドは、 ワークスペース内のモジュールを列挙した go.work ファイルを作成します。引数なしで go work init を実行すると、 空のワークスペースが作成されます。

ワークスペースにモジュールを追加するには、 go work use [moddir] を実行するか、 go.work ファイルを 手動で編集します。 go work use -r . を実行すると、引数に指定したディレクトリ配下で go.mod ファイルを持つ ディレクトリを再帰的にワークスペースへ追加します。あるディレクトリに go.mod ファイルがない場合、あるいは そのディレクトリがすでに存在しない場合は、そのディレクトリに対する use ディレクティブが go.work ファイルから 削除されます。

go.work ファイルの構文は go.mod ファイルと似ており、次のディレクティブを含みます。

  • go:goツールチェインのバージョン(例えば go 1.18
  • use:ディスク上のモジュールをワークスペース内のメインモジュール群に追加します。引数には、そのモジュールの go.mod ファイルを含むディレクトリへの相対パスを指定します。 use ディレクティブは、指定したディレクトリの サブディレクトリにあるモジュールは追加しません。
  • replacego.mod ファイルの replace ディレクティブと同様に、 go.work ファイルの replace ディレクティブは、あるモジュールの特定のバージョン、またはすべてのバージョンの内容を、別の場所にある内容で 置き換えます。

ワークフロー

ワークスペースは柔軟で、さまざまなワークフローに対応しています。以下の節では、私たちが最もよく使われると 考えているワークフローの概要を簡単に紹介します。

上流モジュールに機能を追加し、自分のモジュールで利用する

  1. ワークスペース用のディレクトリを作成します。

  2. 編集したい上流モジュールをクローンします。

  3. 上流モジュールのローカルバージョンに、自分の機能を追加します。

  4. ワークスペースフォルダで go work init [path-to-upstream-mod-dir] を実行します。

  5. 上流モジュールに追加した機能を実装するために、自分のモジュールに変更を加えます。

  6. ワークスペースフォルダで go work use [path-to-your-module] を実行します。

    go work use コマンドは、自分のモジュールへのパスを go.work ファイルに追加します。

    go 1.18
    
    use (
           ./path-to-upstream-mod-dir
           ./path-to-your-module
    )
    
  7. 上流モジュールに追加された新機能を使って、自分のモジュールを実行しテストします。

  8. 新機能を加えた上流モジュールを公開します。

  9. その新機能を利用する自分のモジュールを公開します。

同一リポジトリ内にある相互依存する複数のモジュールを扱う

同一リポジトリ内の複数のモジュールで作業する場合、各モジュールの go.mod ファイルで replace ディレクティブを使う代わりに、 go.work ファイルでワークスペースを定義します。

  1. ワークスペース用のディレクトリを作成します。

  2. 編集したいモジュールを含むリポジトリをクローンします。 use ディレクティブで各モジュールへの相対パスを 指定するため、モジュールをワークスペースフォルダの中に置く必要はありません。

  3. ワークスペースディレクトリで go work init [path-to-module-one] [path-to-module-two] を実行します。

    例えば、 example.com/x/tools モジュール内の他のパッケージに依存する example.com/x/tools/groundhog を作業対象とします。

    リポジトリをクローンし、ワークスペースフォルダで go work init tools tools/groundhog を実行します。

    go.work ファイルの内容は次のようになります。

    go 1.18
    
    use (
            ./tools
            ./tools/groundhog
    )
    

    tools モジュールに加えたローカルの変更は、ワークスペース内の tools/groundhog から利用されます。

依存関係の設定を切り替える

異なる依存関係の設定でモジュールをテストするには、別々の go.work ファイルを持つ複数のワークスペースを 作成するか、あるいは1つのワークスペースを維持したまま、1つの go.work ファイル内で不要な use ディレクティブをコメントアウトするという方法があります。

複数のワークスペースを作成するには次のようにします。

  1. 依存関係のニーズごとに別々のディレクトリを作成します。
  2. 各ワークスペースディレクトリで go work init を実行します。
  3. go work use [path-to-dependency] を使って、各ディレクトリに必要な依存関係を追加します。
  4. 各ワークスペースディレクトリで go run [path-to-your-module] を実行すると、その go.work ファイルで指定された依存関係が使われます。

同一ワークスペース内で異なる依存関係を試すには、 go.work ファイルを開いて、必要な依存関係を追加したり、 不要なものをコメントアウトしたりします。

GOPATHを使っている場合

ワークスペースを使うことで、考えが変わるかもしれません。 GOPATH を使っているユーザーは、 GOPATH ディレクトリの基点に置いた go.work ファイルを使って依存関係を解決できます。ワークスペースは GOPATH のすべてのワークフローを完全に再現することを目指しているわけではありませんが、モジュールの利点を保ちながら、 GOPATH の利便性の一部を共有するセットアップを作れます。

GOPATH用のワークスペースを作成するには次のようにします。

  1. GOPATH ディレクトリのルートで go work init を実行します。
  2. ローカルモジュールや特定のバージョンをワークスペース内の依存関係として使うには、 go work use [path-to-module] を実行します。
  3. モジュールの go.mod ファイル内の既存の依存関係を置き換えるには、 go work replace [path-to-module] を使います。
  4. GOPATH 内、あるいは任意のディレクトリにあるすべてのモジュールを追加するには、 go work use -r を実行します。これにより、 go.mod ファイルを持つディレクトリが再帰的にワークスペースへ追加されます。 あるディレクトリに go.mod ファイルがない場合、あるいはそのディレクトリがすでに存在しない場合は、 そのディレクトリに対する use ディレクティブが go.work ファイルから削除されます。

go.mod ファイルを持たないプロジェクトをワークスペースに追加したい場合は、そのプロジェクトディレクトリに 移動して go mod init を実行し、その後 go work use [path-to-module] で新しいモジュールをワークスペースに 追加してください。

ワークスペースのコマンド

go work initgo work use に加えて、Go 1.18ではワークスペース向けに次のコマンドが導入されました。

  • go work syncgo.work ファイル内の依存関係を、ワークスペース内の各モジュールの go.mod ファイルへ反映します。
  • go work editgo.work を編集するためのコマンドラインインターフェースを提供します。主にツールや スクリプトからの利用を想定しています。

モジュール対応のビルドコマンドや一部の go mod サブコマンドは、ワークスペースのコンテキスト内にあるかどうかを 判定するために、 GOWORK 環境変数を調べます。

GOWORK 変数が .work で終わるファイルへのパスを示している場合、ワークスペースモードが有効になります。 どの go.work ファイルが使われているかを確認するには、 go env GOWORK を実行します。 go コマンドが ワークスペースモードでない場合、出力は空になります。

ワークスペースモードが有効な場合、 go.work ファイルが解析され、ワークスペースモードの3つのパラメータ、 すなわちGoのバージョン、ディレクトリのリスト、置き換え(replacement)のリストが決定されます。

ワークスペースモードで試してみるとよいコマンドをいくつか挙げます(すでに何をするコマンドかご存知の前提です)。

go work init
go work sync
go work use
go list
go build
go test
go run
go vet

エディタ体験の改善

私たちが特に心待ちにしているのは、Goの言語サーバーである goplsVSCode Go拡張機能のアップグレードです。 これにより、LSP対応エディタで複数のモジュールを扱う作業が、スムーズでやりがいのある体験になります。

参照の検索、コード補完、定義へのジャンプは、ワークスペース内のモジュールをまたいで機能します。 goplsバージョン0.8.1では、 go.work ファイルに対する診断、補完、フォーマット、ホバー表示が導入されました。これらの gopls の機能は、任意の LSP対応エディタで利用できます。

エディタ固有の注意点

  • 最新のvscode-goリリースでは、Goステータス バーのクイックピックメニューから、ワークスペースの go.work ファイルにすばやくアクセスできます。

Goステータスバーのクイックピックメニューからgo.workファイルにアクセスする

  • GoLandはワークスペースをサポートしており、 go.work ファイルに対する シンタックスハイライトとコード補完を追加する計画があります。

さまざまなエディタで gopls を使う方法の詳細については、 goplsのドキュメントを参照してください。

次のステップ

By Beth Brown, for the Go team