Make `@rules_java//java:http_jar.bzl` compatible with Bazel 6 We achieve this by using a redirect via the `compatibility_proxy` repo, which either invokes the rules-java-local http_jar in java/bazel/http_jar (for Bazel 8), or falls back to the one in `@bazel_tools` (for Bazel < 8). This also allows dropping the workaround in the integration test `WORKSPACE` setup, which proves this is WAI :) PiperOrigin-RevId: 703053887 Change-Id: Ifb7fbb901678f2e37afda10a632348776aa77b53
diff --git a/java/BUILD b/java/BUILD index 2074c38..a436327 100644 --- a/java/BUILD +++ b/java/BUILD
@@ -69,7 +69,7 @@ name = "http_jar_bzl", srcs = ["http_jar.bzl"], visibility = ["//visibility:public"], - deps = ["@bazel_tools//tools:bzl_srcs"], + deps = ["@compatibility_proxy//:proxy_bzl"], ) filegroup(
diff --git a/java/bazel/BUILD.bazel b/java/bazel/BUILD.bazel index b5ddea9..2c26d11 100644 --- a/java/bazel/BUILD.bazel +++ b/java/bazel/BUILD.bazel
@@ -11,6 +11,8 @@ # 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. + +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load(":repositories_util.bzl", "FLAT_CONFIGS") # build this to generate _REMOTE_JDK_CONFIGS_LIST in repositories.bzl @@ -54,6 +56,13 @@ visibility = ["//visibility:private"], ) +bzl_library( + name = "http_jar_bzl", + srcs = ["http_jar.bzl"], + visibility = ["@compatibility_proxy//:__pkg__"], + deps = ["@bazel_tools//tools:bzl_srcs"], +) + filegroup( name = "for_bazel_tests", testonly = 1,
diff --git a/java/bazel/http_jar.bzl b/java/bazel/http_jar.bzl new file mode 100644 index 0000000..6ba729c --- /dev/null +++ b/java/bazel/http_jar.bzl
@@ -0,0 +1,178 @@ +"""The http_jar repo rule, for downloading jars over HTTP.""" + +load("@bazel_tools//tools/build_defs/repo:cache.bzl", "CANONICAL_ID_DOC", "DEFAULT_CANONICAL_ID_ENV", "get_default_canonical_id") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "get_auth", "update_attrs") + +_URL_DOC = """A URL to the jar that will be made available to Bazel. + +This must be a file, http or https URL. Redirections are followed. +Authentication is not supported. + +More flexibility can be achieved by the urls parameter that allows +to specify alternative URLs to fetch from.""" + +_URLS_DOC = """A list of URLs to the jar that will be made available to Bazel. + +Each entry must be a file, http or https URL. Redirections are followed. +Authentication is not supported. + +URLs are tried in order until one succeeds, so you should list local mirrors first. +If all downloads fail, the rule will fail.""" + +_AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns. + +If a URL's host name is present in this dict the value will be used as a pattern when +generating the authorization header for the http request. This enables the use of custom +authorization schemes used in a lot of common cloud storage providers. + +The pattern currently supports 2 tokens: <code><login></code> and +<code><password></code>, which are replaced with their equivalent value +in the netrc file for the same host name. After formatting, the result is set +as the value for the <code>Authorization</code> field of the HTTP request. + +Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token: + +<pre> +auth_patterns = { + "storage.cloudprovider.com": "Bearer <password>" +} +</pre> + +netrc: + +<pre> +machine storage.cloudprovider.com + password RANDOM-TOKEN +</pre> + +The final HTTP request would have the following header: + +<pre> +Authorization: Bearer RANDOM-TOKEN +</pre> +""" + +def _get_source_urls(ctx): + """Returns source urls provided via the url, urls attributes. + + Also checks that at least one url is provided.""" + if not ctx.attr.url and not ctx.attr.urls: + fail("At least one of url and urls must be provided") + + source_urls = [] + if ctx.attr.urls: + source_urls = ctx.attr.urls + if ctx.attr.url: + source_urls = [ctx.attr.url] + source_urls + return source_urls + +def _update_integrity_attr(ctx, attrs, download_info): + # We don't need to override the integrity attribute if sha256 is already specified. + integrity_override = {} if ctx.attr.sha256 else {"integrity": download_info.integrity} + return update_attrs(ctx.attr, attrs.keys(), integrity_override) + +_HTTP_JAR_BUILD = """\ +load("{java_import_bzl}", "java_import") + +java_import( + name = 'jar', + jars = ["{file_name}"], + visibility = ['//visibility:public'], +) + +filegroup( + name = 'file', + srcs = ["{file_name}"], + visibility = ['//visibility:public'], +) + +""" + +def _http_jar_impl(ctx): + """Implementation of the http_jar rule.""" + source_urls = _get_source_urls(ctx) + downloaded_file_name = ctx.attr.downloaded_file_name + download_info = ctx.download( + source_urls, + "jar/" + downloaded_file_name, + ctx.attr.sha256, + canonical_id = ctx.attr.canonical_id or get_default_canonical_id(ctx, source_urls), + auth = get_auth(ctx, source_urls), + integrity = ctx.attr.integrity, + ) + ctx.file("jar/BUILD", _HTTP_JAR_BUILD.format( + java_import_bzl = str(Label("//java:java_import.bzl")), + file_name = downloaded_file_name, + )) + + return _update_integrity_attr(ctx, _http_jar_attrs, download_info) + +_http_jar_attrs = { + "sha256": attr.string( + doc = """The expected SHA-256 of the jar downloaded. + +This must match the SHA-256 of the jar downloaded. _It is a security risk +to omit the SHA-256 as remote files can change._ At best omitting this +field will make your build non-hermetic. It is optional to make development +easier but either this attribute or `integrity` should be set before shipping.""", + ), + "integrity": attr.string( + doc = """Expected checksum in Subresource Integrity format of the jar downloaded. + +This must match the checksum of the file downloaded. _It is a security risk +to omit the checksum as remote files can change._ At best omitting this +field will make your build non-hermetic. It is optional to make development +easier but either this attribute or `sha256` should be set before shipping.""", + ), + "canonical_id": attr.string( + doc = CANONICAL_ID_DOC, + ), + "url": attr.string(doc = _URL_DOC + "\n\nThe URL must end in `.jar`."), + "urls": attr.string_list(doc = _URLS_DOC + "\n\nAll URLs must end in `.jar`."), + "netrc": attr.string( + doc = "Location of the .netrc file to use for authentication", + ), + "auth_patterns": attr.string_dict( + doc = _AUTH_PATTERN_DOC, + ), + "downloaded_file_name": attr.string( + default = "downloaded.jar", + doc = "Filename assigned to the jar downloaded", + ), +} + +http_jar = repository_rule( + implementation = _http_jar_impl, + attrs = _http_jar_attrs, + environ = [DEFAULT_CANONICAL_ID_ENV], + doc = + """Downloads a jar from a URL and makes it available as java_import + +Downloaded files must have a .jar extension. + +Examples: + Suppose the current repository contains the source code for a chat program, rooted at the + directory `~/chat-app`. It needs to depend on an SSL library which is available from + `http://example.com/openssl-0.2.jar`. + + Targets in the `~/chat-app` repository can depend on this target if the following lines are + added to `~/chat-app/MODULE.bazel`: + + ```python + http_jar = use_repo_rule("@rules_java//java:http_jar.bzl", "http_jar") + + http_jar( + name = "my_ssl", + url = "http://example.com/openssl-0.2.jar", + sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + ) + ``` + + Targets would specify `@my_ssl//jar` as a dependency to depend on this jar. + + You may also reference files on the current system (localhost) by using "file:///path/to/file" + if you are on Unix-based systems. If you're on Windows, use "file:///c:/path/to/file". In both + examples, note the three slashes (`/`) -- the first two slashes belong to `file://` and the third + one belongs to the absolute path to the file. +""", +)
diff --git a/java/http_jar.bzl b/java/http_jar.bzl index 8865482..ed3c331 100644 --- a/java/http_jar.bzl +++ b/java/http_jar.bzl
@@ -22,179 +22,6 @@ ``` """ -load("@bazel_tools//tools/build_defs/repo:cache.bzl", "CANONICAL_ID_DOC", "DEFAULT_CANONICAL_ID_ENV", "get_default_canonical_id") -load("@bazel_tools//tools/build_defs/repo:utils.bzl", "get_auth", "update_attrs") +load("@compatibility_proxy//:proxy.bzl", _http_jar = "http_jar") -_URL_DOC = """A URL to the jar that will be made available to Bazel. - -This must be a file, http or https URL. Redirections are followed. -Authentication is not supported. - -More flexibility can be achieved by the urls parameter that allows -to specify alternative URLs to fetch from.""" - -_URLS_DOC = """A list of URLs to the jar that will be made available to Bazel. - -Each entry must be a file, http or https URL. Redirections are followed. -Authentication is not supported. - -URLs are tried in order until one succeeds, so you should list local mirrors first. -If all downloads fail, the rule will fail.""" - -_AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns. - -If a URL's host name is present in this dict the value will be used as a pattern when -generating the authorization header for the http request. This enables the use of custom -authorization schemes used in a lot of common cloud storage providers. - -The pattern currently supports 2 tokens: <code><login></code> and -<code><password></code>, which are replaced with their equivalent value -in the netrc file for the same host name. After formatting, the result is set -as the value for the <code>Authorization</code> field of the HTTP request. - -Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token: - -<pre> -auth_patterns = { - "storage.cloudprovider.com": "Bearer <password>" -} -</pre> - -netrc: - -<pre> -machine storage.cloudprovider.com - password RANDOM-TOKEN -</pre> - -The final HTTP request would have the following header: - -<pre> -Authorization: Bearer RANDOM-TOKEN -</pre> -""" - -def _get_source_urls(ctx): - """Returns source urls provided via the url, urls attributes. - - Also checks that at least one url is provided.""" - if not ctx.attr.url and not ctx.attr.urls: - fail("At least one of url and urls must be provided") - - source_urls = [] - if ctx.attr.urls: - source_urls = ctx.attr.urls - if ctx.attr.url: - source_urls = [ctx.attr.url] + source_urls - return source_urls - -def _update_integrity_attr(ctx, attrs, download_info): - # We don't need to override the integrity attribute if sha256 is already specified. - integrity_override = {} if ctx.attr.sha256 else {"integrity": download_info.integrity} - return update_attrs(ctx.attr, attrs.keys(), integrity_override) - -_HTTP_JAR_BUILD = """\ -load("{java_import_bzl}", "java_import") - -java_import( - name = 'jar', - jars = ["{file_name}"], - visibility = ['//visibility:public'], -) - -filegroup( - name = 'file', - srcs = ["{file_name}"], - visibility = ['//visibility:public'], -) - -""" - -def _http_jar_impl(ctx): - """Implementation of the http_jar rule.""" - source_urls = _get_source_urls(ctx) - downloaded_file_name = ctx.attr.downloaded_file_name - download_info = ctx.download( - source_urls, - "jar/" + downloaded_file_name, - ctx.attr.sha256, - canonical_id = ctx.attr.canonical_id or get_default_canonical_id(ctx, source_urls), - auth = get_auth(ctx, source_urls), - integrity = ctx.attr.integrity, - ) - ctx.file("jar/BUILD", _HTTP_JAR_BUILD.format( - java_import_bzl = str(Label("//java:java_import.bzl")), - file_name = downloaded_file_name, - )) - - return _update_integrity_attr(ctx, _http_jar_attrs, download_info) - -_http_jar_attrs = { - "sha256": attr.string( - doc = """The expected SHA-256 of the jar downloaded. - -This must match the SHA-256 of the jar downloaded. _It is a security risk -to omit the SHA-256 as remote files can change._ At best omitting this -field will make your build non-hermetic. It is optional to make development -easier but either this attribute or `integrity` should be set before shipping.""", - ), - "integrity": attr.string( - doc = """Expected checksum in Subresource Integrity format of the jar downloaded. - -This must match the checksum of the file downloaded. _It is a security risk -to omit the checksum as remote files can change._ At best omitting this -field will make your build non-hermetic. It is optional to make development -easier but either this attribute or `sha256` should be set before shipping.""", - ), - "canonical_id": attr.string( - doc = CANONICAL_ID_DOC, - ), - "url": attr.string(doc = _URL_DOC + "\n\nThe URL must end in `.jar`."), - "urls": attr.string_list(doc = _URLS_DOC + "\n\nAll URLs must end in `.jar`."), - "netrc": attr.string( - doc = "Location of the .netrc file to use for authentication", - ), - "auth_patterns": attr.string_dict( - doc = _AUTH_PATTERN_DOC, - ), - "downloaded_file_name": attr.string( - default = "downloaded.jar", - doc = "Filename assigned to the jar downloaded", - ), -} - -http_jar = repository_rule( - implementation = _http_jar_impl, - attrs = _http_jar_attrs, - environ = [DEFAULT_CANONICAL_ID_ENV], - doc = - """Downloads a jar from a URL and makes it available as java_import - -Downloaded files must have a .jar extension. - -Examples: - Suppose the current repository contains the source code for a chat program, rooted at the - directory `~/chat-app`. It needs to depend on an SSL library which is available from - `http://example.com/openssl-0.2.jar`. - - Targets in the `~/chat-app` repository can depend on this target if the following lines are - added to `~/chat-app/MODULE.bazel`: - - ```python - http_jar = use_repo_rule("@rules_java//java:http_jar.bzl", "http_jar") - - http_jar( - name = "my_ssl", - url = "http://example.com/openssl-0.2.jar", - sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - ) - ``` - - Targets would specify `@my_ssl//jar` as a dependency to depend on this jar. - - You may also reference files on the current system (localhost) by using "file:///path/to/file" - if you are on Unix-based systems. If you're on Windows, use "file:///c:/path/to/file". In both - examples, note the three slashes (`/`) -- the first two slashes belong to `file://` and the third - one belongs to the absolute path to the file. -""", -) +http_jar = _http_jar
diff --git a/java/rules_java_deps.bzl b/java/rules_java_deps.bzl index 9e7fd80..98a2907 100644 --- a/java/rules_java_deps.bzl +++ b/java/rules_java_deps.bzl
@@ -19,7 +19,7 @@ "@rules_java//java/bazel/rules", "@rules_java//java/common/rules:toolchain_rules", "@rules_java//java/private:internals", - "@rules_java//java:http_jar_bzl", + "@rules_java//java/bazel:http_jar_bzl", ], visibility = ["//visibility:public"] ) @@ -33,13 +33,13 @@ load("@rules_java//java/bazel/rules:bazel_java_library.bzl", _java_library = "java_library") load("@rules_java//java/bazel/rules:bazel_java_plugin.bzl", _java_plugin = "java_plugin") load("@rules_java//java/bazel/rules:bazel_java_test.bzl", _java_test = "java_test") +load("@rules_java//java/bazel:http_jar.bzl", _http_jar = "http_jar") load("@rules_java//java/common/rules:java_package_configuration.bzl", _java_package_configuration = "java_package_configuration") load("@rules_java//java/common/rules:java_runtime.bzl", _java_runtime = "java_runtime") load("@rules_java//java/common/rules:java_toolchain.bzl", _java_toolchain = "java_toolchain") load("@rules_java//java/private:java_common.bzl", _java_common = "java_common") load("@rules_java//java/private:java_common_internal.bzl", _java_common_internal_compile = "compile") load("@rules_java//java/private:java_info.bzl", _JavaInfo = "JavaInfo", _JavaPluginInfo = "JavaPluginInfo", _java_info_internal_merge = "merge") -load("@rules_java//java:http_jar.bzl", _http_jar = "http_jar") java_binary = _java_binary java_import = _java_import
diff --git a/test/repo/WORKSPACE b/test/repo/WORKSPACE index 1a135b6..872e89a 100644 --- a/test/repo/WORKSPACE +++ b/test/repo/WORKSPACE
@@ -19,7 +19,7 @@ rules_java_toolchains() -load("@compatibility_proxy//:proxy.bzl", "http_jar") +load("@rules_java//java:http_jar.bzl", "http_jar") http_jar( name = "my_jar",