• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""The http_jar repo rule, for downloading jars over HTTP."""
2
3load("@bazel_tools//tools/build_defs/repo:cache.bzl", "CANONICAL_ID_DOC", "DEFAULT_CANONICAL_ID_ENV", "get_default_canonical_id")
4load("@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
8This must be a file, http or https URL. Redirections are followed.
9Authentication is not supported.
10
11More flexibility can be achieved by the urls parameter that allows
12to 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
16Each entry must be a file, http or https URL. Redirections are followed.
17Authentication is not supported.
18
19URLs are tried in order until one succeeds, so you should list local mirrors first.
20If all downloads fail, the rule will fail."""
21
22_AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns.
23
24If a URL's host name is present in this dict the value will be used as a pattern when
25generating the authorization header for the http request. This enables the use of custom
26authorization schemes used in a lot of common cloud storage providers.
27
28The pattern currently supports 2 tokens: <code>&lt;login&gt;</code> and
29<code>&lt;password&gt;</code>, which are replaced with their equivalent value
30in the netrc file for the same host name. After formatting, the result is set
31as the value for the <code>Authorization</code> field of the HTTP request.
32
33Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token:
34
35<pre>
36auth_patterns = {
37    "storage.cloudprovider.com": "Bearer &lt;password&gt;"
38}
39</pre>
40
41netrc:
42
43<pre>
44machine storage.cloudprovider.com
45        password RANDOM-TOKEN
46</pre>
47
48The final HTTP request would have the following header:
49
50<pre>
51Authorization: Bearer RANDOM-TOKEN
52</pre>
53"""
54
55def _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
69def _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 = """\
75load("{java_import_bzl}", "java_import")
76
77java_import(
78  name = 'jar',
79  jars = ["{file_name}"],
80  visibility = ['//visibility:public'],
81)
82
83filegroup(
84  name = 'file',
85  srcs = ["{file_name}"],
86  visibility = ['//visibility:public'],
87)
88
89"""
90
91def _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
114This must match the SHA-256 of the jar downloaded. _It is a security risk
115to omit the SHA-256 as remote files can change._ At best omitting this
116field will make your build non-hermetic. It is optional to make development
117easier 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
122This must match the checksum of the file downloaded. _It is a security risk
123to omit the checksum as remote files can change._ At best omitting this
124field will make your build non-hermetic. It is optional to make development
125easier 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
144http_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
151Downloaded files must have a .jar extension.
152
153Examples:
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)
179