Skip to content

Commit c72c7bc

Browse files
authored
feat: Support specifying multiple download URLs in tool_versions. (#1145)
The interface of `repository_ctx.download` and `repository_ctx.download_and_extract` supports string lists as well as strings as the value of the `url` argument. This is the ultimate destination of the `url` attribute in the `tool_versions` dictionary, so it makes sense for it to support lists as well. It is often useful to provide multiple download URLs, e.g. when vendoring deps through a mirror (to guard against issues like [git archive checksums changing](https://github.blog/changelog/2023-01-30-git-archive-checksums-may-change/) while still keeping the canonical download URL) or in an airgapped setting (to support internal URLs alongside external URLs). This is also pretty common around Bazel repository rules that download things, e.g. [http_archive](https://bazel.build/rules/lib/repo/http#http_archive-urls), so it can be expected to work with `tool_versions` too.
1 parent ebe81b7 commit c72c7bc

File tree

2 files changed

+33
-17
lines changed

2 files changed

+33
-17
lines changed

python/repositories.bzl

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,14 @@ def is_standalone_interpreter(rctx, python_interpreter_target):
9999
def _python_repository_impl(rctx):
100100
if rctx.attr.distutils and rctx.attr.distutils_content:
101101
fail("Only one of (distutils, distutils_content) should be set.")
102+
if bool(rctx.attr.url) == bool(rctx.attr.urls):
103+
fail("Exactly one of (url, urls) must be set.")
102104

103105
platform = rctx.attr.platform
104106
python_version = rctx.attr.python_version
105107
python_short_version = python_version.rpartition(".")[0]
106108
release_filename = rctx.attr.release_filename
107-
url = rctx.attr.url
109+
url = rctx.attr.urls or [rctx.attr.url]
108110

109111
if release_filename.endswith(".zst"):
110112
rctx.download(
@@ -428,8 +430,10 @@ For more information see the official bazel docs
428430
doc = "A directory prefix to strip from the extracted files.",
429431
),
430432
"url": attr.string(
431-
doc = "The URL of the interpreter to download",
432-
mandatory = True,
433+
doc = "The URL of the interpreter to download. Exactly one of url and urls must be set.",
434+
),
435+
"urls": attr.string_list(
436+
doc = "The URL of the interpreter to download. Exactly one of url and urls must be set.",
433437
),
434438
"zstd_sha256": attr.string(
435439
default = "7c42d56fac126929a6a85dbc73ff1db2411d04f104fae9bdea51305663a83fd0",
@@ -506,7 +510,7 @@ def python_register_toolchains(
506510
if not sha256:
507511
continue
508512

509-
(release_filename, url, strip_prefix, patches) = get_release_info(platform, python_version, base_url, tool_versions)
513+
(release_filename, urls, strip_prefix, patches) = get_release_info(platform, python_version, base_url, tool_versions)
510514

511515
# allow passing in a tool version
512516
coverage_tool = None
@@ -536,7 +540,7 @@ def python_register_toolchains(
536540
platform = platform,
537541
python_version = python_version,
538542
release_filename = release_filename,
539-
url = url,
543+
urls = urls,
540544
distutils = distutils,
541545
distutils_content = distutils_content,
542546
strip_prefix = strip_prefix,

python/versions.bzl

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ DEFAULT_RELEASE_BASE_URL = "https://github.com/indygreg/python-build-standalone/
4141
# "strip_prefix": "python",
4242
# },
4343
#
44+
# It is possible to provide lists in "url".
45+
#
4446
# buildifier: disable=unsorted-dict-items
4547
TOOL_VERSIONS = {
4648
"3.8.10": {
@@ -281,19 +283,28 @@ def get_release_info(platform, python_version, base_url = DEFAULT_RELEASE_BASE_U
281283
if type(url) == type({}):
282284
url = url[platform]
283285

286+
if type(url) != type([]):
287+
url = [url]
288+
284289
strip_prefix = tool_versions[python_version].get("strip_prefix", None)
285290
if type(strip_prefix) == type({}):
286291
strip_prefix = strip_prefix[platform]
287292

288-
release_filename = url.format(
289-
platform = platform,
290-
python_version = python_version,
291-
build = "shared-install_only" if (WINDOWS_NAME in platform) else "install_only",
292-
)
293-
if "://" in release_filename: # is absolute url?
294-
url = release_filename
295-
else:
296-
url = "/".join([base_url, release_filename])
293+
release_filename = None
294+
rendered_urls = []
295+
for u in url:
296+
release_filename = u.format(
297+
platform = platform,
298+
python_version = python_version,
299+
build = "shared-install_only" if (WINDOWS_NAME in platform) else "install_only",
300+
)
301+
if "://" in release_filename: # is absolute url?
302+
rendered_urls.append(release_filename)
303+
else:
304+
rendered_urls.append("/".join([base_url, release_filename]))
305+
306+
if release_filename == None:
307+
fail("release_filename should be set by now; were any download URLs given?")
297308

298309
patches = tool_versions[python_version].get("patches", [])
299310
if type(patches) == type({}):
@@ -302,7 +313,7 @@ def get_release_info(platform, python_version, base_url = DEFAULT_RELEASE_BASE_U
302313
else:
303314
patches = []
304315

305-
return (release_filename, url, strip_prefix, patches)
316+
return (release_filename, rendered_urls, strip_prefix, patches)
306317

307318
def print_toolchains_checksums(name):
308319
native.genrule(
@@ -333,10 +344,11 @@ def _commands_for_version(python_version):
333344
"echo \"{python_version}: {platform}: $$(curl --location --fail {release_url_sha256} 2>/dev/null || curl --location --fail {release_url} 2>/dev/null | shasum -a 256 | awk '{{ print $$1 }}')\"".format(
334345
python_version = python_version,
335346
platform = platform,
336-
release_url = get_release_info(platform, python_version)[1],
337-
release_url_sha256 = get_release_info(platform, python_version)[1] + ".sha256",
347+
release_url = release_url,
348+
release_url_sha256 = release_url + ".sha256",
338349
)
339350
for platform in TOOL_VERSIONS[python_version]["sha256"].keys()
351+
for release_url in get_release_info(platform, python_version)[1]
340352
])
341353

342354
def gen_python_config_settings(name = ""):

0 commit comments

Comments
 (0)