|
15 | 15 | load("@io_bazel_rules_go_bazel_features//:features.bzl", "bazel_features") |
16 | 16 | load("//go/private:go_mod.bzl", "version_from_go_mod") |
17 | 17 | load("//go/private:nogo.bzl", "DEFAULT_NOGO", "NOGO_DEFAULT_EXCLUDES", "NOGO_DEFAULT_INCLUDES", "go_register_nogo") |
18 | | -load("//go/private:sdk.bzl", "detect_host_platform", "go_download_sdk_rule", "go_host_sdk_rule", "go_multiple_toolchains", "go_wrap_sdk_rule") |
| 18 | +load("//go/private:sdk.bzl", "detect_host_platform", "fetch_sdks_by_version", "go_download_sdk_rule", "go_host_sdk_rule", "go_multiple_toolchains", "go_wrap_sdk_rule") |
19 | 19 |
|
20 | 20 | def host_compatible_toolchain_impl(ctx): |
21 | 21 | ctx.file("BUILD.bazel") |
@@ -197,6 +197,38 @@ def _go_sdk_impl(ctx): |
197 | 197 | first_host_compatible_toolchain = None |
198 | 198 | host_detected_goos, host_detected_goarch = detect_host_platform(ctx) |
199 | 199 | toolchains = [] |
| 200 | + |
| 201 | + all_sdks_by_version = {} |
| 202 | + used_sdks_by_version = {} |
| 203 | + facts = getattr(ctx, "facts", {}) |
| 204 | + |
| 205 | + def get_sdks_by_version_cached(version): |
| 206 | + # Avoid a download without a known digest in the SDK repo rule by fetching the SDKs filename |
| 207 | + # and digest here. When using a version of Bazel that supports module extension facts, this |
| 208 | + # info will be persisted in the lockfile, allowing for truly airgapped builds with an |
| 209 | + # up-to-date lockfile and download (formerly repository) cache. |
| 210 | + sdks = facts.get(version) |
| 211 | + if sdks == None: |
| 212 | + # Lazily fetch the information about all SDKs so that we avoid the download if the facts |
| 213 | + # already contain all the versions we care about. We take care to only do this once and |
| 214 | + # also accept failures to support airgapped builds: the user may have set sdk hashes on |
| 215 | + # all SDK repos they actually intend to use, but others (e.g., the default SDK added by |
| 216 | + # rules_go) trigger this path even if they would never be selected by toolchain |
| 217 | + # resolution. We must not break those builds. |
| 218 | + if not all_sdks_by_version: |
| 219 | + all_sdks_by_version.clear() |
| 220 | + all_sdks_by_version.update(fetch_sdks_by_version(ctx, allow_fail = True) or { |
| 221 | + "fetch_failed_but_should_not_fetch_again_sentinel": [], |
| 222 | + }) |
| 223 | + sdks = all_sdks_by_version.get(version) |
| 224 | + if sdks == None: |
| 225 | + # This is either caused by an invalid version or because we are in an airgapped build |
| 226 | + # and the version wasn't present in facts. Since we don't want to fail in the latter |
| 227 | + # case, we leave it to the repository rule to report a useful error message. |
| 228 | + return None |
| 229 | + used_sdks_by_version[version] = sdks |
| 230 | + return sdks |
| 231 | + |
200 | 232 | for module in ctx.modules: |
201 | 233 | # Apply wrapped toolchains first to override specific platforms from the |
202 | 234 | # default toolchain or any downloads. |
@@ -261,18 +293,12 @@ def _go_sdk_impl(ctx): |
261 | 293 | index = index, |
262 | 294 | ) |
263 | 295 |
|
264 | | - # Keep in sync with the other calls to `go_download_sdk_rule` above and below. |
265 | | - go_download_sdk_rule( |
| 296 | + _download_sdk( |
| 297 | + get_sdks_by_version = get_sdks_by_version_cached, |
266 | 298 | name = name, |
267 | 299 | goos = download_tag.goos, |
268 | 300 | goarch = download_tag.goarch, |
269 | | - sdks = download_tag.sdks, |
270 | | - experiments = download_tag.experiments, |
271 | | - patches = download_tag.patches, |
272 | | - patch_strip = download_tag.patch_strip, |
273 | | - urls = download_tag.urls, |
274 | | - version = download_tag.version, |
275 | | - strip_prefix = download_tag.strip_prefix, |
| 301 | + download_tag = download_tag, |
276 | 302 | ) |
277 | 303 |
|
278 | 304 | if (not download_tag.goos or download_tag.goos == host_detected_goos) and (not download_tag.goarch or download_tag.goarch == host_detected_goarch): |
@@ -306,18 +332,12 @@ def _go_sdk_impl(ctx): |
306 | 332 | suffix = "_{}_{}".format(goos, goarch), |
307 | 333 | ) |
308 | 334 |
|
309 | | - # Keep in sync with the other calls to `go_download_sdk_rule` above. |
310 | | - go_download_sdk_rule( |
| 335 | + _download_sdk( |
| 336 | + get_sdks_by_version = get_sdks_by_version_cached, |
311 | 337 | name = default_name, |
312 | 338 | goos = goos, |
313 | 339 | goarch = goarch, |
314 | | - sdks = download_tag.sdks, |
315 | | - experiments = download_tag.experiments, |
316 | | - patches = download_tag.patches, |
317 | | - patch_strip = download_tag.patch_strip, |
318 | | - urls = download_tag.urls, |
319 | | - version = download_tag.version, |
320 | | - strip_prefix = download_tag.strip_prefix, |
| 340 | + download_tag = download_tag, |
321 | 341 | ) |
322 | 342 |
|
323 | 343 | toolchains.append(struct( |
@@ -379,7 +399,14 @@ def _go_sdk_impl(ctx): |
379 | 399 | ) |
380 | 400 |
|
381 | 401 | if bazel_features.external_deps.extension_metadata_has_reproducible: |
382 | | - return ctx.extension_metadata(reproducible = True) |
| 402 | + kwargs = { |
| 403 | + "reproducible": True, |
| 404 | + } |
| 405 | + |
| 406 | + # See get_sdks_by_version_cached above for details on these facts. |
| 407 | + if hasattr(ctx, "facts"): |
| 408 | + kwargs["facts"] = used_sdks_by_version |
| 409 | + return ctx.extension_metadata(**kwargs) |
383 | 410 | else: |
384 | 411 | return None |
385 | 412 |
|
@@ -409,6 +436,25 @@ def _left_pad_zero(index, length): |
409 | 436 | fail("index must be non-negative") |
410 | 437 | return ("0" * length + str(index))[-length:] |
411 | 438 |
|
| 439 | +def _download_sdk(*, get_sdks_by_version, name, goos, goarch, download_tag): |
| 440 | + version = download_tag.version |
| 441 | + sdks = download_tag.sdks |
| 442 | + if version and not sdks: |
| 443 | + sdks = get_sdks_by_version(version) |
| 444 | + |
| 445 | + go_download_sdk_rule( |
| 446 | + name = name, |
| 447 | + goos = goos, |
| 448 | + goarch = goarch, |
| 449 | + sdks = sdks, |
| 450 | + experiments = download_tag.experiments, |
| 451 | + patches = download_tag.patches, |
| 452 | + patch_strip = download_tag.patch_strip, |
| 453 | + urls = download_tag.urls, |
| 454 | + version = download_tag.version, |
| 455 | + strip_prefix = download_tag.strip_prefix, |
| 456 | + ) |
| 457 | + |
412 | 458 | go_sdk_extra_kwargs = { |
413 | 459 | # The choice of a host-compatible SDK is expressed in repository rule attribute values and |
414 | 460 | # depends on host OS and architecture. |
|
0 commit comments