| """Repository rule that relies on fetching a protoc binary from GitHub Releases. |
| |
| It exposes bin/protoc as a proto_toolchain. |
| """ |
| |
| load(":versions.bzl", "PROTOC_PLATFORMS", "PROTOC_VERSIONS") |
| |
| # TODO: we should read this dynamically by `ls *.proto` and then search for "import" statements |
| # inside the files. Currently this assumes the wkt srcs/deps are fixed over time. |
| GOOGLE_PROTOBUF_DEP_EDGES = { |
| "any": [], |
| "api": ["source_context", "type"], |
| "compiler/plugin": ["descriptor"], |
| "descriptor": [], |
| "duration": [], |
| "empty": [], |
| "field_mask": [], |
| "source_context": [], |
| "struct": [], |
| "timestamp": [], |
| "type": ["any", "source_context"], |
| "wrappers": [], |
| } |
| |
| def release_version_to_artifact_name(release_version, platform): |
| # versions have a "v" prefix like "v28.0" |
| stripped_version = release_version.removeprefix("v") |
| |
| # release candidate versions like "v29.0-rc3" have artifact names |
| # like "protoc-29.0-rc-3-osx-x86_64.zip" |
| artifact_version = stripped_version.replace("rc", "rc-") |
| |
| return "{}-{}-{}.zip".format( |
| "protoc", |
| artifact_version, |
| platform, |
| ) |
| |
| def _prebuilt_protoc_repo_impl(rctx): |
| release_version = rctx.attr.version |
| if release_version == "LATEST": |
| release_version = PROTOC_VERSIONS.keys()[0] |
| |
| filename = release_version_to_artifact_name( |
| release_version, |
| rctx.attr.platform, |
| ) |
| url = "https://github.com/protocolbuffers/protobuf/releases/download/{}/{}".format( |
| release_version, |
| filename, |
| ) |
| rctx.download_and_extract( |
| url = url, |
| integrity = PROTOC_VERSIONS[release_version][filename], |
| ) |
| build_content = """\ |
| # Generated by @rules_proto//proto/toolchains:prebuilt_protoc_toolchain.bzl |
| |
| # This is a workaround for proto_toolchain not allowing to set visibility. |
| package(default_visibility = ["//visibility:public"]) |
| |
| load("@rules_proto//proto:proto_toolchain.bzl", "proto_toolchain") |
| load("@rules_proto//proto:defs.bzl", "proto_library") |
| |
| proto_toolchain( |
| name = "prebuilt_protoc_toolchain", |
| proto_compiler = "{protoc_label}", |
| ) |
| """.format( |
| protoc_label = ":bin/protoc.exe" if rctx.attr.platform.startswith("win") else ":bin/protoc", |
| ) |
| |
| for src, deps in GOOGLE_PROTOBUF_DEP_EDGES.items(): |
| build_content += """\ |
| proto_library( |
| name = "{0}_proto", |
| srcs = ["include/google/protobuf/{0}.proto"], |
| deps = [":%s_proto" % dep for dep in {1}], |
| strip_import_prefix = "include", |
| ) |
| """.format(src, deps) |
| rctx.file("BUILD.bazel", build_content) |
| |
| prebuilt_protoc_repo = repository_rule( |
| doc = "Download a pre-built protoc and create a concrete toolchains for it", |
| implementation = _prebuilt_protoc_repo_impl, |
| attrs = { |
| "platform": attr.string( |
| doc = "A platform that protobuf ships a release for", |
| mandatory = True, |
| values = PROTOC_PLATFORMS.keys(), |
| ), |
| "version": attr.string( |
| doc = "Release tag from protocolbuffers/protobuf repo, e.g. 'v25.3'", |
| mandatory = True, |
| ), |
| }, |
| ) |