Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"Bazel module definition for bzlmod"
module(
name = "rules_buf",
version = "0.0.0", # Replaced when publishing
compatibility_level = 1,
)

bazel_dep(name = "platforms", version = "0.0.4")
# Only needed because rules_proto doesn't provide the protoc toolchain yet.
# TODO: remove in the future
bazel_dep(name = "protobuf", version = "21.7", repo_name = "com_google_protobuf")
bazel_dep(name = "rules_proto", version = "5.3.0-21.7")

# We depend on gazelle at runtime to generate our proto_library rules
bazel_dep(name = "gazelle", version = "0.33.0")

# ... and then reach inside to get the gazelle binary from this repository
non_module_deps = use_extension("@gazelle//internal/bzlmod:non_module_deps.bzl", "non_module_deps")
use_repo(non_module_deps, "bazel_gazelle_go_repository_tools")

ext = use_extension("//buf:extensions.bzl", "buf")
use_repo(ext, "rules_buf_toolchains")
register_toolchains("@rules_buf_toolchains//:all")
78 changes: 78 additions & 0 deletions buf/extensions.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""Define module extensions for using rules_buf with bzlmod.
See https://bazel.build/docs/bzlmod#extension-definition
"""

load("//buf/internal:toolchain.bzl", "buf_download_releases")
load("//buf/internal:repo.bzl", "buf_dependencies")

# NB: this should be updated periodically
_DEFAULT_VERSION = "v1.27.0"
_DEFAULT_TOOLCHAIN_NAME = "rules_buf_toolchains"
_DEFAULT_DEPS = "buf_deps"

dependency = tag_class(attrs = {
"name": attr.string(doc = "name of resulting deps repo", default = _DEFAULT_DEPS),
"module": attr.string(doc = "A module name from the Buf Schema Registry, see https://buf.build/docs/bsr/module/manage"),
})

toolchains = tag_class(attrs = {
"name": attr.string(doc = "name of resulting buf toolchains repo", default = _DEFAULT_TOOLCHAIN_NAME),
"version": attr.string(doc = "Version of the buf tool, see https://github.com/bufbuild/buf/releases"),
})

def _extension_impl(module_ctx):
registrations = {}
dependencies = {}

# Iterate over the global modules registered either directly by the user
# or transitively by some other bazel module they use.
for mod in module_ctx.modules:

# collect all buf.dependency tags, group by name of resulting buf_dependencies repo
for dependency in mod.tags.dependency:
if dependency.name not in dependencies.keys():
dependencies[dependency.name] = []
dependencies[dependency.name].append(dependency.module)

# collect all toolchain versions, group by name of toolchain repo
for toolchains in mod.tags.toolchains:
if toolchains.name != _DEFAULT_TOOLCHAIN_NAME and not mod.is_root:
fail("""\
Only the root module may override the default name for the buf toolchains.
This prevents conflicting registrations in the global namespace of external repos.
""")
if toolchains.name not in registrations.keys():
registrations[toolchains.name] = []
registrations[toolchains.name].append(toolchains.version)

# Don't require that the user manually registers a toolchain
if len(registrations) == 0:
Comment thread
alexeagle marked this conversation as resolved.
registrations = {_DEFAULT_TOOLCHAIN_NAME: [_DEFAULT_VERSION]}

for name, versions in registrations.items():
if len(versions) > 1:
# TODO: should be semver-aware, using MVS
selected = sorted(versions, reverse = True)[0]

# buildifier: disable=print
print("NOTE: buf toolchains {} has multiple versions {}, selected {}".format(name, versions, selected))
Comment thread
alexeagle marked this conversation as resolved.
else:
selected = versions[0]
buf_download_releases(
name = name,
version = selected,
)

for name, modules in dependencies.items():
buf_dependencies(
name = name,
modules = modules,
)

buf = module_extension(
implementation = _extension_impl,
tag_classes = {
"dependency": dependency,
"toolchains": toolchains,
},
)
6 changes: 3 additions & 3 deletions buf/internal/toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def declare_buf_toolchains(os, cpu, rules_buf_repo_name):
native.toolchain(
name = cmd + "_toolchain",
toolchain = ":" + toolchain_impl,
toolchain_type = "@{}//tools/{}:toolchain_type".format(rules_buf_repo_name, cmd),
toolchain_type = "@@{}//tools/{}:toolchain_type".format(rules_buf_repo_name, cmd),
exec_compatible_with = [
"@platforms//os:" + os,
"@platforms//cpu:" + cpu,
Expand Down Expand Up @@ -202,7 +202,7 @@ def _buf_download_releases_impl(ctx):
)
return update_attrs(ctx.attr, ["version", "sha256"], {"version": version, "sha256": sha256})

_buf_download_releases = repository_rule(
buf_download_releases = repository_rule(
implementation = _buf_download_releases_impl,
attrs = {
"version": attr.string(
Expand All @@ -229,7 +229,7 @@ def rules_buf_toolchains(name = _TOOLCHAINS_REPO, version = None, sha256 = None,
repository_url: The repository url base used for downloads. Defaults to "https://github.com/bufbuild/buf/releases/download"
"""

_buf_download_releases(name = name, version = version, sha256 = sha256, repository_url = repository_url)
buf_download_releases(name = name, version = version, sha256 = sha256, repository_url = repository_url)

_register_toolchains(name, "buf")
_register_toolchains(name, "protoc-gen-buf-breaking")
Expand Down
1 change: 1 addition & 0 deletions examples/bzlmod/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
common --enable_bzlmod
25 changes: 25 additions & 0 deletions examples/bzlmod/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
load("@rules_buf//buf:defs.bzl", "buf_lint_test")
load("@rules_proto//proto:defs.bzl", "proto_library")

exports_files(["buf.yaml"], visibility = ["//visibility:public"])

proto_library(
name = "unused",
srcs = ["unused.proto"],
)

proto_library(
name = "foo_proto",
srcs = ["file.proto"],
deps = [
# imports "validate/validate.proto"
"@buf_deps//validate:validate_proto",
":unused",
],
)

buf_lint_test(
name = "foo_proto_lint",
targets = [":foo_proto"],
config = "buf.yaml",
)
19 changes: 19 additions & 0 deletions examples/bzlmod/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"Bazel dependencies"
bazel_dep(name = "rules_buf", dev_dependency = True, version = "0.0.0")

local_path_override(
module_name = "rules_buf",
path = "../..",
)

buf = use_extension("@rules_buf//buf:extensions.bzl", "buf")

# Override the default version of buf
buf.toolchains(version = "v1.26.0")

# See https://buf.build/docs/build-systems/bazel#buf-dependencies
buf.dependency(module = "buf.build/envoyproxy/protoc-gen-validate:eac44469a7af47e7839a7f1f3d7ac004")
buf.dependency(module = "buf.build/acme/petapis:7abdb7802c8f4737a1a23a35ca8266ef")

# Allow references to labels under @buf_deps
use_repo(buf, "buf_deps")
1 change: 1 addition & 0 deletions examples/bzlmod/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Marker that this folder is the root of a Bazel workspace
4 changes: 4 additions & 0 deletions examples/bzlmod/buf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
version: v1
lint:
use:
- IMPORT_USED
4 changes: 4 additions & 0 deletions examples/bzlmod/file.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
syntax = "proto3";

import "unused.proto";
import "validate/validate.proto";
1 change: 1 addition & 0 deletions examples/bzlmod/unused.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
syntax = "proto3";