blob: a42f375887f8f8a05ec9a6b19a02b4d2a2f1b449 [file] [log] [blame]
"""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,
),
},
)