Search code examples
gobazelgazelle

`go mod tidy` complains that the bazel-generated protobuf package is missing


I have a .proto protobuf definition file in a dir and I'm building a go library from it with Bazel like so (BUILD.bazel file below generated using gazelle):

load("@rules_proto//proto:defs.bzl", "proto_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")

proto_library(
    name = "events_proto",
    srcs = ["events.proto"],
    visibility = ["//visibility:public"],
    deps = ["@com_google_protobuf//:timestamp_proto"],
)

go_proto_library(
    name = "proto_go_proto",
    importpath = "github.com/acme/icoyote/proto",
    proto = ":events_proto",
    visibility = ["//visibility:public"],
)

go_library(
    name = "proto",
    embed = [":proto_go_proto"],
    importpath = "github.com/acme/icoyote/proto",
    visibility = ["//visibility:public"],
)

Some other code depends on //icoyote/proto:proto, and when I run go mod tidy in my module, it complains that it can't find the package github.com/acme/icoyote/proto:

go: finding module for package github.com/acme/icoyote/proto
github.com/acme/icoyote/cmd/icoyote imports
        github.com/acme/icoyote/proto: no matching versions for query "latest"

Any IDE that doesn't have Bazel integration (e.g. VSCode, GoLand/IntelliJ without the Bazel plugin) complains as well

What do I do?


Solution

  • This is happening of course because because Bazel does generate .go files using protoc under the covers for the go_proto_library rule in the BUILD file, but only writes them out to a temp dir under bazel-bin to be used by the go_library rule, and go mod tidy doesn't seem look into bazel-bin (probably because it's a symlink but also if it did, the path of those files relative to the location of go.mod is all wrong)

    One option is to manually generate the go files by calling protoc on your own, and remove the proto_library and go_proto_library rules in the BUILD file, then change the go_library rule to build your generated files. This is suboptimal because you have to manually rerun protoc every time you make changes to the .proto file (and if you put it into a //go:generate directive, you have to rerun go generate).

    Instead, we can do the following:

    1. Add a file empty.go to the dir that contains the .proto file. It should look like this:
    package proto
    
    1. Then tell gazelle to ignore empty.go (so it doesn't try to add a go_library rule to the BUILD file when you run gazelle --fix). We do that by adding the following to the BUILD file:
    # gazelle:exclude empty.go
    

    That's enough to make go mod tidy shut up.

    This will also make the IDE stop complaining about the import, although you'll still get errors when referring to anything that's supposed to be in that package. If you don't want to abandon your IDE for an excellent GoLand or IntelliJ IDEA with a Bazel plugin, you might have to resort to the manual protoc method. Perhaps there's a way to create a symlink to wherever Bazel writes out the generated .go files under bazel-bin and force go mod tidy to follow it, but I haven't tried that. If you do and it works, do share!