protoc-gen-multi

command module
v0.0.0-...-e3f8a3d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2024 License: Apache-2.0 Imports: 11 Imported by: 0

README

protoc-gen-multi

Combine multiple protoc plugin invocations into one with protoc-gen-multi.

Custom multi-plugin for Generated SDKs

Some plugins depend on generated code from other plugins. A common example is protoc-gen-go-grpc and protoc-gen-go. The gRPC code will reference types (messages, enums, etc.) generated by the base plugin.

In this scenario the gRPC generated code assumes the types will be available in the same package. There are limitations when generating code to the same package, however, it's beyond the scope of this document to go into detail.

Due to these limitations, Generated SDKs from the BSR are split in to separate packages and treated as individual modules. This is done by the BSR automatically when generating code for plugins that depend on other plugins.

However, there are some plugins that produce code that cannot be generated to a different package. One such example is the protoc-gen-go-vtproto plugin, which generates optimized marshaling/unmarshaling Go code alongside the base types.

So, what do you do if you want to use Generated SDKs from the BSR, but also want to use a plugin that cannot be generated to a different package?

The answer is to use a custom plugin that wraps the base plugin and any other plugin(s) that cannot be generated to a different package. This custom plugin will output code to the same package and utilize Generated SDKs from the BSR.

In this example, we’ll demonstrate how to package the following plugins into the same Docker image:

  • protoc-gen-go-grpc
  • protoc-gen-go
  • protoc-gen-go-vtproto
  • protoc-gen-grpc-gateway
Step 1 - Create an organization to push custom plugin(s)

For this example let’s use https://buf.example.com/custom-plugins

Step 2 - Build a Docker image

Create a docker image with all the protoc plugins desired, plus protoc-gen-multi:

# syntax=docker/dockerfile:1.6
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS build
ARG TARGETOS TARGETARCH

ENV CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH 

# Install protoc-gen-multi, must be installed.
RUN go install -ldflags "-s -w" github.com/bufbuild/tools/cmd/protoc-gen-multi@latest

# Add custom plugins here
RUN go install -ldflags "-s -w" google.golang.org/protobuf/cmd/protoc-gen-go@v1.32 \
    && go install -ldflags "-s -w" google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3 \
    && go install -ldflags "-s -w" github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto@v0.6.0 \
    && go install -ldflags "-s -w" github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.19

# Move binaries prefixed with GOOS_GOARCH to /go/bin.
RUN mv /go/bin/${TARGETOS}_${TARGETARCH}/* /go/bin || true

# Build final image.
FROM scratch
COPY --from=build --link /etc/passwd /etc/passwd
COPY --from=build /go/bin/ /bin
USER nobody
ENTRYPOINT [ "protoc-gen-multi" ]

Build the image with a tag referencing the organization and plugin name:

docker buildx build --platform linux/amd64 -t buf.example.com/custom-plugins/multi:v0.1.0 .
Step 3 - Create a buf.plugin.yaml file

At the very minimum you’ll need the following fields set:

version: v1
name: buf.example.com/custom-plugins/multi
plugin_version: v0.1.0
output_languages:
  - go
registry:
  # Add the runtime deps required by your plugins for the generated SDK.
  go:
    deps:
      - module: google.golang.org/protobuf
        version: v1.32.0
      - module: google.golang.org/grpc
        version: v1.3.0
      - module: github.com/planetscale/vtprotobuf
        version: v0.6.0
      - module: github.com/grpc-ecosystem/grpc-gateway/v2
        version: v2.19
  # Add the options to invoke each plugin for the generated SDK.
  opts:
    - --go_out=.
    - --go_opt=paths=source_relative
    - --go-grpc_out=.
    - --go-grpc_opt=paths=source_relative
    - --go-vtproto_out=.
    - --go-vtproto_opt=paths=source_relative,features=marshal+unmarshal+size
    - --grpc-gateway_out=.
    - --grpc-gateway_opt=paths=source_relative,generate_unbound_methods=true

Note that typically a buf.plugin.yaml file defines a single plugin. However, in this case, we have three different plugins with different versions. So the version specified here should be whatever makes sense for your setup.

There are additional fields that can be set. Please refer to the buf.plugin.yaml file documentation for more information. Link to the documentation

Step 4 - Push plugin to the BSR
buf beta registry plugin push \
    --visibility public \
    --image buf.example.com/custom-plugins/multi:v0.1.0 \
    --override-remote=buf.example.com

Now, when you install a Generated SDK from the BSR, e.g.

go get buf.example.com/gen/go/acme/petapis/custom-plugins/multi@latest

The BSR will generate a single package containing the output of all three plugins. It will not attempt to build plugin dependencies. This replicates the behavior of manually generating these plugins into the same output directory.

Documentation

The Go Gopher

There is no documentation for this package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL