Repository: bazelbuild/bazel
Issue: Allow access or generation of repo mapping files in Starlark
Labels: type: feature request
untriaged
team-Rules-API

### Description of the feature request:


There is currently no way to access the repo mapping file in Starlark. This causes problems when you need to make an binary that uses a runfiles libraries runnable outside of Bazel e.g. in an container or if you just want to package the binary in some way.

To make the binary runnable outside of bazel the `.repo_mapping` file is required so that runfiles lookups don't fail. That means that there needs to be an way to either generate or copy the `.repo_mapping` file in starlark so that e.g. a tar rule can list the repo mapping file in it's inputs.

There is currently an workaround for this for Python zip that is not available to others: https://github.com/bazelbuild/bazel/commit/4e60992432a49dda255eb005544ae8c03b30e243#diff-06b3fa5571583c2c73ec269859f1b9194038c26cc6c0e9c8897f53b992731658R382

This API could be publicly exposed or if it's possible the repo mapping could be exposed on the `FilesToRunProvider` like the runfiles manifest is exposed today.

Tagging @fmeum and @Wyverald since there is some context in a couple of Slack threads that they were part of:
https://bazelbuild.slack.com/archives/C014RARENH0/p1698153613312699
https://bazelbuild.slack.com/archives/CA3NW13MH/p1697050350018059?thread_ts=1697034827.979009&cid=CA3NW13MH

### Which category does this issue belong to?


Rules API


Issue comments:
I also think that this should be solved in 7.0 since this will make migrations to bzlmod more painful.
Exposing the repo mapping on `FilesToRunProvider` seems very low risk to me, but only allows you to get the repo mapping for existing executable targets, not arbitrary collections of runfiles. When packaging multiple binary targets this would require some kind of merging logic.

@purkhusid Would this be sufficient for your use case?

Edit: Whatever we decide to do here, the change should be straightforward and cherry-pickable.
My exact use case i only packaging a single executable with it's runfiles so that would be sufficient for me. It could be a first step if you want to think a bit better about an public API for generating mappings files for arbitrary runfiles.
A fix for this issue has been included in [Bazel 7.0.0 RC5](https://releases.bazel.build/7.0.0/rc5/index.html). Please test out the release candidate and report any issues as soon as possible. Thanks!

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java
index ee5a12ae32a568..f07c201aede21a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java
@@ -95,6 +95,13 @@ public final Artifact getRunfilesManifest() {
     return runfilesSupport != null ? runfilesSupport.getRunfilesManifest() : null;
   }
 
+  @Nullable
+  @Override
+  public Artifact getRepoMappingManifest() {
+    var runfilesSupport = getRunfilesSupport();
+    return runfilesSupport != null ? runfilesSupport.getRepoMappingManifest() : null;
+  }
+
   /** Returns a {@link RunfilesSupplier} encapsulating runfiles for this tool. */
   public final RunfilesSupplier getRunfilesSupplier() {
     return firstNonNull(getRunfilesSupport(), EmptyRunfilesSupplier.INSTANCE);
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/FilesToRunProviderApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/FilesToRunProviderApi.java
index 7dab417d98e9e4..5c0006bf053905 100644
--- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/FilesToRunProviderApi.java
+++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/FilesToRunProviderApi.java
@@ -39,4 +39,12 @@ public interface FilesToRunProviderApi<FileT extends FileApi> extends StarlarkVa
       allowReturnNones = true)
   @Nullable
   FileT getRunfilesManifest();
+
+  @StarlarkMethod(
+      name = "repo_mapping_manifest",
+      doc = "The repo mapping manifest or None if it does not exist.",
+      structField = true,
+      allowReturnNones = true)
+  @Nullable
+  FileT getRepoMappingManifest();
 }


Test patch:
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/RunfilesRepoMappingManifestTest.java b/src/test/java/com/google/devtools/build/lib/analysis/RunfilesRepoMappingManifestTest.java
index e7949ebee49215..21cd1832c3ba50 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/RunfilesRepoMappingManifestTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/RunfilesRepoMappingManifestTest.java
@@ -391,6 +391,32 @@ public void hasMappingForSymlinks() throws Exception {
         .inOrder();
   }
 
+  @Test
+  public void repoMappingOnFilesToRunProvider() throws Exception {
+    scratch.overwriteFile("MODULE.bazel", "bazel_dep(name='bare_rule',version='1.0')");
+    scratch.overwriteFile(
+        "defs.bzl",
+        "def _get_repo_mapping_impl(ctx):",
+        "    files_to_run = ctx.attr.bin[DefaultInfo].files_to_run",
+        "    return [",
+        "        DefaultInfo(files = depset([files_to_run.repo_mapping_manifest])),",
+        "    ]",
+        "get_repo_mapping = rule(",
+        "    implementation = _get_repo_mapping_impl,",
+        "    attrs = {'bin':attr.label(cfg='target',executable=True)}",
+        ")");
+    scratch.overwriteFile(
+        "BUILD",
+        "load('@bare_rule//:defs.bzl', 'bare_binary')",
+        "load('//:defs.bzl', 'get_repo_mapping')",
+        "bare_binary(name='aaa')",
+        "get_repo_mapping(name='get_repo_mapping', bin=':aaa')");
+    invalidatePackages();
+
+    assertThat(getFilesToBuild(getConfiguredTarget("//:get_repo_mapping")).toList())
+        .containsExactly(getRunfilesSupport("//:aaa").getRepoMappingManifest());
+  }
+
   /**
    * Similar to {@link BuildViewTestCase#rewriteWorkspace(String...)}, but does not call {@link
    * BuildViewTestCase#invalidatePackages()}.