13
13
// limitations under the License.
14
14
package com .google .devtools .build .lib .remote ;
15
15
16
- import static com .google .common .base .Preconditions .checkArgument ;
17
16
import static com .google .common .base .Preconditions .checkNotNull ;
18
17
import static com .google .common .base .Preconditions .checkState ;
19
18
import static com .google .common .util .concurrent .Futures .immediateFailedFuture ;
41
40
import com .google .devtools .build .lib .actions .Artifact .TreeFileArtifact ;
42
41
import com .google .devtools .build .lib .actions .FileArtifactValue ;
43
42
import com .google .devtools .build .lib .actions .FileContentsProxy ;
43
+ import com .google .devtools .build .lib .actions .FileStateType ;
44
44
import com .google .devtools .build .lib .actions .InputMetadataProvider ;
45
45
import com .google .devtools .build .lib .actions .cache .OutputMetadataStore ;
46
46
import com .google .devtools .build .lib .actions .cache .VirtualActionInput ;
@@ -196,15 +196,14 @@ void setOutputPermissions(Path dir) throws IOException {
196
196
private final DirectoryTracker directoryTracker = new DirectoryTracker ();
197
197
198
198
/** A symlink in the output tree. */
199
- record Symlink (PathFragment linkExecPath , PathFragment targetExecPath ) {
199
+ record Symlink (Path linkPath , Path targetPath ) {
200
200
Symlink {
201
- requireNonNull (linkExecPath , "linkExecPath" );
202
- requireNonNull (targetExecPath , "targetExecPath" );
203
- checkArgument (!linkExecPath .equals (targetExecPath ));
201
+ requireNonNull (linkPath , "linkPath" );
202
+ requireNonNull (targetPath , "targetPath" );
204
203
}
205
204
206
- static Symlink of (PathFragment linkExecPath , PathFragment targetExecPath ) {
207
- return new Symlink (linkExecPath , targetExecPath );
205
+ static Symlink of (Path linkPath , Path targetPath ) {
206
+ return new Symlink (linkPath , targetPath );
208
207
}
209
208
}
210
209
@@ -382,47 +381,56 @@ private ListenableFuture<Void> prefetchFile(
382
381
return immediateVoidFuture ();
383
382
}
384
383
385
- PathFragment execPath = input .getExecPath ();
384
+ Path path = execRoot . getRelative ( input .getExecPath () );
386
385
387
386
// Metadata may legitimately be missing, e.g. if this is an optional test output.
388
387
FileArtifactValue metadata = metadataSupplier .getMetadata (input );
389
- if (metadata == null || !canDownloadFile ( execRoot . getRelative ( execPath ), metadata )) {
388
+ if (metadata == null || !metadata . isLazy ( )) {
390
389
return immediateVoidFuture ();
391
390
}
392
391
393
392
@ Nullable Symlink symlink = maybeGetSymlink (input , metadata , metadataSupplier );
394
393
395
394
if (symlink != null ) {
396
- checkState (execPath .startsWith (symlink .linkExecPath ()));
397
- execPath =
398
- symlink .targetExecPath ().getRelative (execPath .relativeTo (symlink .linkExecPath ()));
395
+ checkState (path .startsWith (symlink .linkPath ()));
396
+ path = symlink .targetPath ().getRelative (path .relativeTo (symlink .linkPath ()));
399
397
}
400
398
401
399
@ Nullable PathFragment treeRootExecPath = maybeGetTreeRoot (input , metadataSupplier );
402
400
403
- Completable result =
404
- downloadFileNoCheckRx (
405
- action ,
406
- execRoot .getRelative (execPath ),
407
- treeRootExecPath != null ? execRoot .getRelative (treeRootExecPath ) : null ,
408
- dirsWithOutputPermissions ,
409
- input ,
410
- metadata ,
411
- priority ,
412
- reason )
413
- .onErrorResumeNext (
414
- t -> {
415
- if (t instanceof CacheNotFoundException cacheNotFoundException ) {
416
- // Only the symlink itself is guaranteed to be an input to the action, so
417
- // report its path for rewinding.
418
- cacheNotFoundException .setExecPath (input .getExecPath ());
419
- return Completable .error (cacheNotFoundException );
420
- }
421
- return Completable .error (t );
422
- });
401
+ Completable result ;
402
+ if (canDownloadFile (path , metadata )) {
403
+ result =
404
+ downloadFileNoCheckRx (
405
+ action ,
406
+ path ,
407
+ treeRootExecPath != null ? execRoot .getRelative (treeRootExecPath ) : null ,
408
+ dirsWithOutputPermissions ,
409
+ input ,
410
+ metadata ,
411
+ priority ,
412
+ reason )
413
+ .onErrorResumeNext (
414
+ t -> {
415
+ if (t instanceof CacheNotFoundException cacheNotFoundException ) {
416
+ // Only the symlink itself is guaranteed to be an input to the action, so
417
+ // report its path for rewinding.
418
+ cacheNotFoundException .setExecPath (input .getExecPath ());
419
+ return Completable .error (cacheNotFoundException );
420
+ }
421
+ return Completable .error (t );
422
+ });
423
+ } else if (metadata .getType () == FileStateType .SYMLINK ) {
424
+ result = plantRelativeSymlink (path , metadata .getUnresolvedSymlinkTarget ());
425
+ } else {
426
+ // This is a symlink to a local file.
427
+ checkState (metadata .getResolvedPath () != null );
428
+ checkState (!metadata .isRemote ());
429
+ result = Completable .complete ();
430
+ }
423
431
424
432
if (symlink != null ) {
425
- result = result .andThen (plantSymlink (symlink ));
433
+ result = result .andThen (plantAbsoluteSymlink (symlink ));
426
434
}
427
435
428
436
return toListenableFuture (result );
@@ -474,9 +482,7 @@ private PathFragment maybeGetTreeRoot(ActionInput input, MetadataSupplier metada
474
482
*/
475
483
@ Nullable
476
484
private Symlink maybeGetSymlink (
477
- ActionInput input ,
478
- FileArtifactValue metadata ,
479
- MetadataSupplier metadataSupplier )
485
+ ActionInput input , FileArtifactValue metadata , MetadataSupplier metadataSupplier )
480
486
throws IOException , InterruptedException {
481
487
if (input instanceof TreeFileArtifact treeFile ) {
482
488
SpecialArtifact treeArtifact = treeFile .getParent ();
@@ -493,13 +499,13 @@ private Symlink maybeGetSymlink(
493
499
}
494
500
return maybeGetSymlink (treeArtifact , treeMetadata , metadataSupplier );
495
501
}
496
- PathFragment execPath = input .getExecPath ();
497
- PathFragment resolvedExecPath = execPath ;
502
+ Path path = execRoot . getRelative ( input .getExecPath () );
503
+ Path resolvedPath = path ;
498
504
if (metadata .getResolvedPath () != null ) {
499
- resolvedExecPath = metadata . getResolvedPath (). relativeTo ( execRoot . asFragment ());
505
+ resolvedPath = execRoot . getRelative ( metadata . getResolvedPath ());
500
506
}
501
- if (!resolvedExecPath .equals (execPath )) {
502
- return Symlink .of (execPath , resolvedExecPath );
507
+ if (!resolvedPath .equals (path )) {
508
+ return Symlink .of (path , resolvedPath );
503
509
}
504
510
return null ;
505
511
}
@@ -683,17 +689,27 @@ private static void deletePartialDownload(Path path) {
683
689
}
684
690
}
685
691
686
- private Completable plantSymlink (Symlink symlink ) {
692
+ private Completable plantRelativeSymlink (Path linkPath , String target ) {
693
+ return downloadCache .executeIfNot (
694
+ linkPath ,
695
+ Completable .fromAction (
696
+ () -> {
697
+ // Delete the link path if it already exists. This is the case for tree artifacts,
698
+ // whose root directory is created before the action runs.
699
+ linkPath .delete ();
700
+ linkPath .createSymbolicLink (PathFragment .create (target ));
701
+ }));
702
+ }
703
+
704
+ private Completable plantAbsoluteSymlink (Symlink symlink ) {
687
705
return downloadCache .executeIfNot (
688
- execRoot . getRelative ( symlink .linkExecPath () ),
706
+ symlink .linkPath ( ),
689
707
Completable .defer (
690
708
() -> {
691
- Path link = execRoot .getRelative (symlink .linkExecPath ());
692
- Path target = execRoot .getRelative (symlink .targetExecPath ());
693
709
// Delete the link path if it already exists. This is the case for tree artifacts,
694
710
// whose root directory is created before the action runs.
695
- link .delete ();
696
- link . createSymbolicLink (target );
711
+ symlink . linkPath () .delete ();
712
+ symlink . linkPath (). createSymbolicLink (symlink . targetPath () );
697
713
return Completable .complete ();
698
714
}));
699
715
}
@@ -732,7 +748,7 @@ public void finalizeAction(Action action, OutputMetadataStore outputMetadataStor
732
748
}
733
749
734
750
var metadata = outputMetadataStore .getOutputMetadata (output );
735
- if (!metadata .isRemote ()) {
751
+ if (!metadata .isLazy ()) {
736
752
continue ;
737
753
}
738
754
0 commit comments