From e80bb2c02752a71042b9898cac470980cfcc7016 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Fri, 1 Jul 2022 19:09:33 +0200 Subject: [PATCH] Basic bzlmod setup (#3047) * Replace Label(...).workspace_name with explicit repo name With the repository mappings used by bzlmod, the Label(...).workspace_name construct always returns the canonical, post-repo mapping repo name, which can't be used to construct a valid label. Until https://github.com/bazelbuild/bazel/issues/15593 has been fixed, we have to hardcode the non-canonical repo name here. * Remove remaining repo-absolute labels in load statements * Refactor repository macros for bzlmod The existing repository macros can be reused for the module setup with only very few fully backwards compatible changes: * The macros wrapping the Go SDK repository rules should make toolchain registration optional. With bzlmod, toolchains are registered with the toolchains_to_register attribute of the module function instead. * The repository macro should not use _maybe with bzlmod. Instead, repos loaded by module extensions are given globally unique internal names automatically. * Add basic bzlmod setup This commit adds a MODULE.bazel that makes rules_go usable as a bzlmod module for basic use cases. The new module definition is verified by a test module that will be used in the presubmit tests of the Bazel Central Registry (BCR). The following features require more thought and/or work and are not yet supported: * SDK rules other than go_host_sdk and go_download_sdk. * non-no-op nogo * go_proto_library --- .bazelci/presubmit.yml | 14 ++++++++++ .bazelignore | 1 + .gitignore | 1 + BUILD.bazel | 12 ++++----- MODULE.bazel | 23 ++++++++++++++++ go/extensions.bzl | 3 +++ go/private/extensions.bzl | 53 +++++++++++++++++++++++++++++++++++++ go/private/repositories.bzl | 34 +++++++++++++++--------- go/private/sdk.bzl | 22 ++++++++------- tests/bcr/.bazelrc | 1 + tests/bcr/.bazelversion | 1 + tests/bcr/BUILD.bazel | 19 +++++++++++++ tests/bcr/MODULE.bazel | 15 +++++++++++ tests/bcr/WORKSPACE | 0 tests/bcr/lib.go | 5 ++++ tests/bcr/main.go | 11 ++++++++ tests/bcr/test.go | 11 ++++++++ 17 files changed, 198 insertions(+), 28 deletions(-) create mode 100644 .bazelignore create mode 100644 MODULE.bazel create mode 100644 go/extensions.bzl create mode 100644 go/private/extensions.bzl create mode 100644 tests/bcr/.bazelrc create mode 100644 tests/bcr/.bazelversion create mode 100644 tests/bcr/BUILD.bazel create mode 100644 tests/bcr/MODULE.bazel create mode 100644 tests/bcr/WORKSPACE create mode 100644 tests/bcr/lib.go create mode 100644 tests/bcr/main.go create mode 100644 tests/bcr/test.go diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 2c62debc75..0984956740 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -23,6 +23,20 @@ tasks: - "//..." test_targets: - "//..." + ubuntu2004_bcr_tests: + name: BCR test module + platform: ubuntu2004 + bazel: 6.0.0-pre.20220526.1 + working_directory: tests/bcr + build_flags: + - "--experimental_enable_bzlmod" + test_flags: + - "--experimental_enable_bzlmod" + build_targets: + - "//..." + - "@go_sdk//..." + test_targets: + - "//..." macos: shell_commands: - tests/core/cgo/generate_imported_dylib.sh diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 0000000000..23758d5ac9 --- /dev/null +++ b/.bazelignore @@ -0,0 +1 @@ +tests/bcr diff --git a/.gitignore b/.gitignore index 0f1e744f59..058e45bf49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /bazel-* /tests/core/cgo/libimported.* /tests/core/cgo/libversioned.* +/tests/bcr/bazel-* diff --git a/BUILD.bazel b/BUILD.bazel index 4c9cb5f912..2687c95b81 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,28 +1,28 @@ load( - "@io_bazel_rules_go//go/private/tools:lines_sorted_test.bzl", + "//go/private/tools:lines_sorted_test.bzl", "lines_sorted_test", ) load( - "@io_bazel_rules_go//go/private/rules:nogo.bzl", + "//go/private/rules:nogo.bzl", "nogo", ) load( - "@io_bazel_rules_go//go/private/rules:info.bzl", + "//go/private/rules:info.bzl", "go_info", ) load( - "@io_bazel_rules_go//go:def.bzl", + "//go:def.bzl", "TOOLS_NOGO", ) load( - "@io_bazel_rules_go//go/private:context.bzl", + "//go/private:context.bzl", "cgo_context_data", "cgo_context_data_proxy", "go_config", "go_context_data", ) load( - "@io_bazel_rules_go//go/private/rules:stdlib.bzl", + "//go/private/rules:stdlib.bzl", "stdlib", ) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000000..820be22d2c --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,23 @@ +module( + name = "io_bazel_rules_go", + version = "0.33.0", + compatibility_level = 0, + toolchains_to_register = [ + "@go_default_sdk//:all", + ], +) + +print("WARNING: The rules_go Bazel module is still highly experimental and subject to change at any time. Only use it to try out bzlmod for now.") + +bazel_dep(name = "bazel_skylib", version = "1.2.0") +bazel_dep(name = "platforms", version = "0.0.4") + +non_module_dependencies = use_extension("@io_bazel_rules_go//go/private:extensions.bzl", "non_module_dependencies") +use_repo( + non_module_dependencies, + "io_bazel_rules_nogo", +) + +go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk") +go_sdk.download(name = "go_default_sdk", version = "1.18.3") +use_repo(go_sdk, "go_default_sdk") diff --git a/go/extensions.bzl b/go/extensions.bzl new file mode 100644 index 0000000000..f7c86ada2a --- /dev/null +++ b/go/extensions.bzl @@ -0,0 +1,3 @@ +load("//go/private:extensions.bzl", _go_sdk = "go_sdk") + +go_sdk = _go_sdk diff --git a/go/private/extensions.bzl b/go/private/extensions.bzl new file mode 100644 index 0000000000..cb88521cf7 --- /dev/null +++ b/go/private/extensions.bzl @@ -0,0 +1,53 @@ +load("//go/private:sdk.bzl", "go_download_sdk", "go_host_sdk") +load("//go/private:repositories.bzl", "go_rules_dependencies") + +_download_tag = tag_class( + attrs = { + "name": attr.string(mandatory = True), + "goos": attr.string(), + "goarch": attr.string(), + "sdks": attr.string_list_dict(), + "urls": attr.string_list(default = ["https://dl.google.com/go/{}"]), + "version": attr.string(), + "strip_prefix": attr.string(default = "go"), + }, +) + +_host_tag = tag_class( + attrs = { + "name": attr.string(mandatory = True), + }, +) + +def _go_sdk_impl(ctx): + for mod in ctx.modules: + for download_tag in mod.tags.download: + go_download_sdk( + name = download_tag.name, + goos = download_tag.goos, + goarch = download_tag.goarch, + sdks = download_tag.sdks, + urls = download_tag.urls, + version = download_tag.version, + register_toolchains = False, + ) + for host_tag in mod.tags.host: + go_host_sdk( + name = host_tag.name, + register_toolchains = False, + ) + +go_sdk = module_extension( + implementation = _go_sdk_impl, + tag_classes = { + "download": _download_tag, + "host": _host_tag, + }, +) + +def _non_module_dependencies_impl(ctx): + go_rules_dependencies(force = True) + +non_module_dependencies = module_extension( + implementation = _non_module_dependencies_impl, +) diff --git a/go/private/repositories.bzl b/go/private/repositories.bzl index f2cbe12cbb..425baad0c7 100644 --- a/go/private/repositories.bzl +++ b/go/private/repositories.bzl @@ -20,7 +20,7 @@ load("//go/private:nogo.bzl", "DEFAULT_NOGO", "go_register_nogo") load("//proto:gogo.bzl", "gogo_special_proto") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -def go_rules_dependencies(): +def go_rules_dependencies(force = False): """Declares workspaces the Go rules depend on. Workspaces that use rules_go should call this. @@ -38,11 +38,16 @@ def go_rules_dependencies(): if getattr(native, "bazel_version", None): versions.check(MINIMUM_BAZEL_VERSION, bazel_version = native.bazel_version) + if force: + wrapper = _always + else: + wrapper = _maybe + # Needed by rules_go implementation and tests. # We can't call bazel_skylib_workspace from here. At the moment, it's only # used to register unittest toolchains, which rules_go does not need. # releaser:upgrade-dep bazelbuild bazel-skylib - _maybe( + wrapper( http_archive, name = "bazel_skylib", # 1.2.1, latest as of 2022-06-05 @@ -56,7 +61,7 @@ def go_rules_dependencies(): # Needed for nogo vet checks and go/packages. # releaser:upgrade-dep golang tools - _maybe( + wrapper( http_archive, name = "org_golang_x_tools", # v0.1.9, latest as of 2022-03-14 @@ -78,7 +83,7 @@ def go_rules_dependencies(): ) # releaser:upgrade-dep golang sys - _maybe( + wrapper( http_archive, name = "org_golang_x_sys", # master, as of 2022-06-05 @@ -97,7 +102,7 @@ def go_rules_dependencies(): # Needed by golang.org/x/tools/go/packages # releaser:upgrade-dep golang xerrors - _maybe( + wrapper( http_archive, name = "org_golang_x_xerrors", # master, as of 2022-06-05 @@ -132,7 +137,7 @@ def go_rules_dependencies(): # Go protobuf runtime library and utilities. # releaser:upgrade-dep protocolbuffers protobuf-go - _maybe( + wrapper( http_archive, name = "org_golang_google_protobuf", sha256 = "dc4339bd2011a230d81d5ec445361efeb78366f1d30a7757e8fbea3e7221080e", @@ -155,7 +160,7 @@ def go_rules_dependencies(): # We need to apply a patch to enable both go_proto_library and # go_library with pre-generated sources. # releaser:upgrade-dep golang protobuf - _maybe( + wrapper( http_archive, name = "com_github_golang_protobuf", # v1.5.2, latest as of 2022-06-05 @@ -175,7 +180,7 @@ def go_rules_dependencies(): # Extra protoc plugins and libraries. # Doesn't belong here, but low maintenance. # releaser:upgrade-dep mwitkow go-proto-validators - _maybe( + wrapper( http_archive, name = "com_github_mwitkow_go_proto_validators", # v0.3.2, latest as of 2022-06-05 @@ -189,7 +194,7 @@ def go_rules_dependencies(): ) # releaser:upgrade-dep gogo protobuf - _maybe( + wrapper( http_archive, name = "com_github_gogo_protobuf", # v1.3.2, latest as of 2022-06-05 @@ -206,7 +211,7 @@ def go_rules_dependencies(): patch_args = ["-p1"], ) - _maybe( + wrapper( gogo_special_proto, name = "gogo_special_proto", ) @@ -216,7 +221,7 @@ def go_rules_dependencies(): # Doesn't belong here, but it would be an annoying source of errors if # this weren't generated with -proto disable_global. # releaser:upgrade-dep googleapis go-genproto - _maybe( + wrapper( http_archive, name = "org_golang_google_genproto", # main, as of 2022-06-05 @@ -239,7 +244,7 @@ def go_rules_dependencies(): # here. Gazelle should resolve dependencies to com_google_googleapis # instead, and we should remove this. # releaser:upgrade-dep googleapis googleapis - _maybe( + wrapper( http_archive, name = "go_googleapis", # master, as of 2022-06-05 @@ -281,7 +286,7 @@ def go_rules_dependencies(): # This may be overridden by go_register_toolchains, but it's not mandatory # for users to call that function (they may declare their own @go_sdk and # register their own toolchains). - _maybe( + wrapper( go_register_nogo, name = "io_bazel_rules_nogo", nogo = DEFAULT_NOGO, @@ -290,3 +295,6 @@ def go_rules_dependencies(): def _maybe(repo_rule, name, **kwargs): if name not in native.existing_rules(): repo_rule(name = name, **kwargs) + +def _always(repo_rule, name, **kwargs): + repo_rule(name = name, **kwargs) diff --git a/go/private/sdk.bzl b/go/private/sdk.bzl index 73234112ed..ee53cb0b8a 100644 --- a/go/private/sdk.bzl +++ b/go/private/sdk.bzl @@ -38,9 +38,10 @@ _go_host_sdk = repository_rule( environ = ["GOROOT"], ) -def go_host_sdk(name, **kwargs): +def go_host_sdk(name, register_toolchains = True, **kwargs): _go_host_sdk(name = name, **kwargs) - _register_toolchains(name) + if register_toolchains: + _register_toolchains(name) def _go_download_sdk_impl(ctx): if not ctx.attr.goos and not ctx.attr.goarch: @@ -125,9 +126,10 @@ _go_download_sdk = repository_rule( }, ) -def go_download_sdk(name, **kwargs): +def go_download_sdk(name, register_toolchains = True, **kwargs): _go_download_sdk(name = name, **kwargs) - _register_toolchains(name) + if register_toolchains: + _register_toolchains(name) def _go_local_sdk_impl(ctx): goroot = ctx.attr.path @@ -142,9 +144,10 @@ _go_local_sdk = repository_rule( }, ) -def go_local_sdk(name, **kwargs): +def go_local_sdk(name, register_toolchains = True, **kwargs): _go_local_sdk(name = name, **kwargs) - _register_toolchains(name) + if register_toolchains: + _register_toolchains(name) def _go_wrap_sdk_impl(ctx): if not ctx.attr.root_file and not ctx.attr.root_files: @@ -178,9 +181,10 @@ _go_wrap_sdk = repository_rule( }, ) -def go_wrap_sdk(name, **kwargs): +def go_wrap_sdk(name, register_toolchains = True, **kwargs): _go_wrap_sdk(name = name, **kwargs) - _register_toolchains(name) + if register_toolchains: + _register_toolchains(name) def _register_toolchains(repo): labels = [ @@ -233,7 +237,7 @@ def _sdk_build_file(ctx, platform): "{goos}": goos, "{goarch}": goarch, "{exe}": ".exe" if goos == "windows" else "", - "{rules_go_repo_name}": Label("//go/private:BUILD.sdk.bazel").workspace_name, + "{rules_go_repo_name}": "io_bazel_rules_go", }, ) diff --git a/tests/bcr/.bazelrc b/tests/bcr/.bazelrc new file mode 100644 index 0000000000..e2ece0c386 --- /dev/null +++ b/tests/bcr/.bazelrc @@ -0,0 +1 @@ +build --experimental_enable_bzlmod diff --git a/tests/bcr/.bazelversion b/tests/bcr/.bazelversion new file mode 100644 index 0000000000..7229a26b2f --- /dev/null +++ b/tests/bcr/.bazelversion @@ -0,0 +1 @@ +6.0.0-pre.20220526.1 diff --git a/tests/bcr/BUILD.bazel b/tests/bcr/BUILD.bazel new file mode 100644 index 0000000000..5da66dfa88 --- /dev/null +++ b/tests/bcr/BUILD.bazel @@ -0,0 +1,19 @@ +load("@my_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") + +go_library( + name = "lib", + srcs = ["lib.go"], + importpath = "example.com/lib", +) + +go_binary( + name = "main", + srcs = ["main.go"], + deps = [":lib"], +) + +go_test( + name = "test", + srcs = ["test.go"], + embed = [":lib"], +) diff --git a/tests/bcr/MODULE.bazel b/tests/bcr/MODULE.bazel new file mode 100644 index 0000000000..9d7a1bd8df --- /dev/null +++ b/tests/bcr/MODULE.bazel @@ -0,0 +1,15 @@ +module( + name = "rules_go_bcr_tests", + # Test that the default SDK is registered by not registering one from the test module. +) + +bazel_dep(name = "io_bazel_rules_go", version = "", repo_name = "my_rules_go") +local_path_override( + module_name = "io_bazel_rules_go", + path = "../..", +) + +# Test that this correctly downloads the SDK by requesting it from the commandline (see presubmit.yml). +go_sdk = use_extension("@my_rules_go//go:extensions.bzl", "go_sdk") +go_sdk.download(name = "go_sdk", version = "1.17.5") +use_repo(go_sdk, "go_sdk") diff --git a/tests/bcr/WORKSPACE b/tests/bcr/WORKSPACE new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/bcr/lib.go b/tests/bcr/lib.go new file mode 100644 index 0000000000..d162287c3d --- /dev/null +++ b/tests/bcr/lib.go @@ -0,0 +1,5 @@ +package lib + +func Name() string { + return "bzlmod" +} diff --git a/tests/bcr/main.go b/tests/bcr/main.go new file mode 100644 index 0000000000..46c058ef1d --- /dev/null +++ b/tests/bcr/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "fmt" + + "example.com/lib" +) + +func main() { + fmt.Printf("Hello %s!", lib.Name()) +} diff --git a/tests/bcr/test.go b/tests/bcr/test.go new file mode 100644 index 0000000000..910c06beec --- /dev/null +++ b/tests/bcr/test.go @@ -0,0 +1,11 @@ +package lib + +import ( + "testing" +) + +func TestName(t *testing.T) { + if Name() != "bzlmod" { + t.Fail() + } +}