Return repo_metadata from repository rules (#4146)

This allows the remote repo contents cache to cache the result of these
diff --git a/cargo/private/cargo_bootstrap.bzl b/cargo/private/cargo_bootstrap.bzl
index 44c27f4..64d0090 100644
--- a/cargo/private/cargo_bootstrap.bzl
+++ b/cargo/private/cargo_bootstrap.bzl
@@ -236,6 +236,9 @@
         binary_name = binary_name,
         binary = built_binary,
     ))
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 cargo_bootstrap_repository = repository_rule(
     doc = "A rule for bootstrapping a Rust binary using [Cargo](https://doc.rust-lang.org/cargo/)",
diff --git a/crate_universe/private/crates_vendor.bzl b/crate_universe/private/crates_vendor.bzl
index 2b24481..1183bfb 100644
--- a/crate_universe/private/crates_vendor.bzl
+++ b/crate_universe/private/crates_vendor.bzl
@@ -745,6 +745,9 @@
     repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
         repository_ctx.name,
     ))
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 crates_vendor_remote_repository = repository_rule(
     doc = (
diff --git a/crate_universe/private/local_crate_mirror.bzl b/crate_universe/private/local_crate_mirror.bzl
index 06fed95..208c3fd 100644
--- a/crate_universe/private/local_crate_mirror.bzl
+++ b/crate_universe/private/local_crate_mirror.bzl
@@ -25,6 +25,9 @@
     execute(repository_ctx, [generator, "render", "--options-json", repository_ctx.attr.options_json, "--output-path", repository_ctx.path("BUILD.bazel")])
 
     repository_ctx.file("WORKSPACE.bazel", "")
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 local_crate_mirror = repository_rule(
     doc = """This is a private implementation detail of crate_universe, and should not be relied on in manually written code.
diff --git a/extensions/mdbook/private/toolchain.bzl b/extensions/mdbook/private/toolchain.bzl
index 8b92119..2a97510 100644
--- a/extensions/mdbook/private/toolchain.bzl
+++ b/extensions/mdbook/private/toolchain.bzl
@@ -120,6 +120,9 @@
         mdbook = str(Label(repository_ctx.attr.mdbook)),
         exec_constraint_sets_serialized = repr(repository_ctx.attr.exec_compatible_with),
     ))
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 mdbook_toolchain_repository = repository_rule(
     implementation = _mdbook_toolchain_repository_impl,
diff --git a/extensions/wasm_bindgen/private/webdrivers/firefox/webdriver_firefox.bzl b/extensions/wasm_bindgen/private/webdrivers/firefox/webdriver_firefox.bzl
index dab3cc3..ae21411 100644
--- a/extensions/wasm_bindgen/private/webdrivers/firefox/webdriver_firefox.bzl
+++ b/extensions/wasm_bindgen/private/webdrivers/firefox/webdriver_firefox.bzl
@@ -81,6 +81,9 @@
     )
 
     repository_ctx.file("BUILD.bazel", _FIREFOX_BUILD_CONTENT_WINDOWS if is_windows else _FIREFOX_BUILD_CONTENT_UNIX)
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 firefox_local_repository = repository_rule(
     doc = """\
diff --git a/extensions/wasm_bindgen/private/webdrivers/safari/webdriver_safari.bzl b/extensions/wasm_bindgen/private/webdrivers/safari/webdriver_safari.bzl
index 863e14c..4d8c739 100644
--- a/extensions/wasm_bindgen/private/webdrivers/safari/webdriver_safari.bzl
+++ b/extensions/wasm_bindgen/private/webdrivers/safari/webdriver_safari.bzl
@@ -43,6 +43,9 @@
     )
 
     repository_ctx.file("BUILD.bazel", _SAFARIDRIVER_BUILD_CONTENT)
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = False)
+    return None
 
 safaridriver_repository = repository_rule(
     doc = """\
diff --git a/extensions/wasm_bindgen/private/webdrivers/webdriver_utils.bzl b/extensions/wasm_bindgen/private/webdrivers/webdriver_utils.bzl
index e3c1258..18c2449 100644
--- a/extensions/wasm_bindgen/private/webdrivers/webdriver_utils.bzl
+++ b/extensions/wasm_bindgen/private/webdrivers/webdriver_utils.bzl
@@ -9,6 +9,9 @@
     ))
 
     repository_ctx.file("BUILD.bazel", repository_ctx.read(repository_ctx.path(repository_ctx.attr.build_file)))
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 build_file_repository = repository_rule(
     doc = "A repository rule for generating external repositories with a specific build file.",
diff --git a/rust/extensions.bzl b/rust/extensions.bzl
index b441472..4460153 100644
--- a/rust/extensions.bzl
+++ b/rust/extensions.bzl
@@ -42,6 +42,9 @@
         repository_ctx.name,
     ))
     repository_ctx.file("BUILD.bazel", "")
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 _empty_repository = repository_rule(
     doc = "Declare an empty repository.",
diff --git a/rust/private/repositories.bzl b/rust/private/repositories.bzl
index 409f07b..d25ccc9 100644
--- a/rust/private/repositories.bzl
+++ b/rust/private/repositories.bzl
@@ -548,6 +548,9 @@
         target_compatible_with = repository_ctx.attr.target_compatible_with,
         exec_compatible_with = repository_ctx.attr.exec_compatible_with,
     ))
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 toolchain_repository_proxy = repository_rule(
     doc = (
diff --git a/rust/private/repository_utils.bzl b/rust/private/repository_utils.bzl
index 4c41119..e28165c 100644
--- a/rust/private/repository_utils.bzl
+++ b/rust/private/repository_utils.bzl
@@ -1138,6 +1138,10 @@
         exec_compatible_with = repository_ctx.attr.exec_compatible_with,
     ))
 
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
+
 toolchain_repository_hub = repository_rule(
     doc = (
         "Generates a toolchain-bearing repository that declares a set of other toolchains from other " +
diff --git a/test/generated_inputs/external_repo.bzl b/test/generated_inputs/external_repo.bzl
index 7907c14..f6d6940 100644
--- a/test/generated_inputs/external_repo.bzl
+++ b/test/generated_inputs/external_repo.bzl
@@ -48,6 +48,9 @@
         "{}/lib.rs".format(repo_path),
         content = _LIB_RS_CONTENT,
     )
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 _generated_inputs_in_external_repo = repository_rule(
     implementation = _generated_inputs_in_external_repo_impl,
diff --git a/test/unit/toolchain/toolchain_test_utils.bzl b/test/unit/toolchain/toolchain_test_utils.bzl
index e5696f2..127af95 100644
--- a/test/unit/toolchain/toolchain_test_utils.bzl
+++ b/test/unit/toolchain/toolchain_test_utils.bzl
@@ -10,6 +10,9 @@
     repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
         repository_ctx.name,
     ))
+    if hasattr(repository_ctx, "repo_metadata"):
+        return repository_ctx.repo_metadata(reproducible = True)
+    return None
 
 rules_rust_toolchain_test_target_json_repository = repository_rule(
     doc = (