Go の workspace を使ってみる

Go の workspace の備忘録。以下は公式チュートリアル

Tutorial: Getting started with multi-module workspaces

環境

  • go 1.19.2

workspace とは

workspace とは、複数の go module を同一ディスク上で管理できる仕組みです。

A workspace is a collection of modules on disk that are used as the main modules when running minimal version selection (MVS).

A workspace can be declared in a go.work file that specifies relative paths to the module directories of each of the modules in the workspace. When no go.work file exists, the workspace consists of the single module containing the current directory.

Most go subcommands that work with modules operate on the set of modules determined by the current workspace. go mod init, go mod why, go mod edit, go mod tidy, go mod vendor, and go get always operate on a single main module.

Go Modules Reference - Workspaces

minimal version selection(MVS) とは、Go のパッケージマネージャーである go module がパッケージの依存関係を解決するアルゴリズムのこと。Go のデフォルトでは、依存関係を満たす最少のバージョンを見つけてくる、らしいです。

Minimal Version Selection (Go & Versioning, Part 4)

ファイル構造

モノレポ環境にて、1つのリポジトリ内に複数の Go modules が管理されているとします。

.
├── go
│   ├── aaa      # module sample.com/sample/aaa
│   │   ├── cmd
│   │   │   └── main.go
│   │   ├── go.mod
│   │   └── go.sum
│   └── bbb      # module sample.com/sample/bbb
│       ├── cmd
│       │   └── main.go
│       └── go.mod
└── go.work      # これが workspace の管理ファイル

workspace を利用しない場合に困る点として、IDE のプロジェクトフォルダとしてリポジトリのルートフォルダを指定すると、gopls が go.mod ファイルを見つけることができず、言語サーバーの機能が正しく動いてくれないことです。workspace を使えば解決します。

手順

初期化

リポジトリのルートフォルダで実行。

$ go work init

go.work ファイルが作成されます。

モジュールの追加

workspace で管理したい go モジュールを追加します。go.mod ファイルのあるパスを指定。

$ go work use ./go/aaa
$ go work use ./go/bbb

go.work ファイル内に記述されます。

$ cat go.work
go 1.19

use (
        ./go/aaa
        ./go/bbb
)

コードを実行してみる

go.work ファイルのあるパスより、各モジュールに対して go コマンドを実行できます。

$ go build -o aaa ./go/aaa/cmd/main.go
$ ls
aaa  go  go.work
$
$ go run go/aaa/cmd/main.go

その他設定の編集

go work edit コマンドで、go mod コマンドと同じようにコンフィグ編集ができる、とのこと。

go work edit edits the go.work file similarly to go mod edit

go.workreplace ディレクティブで設定された内容は、workspace で管理されている go.mod を上書きするとのこと。

Similar to a replace directive in a go.mod file, a replace directive in a go.work file replaces the contents of a specific version of a module, or all versions of a module, with contents found elsewhere. A wildcard replace in go.work overrides a version-specific replace in a go.mod file.

replace directives in go.work files override any replaces of the same module or module version in workspace modules.

Go Modules Reference - Workspace replace

例えば、.go/util/example に新しくモジュールを作成し、その配下にパッケージを用意しておきます。

.
├── go
│   ├── aaa
│   │   ├── ...
│   │   └── go.sum
│   ├── bbb
│   │   ├── ...
│   │   └── go.mod
│   └── util                # あたらしく作る
│       └── example         # あたらしく作る
│           ├── ...         # パッケージにあたるコードを用意
│           └── go.mod      # あたらしく作る
└── go.work

モジュール golang.org/x/example の代わりにローカル上のモジュールを利用するよう、編集コマンドを実行。

$ go work edit -replace golang.org/x/example=./go/util/example
$ cat go.work
...

replace golang.org/x/example => ./go/util/example

この時、workspace で管理されるモジュール内で golang.org/x/example を指定したものがある場合、./go/util/example を利用するように上書きされます。


コマンドリファレンス。

cmd go - workspace