| # Copyright 2016 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. | 
 |  | 
 | # WARNING: | 
 | # https://github.com/bazelbuild/bazel/issues/17713 | 
 | # .bzl files in this package (tools/build_defs/repo) are evaluated | 
 | # in a Starlark environment without "@_builtins" injection, and must not refer | 
 | # to symbols associated with build/workspace .bzl files | 
 |  | 
 | """Rules for downloading files and archives over HTTP. | 
 |  | 
 | ### Setup | 
 |  | 
 | To use these rules in a module extension, load them in your .bzl file and then call them from your | 
 | extension's implementation function. For example, to use `http_archive`: | 
 |  | 
 | ```python | 
 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") | 
 |  | 
 | def _my_extension_impl(mctx): | 
 |   http_archive(name = "foo", urls = [...]) | 
 |  | 
 | my_extension = module_extension(implementation = _my_extension_impl) | 
 | ``` | 
 |  | 
 | Alternatively, you can directly call these repo rules in your MODULE.bazel file with | 
 | `use_repo_rule`: | 
 |  | 
 | ```python | 
 | http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") | 
 | http_archive(name = "foo", urls = [...]) | 
 | ``` | 
 | """ | 
 |  | 
 | load( | 
 |     ":cache.bzl", | 
 |     "CANONICAL_ID_DOC", | 
 |     "DEFAULT_CANONICAL_ID_ENV", | 
 |     "get_default_canonical_id", | 
 | ) | 
 | load( | 
 |     ":utils.bzl", | 
 |     "download_remote_files", | 
 |     "get_auth", | 
 |     "patch", | 
 |     "update_attrs", | 
 |     "workspace_and_buildfile", | 
 | ) | 
 |  | 
 | # Shared between http_jar, http_file and http_archive. | 
 |  | 
 | _URL_DOC = """A URL to a file 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 a file 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.""" | 
 |  | 
 | 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 | 
 |  | 
 | _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 _update_integrity_attr(ctx, attrs, download_info): | 
 |     # We don't need to override the integrity attribute if sha256 is already specified. | 
 |     if ctx.attr.sha256 or ctx.attr.integrity: | 
 |         return ctx.repo_metadata(reproducible = True) | 
 |     integrity_override = {"integrity": download_info.integrity} | 
 |     return ctx.repo_metadata(attrs_for_reproducibility = update_attrs(ctx.attr, attrs.keys(), integrity_override)) | 
 |  | 
 | def _update_http_archive_integrity_attrs(ctx, attrs, integrity): | 
 |     integrity_override = {} | 
 |  | 
 |     # We don't need to override the integrity attribute if sha256 is already specified. | 
 |     if not ctx.attr.sha256 and not ctx.attr.integrity: | 
 |         integrity_override["integrity"] = integrity.archive | 
 |     if ctx.attr.remote_module_file_urls and not ctx.attr.remote_module_file_integrity: | 
 |         integrity_override["remote_module_file_integrity"] = integrity.remote_module_file | 
 |     if ctx.attr.remote_file_integrity != integrity.remote_files: | 
 |         integrity_override["remote_file_integrity"] = integrity.remote_files | 
 |     if ctx.attr.remote_patches != integrity.remote_patches: | 
 |         integrity_override["remote_patches"] = integrity.remote_patches | 
 |     if not integrity_override: | 
 |         return ctx.repo_metadata(reproducible = True) | 
 |     return ctx.repo_metadata(attrs_for_reproducibility = update_attrs(ctx.attr, attrs.keys(), integrity_override)) | 
 |  | 
 | def _http_archive_impl(ctx): | 
 |     """Implementation of the http_archive rule.""" | 
 |     if ctx.attr.build_file and ctx.attr.build_file_content: | 
 |         fail("Only one of build_file and build_file_content can be provided.") | 
 |  | 
 |     source_urls = _get_source_urls(ctx) | 
 |     download_info = ctx.download_and_extract( | 
 |         source_urls, | 
 |         ctx.attr.add_prefix, | 
 |         ctx.attr.sha256, | 
 |         ctx.attr.type, | 
 |         ctx.attr.strip_prefix, | 
 |         canonical_id = ctx.attr.canonical_id or get_default_canonical_id(ctx, source_urls), | 
 |         auth = get_auth(ctx, source_urls), | 
 |         integrity = ctx.attr.integrity, | 
 |     ) | 
 |     workspace_and_buildfile(ctx) | 
 |  | 
 |     remote_files_info = download_remote_files(ctx) | 
 |     remote_patches_info = patch(ctx) | 
 |  | 
 |     # Download the module file after applying patches since modules may decide | 
 |     # to patch their packaged module and the patch may not apply to the file | 
 |     # checked in to the registry. This overrides the file if it exists. | 
 |     remote_module_file_integrity = "" | 
 |     if ctx.attr.remote_module_file_urls: | 
 |         remote_module_file_integrity = ctx.download( | 
 |             ctx.attr.remote_module_file_urls, | 
 |             "MODULE.bazel", | 
 |             auth = get_auth(ctx, ctx.attr.remote_module_file_urls), | 
 |             integrity = ctx.attr.remote_module_file_integrity, | 
 |         ).integrity | 
 |  | 
 |     integrity = struct( | 
 |         archive = download_info.integrity, | 
 |         remote_files = {path: info.integrity for path, info in remote_files_info.items()}, | 
 |         remote_patches = {url: info.integrity for url, info in remote_patches_info.items()}, | 
 |         remote_module_file = remote_module_file_integrity, | 
 |     ) | 
 |  | 
 |     return _update_http_archive_integrity_attrs(ctx, _http_archive_attrs, integrity) | 
 |  | 
 | _HTTP_FILE_BUILD = """\ | 
 | package(default_visibility = ["//visibility:public"]) | 
 |  | 
 | filegroup( | 
 |     name = "file", | 
 |     srcs = ["{}"], | 
 | ) | 
 | """ | 
 |  | 
 | def _http_file_impl(ctx): | 
 |     """Implementation of the http_file rule.""" | 
 |     repo_root = ctx.path(".") | 
 |     forbidden_files = [ | 
 |         repo_root, | 
 |         ctx.path("WORKSPACE"), | 
 |         ctx.path("BUILD"), | 
 |         ctx.path("BUILD.bazel"), | 
 |         ctx.path("file/BUILD"), | 
 |         ctx.path("file/BUILD.bazel"), | 
 |     ] | 
 |     downloaded_file_path = ctx.attr.downloaded_file_path | 
 |     download_path = ctx.path("file/" + downloaded_file_path) | 
 |     if download_path in forbidden_files or not str(download_path).startswith(str(repo_root)): | 
 |         fail("'%s' cannot be used as downloaded_file_path in http_file" % ctx.attr.downloaded_file_path) | 
 |     source_urls = _get_source_urls(ctx) | 
 |     download_info = ctx.download( | 
 |         source_urls, | 
 |         "file/" + downloaded_file_path, | 
 |         ctx.attr.sha256, | 
 |         ctx.attr.executable, | 
 |         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("WORKSPACE", "workspace(name = \"{name}\")".format(name = ctx.name)) | 
 |     ctx.file("file/BUILD", _HTTP_FILE_BUILD.format(downloaded_file_path)) | 
 |  | 
 |     return _update_integrity_attr(ctx, _http_file_attrs, download_info) | 
 |  | 
 | _HTTP_JAR_BUILD = """\ | 
 | package(default_visibility = ["//visibility:public"]) | 
 |  | 
 | 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("WORKSPACE", "workspace(name = \"{name}\")".format(name = ctx.name)) | 
 |     ctx.file("jar/BUILD", _HTTP_JAR_BUILD.format( | 
 |         file_name = downloaded_file_name, | 
 |     )) | 
 |  | 
 |     return _update_integrity_attr(ctx, _http_jar_attrs, download_info) | 
 |  | 
 | _http_archive_attrs = { | 
 |     "url": attr.string(doc = _URL_DOC), | 
 |     "urls": attr.string_list(doc = _URLS_DOC), | 
 |     "sha256": attr.string( | 
 |         doc = """The expected SHA-256 of the file downloaded. | 
 |  | 
 | This must match the SHA-256 of the file 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 file 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.""", | 
 |     ), | 
 |     "netrc": attr.string( | 
 |         doc = "Location of the .netrc file to use for authentication", | 
 |     ), | 
 |     "auth_patterns": attr.string_dict( | 
 |         doc = _AUTH_PATTERN_DOC, | 
 |     ), | 
 |     "canonical_id": attr.string( | 
 |         doc = CANONICAL_ID_DOC, | 
 |     ), | 
 |     "strip_prefix": attr.string( | 
 |         doc = """A directory prefix to strip from the extracted files. | 
 |  | 
 | Many archives contain a top-level directory that contains all of the useful | 
 | files in archive. Instead of needing to specify this prefix over and over | 
 | in the `build_file`, this field can be used to strip it from all of the | 
 | extracted files. | 
 |  | 
 | For example, suppose you are using `foo-lib-latest.zip`, which contains the | 
 | directory `foo-lib-1.2.3/` under which there is a `WORKSPACE` file and are | 
 | `src/`, `lib/`, and `test/` directories that contain the actual code you | 
 | wish to build. Specify `strip_prefix = "foo-lib-1.2.3"` to use the | 
 | `foo-lib-1.2.3` directory as your top-level directory. | 
 |  | 
 | Note that if there are files outside of this directory, they will be | 
 | discarded and inaccessible (e.g., a top-level license file). This includes | 
 | files/directories that start with the prefix but are not in the directory | 
 | (e.g., `foo-lib-1.2.3.release-notes`). If the specified prefix does not | 
 | match a directory in the archive, Bazel will return an error.""", | 
 |     ), | 
 |     "add_prefix": attr.string( | 
 |         default = "", | 
 |         doc = """Destination directory relative to the repository directory. | 
 |  | 
 | The archive will be unpacked into this directory, after applying `strip_prefix` | 
 | (if any) to the file paths within the archive. For example, file | 
 | `foo-1.2.3/src/foo.h` will be unpacked to `bar/src/foo.h` if `add_prefix = "bar"` | 
 | and `strip_prefix = "foo-1.2.3"`.""", | 
 |     ), | 
 |     "type": attr.string( | 
 |         doc = """The archive type of the downloaded file. | 
 |  | 
 | By default, the archive type is determined from the file extension of the | 
 | URL. If the file has no extension, you can explicitly specify one of the | 
 | following: `"zip"`, `"jar"`, `"war"`, `"aar"`, `"tar"`, `"tar.gz"`, `"tgz"`, | 
 | `"tar.xz"`, `"txz"`, `"tar.zst"`, `"tzst"`, `"tar.bz2"`, `"ar"`, or `"deb"`.""", | 
 |     ), | 
 |     "patches": attr.label_list( | 
 |         default = [], | 
 |         doc = | 
 |             "A list of files that are to be applied as patches after " + | 
 |             "extracting the archive. By default, it uses the Bazel-native patch implementation " + | 
 |             "which doesn't support fuzz match and binary patch, but Bazel will fall back to use " + | 
 |             "patch command line tool if `patch_tool` attribute is specified or there are " + | 
 |             "arguments other than `-p` in `patch_args` attribute.", | 
 |     ), | 
 |     "remote_file_urls": attr.string_list_dict( | 
 |         default = {}, | 
 |         doc = | 
 |             "A map of relative paths (key) to a list of URLs (value) that are to be downloaded " + | 
 |             "and made available as overlaid files on the repo. This is useful when you want " + | 
 |             "to add WORKSPACE or BUILD.bazel files atop an existing repository. The files " + | 
 |             "are downloaded before applying the patches in the `patches` attribute and the list of URLs " + | 
 |             "should all be possible mirrors of the same file. The URLs are tried in order until one succeeds. ", | 
 |     ), | 
 |     "remote_file_integrity": attr.string_dict( | 
 |         default = {}, | 
 |         doc = | 
 |             "A map of file relative paths (key) to its integrity value (value). These relative paths should map " + | 
 |             "to the files (key) in the `remote_file_urls` attribute.", | 
 |     ), | 
 |     "remote_module_file_urls": attr.string_list( | 
 |         default = [], | 
 |         doc = "For internal use only.", | 
 |     ), | 
 |     "remote_module_file_integrity": attr.string( | 
 |         default = "", | 
 |         doc = "For internal use only.", | 
 |     ), | 
 |     "remote_patches": attr.string_dict( | 
 |         default = {}, | 
 |         doc = | 
 |             "A map of patch file URL to its integrity value, they are applied after extracting " + | 
 |             "the archive and before applying patch files from the `patches` attribute. " + | 
 |             "It uses the Bazel-native patch implementation, you can specify the patch strip " + | 
 |             "number with `remote_patch_strip`", | 
 |     ), | 
 |     "remote_patch_strip": attr.int( | 
 |         default = 0, | 
 |         doc = | 
 |             "The number of leading slashes to be stripped from the file name in the remote patches.", | 
 |     ), | 
 |     "patch_tool": attr.string( | 
 |         default = "", | 
 |         doc = "The patch(1) utility to use. If this is specified, Bazel will use the specified " + | 
 |               "patch tool instead of the Bazel-native patch implementation.", | 
 |     ), | 
 |     "patch_args": attr.string_list( | 
 |         default = [], | 
 |         doc = | 
 |             "The arguments given to the patch tool. Defaults to -p0 (see the `patch_strip` " + | 
 |             "attribute), however -p1 will usually be needed for patches generated by " + | 
 |             "git. If multiple -p arguments are specified, the last one will take effect." + | 
 |             "If arguments other than -p are specified, Bazel will fall back to use patch " + | 
 |             "command line tool instead of the Bazel-native patch implementation. When falling " + | 
 |             "back to patch command line tool and patch_tool attribute is not specified, " + | 
 |             "`patch` will be used. This only affects patch files in the `patches` attribute.", | 
 |     ), | 
 |     "patch_strip": attr.int( | 
 |         default = 0, | 
 |         doc = "When set to `N`, this is equivalent to inserting `-pN` to the beginning of `patch_args`.", | 
 |     ), | 
 |     "patch_cmds": attr.string_list( | 
 |         default = [], | 
 |         doc = "Sequence of Bash commands to be applied on Linux/Macos after patches are applied.", | 
 |     ), | 
 |     "patch_cmds_win": attr.string_list( | 
 |         default = [], | 
 |         doc = "Sequence of Powershell commands to be applied on Windows after patches are " + | 
 |               "applied. If this attribute is not set, patch_cmds will be executed on Windows, " + | 
 |               "which requires Bash binary to exist.", | 
 |     ), | 
 |     "build_file": attr.label( | 
 |         allow_single_file = True, | 
 |         doc = | 
 |             "The file to use as the BUILD file for this repository." + | 
 |             "This attribute is an absolute label (use '@//' for the main " + | 
 |             "repo). The file does not need to be named BUILD, but can " + | 
 |             "be (something like BUILD.new-repo-name may work well for " + | 
 |             "distinguishing it from the repository's actual BUILD files. " + | 
 |             "Either build_file or build_file_content can be specified, but " + | 
 |             "not both.", | 
 |     ), | 
 |     "build_file_content": attr.string( | 
 |         doc = | 
 |             "The content for the BUILD file for this repository. " + | 
 |             "Either build_file or build_file_content can be specified, but " + | 
 |             "not both.", | 
 |     ), | 
 |     "workspace_file": attr.label( | 
 |         doc = "No-op attribute; do not use.", | 
 |     ), | 
 |     "workspace_file_content": attr.string( | 
 |         doc = "No-op attribute; do not use.", | 
 |     ), | 
 | } | 
 |  | 
 | http_archive = repository_rule( | 
 |     implementation = _http_archive_impl, | 
 |     attrs = _http_archive_attrs, | 
 |     environ = [DEFAULT_CANONICAL_ID_ENV], | 
 |     doc = | 
 |         """Downloads a Bazel repository as a compressed archive file, decompresses it, | 
 | and makes its targets available for binding. | 
 |  | 
 | It supports the following file extensions: `"zip"`, `"jar"`, `"war"`, `"aar"`, `"tar"`, | 
 | `"tar.gz"`, `"tgz"`, `"tar.xz"`, `"txz"`, `"tar.zst"`, `"tzst"`, `tar.bz2`, `"ar"`, | 
 | or `"deb"`. | 
 |  | 
 | 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.zip. This `.zip` file | 
 |   contains the following directory structure: | 
 |  | 
 |   ``` | 
 |   WORKSPACE | 
 |   src/ | 
 |     openssl.cc | 
 |     openssl.h | 
 |   ``` | 
 |  | 
 |   In the local repository, the user creates a `openssl.BUILD` file which | 
 |   contains the following target definition: | 
 |  | 
 |   ```python | 
 |   cc_library( | 
 |       name = "openssl-lib", | 
 |       srcs = ["src/openssl.cc"], | 
 |       hdrs = ["src/openssl.h"], | 
 |   ) | 
 |   ``` | 
 |  | 
 |   Targets in the `~/chat-app` repository can depend on this target if the | 
 |   following lines are added to `~/chat-app/WORKSPACE`: | 
 |  | 
 |   ```python | 
 |   load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") | 
 |  | 
 |   http_archive( | 
 |       name = "my_ssl", | 
 |       url = "http://example.com/openssl.zip", | 
 |       sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | 
 |       build_file = "@//:openssl.BUILD", | 
 |   ) | 
 |   ``` | 
 |  | 
 |   Then targets would specify `@my_ssl//:openssl-lib` as a dependency. | 
 | """, | 
 | ) | 
 |  | 
 | _http_file_attrs = { | 
 |     "executable": attr.bool( | 
 |         doc = "If the downloaded file should be made executable.", | 
 |     ), | 
 |     "downloaded_file_path": attr.string( | 
 |         default = "downloaded", | 
 |         doc = "Path assigned to the file downloaded", | 
 |     ), | 
 |     "sha256": attr.string( | 
 |         doc = """The expected SHA-256 of the file downloaded. | 
 |  | 
 | This must match the SHA-256 of the file 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 should be set before shipping.""", | 
 |     ), | 
 |     "integrity": attr.string( | 
 |         doc = """Expected checksum in Subresource Integrity format of the file 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), | 
 |     "urls": attr.string_list(doc = _URLS_DOC), | 
 |     "netrc": attr.string( | 
 |         doc = "Location of the .netrc file to use for authentication", | 
 |     ), | 
 |     "auth_patterns": attr.string_dict( | 
 |         doc = _AUTH_PATTERN_DOC, | 
 |     ), | 
 | } | 
 |  | 
 | http_file = repository_rule( | 
 |     implementation = _http_file_impl, | 
 |     attrs = _http_file_attrs, | 
 |     environ = [DEFAULT_CANONICAL_ID_ENV], | 
 |     doc = | 
 |         """Downloads a file from a URL and makes it available to be used as a file | 
 | group. | 
 |  | 
 | Examples: | 
 |   Suppose you need to have a debian package for your custom rules. This package | 
 |   is available from http://example.com/package.deb. Then you can add to your | 
 |   WORKSPACE file: | 
 |  | 
 |   ```python | 
 |   load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") | 
 |  | 
 |   http_file( | 
 |       name = "my_deb", | 
 |       url = "http://example.com/package.deb", | 
 |       sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | 
 |   ) | 
 |   ``` | 
 |  | 
 |   Targets would specify `@my_deb//file` as a dependency to depend on this file. | 
 | """, | 
 | ) | 
 |  | 
 | _http_jar_attrs = { | 
 |     "sha256": attr.string( | 
 |         doc = """The expected SHA-256 of the file downloaded. | 
 |  | 
 | This must match the SHA-256 of the file 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 file 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/WORKSPACE`: | 
 |  | 
 |   ```python | 
 |   load("@bazel_tools//tools/build_defs/repo:http.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. | 
 | """, | 
 | ) |