Skip to content

Commit fd9e39c

Browse files
hvadehrarules_java Copybara
authored andcommitted
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
1 parent 084b75a commit fd9e39c

6 files changed

Lines changed: 193 additions & 179 deletions

File tree

java/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ bzl_library(
6969
name = "http_jar_bzl",
7070
srcs = ["http_jar.bzl"],
7171
visibility = ["//visibility:public"],
72-
deps = ["@bazel_tools//tools:bzl_srcs"],
72+
deps = ["@compatibility_proxy//:proxy_bzl"],
7373
)
7474

7575
filegroup(

java/bazel/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
1416
load(":repositories_util.bzl", "FLAT_CONFIGS")
1517

1618
# build this to generate _REMOTE_JDK_CONFIGS_LIST in repositories.bzl
@@ -54,6 +56,13 @@ done <<< '{configs}' >> $@
5456
visibility = ["//visibility:private"],
5557
)
5658

59+
bzl_library(
60+
name = "http_jar_bzl",
61+
srcs = ["http_jar.bzl"],
62+
visibility = ["@compatibility_proxy//:__pkg__"],
63+
deps = ["@bazel_tools//tools:bzl_srcs"],
64+
)
65+
5766
filegroup(
5867
name = "for_bazel_tests",
5968
testonly = 1,

java/bazel/http_jar.bzl

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
"""The http_jar repo rule, for downloading jars over HTTP."""
2+
3+
load("@bazel_tools//tools/build_defs/repo:cache.bzl", "CANONICAL_ID_DOC", "DEFAULT_CANONICAL_ID_ENV", "get_default_canonical_id")
4+
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "get_auth", "update_attrs")
5+
6+
_URL_DOC = """A URL to the jar that will be made available to Bazel.
7+
8+
This must be a file, http or https URL. Redirections are followed.
9+
Authentication is not supported.
10+
11+
More flexibility can be achieved by the urls parameter that allows
12+
to specify alternative URLs to fetch from."""
13+
14+
_URLS_DOC = """A list of URLs to the jar that will be made available to Bazel.
15+
16+
Each entry must be a file, http or https URL. Redirections are followed.
17+
Authentication is not supported.
18+
19+
URLs are tried in order until one succeeds, so you should list local mirrors first.
20+
If all downloads fail, the rule will fail."""
21+
22+
_AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns.
23+
24+
If a URL's host name is present in this dict the value will be used as a pattern when
25+
generating the authorization header for the http request. This enables the use of custom
26+
authorization schemes used in a lot of common cloud storage providers.
27+
28+
The pattern currently supports 2 tokens: <code>&lt;login&gt;</code> and
29+
<code>&lt;password&gt;</code>, which are replaced with their equivalent value
30+
in the netrc file for the same host name. After formatting, the result is set
31+
as the value for the <code>Authorization</code> field of the HTTP request.
32+
33+
Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token:
34+
35+
<pre>
36+
auth_patterns = {
37+
"storage.cloudprovider.com": "Bearer &lt;password&gt;"
38+
}
39+
</pre>
40+
41+
netrc:
42+
43+
<pre>
44+
machine storage.cloudprovider.com
45+
password RANDOM-TOKEN
46+
</pre>
47+
48+
The final HTTP request would have the following header:
49+
50+
<pre>
51+
Authorization: Bearer RANDOM-TOKEN
52+
</pre>
53+
"""
54+
55+
def _get_source_urls(ctx):
56+
"""Returns source urls provided via the url, urls attributes.
57+
58+
Also checks that at least one url is provided."""
59+
if not ctx.attr.url and not ctx.attr.urls:
60+
fail("At least one of url and urls must be provided")
61+
62+
source_urls = []
63+
if ctx.attr.urls:
64+
source_urls = ctx.attr.urls
65+
if ctx.attr.url:
66+
source_urls = [ctx.attr.url] + source_urls
67+
return source_urls
68+
69+
def _update_integrity_attr(ctx, attrs, download_info):
70+
# We don't need to override the integrity attribute if sha256 is already specified.
71+
integrity_override = {} if ctx.attr.sha256 else {"integrity": download_info.integrity}
72+
return update_attrs(ctx.attr, attrs.keys(), integrity_override)
73+
74+
_HTTP_JAR_BUILD = """\
75+
load("{java_import_bzl}", "java_import")
76+
77+
java_import(
78+
name = 'jar',
79+
jars = ["{file_name}"],
80+
visibility = ['//visibility:public'],
81+
)
82+
83+
filegroup(
84+
name = 'file',
85+
srcs = ["{file_name}"],
86+
visibility = ['//visibility:public'],
87+
)
88+
89+
"""
90+
91+
def _http_jar_impl(ctx):
92+
"""Implementation of the http_jar rule."""
93+
source_urls = _get_source_urls(ctx)
94+
downloaded_file_name = ctx.attr.downloaded_file_name
95+
download_info = ctx.download(
96+
source_urls,
97+
"jar/" + downloaded_file_name,
98+
ctx.attr.sha256,
99+
canonical_id = ctx.attr.canonical_id or get_default_canonical_id(ctx, source_urls),
100+
auth = get_auth(ctx, source_urls),
101+
integrity = ctx.attr.integrity,
102+
)
103+
ctx.file("jar/BUILD", _HTTP_JAR_BUILD.format(
104+
java_import_bzl = str(Label("//java:java_import.bzl")),
105+
file_name = downloaded_file_name,
106+
))
107+
108+
return _update_integrity_attr(ctx, _http_jar_attrs, download_info)
109+
110+
_http_jar_attrs = {
111+
"sha256": attr.string(
112+
doc = """The expected SHA-256 of the jar downloaded.
113+
114+
This must match the SHA-256 of the jar downloaded. _It is a security risk
115+
to omit the SHA-256 as remote files can change._ At best omitting this
116+
field will make your build non-hermetic. It is optional to make development
117+
easier but either this attribute or `integrity` should be set before shipping.""",
118+
),
119+
"integrity": attr.string(
120+
doc = """Expected checksum in Subresource Integrity format of the jar downloaded.
121+
122+
This must match the checksum of the file downloaded. _It is a security risk
123+
to omit the checksum as remote files can change._ At best omitting this
124+
field will make your build non-hermetic. It is optional to make development
125+
easier but either this attribute or `sha256` should be set before shipping.""",
126+
),
127+
"canonical_id": attr.string(
128+
doc = CANONICAL_ID_DOC,
129+
),
130+
"url": attr.string(doc = _URL_DOC + "\n\nThe URL must end in `.jar`."),
131+
"urls": attr.string_list(doc = _URLS_DOC + "\n\nAll URLs must end in `.jar`."),
132+
"netrc": attr.string(
133+
doc = "Location of the .netrc file to use for authentication",
134+
),
135+
"auth_patterns": attr.string_dict(
136+
doc = _AUTH_PATTERN_DOC,
137+
),
138+
"downloaded_file_name": attr.string(
139+
default = "downloaded.jar",
140+
doc = "Filename assigned to the jar downloaded",
141+
),
142+
}
143+
144+
http_jar = repository_rule(
145+
implementation = _http_jar_impl,
146+
attrs = _http_jar_attrs,
147+
environ = [DEFAULT_CANONICAL_ID_ENV],
148+
doc =
149+
"""Downloads a jar from a URL and makes it available as java_import
150+
151+
Downloaded files must have a .jar extension.
152+
153+
Examples:
154+
Suppose the current repository contains the source code for a chat program, rooted at the
155+
directory `~/chat-app`. It needs to depend on an SSL library which is available from
156+
`http://example.com/openssl-0.2.jar`.
157+
158+
Targets in the `~/chat-app` repository can depend on this target if the following lines are
159+
added to `~/chat-app/MODULE.bazel`:
160+
161+
```python
162+
http_jar = use_repo_rule("@rules_java//java:http_jar.bzl", "http_jar")
163+
164+
http_jar(
165+
name = "my_ssl",
166+
url = "http://example.com/openssl-0.2.jar",
167+
sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
168+
)
169+
```
170+
171+
Targets would specify `@my_ssl//jar` as a dependency to depend on this jar.
172+
173+
You may also reference files on the current system (localhost) by using "file:///path/to/file"
174+
if you are on Unix-based systems. If you're on Windows, use "file:///c:/path/to/file". In both
175+
examples, note the three slashes (`/`) -- the first two slashes belong to `file://` and the third
176+
one belongs to the absolute path to the file.
177+
""",
178+
)

java/http_jar.bzl

Lines changed: 2 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -22,179 +22,6 @@ http_jar(name = "foo", urls = [...])
2222
```
2323
"""
2424

25-
load("@bazel_tools//tools/build_defs/repo:cache.bzl", "CANONICAL_ID_DOC", "DEFAULT_CANONICAL_ID_ENV", "get_default_canonical_id")
26-
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "get_auth", "update_attrs")
25+
load("@compatibility_proxy//:proxy.bzl", _http_jar = "http_jar")
2726

28-
_URL_DOC = """A URL to the jar that will be made available to Bazel.
29-
30-
This must be a file, http or https URL. Redirections are followed.
31-
Authentication is not supported.
32-
33-
More flexibility can be achieved by the urls parameter that allows
34-
to specify alternative URLs to fetch from."""
35-
36-
_URLS_DOC = """A list of URLs to the jar that will be made available to Bazel.
37-
38-
Each entry must be a file, http or https URL. Redirections are followed.
39-
Authentication is not supported.
40-
41-
URLs are tried in order until one succeeds, so you should list local mirrors first.
42-
If all downloads fail, the rule will fail."""
43-
44-
_AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns.
45-
46-
If a URL's host name is present in this dict the value will be used as a pattern when
47-
generating the authorization header for the http request. This enables the use of custom
48-
authorization schemes used in a lot of common cloud storage providers.
49-
50-
The pattern currently supports 2 tokens: <code>&lt;login&gt;</code> and
51-
<code>&lt;password&gt;</code>, which are replaced with their equivalent value
52-
in the netrc file for the same host name. After formatting, the result is set
53-
as the value for the <code>Authorization</code> field of the HTTP request.
54-
55-
Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token:
56-
57-
<pre>
58-
auth_patterns = {
59-
"storage.cloudprovider.com": "Bearer &lt;password&gt;"
60-
}
61-
</pre>
62-
63-
netrc:
64-
65-
<pre>
66-
machine storage.cloudprovider.com
67-
password RANDOM-TOKEN
68-
</pre>
69-
70-
The final HTTP request would have the following header:
71-
72-
<pre>
73-
Authorization: Bearer RANDOM-TOKEN
74-
</pre>
75-
"""
76-
77-
def _get_source_urls(ctx):
78-
"""Returns source urls provided via the url, urls attributes.
79-
80-
Also checks that at least one url is provided."""
81-
if not ctx.attr.url and not ctx.attr.urls:
82-
fail("At least one of url and urls must be provided")
83-
84-
source_urls = []
85-
if ctx.attr.urls:
86-
source_urls = ctx.attr.urls
87-
if ctx.attr.url:
88-
source_urls = [ctx.attr.url] + source_urls
89-
return source_urls
90-
91-
def _update_integrity_attr(ctx, attrs, download_info):
92-
# We don't need to override the integrity attribute if sha256 is already specified.
93-
integrity_override = {} if ctx.attr.sha256 else {"integrity": download_info.integrity}
94-
return update_attrs(ctx.attr, attrs.keys(), integrity_override)
95-
96-
_HTTP_JAR_BUILD = """\
97-
load("{java_import_bzl}", "java_import")
98-
99-
java_import(
100-
name = 'jar',
101-
jars = ["{file_name}"],
102-
visibility = ['//visibility:public'],
103-
)
104-
105-
filegroup(
106-
name = 'file',
107-
srcs = ["{file_name}"],
108-
visibility = ['//visibility:public'],
109-
)
110-
111-
"""
112-
113-
def _http_jar_impl(ctx):
114-
"""Implementation of the http_jar rule."""
115-
source_urls = _get_source_urls(ctx)
116-
downloaded_file_name = ctx.attr.downloaded_file_name
117-
download_info = ctx.download(
118-
source_urls,
119-
"jar/" + downloaded_file_name,
120-
ctx.attr.sha256,
121-
canonical_id = ctx.attr.canonical_id or get_default_canonical_id(ctx, source_urls),
122-
auth = get_auth(ctx, source_urls),
123-
integrity = ctx.attr.integrity,
124-
)
125-
ctx.file("jar/BUILD", _HTTP_JAR_BUILD.format(
126-
java_import_bzl = str(Label("//java:java_import.bzl")),
127-
file_name = downloaded_file_name,
128-
))
129-
130-
return _update_integrity_attr(ctx, _http_jar_attrs, download_info)
131-
132-
_http_jar_attrs = {
133-
"sha256": attr.string(
134-
doc = """The expected SHA-256 of the jar downloaded.
135-
136-
This must match the SHA-256 of the jar downloaded. _It is a security risk
137-
to omit the SHA-256 as remote files can change._ At best omitting this
138-
field will make your build non-hermetic. It is optional to make development
139-
easier but either this attribute or `integrity` should be set before shipping.""",
140-
),
141-
"integrity": attr.string(
142-
doc = """Expected checksum in Subresource Integrity format of the jar downloaded.
143-
144-
This must match the checksum of the file downloaded. _It is a security risk
145-
to omit the checksum as remote files can change._ At best omitting this
146-
field will make your build non-hermetic. It is optional to make development
147-
easier but either this attribute or `sha256` should be set before shipping.""",
148-
),
149-
"canonical_id": attr.string(
150-
doc = CANONICAL_ID_DOC,
151-
),
152-
"url": attr.string(doc = _URL_DOC + "\n\nThe URL must end in `.jar`."),
153-
"urls": attr.string_list(doc = _URLS_DOC + "\n\nAll URLs must end in `.jar`."),
154-
"netrc": attr.string(
155-
doc = "Location of the .netrc file to use for authentication",
156-
),
157-
"auth_patterns": attr.string_dict(
158-
doc = _AUTH_PATTERN_DOC,
159-
),
160-
"downloaded_file_name": attr.string(
161-
default = "downloaded.jar",
162-
doc = "Filename assigned to the jar downloaded",
163-
),
164-
}
165-
166-
http_jar = repository_rule(
167-
implementation = _http_jar_impl,
168-
attrs = _http_jar_attrs,
169-
environ = [DEFAULT_CANONICAL_ID_ENV],
170-
doc =
171-
"""Downloads a jar from a URL and makes it available as java_import
172-
173-
Downloaded files must have a .jar extension.
174-
175-
Examples:
176-
Suppose the current repository contains the source code for a chat program, rooted at the
177-
directory `~/chat-app`. It needs to depend on an SSL library which is available from
178-
`http://example.com/openssl-0.2.jar`.
179-
180-
Targets in the `~/chat-app` repository can depend on this target if the following lines are
181-
added to `~/chat-app/MODULE.bazel`:
182-
183-
```python
184-
http_jar = use_repo_rule("@rules_java//java:http_jar.bzl", "http_jar")
185-
186-
http_jar(
187-
name = "my_ssl",
188-
url = "http://example.com/openssl-0.2.jar",
189-
sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
190-
)
191-
```
192-
193-
Targets would specify `@my_ssl//jar` as a dependency to depend on this jar.
194-
195-
You may also reference files on the current system (localhost) by using "file:///path/to/file"
196-
if you are on Unix-based systems. If you're on Windows, use "file:///c:/path/to/file". In both
197-
examples, note the three slashes (`/`) -- the first two slashes belong to `file://` and the third
198-
one belongs to the absolute path to the file.
199-
""",
200-
)
27+
http_jar = _http_jar

0 commit comments

Comments
 (0)