From ec686efef310d19e4a019eeb297a9f3b264d6c58 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Mon, 14 Oct 2024 23:36:37 +0200 Subject: [PATCH] Fall back to native rules if possible (#10) Provides compatibility with Bazel versions before 7.4.0. Also requires adding `bazel_skylib` to the dependency macro. Fixes #9 --- .bazelci/presubmit.yml | 12 +++- shell/private/BUILD | 7 ++- shell/private/sh_binary.bzl | 22 +++++++ shell/private/sh_library.bzl | 118 +++++++++++++++++++++++++++++++++++ shell/private/sh_test.bzl | 39 ++++++++++++ shell/repositories.bzl | 12 +++- shell/sh_binary.bzl | 4 +- shell/sh_library.bzl | 102 +----------------------------- shell/sh_test.bzl | 21 +------ 9 files changed, 213 insertions(+), 124 deletions(-) create mode 100644 shell/private/sh_binary.bzl create mode 100644 shell/private/sh_library.bzl create mode 100644 shell/private/sh_test.bzl diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 4ca63d2..d499c80 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -5,8 +5,7 @@ matrix: platform: - ubuntu2004 - macos - # TODO: Enable Windows once the private API it allowlists rules_shell. - # - windows + - windows tasks: test_module_bzlmod: @@ -39,6 +38,15 @@ tasks: - "--enable_workspace" test_targets: - "//..." + test_module_workspace_bazel6: + name: "Test module (Bazel 6.5.0, WORKSPACE)" + working_directory: "tests/bcr" + bazel: 6.5.0 + platform: ${{ platform }} + build_targets: + - "//..." + test_targets: + - "//..." test_module_head: name: "Test module (Bazel@HEAD, Bzlmod)" working_directory: "tests/bcr" diff --git a/shell/private/BUILD b/shell/private/BUILD index 59632c1..d0eebed 100644 --- a/shell/private/BUILD +++ b/shell/private/BUILD @@ -2,6 +2,11 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") bzl_library( name = "private_bzl", - srcs = ["sh_executable.bzl"], + srcs = [ + "sh_binary.bzl", + "sh_executable.bzl", + "sh_library.bzl", + "sh_test.bzl", + ], visibility = ["//shell:__pkg__"], ) diff --git a/shell/private/sh_binary.bzl b/shell/private/sh_binary.bzl new file mode 100644 index 0000000..eec109a --- /dev/null +++ b/shell/private/sh_binary.bzl @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +"""sh_binary rule definition.""" + +load(":sh_executable.bzl", "make_sh_executable_rule") + +# For doc generation only. +visibility("public") + +sh_binary = make_sh_executable_rule(executable = True) diff --git a/shell/private/sh_library.bzl b/shell/private/sh_library.bzl new file mode 100644 index 0000000..2f3613c --- /dev/null +++ b/shell/private/sh_library.bzl @@ -0,0 +1,118 @@ +# Copyright 2024 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. + +"""sh_library rule definition.""" + +# For doc generation only. +visibility("public") + +def _sh_library_impl(ctx): + transitive_files = [] + for target in ctx.attr.srcs: + transitive_files.append(target[DefaultInfo].files) + for target in ctx.attr.deps: + transitive_files.append(target[DefaultInfo].files) + for target in ctx.attr.data: + transitive_files.append(target[DefaultInfo].files) + files = depset(transitive = transitive_files) + + runfiles = ctx.runfiles(transitive_files = files, collect_default = True) + + instrumented_files_info = coverage_common.instrumented_files_info( + ctx, + source_attributes = ["srcs"], + dependency_attributes = ["deps", "data"], + ) + + return [ + DefaultInfo( + files = files, + runfiles = runfiles, + ), + instrumented_files_info, + ] + +sh_library = rule( + _sh_library_impl, + doc = """ +

+ The main use for this rule is to aggregate together a logical + "library" consisting of related scripts—programs in an + interpreted language that does not require compilation or linking, + such as the Bourne shell—and any data those programs need at + run-time. Such "libraries" can then be used from + the data attribute of one or + more sh_binary rules. +

+ +

+ You can use the filegroup rule to aggregate data + files. +

+ +

+ In interpreted programming languages, there's not always a clear + distinction between "code" and "data": after all, the program is + just "data" from the interpreter's point of view. For this reason + this rule has three attributes which are all essentially equivalent: + srcs, deps and data. + The current implementation does not distinguish between the elements of these lists. + All three attributes accept rules, source files and generated files. + It is however good practice to use the attributes for their usual purpose (as with other rules). +

+ +

Examples

+ +
+sh_library(
+    name = "foo",
+    data = [
+        ":foo_service_script",  # an sh_binary with srcs
+        ":deploy_foo",  # another sh_binary with srcs
+    ],
+)
+
+""", + attrs = { + "srcs": attr.label_list( + allow_files = True, + doc = """ +The list of input files. +

+ This attribute should be used to list shell script source files that belong to + this library. Scripts can load other scripts using the shell's source + or . command. +

+""", + ), + "data": attr.label_list( + allow_files = True, + flags = ["SKIP_CONSTRAINTS_OVERRIDE"], + ), + "deps": attr.label_list( + allow_rules = ["sh_library"], + doc = """ +The list of "library" targets to be aggregated into this target. +See general comments about deps +at Typical attributes defined by +most build rules. +

+ This attribute should be used to list other sh_library rules that provide + interpreted program source code depended on by the code in srcs. The files + provided by these rules will be present among the runfiles of this target. +

+""", + ), + }, +) diff --git a/shell/private/sh_test.bzl b/shell/private/sh_test.bzl new file mode 100644 index 0000000..c12622a --- /dev/null +++ b/shell/private/sh_test.bzl @@ -0,0 +1,39 @@ +# Copyright 2024 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. + +"""sh_test rule definition.""" + +load(":sh_executable.bzl", "make_sh_executable_rule") + +# For doc generation only. +visibility("public") + +sh_test = make_sh_executable_rule( + test = True, + fragments = ["coverage"], + extra_attrs = { + "_lcov_merger": attr.label( + cfg = "exec", + default = configuration_field(fragment = "coverage", name = "output_generator"), + executable = True, + ), + # Add the script as an attribute in order for sh_test to output code coverage results for + # code covered by CC binaries invocations. + "_collect_cc_coverage": attr.label( + cfg = "exec", + default = "@bazel_tools//tools/test:collect_cc_coverage", + executable = True, + ), + }, +) diff --git a/shell/repositories.bzl b/shell/repositories.bzl index 81b1cc0..62a0ff1 100644 --- a/shell/repositories.bzl +++ b/shell/repositories.bzl @@ -14,6 +14,8 @@ """WORKSPACE dependency macros for the shell rules.""" +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") load("//shell/private/repositories:sh_config.bzl", "sh_config") visibility("public") @@ -21,7 +23,15 @@ visibility("public") # buildifier: disable=unnamed-macro def rules_shell_dependencies(): """Instantiates repositories required by rules_shell.""" - pass + maybe( + http_archive, + name = "bazel_skylib", + sha256 = "bc283cdfcd526a52c3201279cda4bc298652efa898b10b4db0837dc51652756f", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", + ], + ) # buildifier: disable=unnamed-macro def rules_shell_toolchains(): diff --git a/shell/sh_binary.bzl b/shell/sh_binary.bzl index 5e3a422..9e4a30d 100644 --- a/shell/sh_binary.bzl +++ b/shell/sh_binary.bzl @@ -14,8 +14,8 @@ """sh_binary rule definition.""" -load("//shell/private:sh_executable.bzl", "make_sh_executable_rule") +load("//shell/private:sh_binary.bzl", _sh_binary = "sh_binary") visibility("public") -sh_binary = make_sh_executable_rule(executable = True) +sh_binary = getattr(native, "sh_binary", _sh_binary) diff --git a/shell/sh_library.bzl b/shell/sh_library.bzl index fd6aef9..b51aeaa 100644 --- a/shell/sh_library.bzl +++ b/shell/sh_library.bzl @@ -14,104 +14,8 @@ """sh_library rule definition.""" -visibility("public") - -def _sh_library_impl(ctx): - transitive_files = [] - for target in ctx.attr.srcs: - transitive_files.append(target[DefaultInfo].files) - for target in ctx.attr.deps: - transitive_files.append(target[DefaultInfo].files) - for target in ctx.attr.data: - transitive_files.append(target[DefaultInfo].files) - files = depset(transitive = transitive_files) - - runfiles = ctx.runfiles(transitive_files = files, collect_default = True) - - instrumented_files_info = coverage_common.instrumented_files_info( - ctx, - source_attributes = ["srcs"], - dependency_attributes = ["deps", "data"], - ) - - return [ - DefaultInfo( - files = files, - runfiles = runfiles, - ), - instrumented_files_info, - ] +load("//shell/private:sh_library.bzl", _sh_library = "sh_library") -sh_library = rule( - _sh_library_impl, - doc = """ -

- The main use for this rule is to aggregate together a logical - "library" consisting of related scripts—programs in an - interpreted language that does not require compilation or linking, - such as the Bourne shell—and any data those programs need at - run-time. Such "libraries" can then be used from - the data attribute of one or - more sh_binary rules. -

- -

- You can use the filegroup rule to aggregate data - files. -

- -

- In interpreted programming languages, there's not always a clear - distinction between "code" and "data": after all, the program is - just "data" from the interpreter's point of view. For this reason - this rule has three attributes which are all essentially equivalent: - srcs, deps and data. - The current implementation does not distinguish between the elements of these lists. - All three attributes accept rules, source files and generated files. - It is however good practice to use the attributes for their usual purpose (as with other rules). -

- -

Examples

+visibility("public") -
-sh_library(
-    name = "foo",
-    data = [
-        ":foo_service_script",  # an sh_binary with srcs
-        ":deploy_foo",  # another sh_binary with srcs
-    ],
-)
-
-""", - attrs = { - "srcs": attr.label_list( - allow_files = True, - doc = """ -The list of input files. -

- This attribute should be used to list shell script source files that belong to - this library. Scripts can load other scripts using the shell's source - or . command. -

-""", - ), - "data": attr.label_list( - allow_files = True, - flags = ["SKIP_CONSTRAINTS_OVERRIDE"], - ), - "deps": attr.label_list( - allow_rules = ["sh_library"], - doc = """ -The list of "library" targets to be aggregated into this target. -See general comments about deps -at Typical attributes defined by -most build rules. -

- This attribute should be used to list other sh_library rules that provide - interpreted program source code depended on by the code in srcs. The files - provided by these rules will be present among the runfiles of this target. -

-""", - ), - }, -) +sh_library = getattr(native, "sh_library", _sh_library) diff --git a/shell/sh_test.bzl b/shell/sh_test.bzl index ea5b5a9..272d193 100644 --- a/shell/sh_test.bzl +++ b/shell/sh_test.bzl @@ -14,25 +14,8 @@ """sh_test rule definition.""" -load("//shell/private:sh_executable.bzl", "make_sh_executable_rule") +load("//shell/private:sh_test.bzl", _sh_test = "sh_test") visibility("public") -sh_test = make_sh_executable_rule( - test = True, - fragments = ["coverage"], - extra_attrs = { - "_lcov_merger": attr.label( - cfg = "exec", - default = configuration_field(fragment = "coverage", name = "output_generator"), - executable = True, - ), - # Add the script as an attribute in order for sh_test to output code coverage results for - # code covered by CC binaries invocations. - "_collect_cc_coverage": attr.label( - cfg = "exec", - default = "@bazel_tools//tools/test:collect_cc_coverage", - executable = True, - ), - }, -) +sh_test = getattr(native, "sh_test", _sh_test)