diff --git a/.bcr/metadata.template.json b/.bcr/metadata.template.json index 003a961..61c988e 100644 --- a/.bcr/metadata.template.json +++ b/.bcr/metadata.template.json @@ -1,7 +1,7 @@ { - "homepage": "https://github.com/myorg/rules_mylang", + "homepage": "https://github.com/alexeagle/rules_protoc", "maintainers": [], - "repository": ["github:myorg/rules_mylang"], + "repository": ["github:alexeagle/rules_protoc"], "versions": [], "yanked_versions": {} } diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index cee54d6..0000000 --- a/.gitattributes +++ /dev/null @@ -1,13 +0,0 @@ -# In code review, collapse generated files -docs/*.md linguist-generated=true - -################################# -# Configuration for 'git archive' -# See https://git-scm.com/docs/git-archive#ATTRIBUTES - -# Don't include examples in the distribution artifact, to reduce size. -# You may want to add additional exclusions for folders or files that users don't need. -examples export-ignore - -# Occasionally there's a need to "stamp" the release version into a file -mylang/version.bzl export-subst diff --git a/.github/workflows/mirror_protoc_release.yml b/.github/workflows/mirror_protoc_release.yml new file mode 100644 index 0000000..18fba4c --- /dev/null +++ b/.github/workflows/mirror_protoc_release.yml @@ -0,0 +1,19 @@ +name: Mirror Releases +on: + # Trigger manually in the UI + workflow_dispatch: + # Trigger daily at 06:10 UTC + schedule: + - cron: "10 6 * * *" + +jobs: + mirror: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: | + ./protoc/private/mirror_protoc_releases.sh + npx @bazel/buildifier protoc/private/versions.bzl + - uses: peter-evans/create-pull-request@v5 + with: + commit-message: "chore: mirror protoc release" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5f479a7..7bc22bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,4 +12,4 @@ jobs: release: uses: bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v6 with: - release_files: rules_mylang-*.tar.gz + release_files: rules_protoc-*.tar.gz diff --git a/.github/workflows/release_prep.sh b/.github/workflows/release_prep.sh index cf07386..95aafbb 100755 --- a/.github/workflows/release_prep.sh +++ b/.github/workflows/release_prep.sh @@ -8,8 +8,8 @@ TAG=${GITHUB_REF_NAME} # The prefix is chosen to match what GitHub generates for source archives # This guarantees that users can easily switch from a released artifact to a source archive # with minimal differences in their code (e.g. strip_prefix remains the same) -PREFIX="rules_mylang-${TAG:1}" -ARCHIVE="rules_mylang-$TAG.tar.gz" +PREFIX="rules_protoc-${TAG:1}" +ARCHIVE="rules_protoc-$TAG.tar.gz" # NB: configuration for 'git archive' is in /.gitattributes git archive --format=tar --prefix=${PREFIX}/ ${TAG} | gzip > $ARCHIVE @@ -22,7 +22,7 @@ cat << EOF 2. Add to your \`MODULE.bazel\` file: \`\`\`starlark -bazel_dep(name = "com_myorg_rules_mylang", version = "${TAG:1}") +bazel_dep(name = "toolchains_protoc", version = "${TAG:1}") \`\`\` ## Using WORKSPACE @@ -32,10 +32,10 @@ Paste this snippet into your \`WORKSPACE.bazel\` file: \`\`\`starlark load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( - name = "com_myorg_rules_mylang", + name = "toolchains_protoc", sha256 = "${SHA}", strip_prefix = "${PREFIX}", - url = "https://github.com/myorg/rules_mylang/releases/download/${TAG}/${ARCHIVE}", + url = "https://github.com/alexeagle/rules_protoc/releases/download/${TAG}/${ARCHIVE}", ) EOF diff --git a/.gitignore b/.gitignore index 52646d3..630e0fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ bazel-* .bazelrc.user .idea/ .ijwb/ +# Ignore until it is more stable +MODULE.bazel.lock diff --git a/BUILD.bazel b/BUILD.bazel index bdbc789..e69de29 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,11 +0,0 @@ -load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary") - -gazelle_binary( - name = "gazelle_bin", - languages = ["@bazel_skylib_gazelle_plugin//bzl"], -) - -gazelle( - name = "gazelle", - gazelle = "gazelle_bin", -) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3d755de..7ec47a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,7 @@ Run `bazel run //:gazelle` to keep them up-to-date. ## Using this as a development dependency of other rules You'll commonly find that you develop in another WORKSPACE, such as -some other ruleset that depends on rules_mylang, or in a nested +some other ruleset that depends on rules_protoc, or in a nested WORKSPACE in the integration_tests folder. To always tell Bazel to use this directory rather than some release @@ -36,11 +36,11 @@ artifact or a version fetched from the internet, run this from this directory: ```sh -OVERRIDE="--override_repository=rules_mylang=$(pwd)/rules_mylang" +OVERRIDE="--override_repository=rules_protoc=$(pwd)/rules_protoc" echo "common $OVERRIDE" >> ~/.bazelrc ``` -This means that any usage of `@rules_mylang` on your system will point to this folder. +This means that any usage of `@rules_protoc` on your system will point to this folder. ## Releasing diff --git a/MODULE.bazel b/MODULE.bazel index 9884c03..0d9ec07 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,21 +1,20 @@ "Bazel dependencies" module( - name = "com_myorg_rules_mylang", + name = "toolchains_protoc", version = "0.0.0", compatibility_level = 1, ) bazel_dep(name = "bazel_skylib", version = "1.4.1") -bazel_dep(name = "platforms", version = "0.0.5") +bazel_dep(name = "rules_proto", version = "6.0.0-rc2") +bazel_dep(name = "platforms", version = "0.0.8") -bazel_dep(name = "gazelle", version = "0.35.0", dev_dependency = True, repo_name = "bazel_gazelle") -bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.4.1", dev_dependency = True) bazel_dep(name = "aspect_bazel_lib", version = "1.32.1", dev_dependency = True) bazel_dep(name = "buildifier_prebuilt", version = "6.1.2", dev_dependency = True) -mylang = use_extension("//mylang:extensions.bzl", "mylang") -mylang.toolchain(mylang_version = "1.14.2") -use_repo(mylang, "mylang_toolchains") +protoc = use_extension("//protoc:extensions.bzl", "protoc") +protoc.toolchain(version = "v25.3") +use_repo(protoc, "toolchains_protoc_hub") -register_toolchains("@mylang_toolchains//:all") +register_toolchains("@toolchains_protoc_hub//:all") diff --git a/README.md b/README.md index 20a04a3..4874986 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,28 @@ -# Template for Bazel rules +# Bazel toolchain for pre-built protoc -Copy this template to create a Bazel ruleset. +protoc has always been distributed as pre-built binaries on https://github.com/protocolbuffers/protobuf/releases -Features: +Bazel 7 introduced `--incompatible_enable_proto_toolchain_resolution` to allow us fetch that binary rather than re-build it! -- follows the official style guide at https://docs.bazel.build/versions/main/skylark/deploying.html -- allows for both WORKSPACE.bazel and bzlmod (MODULE.bazel) usage -- includes Bazel formatting as a pre-commit hook (using [buildifier]) -- includes stardoc API documentation generator -- includes typical toolchain setup -- CI configured with GitHub Actions -- release using GitHub Actions just by pushing a tag -- the release artifact doesn't need to be built by Bazel, but can still exclude files and stamp the version +See https://github.com/bazelbuild/examples/blob/never_compile_protoc_again/proto/README.md -See https://docs.bazel.build/versions/main/skylark/deploying.html#readme +## Why a separate Bazel module? -[buildifier]: https://github.com/bazelbuild/buildtools/tree/master/buildifier#readme +This belongs in rules_proto, see -Ready to get started? Copy this repo, then +- https://github.com/bazelbuild/rules_proto/pull/205 +- https://github.com/bazelbuild/rules_proto/pull/206 -1. search for "com_myorg_rules_mylang" and replace with the name you'll use for your workspace -1. search for "myorg" and replace with GitHub org -1. search for "mylang", "Mylang", "MYLANG" and replace with the language/tool your rules are for -1. rename directory "mylang" similarly -1. run `pre-commit install` to get lints (see CONTRIBUTING.md) -1. if you don't need to fetch platform-dependent tools, then remove anything toolchain-related. -1. (optional) install the [Renovate app](https://github.com/apps/renovate) to get auto-PRs to keep the dependencies up-to-date. -1. delete this section of the README (everything up to the SNIP). - ----- SNIP ---- - -# Bazel rules for mylang +Getting reviews from Googlers is hard so let's not wait for them. ## Installation -From the release you wish to use: - -copy the WORKSPACE snippet into your `WORKSPACE` file. - -To use a commit rather than a release, you can point at any SHA of the repo. +Make sure your `.bazelrc` contains -For example to use commit `abc123`: +``` +# Introduced in Bazel 7. +common --incompatible_enable_proto_toolchain_resolution +``` -1. Replace `url = "https://github.com/myorg/rules_mylang/releases/download/v0.1.0/rules_mylang-v0.1.0.tar.gz"` with a GitHub-provided source archive like `url = "https://github.com/myorg/rules_mylang/archive/abc123.tar.gz"` -1. Replace `strip_prefix = "rules_mylang-0.1.0"` with `strip_prefix = "rules_mylang-abc123"` -1. Update the `sha256`. The easiest way to do this is to comment out the line, then Bazel will - print a message with the correct value. Note that GitHub source archives don't have a strong - guarantee on the sha256 stability, see - +Follow instructions from the release you wish to use: + diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel deleted file mode 100644 index 99c2ed5..0000000 --- a/docs/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -# This load statement must be in the docs/ package rather than anything users depend on -# so that the dependency on stardoc doesn't leak to them. -load("@aspect_bazel_lib//lib:docs.bzl", "stardoc_with_diff_test", "update_docs") - -stardoc_with_diff_test( - name = "rules", - bzl_library_target = "//mylang:defs", -) - -update_docs(name = "update") diff --git a/docs/rules.md b/docs/rules.md deleted file mode 100644 index 3a4dda3..0000000 --- a/docs/rules.md +++ /dev/null @@ -1,16 +0,0 @@ - - -Public API re-exports - - - -## example - -
-example()
-
- -This is an example - - - diff --git a/e2e/smoke/.bazelrc b/e2e/smoke/.bazelrc index e69de29..d5f3317 100644 --- a/e2e/smoke/.bazelrc +++ b/e2e/smoke/.bazelrc @@ -0,0 +1,2 @@ +# The main ingredient: allow us to register toolchains other than com_google_protobuf targets +common --incompatible_enable_proto_toolchain_resolution diff --git a/e2e/smoke/BUILD b/e2e/smoke/BUILD index 31dfb97..9a6e75b 100644 --- a/e2e/smoke/BUILD +++ b/e2e/smoke/BUILD @@ -1,17 +1,6 @@ -"""Provides a simple way to test your rules as an external workspace. -Add a basic smoke-test target below. -""" +load("@rules_proto//proto:defs.bzl", "proto_library") -load("@bazel_skylib//rules:build_test.bzl", "build_test") -# load("@com_myorg_rules_mylang//mylang:defs.bzl", "...") - -# Replace with a usage of your rule/macro -filegroup(name = "empty") - -build_test( - name = "smoke_test", - targets = [ - # targets you add above - ":empty", - ], +proto_library( + name = "foo_proto", + srcs = ["foo.proto"], ) diff --git a/e2e/smoke/MODULE.bazel b/e2e/smoke/MODULE.bazel index 16a1296..ae51e6b 100644 --- a/e2e/smoke/MODULE.bazel +++ b/e2e/smoke/MODULE.bazel @@ -1,7 +1,7 @@ -bazel_dep(name = "com_myorg_rules_mylang", version = "0.0.0", dev_dependency = True) -bazel_dep(name = "bazel_skylib", version = "1.5.0", dev_dependency = True) +bazel_dep(name = "toolchains_protoc", version = "0.0.0") +bazel_dep(name = "rules_proto", version = "6.0.0-rc2") local_path_override( - module_name = "com_myorg_rules_mylang", + module_name = "toolchains_protoc", path = "../..", ) diff --git a/e2e/smoke/README.md b/e2e/smoke/README.md index 3135480..8619651 100644 --- a/e2e/smoke/README.md +++ b/e2e/smoke/README.md @@ -1,5 +1,17 @@ -# smoke test +# No compiling protoc! -This e2e exercises the repo from an end-users perpective. -It catches mistakes in our install instructions, or usages that fail when called from an "external" repository to rules_mylang. -It is also used by the presubmit check for the Bazel Central Registry. +``` +time bazel --output_base=$(mktemp -d) build :all +Starting local Bazel server and connecting to it... +INFO: Analyzed target //:foo_proto (38 packages loaded, 164 targets configured). +INFO: Found 1 target... +Target //:foo_proto up-to-date: + bazel-bin/foo_proto-descriptor-set.proto.bin +INFO: Elapsed time: 1.761s, Critical Path: 0.02s +INFO: 2 processes: 1 internal, 1 linux-sandbox. +INFO: Build completed successfully, 2 total actions + +real 0m2.148s +user 0m0.033s +sys 0m0.005s +``` diff --git a/e2e/smoke/WORKSPACE.bazel b/e2e/smoke/WORKSPACE.bazel index e487105..1492085 100644 --- a/e2e/smoke/WORKSPACE.bazel +++ b/e2e/smoke/WORKSPACE.bazel @@ -1,19 +1,34 @@ # Override http_archive for local testing local_repository( - name = "com_myorg_rules_mylang", + name = "toolchains_protoc", path = "../..", ) #---SNIP--- Below here is re-used in the workspace snippet published on releases ###################### -# rules_mylang setup # +# rules_protoc setup # ###################### -# Fetches the rules_mylang dependencies. +# Fetches the rules_protoc dependencies. # If you want to have a different version of some dependency, # you should fetch it *before* calling this. # Alternatively, you can skip calling this function, so long as you've # already fetched all the dependencies. -load("@com_myorg_rules_mylang//mylang:repositories.bzl", "rules_mylang_dependencies") +load("@toolchains_protoc//protoc:repositories.bzl", "rules_protoc_dependencies") -rules_mylang_dependencies() +rules_protoc_dependencies() + +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies") + +rules_proto_dependencies() + +load("@bazel_features//:deps.bzl", "bazel_features_deps") + +bazel_features_deps() + +load("@toolchains_protoc//protoc:toolchain.bzl", "protoc_toolchains") + +protoc_toolchains( + name = "protoc_toolchains", + version = "v25.3", +) diff --git a/e2e/smoke/foo.proto b/e2e/smoke/foo.proto new file mode 100644 index 0000000..b6c3444 --- /dev/null +++ b/e2e/smoke/foo.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Foo { + string msg = 1; +} diff --git a/mylang/extensions.bzl b/mylang/extensions.bzl deleted file mode 100644 index e2ae7d0..0000000 --- a/mylang/extensions.bzl +++ /dev/null @@ -1,56 +0,0 @@ -"""Extensions for bzlmod. - -Installs a mylang toolchain. -Every module can define a toolchain version under the default name, "mylang". -The latest of those versions will be selected (the rest discarded), -and will always be registered by rules_mylang. - -Additionally, the root module can define arbitrarily many more toolchain versions under different -names (the latest version will be picked for each name) and can register them as it sees fit, -effectively overriding the default named toolchain due to toolchain resolution precedence. -""" - -load(":repositories.bzl", "mylang_register_toolchains") - -_DEFAULT_NAME = "mylang" - -mylang_toolchain = tag_class(attrs = { - "name": attr.string(doc = """\ -Base name for generated repositories, allowing more than one mylang toolchain to be registered. -Overriding the default is only permitted in the root module. -""", default = _DEFAULT_NAME), - "mylang_version": attr.string(doc = "Explicit version of mylang.", mandatory = True), -}) - -def _toolchain_extension(module_ctx): - registrations = {} - for mod in module_ctx.modules: - for toolchain in mod.tags.toolchain: - if toolchain.name != _DEFAULT_NAME and not mod.is_root: - fail("""\ - Only the root module may override the default name for the mylang toolchain. - This prevents conflicting registrations in the global namespace of external repos. - """) - if toolchain.name not in registrations.keys(): - registrations[toolchain.name] = [] - registrations[toolchain.name].append(toolchain.mylang_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: mylang toolchain {} has multiple versions {}, selected {}".format(name, versions, selected)) - else: - selected = versions[0] - - mylang_register_toolchains( - name = name, - mylang_version = selected, - register = False, - ) - -mylang = module_extension( - implementation = _toolchain_extension, - tag_classes = {"toolchain": mylang_toolchain}, -) diff --git a/mylang/private/BUILD.bazel b/mylang/private/BUILD.bazel deleted file mode 100644 index eb2edb6..0000000 --- a/mylang/private/BUILD.bazel +++ /dev/null @@ -1,19 +0,0 @@ -load("@bazel_skylib//:bzl_library.bzl", "bzl_library") - -bzl_library( - name = "toolchains_repo", - srcs = ["toolchains_repo.bzl"], - visibility = ["//mylang:__subpackages__"], -) - -bzl_library( - name = "versions", - srcs = ["versions.bzl"], - visibility = ["//mylang:__subpackages__"], -) - -bzl_library( - name = "resolved_toolchain", - srcs = ["resolved_toolchain.bzl"], - visibility = ["//mylang:__subpackages__"], -) diff --git a/mylang/private/toolchains_repo.bzl b/mylang/private/toolchains_repo.bzl deleted file mode 100644 index 49a3d07..0000000 --- a/mylang/private/toolchains_repo.bzl +++ /dev/null @@ -1,84 +0,0 @@ -"""Create a repository to hold the toolchains - -This follows guidance here: -https://docs.bazel.build/versions/main/skylark/deploying.html#registering-toolchains -" -Note that in order to resolve toolchains in the analysis phase -Bazel needs to analyze all toolchain targets that are registered. -Bazel will not need to analyze all targets referenced by toolchain.toolchain attribute. -If in order to register toolchains you need to perform complex computation in the repository, -consider splitting the repository with toolchain targets -from the repository with _toolchain targets. -Former will be always fetched, -and the latter will only be fetched when user actually needs to build code. -" -The "complex computation" in our case is simply downloading large artifacts. -This guidance tells us how to avoid that: we put the toolchain targets in the alias repository -with only the toolchain attribute pointing into the platform-specific repositories. -""" - -# Add more platforms as needed to mirror all the binaries -# published by the upstream project. -PLATFORMS = { - "x86_64-apple-darwin": struct( - compatible_with = [ - "@platforms//os:macos", - "@platforms//cpu:x86_64", - ], - ), - "aarch64-apple-darwin": struct( - compatible_with = [ - "@platforms//os:macos", - "@platforms//cpu:aarch64", - ], - ), - "x86_64-unknown-linux-gnu": struct( - compatible_with = [ - "@platforms//os:linux", - "@platforms//cpu:x86_64", - ], - ), - "x86_64-pc-windows-msvc": struct( - compatible_with = [ - "@platforms//os:windows", - "@platforms//cpu:x86_64", - ], - ), -} - -def _toolchains_repo_impl(repository_ctx): - build_content = """# Generated by toolchains_repo.bzl -# -# These can be registered in the workspace file or passed to --extra_toolchains flag. -# By default all these toolchains are registered by the mylang_register_toolchains macro -# so you don't normally need to interact with these targets. - -""" - - for [platform, meta] in PLATFORMS.items(): - build_content += """ -# Declare a toolchain Bazel will select for running the tool in an action -# on the execution platform. -toolchain( - name = "{platform}_toolchain", - exec_compatible_with = {compatible_with}, - toolchain = "@{user_repository_name}_{platform}//:mylang_toolchain", - toolchain_type = "@com_myorg_rules_mylang//mylang:toolchain_type", -) -""".format( - platform = platform, - user_repository_name = repository_ctx.attr.user_repository_name, - compatible_with = meta.compatible_with, - ) - - # Base BUILD file for this repository - repository_ctx.file("BUILD.bazel", build_content) - -toolchains_repo = repository_rule( - _toolchains_repo_impl, - doc = """Creates a repository with toolchain definitions for all known platforms - which can be registered or selected.""", - attrs = { - "user_repository_name": attr.string(doc = "what the user chose for the base name"), - }, -) diff --git a/mylang/private/versions.bzl b/mylang/private/versions.bzl deleted file mode 100644 index 7f6c5bd..0000000 --- a/mylang/private/versions.bzl +++ /dev/null @@ -1,14 +0,0 @@ -"""Mirror of release info - -TODO: generate this file from GitHub API""" - -# The integrity hashes can be computed with -# shasum -b -a 384 [downloaded file] | awk '{ print $1 }' | xxd -r -p | base64 -TOOL_VERSIONS = { - "1.14.2": { - "x86_64-apple-darwin": "sha384-ws4+rANvv0YxM1SgIBUXSG9jT8dKw83nls6R5qYkEKzPUB+viBIEozSsyq2e6i+f", - "aarch64-apple-darwin": "sha384-HcvJbxoJtGSavkGu0e7CyD00cBlmDb0TBWJ4JSaNa70zuU3N7XlMOYm3bbQcAv2U", - "x86_64-pc-windows-msvc": "sha384-35YN6TKpT0L9qyRBmq48NucvyXEtHnkeC+txf2YZmmJTmOzrAKREA74BA0EZvpar", - "x86_64-unknown-linux-gnu": "sha384-QgGOwTaetxY0h5HWCKc/3ZtBs4N/fgaaORthn7UcEv++Idm9W+ntCCZRwvBdwHPD", - }, -} diff --git a/mylang/repositories.bzl b/mylang/repositories.bzl deleted file mode 100644 index 137bcef..0000000 --- a/mylang/repositories.bzl +++ /dev/null @@ -1,100 +0,0 @@ -"""Declare runtime dependencies - -These are needed for local dev, and users must install them as well. -See https://docs.bazel.build/versions/main/skylark/deploying.html#dependencies -""" - -load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive") -load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") -load("//mylang/private:toolchains_repo.bzl", "PLATFORMS", "toolchains_repo") -load("//mylang/private:versions.bzl", "TOOL_VERSIONS") - -def http_archive(name, **kwargs): - maybe(_http_archive, name = name, **kwargs) - -# WARNING: any changes in this function may be BREAKING CHANGES for users -# because we'll fetch a dependency which may be different from one that -# they were previously fetching later in their WORKSPACE setup, and now -# ours took precedence. Such breakages are challenging for users, so any -# changes in this function should be marked as BREAKING in the commit message -# and released only in semver majors. -# This is all fixed by bzlmod, so we just tolerate it for now. -def rules_mylang_dependencies(): - # The minimal version of bazel_skylib we require - http_archive( - name = "bazel_skylib", - sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94", - urls = [ - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", - ], - ) - -######## -# Remaining content of the file is only used to support toolchains. -######## -_DOC = "Fetch external tools needed for mylang toolchain" -_ATTRS = { - "mylang_version": attr.string(mandatory = True, values = TOOL_VERSIONS.keys()), - "platform": attr.string(mandatory = True, values = PLATFORMS.keys()), -} - -def _mylang_repo_impl(repository_ctx): - url = "https://github.com/someorg/someproject/releases/download/v{0}/mylang-{1}.zip".format( - repository_ctx.attr.mylang_version, - repository_ctx.attr.platform, - ) - repository_ctx.download_and_extract( - url = url, - integrity = TOOL_VERSIONS[repository_ctx.attr.mylang_version][repository_ctx.attr.platform], - ) - build_content = """# Generated by mylang/repositories.bzl -load("@com_myorg_rules_mylang//mylang:toolchain.bzl", "mylang_toolchain") - -mylang_toolchain( - name = "mylang_toolchain", - target_tool = select({ - "@bazel_tools//src/conditions:host_windows": "mylang_tool.exe", - "//conditions:default": "mylang_tool", - }), -) -""" - - # Base BUILD file for this repository - repository_ctx.file("BUILD.bazel", build_content) - -mylang_repositories = repository_rule( - _mylang_repo_impl, - doc = _DOC, - attrs = _ATTRS, -) - -# Wrapper macro around everything above, this is the primary API -def mylang_register_toolchains(name, register = True, **kwargs): - """Convenience macro for users which does typical setup. - - - create a repository for each built-in platform like "mylang_linux_amd64" - - this repository is lazily fetched when node is needed for that platform. - - TODO: create a convenience repository for the host platform like "mylang_host" - - create a repository exposing toolchains for each platform like "mylang_platforms" - - register a toolchain pointing at each platform - Users can avoid this macro and do these steps themselves, if they want more control. - Args: - name: base name for all created repos, like "mylang1_14" - register: whether to call through to native.register_toolchains. - Should be True for WORKSPACE users, but false when used under bzlmod extension - **kwargs: passed to each node_repositories call - """ - for platform in PLATFORMS.keys(): - mylang_repositories( - name = name + "_" + platform, - platform = platform, - **kwargs - ) - if register: - native.register_toolchains("@%s_toolchains//:%s_toolchain" % (name, platform)) - - toolchains_repo( - name = name + "_toolchains", - user_repository_name = name, - ) diff --git a/mylang/tests/BUILD.bazel b/mylang/tests/BUILD.bazel deleted file mode 100644 index 93eae3c..0000000 --- a/mylang/tests/BUILD.bazel +++ /dev/null @@ -1,3 +0,0 @@ -load(":versions_test.bzl", "versions_test_suite") - -versions_test_suite(name = "versions_test") diff --git a/mylang/tests/versions_test.bzl b/mylang/tests/versions_test.bzl deleted file mode 100644 index 7a9a988..0000000 --- a/mylang/tests/versions_test.bzl +++ /dev/null @@ -1,18 +0,0 @@ -"""Unit tests for starlark helpers -See https://bazel.build/rules/testing#testing-starlark-utilities -""" - -load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") -load("//mylang/private:versions.bzl", "TOOL_VERSIONS") - -def _smoke_test_impl(ctx): - env = unittest.begin(ctx) - asserts.equals(env, "1.14.2", TOOL_VERSIONS.keys()[0]) - return unittest.end(env) - -# The unittest library requires that we export the test cases as named test rules, -# but their names are arbitrary and don't appear anywhere. -_t0_test = unittest.make(_smoke_test_impl) - -def versions_test_suite(name): - unittest.suite(name, _t0_test) diff --git a/mylang/toolchain.bzl b/mylang/toolchain.bzl deleted file mode 100644 index cfa816c..0000000 --- a/mylang/toolchain.bzl +++ /dev/null @@ -1,78 +0,0 @@ -"""This module implements the language-specific toolchain rule. -""" - -MylangInfo = provider( - doc = "Information about how to invoke the tool executable.", - fields = { - "target_tool_path": "Path to the tool executable for the target platform.", - "tool_files": """Files required in runfiles to make the tool executable available. - -May be empty if the target_tool_path points to a locally installed tool binary.""", - }, -) - -# Avoid using non-normalized paths (workspace/../other_workspace/path) -def _to_manifest_path(ctx, file): - if file.short_path.startswith("../"): - return "external/" + file.short_path[3:] - else: - return ctx.workspace_name + "/" + file.short_path - -def _mylang_toolchain_impl(ctx): - if ctx.attr.target_tool and ctx.attr.target_tool_path: - fail("Can only set one of target_tool or target_tool_path but both were set.") - if not ctx.attr.target_tool and not ctx.attr.target_tool_path: - fail("Must set one of target_tool or target_tool_path.") - - tool_files = [] - target_tool_path = ctx.attr.target_tool_path - - if ctx.attr.target_tool: - tool_files = ctx.attr.target_tool.files.to_list() - target_tool_path = _to_manifest_path(ctx, tool_files[0]) - - # Make the $(tool_BIN) variable available in places like genrules. - # See https://docs.bazel.build/versions/main/be/make-variables.html#custom_variables - template_variables = platform_common.TemplateVariableInfo({ - "MYLANG_BIN": target_tool_path, - }) - default = DefaultInfo( - files = depset(tool_files), - runfiles = ctx.runfiles(files = tool_files), - ) - mylanginfo = MylangInfo( - target_tool_path = target_tool_path, - tool_files = tool_files, - ) - - # Export all the providers inside our ToolchainInfo - # so the resolved_toolchain rule can grab and re-export them. - toolchain_info = platform_common.ToolchainInfo( - mylanginfo = mylanginfo, - template_variables = template_variables, - default = default, - ) - return [ - default, - toolchain_info, - template_variables, - ] - -mylang_toolchain = rule( - implementation = _mylang_toolchain_impl, - attrs = { - "target_tool": attr.label( - doc = "A hermetically downloaded executable target for the target platform.", - mandatory = False, - allow_single_file = True, - ), - "target_tool_path": attr.string( - doc = "Path to an existing executable for the target platform.", - mandatory = False, - ), - }, - doc = """Defines a mylang compiler/runtime toolchain. - -For usage see https://docs.bazel.build/versions/main/toolchains.html#defining-toolchains. -""", -) diff --git a/mylang/BUILD.bazel b/protoc/BUILD.bazel similarity index 67% rename from mylang/BUILD.bazel rename to protoc/BUILD.bazel index 27ac1af..c86c660 100644 --- a/mylang/BUILD.bazel +++ b/protoc/BUILD.bazel @@ -1,17 +1,9 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("//mylang/private:resolved_toolchain.bzl", "resolved_toolchain") +load("//protoc/private:resolved_toolchain.bzl", "resolved_toolchain") # For stardoc to reference the files exports_files(["defs.bzl"]) -# This is the target rule authors should put in their "toolchains" -# attribute in order to get a runtime for the correct platform. -# See https://docs.bazel.build/versions/main/toolchains.html#writing-rules-that-use-toolchains -toolchain_type( - name = "toolchain_type", - visibility = ["//visibility:public"], -) - resolved_toolchain( name = "resolved_toolchain", # Marked manual so that `bazel test //...` passes @@ -25,8 +17,7 @@ bzl_library( srcs = ["repositories.bzl"], visibility = ["//visibility:public"], deps = [ - "//mylang/private:toolchains_repo", - "//mylang/private:versions", + "//protoc/private:versions", "@bazel_tools//tools/build_defs/repo:http.bzl", "@bazel_tools//tools/build_defs/repo:utils.bzl", ], diff --git a/mylang/defs.bzl b/protoc/defs.bzl similarity index 100% rename from mylang/defs.bzl rename to protoc/defs.bzl diff --git a/protoc/extensions.bzl b/protoc/extensions.bzl new file mode 100644 index 0000000..0d40f21 --- /dev/null +++ b/protoc/extensions.bzl @@ -0,0 +1,39 @@ +"Module extensions for use under bzlmod" + +load(":toolchain.bzl", "protoc_toolchains") + +DEFAULT_REPOSITORY = "toolchains_protoc_hub" + +def _proto_extension_impl(module_ctx): + registrations = {} + root_name = None + for mod in module_ctx.modules: + for toolchain in mod.tags.toolchain: + if toolchain.name != DEFAULT_REPOSITORY and not mod.is_root: + fail("""\ + Only the root module may override the default name for the toolchain. + This prevents conflicting registrations in the global namespace of external repos. + """) + + # Ensure the root wins in case of differences + if mod.is_root: + protoc_toolchains(toolchain.name, register = False, version = toolchain.version) + root_name = toolchain.name + else: + registrations[toolchain.name] = toolchain.version + for name, version in registrations.items(): + if name != root_name: + protoc_toolchains(name, register = False, version = version) + +protoc = module_extension( + implementation = _proto_extension_impl, + tag_classes = { + "toolchain": tag_class(attrs = { + "name": attr.string(doc = """\ + Base name for generated repositories, allowing more than one toolchain to be registered. + Overriding the default is only permitted in the root module. + """, default = DEFAULT_REPOSITORY), + "version": attr.string(doc = "A tag of protocolbuffers/protobuf repository."), + }), + }, +) diff --git a/protoc/private/BUILD.bazel b/protoc/private/BUILD.bazel new file mode 100644 index 0000000..aac2fe6 --- /dev/null +++ b/protoc/private/BUILD.bazel @@ -0,0 +1,13 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +bzl_library( + name = "versions", + srcs = ["versions.bzl"], + visibility = ["//protoc:__subpackages__"], +) + +bzl_library( + name = "resolved_toolchain", + srcs = ["resolved_toolchain.bzl"], + visibility = ["//protoc:__subpackages__"], +) diff --git a/protoc/private/mirror_protoc_release.sh b/protoc/private/mirror_protoc_release.sh new file mode 100755 index 0000000..cd46ec4 --- /dev/null +++ b/protoc/private/mirror_protoc_release.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# By default, mirrors the most recent release of protoc from +# https://github.com/protocolbuffers/protobuf/releases +# +# To mirror a different version, set VERSION in the environment. +# To use a different fork, set REPOSITORY in the environment. +set -o nounset -o errexit -o pipefail + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +REPOSITORY=${REPOSITORY:-"protocolbuffers/protobuf"} +VERSIONS_BZL="$SCRIPT_DIR/versions.bzl" + +RELEASES=$(mktemp) +curl > $RELEASES \ + --silent \ + --header "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${REPOSITORY}/releases?per_page=50 + +# If $VERSION unset, mirror the latest release +VERSION=${VERSION:-$(jq --raw-output '.[0].tag_name' $RELEASES)} +echo "Mirroring integrity hashes for $REPOSITORY at release $VERSION ..." + +DOWNLOAD_URLS_FILTER=' +map(select(.tag_name == $version))[0] +| .assets +| map(select(.name | startswith("protoc"))) +| map(.browser_download_url)[] +' +# Workaround: protobuf doesn't publish their integrity hashes to e.g. checksums.txt +# Create a file that looks like a checksums.txt from a shasum command, i.e. +# sha384-RVFu8PJJCOSXwYTqH7FyWRSgsP1AAjcEa+VViddVTgtd9wYvZjQoQ8jmlFxwfFw+ protobuf-26.0-rc3.tar.gz +# sha384-JYSXGTSBfwUU6UzqazUTkT3lTZDzx10YdaNQYjojrT7X1Ro1fA+T4tjJw0e8UISV protobuf-26.0-rc3.zip +CHECKSUMS=$(mktemp) +for url in $(jq --arg version $VERSION --raw-output "$DOWNLOAD_URLS_FILTER" <$RELEASES); do + sha=$(curl -sSL $url | shasum -b -a 384 | awk "{ print \$1 }" | xxd -r -p | base64) + echo "sha384-${sha} $(basename $url)" +done | tee "$CHECKSUMS" + +# Format as a dictionary of version to dictionary of filename to sha +# { +# "v26.0-rc3": { +# "protobuf-26.0-rc3.tar.gz": "sha384-RVFu8PJJCOSXwYTqH7FyWRSgsP1AAjcEa+VViddVTgtd9wYvZjQoQ8jmlFxwfFw+", +# "protobuf-26.0-rc3.zip": "sha384-JYSXGTSBfwUU6UzqazUTkT3lTZDzx10YdaNQYjojrT7X1Ro1fA+T4tjJw0e8UISV", +# ... +TO_DICTIONARY_FILTER=' +. +| rtrimstr("\n") +| split("\n") +| map( + split(" ") + | {"key": .[1], "value": .[0]} + ) +| from_entries +| { ($version): .} +' +NEW_VERSION=$(mktemp) +jq "$TO_DICTIONARY_FILTER" \ + --slurp --raw-input \ + --arg version $VERSION \ + $CHECKSUMS \ + > $NEW_VERSION + +# Read existing versions.bzl content into a json object for easy merging +EXISTING_VERSIONS=$(mktemp) +python3 -c "import json; exec(open('$VERSIONS_BZL').read()); print(json.dumps(PROTOC_VERSIONS))" > $EXISTING_VERSIONS + +# Locate the PROTOC_VERSIONS declaration in the source file and replace it with a merge of both data sources +NEW=$(mktemp) +sed '/PROTOC_VERSIONS =/Q' $VERSIONS_BZL > $NEW +echo -n "PROTOC_VERSIONS = " >> $NEW +jq --slurp '.[0] * .[1]' $NEW_VERSION $EXISTING_VERSIONS >> $NEW +cp $NEW $VERSIONS_BZL + +echo "Done, see updates in $VERSIONS_BZL" diff --git a/protoc/private/prebuilt_protoc_toolchain.bzl b/protoc/private/prebuilt_protoc_toolchain.bzl new file mode 100644 index 0000000..fd65502 --- /dev/null +++ b/protoc/private/prebuilt_protoc_toolchain.bzl @@ -0,0 +1,51 @@ +"""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") + +def _prebuilt_protoc_repo_impl(rctx): + release_version = rctx.attr.version + + filename = "{}-{}-{}.zip".format( + "protoc", + release_version.removeprefix("v"), + 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], + ) + rctx.file("BUILD.bazel", """\ +# Generated by @rules_proto//proto/toolchains:prebuilt_protoc_toolchain.bzl +load("@rules_proto//proto/private/rules:proto_toolchain_rule.bzl", "proto_toolchain") + +proto_toolchain( + name = "prebuilt_protoc_toolchain", + proto_compiler = "{protoc_label}", + visibility = ["//visibility:public"], +) +""".format( + protoc_label = ":bin/protoc.exe" if rctx.attr.platform.find("windows") != -1 else ":bin/protoc", + )) + +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, + ), + }, +) diff --git a/protoc/private/protoc_toolchains.bzl b/protoc/private/protoc_toolchains.bzl new file mode 100644 index 0000000..b3dd4ce --- /dev/null +++ b/protoc/private/protoc_toolchains.bzl @@ -0,0 +1,65 @@ +"""Create a repository to reference the pre-built protoc toolchains. + +Ensures that Bazel only downloads required binaries for selected toolchains. + +This follows guidance here: +https://docs.bazel.build/versions/main/skylark/deploying.html#registering-toolchains +" +Note that in order to resolve toolchains in the analysis phase +Bazel needs to analyze all toolchain targets that are registered. +Bazel will not need to analyze all targets referenced by toolchain.toolchain attribute. +If in order to register toolchains you need to perform complex computation in the repository, +consider splitting the repository with toolchain targets +from the repository with _toolchain targets. +Former will be always fetched, +and the latter will only be fetched when user actually needs to build code. +" + +The "complex computation" in our case is simply downloading our pre-built protoc binaries. +This guidance tells us how to avoid that: we put the toolchain targets in the alias repository +with only the toolchain attribute pointing into the platform-specific repositories. +""" + +load(":versions.bzl", "PROTOC_PLATFORMS") + +def _toolchains_repo_impl(repository_ctx): + build_content = """# Generated by protoc/private/protoc_toolchains.bzl +# +# These can be registered in the workspace file or passed to --extra_toolchains flag. +# By default all these toolchains are registered by the rules_proto_toolchains macro +# so you don't normally need to interact with these targets. + +""" + + for [platform, meta] in PROTOC_PLATFORMS.items(): + build_content += """ +toolchain( + name = "{platform}_toolchain", + exec_compatible_with = {compatible_with}, + # Bazel does not follow this attribute during analysis, so the referenced repo + # will only be fetched if this toolchain is selected. + toolchain = "@{user_repository_name}.{platform}//:prebuilt_protoc_toolchain", + toolchain_type = "@rules_proto//proto:toolchain_type", +) +""".format( + platform = platform, + user_repository_name = repository_ctx.attr.user_repository_name, + compatible_with = meta["compatible_with"], + ) + repository_ctx.file("BUILD.bazel", build_content) + +protoc_toolchains_repo = repository_rule( + _toolchains_repo_impl, + doc = """\ + Creates a single repository with toolchain definitions for all known platforms + that can be registered or selected. + """, + attrs = { + "user_repository_name": attr.string( + doc = """What the user chose for the base name. + Needed since bzlmod apparent name has extra tilde segments. + """, + mandatory = True, + ), + }, +) diff --git a/mylang/private/resolved_toolchain.bzl b/protoc/private/resolved_toolchain.bzl similarity index 83% rename from mylang/private/resolved_toolchain.bzl rename to protoc/private/resolved_toolchain.bzl index 29dc34e..c3da6cd 100644 --- a/mylang/private/resolved_toolchain.bzl +++ b/protoc/private/resolved_toolchain.bzl @@ -9,11 +9,11 @@ Workaround for https://github.com/bazelbuild/bazel/issues/14009 # Forward all the providers def _resolved_toolchain_impl(ctx): - toolchain_info = ctx.toolchains["//mylang:toolchain_type"] + toolchain_info = ctx.toolchains["//protoc:toolchain_type"] return [ toolchain_info, toolchain_info.default, - toolchain_info.mylanginfo, + toolchain_info.protocinfo, toolchain_info.template_variables, ] @@ -21,7 +21,7 @@ def _resolved_toolchain_impl(ctx): # https://cs.opensource.google/bazel/bazel/+/master:tools/jdk/java_toolchain_alias.bzl resolved_toolchain = rule( implementation = _resolved_toolchain_impl, - toolchains = ["//mylang:toolchain_type"], + toolchains = ["//protoc:toolchain_type"], incompatible_use_toolchain_transition = True, doc = DOC, ) diff --git a/protoc/private/versions.bzl b/protoc/private/versions.bzl new file mode 100644 index 0000000..5d93170 --- /dev/null +++ b/protoc/private/versions.bzl @@ -0,0 +1,114 @@ +"""Mirrored integrity hashes for the pre-built protoc binaries distributed by the protobuf project. + +See ./mirror_protoc_release.sh for automation to update this file. +See .github/workflows/mirror_protoc_release.yml for automation that runs the script daily. +""" + +# Keys are chosen to match the filenames published on protocolbuffers/protobuf releases +PROTOC_PLATFORMS = { + "linux-aarch_64": { + "compatible_with": [ + "@platforms//os:linux", + "@platforms//cpu:aarch64", + ], + }, + "linux-ppcle_64": { + "compatible_with": [ + "@platforms//os:linux", + "@platforms//cpu:ppc64le", + ], + }, + "linux-s390_64": { + "compatible_with": [ + "@platforms//os:linux", + "@platforms//cpu:s390x", + ], + }, + "linux-x86_64": { + "compatible_with": [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + }, + "osx-aarch_64": { + "compatible_with": [ + "@platforms//os:macos", + "@platforms//cpu:aarch64", + ], + }, + "osx-x86_64": { + "compatible_with": [ + "@platforms//os:macos", + "@platforms//cpu:x86_64", + ], + }, + "win64": { + "compatible_with": [ + "@platforms//os:windows", + "@platforms//cpu:x86_64", + ], + }, +} + +PROTOC_VERSIONS = { + "v25.3": { + "protoc-25.3-linux-aarch_64.zip": "sha384-jwCvnInYx9lD4bNy3EI/leVIVGqpyYkJ3qZSXXtIERcaBRIS1hAi4Tluu9Cy4eiy", + "protoc-25.3-linux-ppcle_64.zip": "sha384-aLa68jnCzwO7pS0ler84UxwzaL7srl+9fFZuR3ykh4FJIDJW/jCQGTeuos8VfWcI", + "protoc-25.3-linux-s390_64.zip": "sha384-PrlMkT15A2RsI4QYbRgvxq/xsNV7i1jzMbIZkSHDUMyZPC2Txf1ydLrmsIdQ/NQP", + "protoc-25.3-linux-x86_32.zip": "sha384-GeYiLamJeiA/5/JY1bE9JisEoQwy9T65ZwQHmfc6JFV2VkWbUkRHGJqt3BeCBtP/", + "protoc-25.3-linux-x86_64.zip": "sha384-RJ5r9hcTEMpphUBr1LLyYhjTc6k4tGkqGOW/UOHqHCSTGyFKG2DD7hfZ0XHdrc7e", + "protoc-25.3-osx-aarch_64.zip": "sha384-B2T/H3pEAm/tEnOLvMhTRae5zq5PCcPMzTjWspe+vjS/CmTxVxnlMH1XjxgibILi", + "protoc-25.3-osx-universal_binary.zip": "sha384-mhajph4BOcfzO74CC5u5JJ/eQ/sY6/Js1sDBVTszZmmo0nxqHU065rnDkHM5yy9i", + "protoc-25.3-osx-x86_64.zip": "sha384-AUt06iBAyAmj1bB9KVjilbCX3moW/RLLUwJK3XNLzM3JY9/jIcaY61Juf/gCON3A", + "protoc-25.3-win32.zip": "sha384-PoVupdbxosMbZs//vJDkLXjTzY2pfF3vI3lJ9J+SoMqsv17r/kFEzH8brM64x0FS", + "protoc-25.3-win64.zip": "sha384-Fe23g3o7lyfGIpl8YNK6zLecYvp1A7dRjOozoztLQPoIFYlKmETsjh5+p4USHrkL", + }, + "v24.4": { + "protoc-24.4-linux-aarch_64.zip": "sha384-1yUAFmmBLZ3LU/vJoLxBX/MWJeanKe7p9SYkVmqlWwghayQEzifO6zsZ65fbQrNZ", + "protoc-24.4-linux-ppcle_64.zip": "sha384-vx5i4cMWTK4d0P7yCucDG5T8z9nk+Ypi85+nOTZNrONPSsBoDpmrsjTeErcAxTD6", + "protoc-24.4-linux-s390_64.zip": "sha384-gXY/gbqiOqNOfnHh7Ae1CJDUeFQ+0ZdgJrjNoeZ0Q5dL5IrRiHIdD0D1nV8wo4d8", + "protoc-24.4-linux-x86_32.zip": "sha384-7ssqfPe6uiKeT2d0WFAOoa8xHePYPWfOpYZrGRHlvj7U7CKO9CweqRCqiZ/ItLVg", + "protoc-24.4-linux-x86_64.zip": "sha384-gpzw2FvYI08YGwr4zWVcNfNvEiy8UegP/oa5NyG7gejthfpyzXWtKAtT3fo5Zmct", + "protoc-24.4-osx-aarch_64.zip": "sha384-OlqTHfI/D8J2R3r0Y9o7BQIrODGYNTPCveDyte0zhniECsgDddFSZHR1JxjjtUj0", + "protoc-24.4-osx-universal_binary.zip": "sha384-cNqrP+ghI+h/Cvd/KBBlfmYiP/rfhdiBjXSJaDUchlJoAJnW6J72jG0W81PXTxpj", + "protoc-24.4-osx-x86_64.zip": "sha384-rM42wIQ9S33LqbL7aTmUT4RIxZfv93GNrShlwj3RYFbAQ4iGJ4vtHOgPwv1QCovr", + "protoc-24.4-win32.zip": "sha384-l9ruRjAjGgLYJAQ/r+2Rw7mcUDSvH5CqFZK422aNMbPKLzmjXxtfhK91JT9xl+cU", + "protoc-24.4-win64.zip": "sha384-HR8U6fkwvpJvc5LlN7fdl6KgAM3BOtxJm0+HyyaT4EWtQIkdKlGW2kd7cQL56X3L", + }, + "v23.4": { + "protoc-23.4-linux-aarch_64.zip": "sha384-36L+9u6RetU65cpV+C1AtfPEMEvqwNarfCdBAy00ukdYT+xXSWeSYynGQxkIMCY8", + "protoc-23.4-linux-ppcle_64.zip": "sha384-Y5y2wQn38Y0obtRe+wNoCspl7hdoExwgwqY4ObBxLEtPug5ZbLZxfrd1g9GbqJLE", + "protoc-23.4-linux-s390_64.zip": "sha384-EWqVU90VXUX9IsMzZuM/eTcvQfg69WC+5oPfl5IZpAjoJehzJuLleHdPYO8b3Af6", + "protoc-23.4-linux-x86_32.zip": "sha384-n0B9jivyQuUDHRKcPUjO4mbKTCikmkBFIzui9IG6L2pTzCoDAQYJ8lEX2zIQ95LT", + "protoc-23.4-linux-x86_64.zip": "sha384-w9VyeEVgTWWlGcZvFG/N2HLWCIDQuIEnizkiiBijZgJK/B81dDUObvSo21VY+aE7", + "protoc-23.4-osx-aarch_64.zip": "sha384-QOXoTVDlsf3GdN8MjGM7Yvp/rVhHVdYgxwHGPb5S+awfYQnGHYXMlL7L8CgdHVDL", + "protoc-23.4-osx-universal_binary.zip": "sha384-Yp9SV5FlW0N37njfqAHFIhflb+eb8R7YQpw5nFiyN6s+u1sxHCw9ZCZh9ZzL9QCq", + "protoc-23.4-osx-x86_64.zip": "sha384-c/SnXBOI72mK6XsVtXR15SzhMapFf/a3PGT1+aCAmtl5uiU04olZagu1BMziIxNR", + "protoc-23.4-win32.zip": "sha384-1NB0mSSMTlp9CHO0QOre51hNrilVnO+JkLafquaowkcCRKgyZV3ZYK+ExLi+DJyX", + "protoc-23.4-win64.zip": "sha384-w7UcenXNSkyH9tTOuYo67Ra2WUMkS/la5ftWAuoAmXy/Suj06fU5LHLCx2kQUgOD", + }, + "v22.5": { + "protoc-22.5-linux-aarch_64.zip": "sha384-4rBMpoB30Rjwti6ggmSo8WYz5xGE/LES2bospjd7blTS3Ygj2IAsJOCt6VmlRhLh", + "protoc-22.5-linux-ppcle_64.zip": "sha384-ulV1n2lPtfD1qEFWXLdpJ5bGswCRmhk0NVYLNjRBUSAlO/O97mplvDYUpwX+8Kqj", + "protoc-22.5-linux-s390_64.zip": "sha384-KzKLDSBMXwMQTHowWexDEEFkpD48jMOsoX7l3GMP4dVrgjSgaf6KIbMZ2/0mwJKr", + "protoc-22.5-linux-x86_32.zip": "sha384-v79Zuw2ak98dSKXqDkzosiMnc3cwSteMuizgEJu7bC5oJvEYMlXHCz37XBIMmftg", + "protoc-22.5-linux-x86_64.zip": "sha384-LvvYFW33r9C1mcCqnNJmt1EoMY2ToXU68CXKyz/+OyvvyIRmgAARLzwVBdIrpORx", + "protoc-22.5-osx-aarch_64.zip": "sha384-bvD409mDuUb3qOLzx58r8SMBsbCTveC2co99WsR+5RX4Tm9IowNM/j3b2tuhx7jw", + "protoc-22.5-osx-universal_binary.zip": "sha384-hDbjYyN52oiIf4j/rMlX2V4r1qagQsoH5Rxsa5S/k5EJDn0th+PHHc/wZVcRMEWd", + "protoc-22.5-osx-x86_64.zip": "sha384-QIsuPiPcfEbLHj0opWR2aJwa/cZO8Zi0a7pXw7fNhLnzzOqGT9NwAGOz1MaDvLNy", + "protoc-22.5-win32.zip": "sha384-zxwlshvYwIYCKAmOczZ3CmY0gMyfi0VUKz/5p0m4U0Illes0g7SAAnRGdpK3zpx0", + "protoc-22.5-win64.zip": "sha384-0jn4kTJ9ueIYdsQo4gwQt0SwVrTF+ROZoyW0WE9f+GSXweLIvfRyxssdCo0Rp1RF", + }, + "v21.7": { + "protoc-21.7-linux-aarch_64.zip": "sha384-NECLy68qRTw4Yo8n6xUZTUbkil0FW5dGjkIUe95r2OOW9emMqMuwWz7p/C+nAfRF", + "protoc-21.7-linux-ppcle_64.zip": "sha384-FCxc5RKUj24BialSjU/UV3ktTebVhhaRNSCPHapkwMBoL8TVuHqpKaHBSTARfNxl", + "protoc-21.7-linux-s390_64.zip": "sha384-OmOg3AuMUA0D5DZmQlamiy48Yzt3IhwioJ3tezC6gAPZg79IYXJhUvc38d/Q7XD/", + "protoc-21.7-linux-x86_32.zip": "sha384-4Z1xX+VE80cOwYGgCopv7GhBQYlvNp9VC78MxLirIoXpFH3TnP8Wy6Z/oCLVwro8", + "protoc-21.7-linux-x86_64.zip": "sha384-ydJtP/R5m7V5l4E9UoAOfWElwty9PSxjWf2reiRMjT/pdA7xHcWU/nAQe6afEVxI", + "protoc-21.7-osx-aarch_64.zip": "sha384-q+E9Xjojjb9f/dhbhXcE+f2ZIuDSmTo0YpRubTQfixzPNQK3C+1VLJzCUwWwU+2C", + "protoc-21.7-osx-universal_binary.zip": "sha384-Rtwb9mDSFKipZV8lEGBfRvLxD7eG7N4hcFCCzgw1lukOPtY+h89b/OlKrYsEaHyS", + "protoc-21.7-osx-x86_64.zip": "sha384-13SIOaU0KOzF10cqkVJ49eaYRip/9iSj98hcvmDjE7lsJfioqXVfWuVPdXwwtrTc", + "protoc-21.7-win32.zip": "sha384-l8UV/UcgL3u18WNgTDxMS45ZDMfqnsAqRmnP9CPWpFw8wR31mgPI3Oaj+KxsMjva", + "protoc-21.7-win64.zip": "sha384-NLDFO3FAsbFziXo+d3vXMnVwQ3CEyP1tVEwgl5CNR1QpPUF3jRr403PsqN4gblE3", + }, +} diff --git a/protoc/repositories.bzl b/protoc/repositories.bzl new file mode 100644 index 0000000..52d78ed --- /dev/null +++ b/protoc/repositories.bzl @@ -0,0 +1,36 @@ +"""Declare runtime dependencies + +These are needed for local dev, and users must install them as well. +See https://docs.bazel.build/versions/main/skylark/deploying.html#dependencies +""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") + +def http_archive(name, **kwargs): + maybe(_http_archive, name = name, **kwargs) + +# WARNING: any changes in this function may be BREAKING CHANGES for users +# because we'll fetch a dependency which may be different from one that +# they were previously fetching later in their WORKSPACE setup, and now +# ours took precedence. Such breakages are challenging for users, so any +# changes in this function should be marked as BREAKING in the commit message +# and released only in semver majors. +# This is all fixed by bzlmod, so we just tolerate it for now. +def rules_protoc_dependencies(): + # The minimal version of bazel_skylib we require + http_archive( + name = "bazel_skylib", + sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94", + urls = [ + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", + ], + ) + + http_archive( + name = "rules_proto", + sha256 = "71fdbed00a0709521ad212058c60d13997b922a5d01dbfd997f0d57d689e7b67", + strip_prefix = "rules_proto-6.0.0-rc2", + url = "https://github.com/bazelbuild/rules_proto/releases/download/6.0.0-rc2/rules_proto-6.0.0-rc2.tar.gz", + ) diff --git a/protoc/toolchain.bzl b/protoc/toolchain.bzl new file mode 100644 index 0000000..47a6855 --- /dev/null +++ b/protoc/toolchain.bzl @@ -0,0 +1,35 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Toolchains required to use rules_proto.""" + +load("//protoc/private:prebuilt_protoc_toolchain.bzl", "prebuilt_protoc_repo") +load("//protoc/private:protoc_toolchains.bzl", "protoc_toolchains_repo") +load("//protoc/private:versions.bzl", "PROTOC_PLATFORMS") + +def protoc_toolchains(name, version, register = True): + """A utility method to load all Protobuf toolchains. + + Args: + name: base name for generated repositories, allowing multiple protoc versions. + version: a release tag from protocolbuffers/protobuf, e.g. 'v25.3' + register: whether to register the resulting toolchains. + Should be True for WORKSPACE and False under bzlmod. + """ + + for platform in PROTOC_PLATFORMS.keys(): + prebuilt_protoc_repo(name = ".".join([name, platform]), platform = platform, version = version) + protoc_toolchains_repo(name = name, user_repository_name = name) + if register: + native.register_toolchains("@{}//:all".format(name))