Skip to content

Commit 5929cb7

Browse files
authored
Stage repository mapping manifest as a root symlink (bazelbuild#16733)
By adding the repository mapping manifest to runfiles as a root symlink, it is staged as `foo.runfiles/_repo_mapping` with all execution strategies. This includes sandboxed and remote execution, which previously did not stage the manifest at all. As a side effect, runfiles libraries can now find the repository mapping manifest via `rlocation("_repo_mapping")`. Fixes bazelbuild#16643 Work towards bazelbuild#16124 Closes bazelbuild#16652. PiperOrigin-RevId: 487532254 Change-Id: I9774b8930337c5967fce92a861cc0db71dea2f0f
1 parent 38c5019 commit 5929cb7

16 files changed

+161
-49
lines changed

src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,14 @@ static Map<PathFragment, Artifact> filterListForObscuringSymlinks(
386386
* normal source tree entries, or runfile conflicts. May be null, in which case obscuring
387387
* symlinks are silently discarded, and conflicts are overwritten.
388388
* @param location Location for eventHandler warnings. Ignored if eventHandler is null.
389+
* @param repoMappingManifest repository mapping manifest to add as a root symlink. This manifest
390+
* has to be added automatically for every executable and is thus not part of the Runfiles
391+
* advertised by a configured target.
389392
* @return Map<PathFragment, Artifact> path fragment to artifact, of normal source tree entries
390393
* and elements that live outside the source tree. Null values represent empty input files.
391394
*/
392395
public Map<PathFragment, Artifact> getRunfilesInputs(
393-
EventHandler eventHandler, Location location) {
396+
EventHandler eventHandler, Location location, @Nullable Artifact repoMappingManifest) {
394397
ConflictChecker checker = new ConflictChecker(conflictPolicy, eventHandler, location);
395398
Map<PathFragment, Artifact> manifest = getSymlinksAsMap(checker);
396399
// Add artifacts (committed to inclusion on construction of runfiles).
@@ -417,6 +420,9 @@ public Map<PathFragment, Artifact> getRunfilesInputs(
417420
checker = new ConflictChecker(ConflictPolicy.WARN, eventHandler, location);
418421
}
419422
builder.add(getRootSymlinksAsMap(checker), checker);
423+
if (repoMappingManifest != null) {
424+
checker.put(builder.manifest, PathFragment.create("_repo_mapping"), repoMappingManifest);
425+
}
420426
return builder.build();
421427
}
422428

src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,20 @@ private static RunfilesSupport create(
132132
}
133133
Preconditions.checkState(!runfiles.isEmpty());
134134

135+
Artifact repoMappingManifest =
136+
createRepoMappingManifestAction(ruleContext, runfiles, owningExecutable);
137+
135138
Artifact runfilesInputManifest;
136139
Artifact runfilesManifest;
137140
if (createManifest) {
138141
runfilesInputManifest = createRunfilesInputManifestArtifact(ruleContext, owningExecutable);
139142
runfilesManifest =
140-
createRunfilesAction(ruleContext, runfiles, buildRunfileLinks, runfilesInputManifest);
143+
createRunfilesAction(
144+
ruleContext, runfiles, buildRunfileLinks, runfilesInputManifest, repoMappingManifest);
141145
} else {
142146
runfilesInputManifest = null;
143147
runfilesManifest = null;
144148
}
145-
Artifact repoMappingManifest =
146-
createRepoMappingManifestAction(ruleContext, runfiles, owningExecutable);
147149
Artifact runfilesMiddleman =
148150
createRunfilesMiddleman(
149151
ruleContext, owningExecutable, runfiles, runfilesManifest, repoMappingManifest);
@@ -387,7 +389,8 @@ private static Artifact createRunfilesAction(
387389
ActionConstructionContext context,
388390
Runfiles runfiles,
389391
boolean createSymlinks,
390-
Artifact inputManifest) {
392+
Artifact inputManifest,
393+
@Nullable Artifact repoMappingManifest) {
391394
// Compute the names of the runfiles directory and its MANIFEST file.
392395
context
393396
.getAnalysisEnvironment()
@@ -397,6 +400,7 @@ private static Artifact createRunfilesAction(
397400
context.getActionOwner(),
398401
inputManifest,
399402
runfiles,
403+
repoMappingManifest,
400404
context.getConfiguration().remotableSourceManifestActions()));
401405

402406
if (!createSymlinks) {
@@ -423,6 +427,7 @@ private static Artifact createRunfilesAction(
423427
inputManifest,
424428
runfiles,
425429
outputManifest,
430+
repoMappingManifest,
426431
/*filesetRoot=*/ null));
427432
return outputManifest;
428433
}

src/main/java/com/google/devtools/build/lib/analysis/SingleRunfilesSupplier.java

+25-6
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
/** {@link RunfilesSupplier} implementation wrapping a single {@link Runfiles} directory mapping. */
3535
@AutoCodec
3636
public final class SingleRunfilesSupplier implements RunfilesSupplier {
37+
3738
private final PathFragment runfilesDir;
3839
private final Runfiles runfiles;
3940
private final Supplier<Map<PathFragment, Artifact>> runfilesInputs;
4041
@Nullable private final Artifact manifest;
42+
@Nullable private final Artifact repoMappingManifest;
4143
private final boolean buildRunfileLinks;
4244
private final boolean runfileLinksEnabled;
4345

@@ -50,28 +52,31 @@ public static SingleRunfilesSupplier create(RunfilesSupport runfilesSupport) {
5052
runfilesSupport.getRunfiles(),
5153
/*runfilesCachingEnabled=*/ false,
5254
/*manifest=*/ null,
55+
runfilesSupport.getRepoMappingManifest(),
5356
runfilesSupport.isBuildRunfileLinks(),
5457
runfilesSupport.isRunfilesEnabled());
5558
}
5659

5760
/**
5861
* Same as {@link SingleRunfilesSupplier#SingleRunfilesSupplier(PathFragment, Runfiles, Artifact,
59-
* boolean, boolean)}, except adds caching for {@linkplain Runfiles#getRunfilesInputs runfiles
60-
* inputs}.
62+
* Artifact, boolean, boolean)}, except adds caching for {@linkplain Runfiles#getRunfilesInputs
63+
* runfiles inputs}.
6164
*
6265
* <p>The runfiles inputs are computed lazily and softly cached. Caching is shared across
6366
* instances created via {@link #withOverriddenRunfilesDir}.
6467
*/
6568
public static SingleRunfilesSupplier createCaching(
6669
PathFragment runfilesDir,
6770
Runfiles runfiles,
71+
@Nullable Artifact repoMappingManifest,
6872
boolean buildRunfileLinks,
6973
boolean runfileLinksEnabled) {
7074
return new SingleRunfilesSupplier(
7175
runfilesDir,
7276
runfiles,
7377
/*runfilesCachingEnabled=*/ true,
7478
/*manifest=*/ null,
79+
repoMappingManifest,
7580
buildRunfileLinks,
7681
runfileLinksEnabled);
7782
}
@@ -92,13 +97,15 @@ public SingleRunfilesSupplier(
9297
PathFragment runfilesDir,
9398
Runfiles runfiles,
9499
@Nullable Artifact manifest,
100+
@Nullable Artifact repoMappingManifest,
95101
boolean buildRunfileLinks,
96102
boolean runfileLinksEnabled) {
97103
this(
98104
runfilesDir,
99105
runfiles,
100106
/*runfilesCachingEnabled=*/ false,
101107
manifest,
108+
repoMappingManifest,
102109
buildRunfileLinks,
103110
runfileLinksEnabled);
104111
}
@@ -108,15 +115,19 @@ private SingleRunfilesSupplier(
108115
Runfiles runfiles,
109116
boolean runfilesCachingEnabled,
110117
@Nullable Artifact manifest,
118+
@Nullable Artifact repoMappingManifest,
111119
boolean buildRunfileLinks,
112120
boolean runfileLinksEnabled) {
113121
this(
114122
runfilesDir,
115123
runfiles,
116124
runfilesCachingEnabled
117-
? new RunfilesCacher(runfiles)
118-
: () -> runfiles.getRunfilesInputs(/*eventHandler=*/ null, /*location=*/ null),
125+
? new RunfilesCacher(runfiles, repoMappingManifest)
126+
: () ->
127+
runfiles.getRunfilesInputs(
128+
/*eventHandler=*/ null, /*location=*/ null, repoMappingManifest),
119129
manifest,
130+
repoMappingManifest,
120131
buildRunfileLinks,
121132
runfileLinksEnabled);
122133
}
@@ -126,13 +137,15 @@ private SingleRunfilesSupplier(
126137
Runfiles runfiles,
127138
Supplier<Map<PathFragment, Artifact>> runfilesInputs,
128139
@Nullable Artifact manifest,
140+
@Nullable Artifact repoMappingManifest,
129141
boolean buildRunfileLinks,
130142
boolean runfileLinksEnabled) {
131143
checkArgument(!runfilesDir.isAbsolute());
132144
this.runfilesDir = checkNotNull(runfilesDir);
133145
this.runfiles = checkNotNull(runfiles);
134146
this.runfilesInputs = checkNotNull(runfilesInputs);
135147
this.manifest = manifest;
148+
this.repoMappingManifest = repoMappingManifest;
136149
this.buildRunfileLinks = buildRunfileLinks;
137150
this.runfileLinksEnabled = runfileLinksEnabled;
138151
}
@@ -199,17 +212,21 @@ public SingleRunfilesSupplier withOverriddenRunfilesDir(PathFragment newRunfiles
199212
runfiles,
200213
runfilesInputs,
201214
manifest,
215+
repoMappingManifest,
202216
buildRunfileLinks,
203217
runfileLinksEnabled);
204218
}
205219

206220
/** Softly caches the result of {@link Runfiles#getRunfilesInputs}. */
207221
private static final class RunfilesCacher implements Supplier<Map<PathFragment, Artifact>> {
222+
208223
private final Runfiles runfiles;
224+
@Nullable private final Artifact repoMappingManifest;
209225
private volatile SoftReference<Map<PathFragment, Artifact>> ref = new SoftReference<>(null);
210226

211-
RunfilesCacher(Runfiles runfiles) {
227+
RunfilesCacher(Runfiles runfiles, @Nullable Artifact repoMappingManifest) {
212228
this.runfiles = runfiles;
229+
this.repoMappingManifest = repoMappingManifest;
213230
}
214231

215232
@Override
@@ -221,7 +238,9 @@ public Map<PathFragment, Artifact> get() {
221238
synchronized (this) {
222239
result = ref.get();
223240
if (result == null) {
224-
result = runfiles.getRunfilesInputs(/*eventHandler=*/ null, /*location=*/ null);
241+
result =
242+
runfiles.getRunfilesInputs(
243+
/*eventHandler=*/ null, /*location=*/ null, repoMappingManifest);
225244
ref = new SoftReference<>(result);
226245
}
227246
}

src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java

+14-4
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public final class SourceManifestAction extends AbstractFileWriteAction {
6161

6262
private static final Comparator<Map.Entry<PathFragment, Artifact>> ENTRY_COMPARATOR =
6363
(path1, path2) -> path1.getKey().getPathString().compareTo(path2.getKey().getPathString());
64-
64+
private final Artifact repoMappingManifest;
6565
/**
6666
* Interface for defining manifest formatting and reporting specifics. Implementations must be
6767
* immutable.
@@ -118,7 +118,7 @@ void writeEntry(
118118
@VisibleForTesting
119119
SourceManifestAction(
120120
ManifestWriter manifestWriter, ActionOwner owner, Artifact primaryOutput, Runfiles runfiles) {
121-
this(manifestWriter, owner, primaryOutput, runfiles, /*remotableSourceManifestActions=*/ false);
121+
this(manifestWriter, owner, primaryOutput, runfiles, null, false);
122122
}
123123

124124
/**
@@ -129,17 +129,20 @@ void writeEntry(
129129
* @param owner the action owner
130130
* @param primaryOutput the file to which to write the manifest
131131
* @param runfiles runfiles
132+
* @param repoMappingManifest the repository mapping manifest for runfiles
132133
*/
133134
public SourceManifestAction(
134135
ManifestWriter manifestWriter,
135136
ActionOwner owner,
136137
Artifact primaryOutput,
137138
Runfiles runfiles,
139+
@Nullable Artifact repoMappingManifest,
138140
boolean remotableSourceManifestActions) {
139141
// The real set of inputs is computed in #getInputs().
140142
super(owner, NestedSetBuilder.emptySet(Order.STABLE_ORDER), primaryOutput, false);
141143
this.manifestWriter = manifestWriter;
142144
this.runfiles = runfiles;
145+
this.repoMappingManifest = repoMappingManifest;
143146
this.remotableSourceManifestActions = remotableSourceManifestActions;
144147
}
145148

@@ -180,7 +183,9 @@ public synchronized NestedSet<Artifact> getInputs() {
180183
@VisibleForTesting
181184
public void writeOutputFile(OutputStream out, @Nullable EventHandler eventHandler)
182185
throws IOException {
183-
writeFile(out, runfiles.getRunfilesInputs(eventHandler, getOwner().getLocation()));
186+
writeFile(
187+
out,
188+
runfiles.getRunfilesInputs(eventHandler, getOwner().getLocation(), repoMappingManifest));
184189
}
185190

186191
/**
@@ -202,7 +207,8 @@ public String getStarlarkContent() throws IOException {
202207
@Override
203208
public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) {
204209
final Map<PathFragment, Artifact> runfilesInputs =
205-
runfiles.getRunfilesInputs(ctx.getEventHandler(), getOwner().getLocation());
210+
runfiles.getRunfilesInputs(
211+
ctx.getEventHandler(), getOwner().getLocation(), repoMappingManifest);
206212
return out -> writeFile(out, runfilesInputs);
207213
}
208214

@@ -247,6 +253,10 @@ protected void computeKey(
247253
fp.addString(GUID);
248254
fp.addBoolean(remotableSourceManifestActions);
249255
runfiles.fingerprint(fp);
256+
fp.addBoolean(repoMappingManifest != null);
257+
if (repoMappingManifest != null) {
258+
fp.addPath(repoMappingManifest.getExecPath());
259+
}
250260
}
251261

252262
@Override

src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkTreeAction.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public final class SymlinkTreeAction extends AbstractAction {
4949
private final boolean enableRunfiles;
5050
private final boolean inprocessSymlinkCreation;
5151
private final boolean skipRunfilesManifests;
52+
private final Artifact repoMappingManifest;
5253

5354
/**
5455
* Creates SymlinkTreeAction instance.
@@ -59,6 +60,7 @@ public final class SymlinkTreeAction extends AbstractAction {
5960
* @param runfiles the input runfiles
6061
* @param outputManifest the generated symlink tree manifest (must have "MANIFEST" base name).
6162
* Symlink tree root will be set to the artifact's parent directory.
63+
* @param repoMappingManifest the repository mapping manifest
6264
* @param filesetRoot non-null if this is a fileset symlink tree
6365
*/
6466
public SymlinkTreeAction(
@@ -67,12 +69,14 @@ public SymlinkTreeAction(
6769
Artifact inputManifest,
6870
@Nullable Runfiles runfiles,
6971
Artifact outputManifest,
72+
@Nullable Artifact repoMappingManifest,
7073
String filesetRoot) {
7174
this(
7275
owner,
7376
inputManifest,
7477
runfiles,
7578
outputManifest,
79+
repoMappingManifest,
7680
filesetRoot,
7781
config.getActionEnvironment(),
7882
config.runfilesEnabled(),
@@ -90,21 +94,24 @@ public SymlinkTreeAction(
9094
* @param runfiles the input runfiles
9195
* @param outputManifest the generated symlink tree manifest (must have "MANIFEST" base name).
9296
* Symlink tree root will be set to the artifact's parent directory.
97+
* @param repoMappingManifest the repository mapping manifest
9398
* @param filesetRoot non-null if this is a fileset symlink tree,
9499
*/
95100
public SymlinkTreeAction(
96101
ActionOwner owner,
97102
Artifact inputManifest,
98103
@Nullable Runfiles runfiles,
99104
Artifact outputManifest,
105+
@Nullable Artifact repoMappingManifest,
100106
@Nullable String filesetRoot,
101107
ActionEnvironment env,
102108
boolean enableRunfiles,
103109
boolean inprocessSymlinkCreation,
104110
boolean skipRunfilesManifests) {
105111
super(
106112
owner,
107-
computeInputs(enableRunfiles, skipRunfilesManifests, runfiles, inputManifest),
113+
computeInputs(
114+
enableRunfiles, skipRunfilesManifests, runfiles, inputManifest, repoMappingManifest),
108115
ImmutableSet.of(outputManifest),
109116
env);
110117
Preconditions.checkArgument(outputManifest.getPath().getBaseName().equals("MANIFEST"));
@@ -118,13 +125,15 @@ public SymlinkTreeAction(
118125
this.inprocessSymlinkCreation = inprocessSymlinkCreation;
119126
this.skipRunfilesManifests = skipRunfilesManifests && enableRunfiles && (filesetRoot == null);
120127
this.inputManifest = this.skipRunfilesManifests ? null : inputManifest;
128+
this.repoMappingManifest = repoMappingManifest;
121129
}
122130

123131
private static NestedSet<Artifact> computeInputs(
124132
boolean enableRunfiles,
125133
boolean skipRunfilesManifests,
126134
Runfiles runfiles,
127-
Artifact inputManifest) {
135+
Artifact inputManifest,
136+
@Nullable Artifact repoMappingManifest) {
128137
NestedSetBuilder<Artifact> inputs = NestedSetBuilder.<Artifact>stableOrder();
129138
if (!skipRunfilesManifests || !enableRunfiles || runfiles == null) {
130139
inputs.add(inputManifest);
@@ -134,6 +143,9 @@ private static NestedSet<Artifact> computeInputs(
134143
// existing, so directory or file links can be made as appropriate.
135144
if (enableRunfiles && runfiles != null && OS.getCurrent() == OS.WINDOWS) {
136145
inputs.addTransitive(runfiles.getAllArtifacts());
146+
if (repoMappingManifest != null) {
147+
inputs.add(repoMappingManifest);
148+
}
137149
}
138150
return inputs.build();
139151
}
@@ -151,6 +163,11 @@ public Artifact getOutputManifest() {
151163
return outputManifest;
152164
}
153165

166+
@Nullable
167+
public Artifact getRepoMappingManifest() {
168+
return repoMappingManifest;
169+
}
170+
154171
public boolean isFilesetTree() {
155172
return filesetRoot != null;
156173
}
@@ -201,6 +218,10 @@ protected void computeKey(
201218
if (runfiles != null) {
202219
runfiles.fingerprint(fp);
203220
}
221+
fp.addBoolean(repoMappingManifest != null);
222+
if (repoMappingManifest != null) {
223+
fp.addPath(repoMappingManifest.getExecPath());
224+
}
204225
}
205226

206227
@Override

src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java

+1
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ private TestParams createTestAction(int shards)
379379
SingleRunfilesSupplier.createCaching(
380380
runfilesSupport.getRunfilesDirectoryExecPath(),
381381
runfilesSupport.getRunfiles(),
382+
runfilesSupport.getRepoMappingManifest(),
382383
runfilesSupport.isBuildRunfileLinks(),
383384
runfilesSupport.isRunfilesEnabled());
384385
} else {

0 commit comments

Comments
 (0)