emahiro/b.log

日々の勉強の記録とか育児の記録とか。

protoc のプラグインを go tool で管理・実行する

Overview

buf.gen.yaml で local の protoc コマンドを hook して実行するときに go tool 経由で実行すると個人の環境差異にとらわれずに実行できて便利、という話です。

Motivation

proto からコードを生成するときに、今では buf generate を利用するのが一般的な選択肢ですが、 buf.gen.yaml で protoc のプラグイン(grpc や openapi) を利用するときに、各々の local 環境にこれからのプラグインがインストールされていて、かつバージョンが揃っていないと期待する生成結果を得られないことがあります。

事前に使うライブラリの種類やバージョンを指定して個々人の端末にインストールを行う make を作ることもできますが、結局実行し忘れたりで buf generate が正常に動作しないこともあります。

go tool で解決する

これを解決するために Go1.24 から導入された go tool を利用します。

詳細は以下ですがこれは Go プロジェクトにおける Module の管理の範囲を各種ツールにも広げた機能で、すでに一般的に使われるようになっているかと思います。

future-architect.github.io

結論から言ってしまうと、protoc に関連するツール郡(ほぼ Go 製)を tool としてプロジェクトの依存管理対象に設定し、 buf.gen.yaml の local での実行コマンドを go tool google.golang.org/protobuf/cmd/protoc-gen-go のように設定します。

例えば protoc において grpc, grpc-gateway, openapi を利用するときの go.modbuf.gen.yaml の plugin 設定は以下のようになります。

# go.mod
tool (
    github.com/bufbuild/buf/cmd/buf
    github.com/google/gnostic/cmd/protoc-gen-openapi
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
    google.golang.org/grpc/cmd/protoc-gen-go-grpc
    google.golang.org/protobuf/cmd/protoc-gen-go
)
# buf.gen.yaml
version: v2
clean: true
managed:
  enabled: true
  disable:
    - file_option: go_package_prefix
plugins:
  - local: [go, tool, google.golang.org/protobuf/cmd/protoc-gen-go]
    out: server/gen
    opt:
      - paths=import
  - local: [go, tool, google.golang.org/grpc/cmd/protoc-gen-go-grpc]
    out: server/gen
    opt:
      - paths=import
  - local: [go, tool, github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway]
    out: server/gen
    opt:
      - paths=import
  - local: [go, tool, github.com/google/gnostic/cmd/protoc-gen-openapi]
    out: openapi
    opt:
      - output_mode=source_relative

これで buf generate すると go tool .... 経由で各種プラグインのコマンドが実行されるので、仮にプラグインのコマンドがインストールされ知なくても go tool 経由でプロジェクト内でインストールされ go tool 経由で実行されます。さらにバージョンも go.mod で管理されるのでバージョン違いによる、出力の違い、ということにも頭を悩ませることはありません。

まとめ

Go のプロジェクト限定にはなりますが、go tool で protoc のプラグインを管理するのは有用だなと思いました。