18
18
import static com .google .common .base .Preconditions .checkState ;
19
19
import static java .util .concurrent .TimeUnit .MINUTES ;
20
20
21
+ import com .google .auto .value .AutoValue ;
21
22
import com .google .common .base .MoreObjects ;
22
23
import com .google .common .collect .ImmutableList ;
23
24
import com .google .common .collect .ImmutableMap ;
@@ -505,7 +506,7 @@ private FileArtifactValue constructFileArtifactValue(
505
506
throws IOException {
506
507
checkState (!artifact .isTreeArtifact (), "%s is a tree artifact" , artifact );
507
508
508
- FileArtifactValue value =
509
+ var statAndValue =
509
510
fileArtifactValueFromArtifact (
510
511
artifact ,
511
512
artifactPathResolver ,
@@ -515,6 +516,7 @@ private FileArtifactValue constructFileArtifactValue(
515
516
// Prevent constant metadata artifacts from notifying the timestamp granularity monitor
516
517
// and potentially delaying the build for no reason.
517
518
artifact .isConstantMetadata () ? null : tsgm );
519
+ var value = statAndValue .fileArtifactValue ();
518
520
519
521
// Ensure that we don't have both an injected digest and a digest from the filesystem.
520
522
byte [] fileDigest = value .getDigest ();
@@ -561,8 +563,17 @@ private FileArtifactValue constructFileArtifactValue(
561
563
if (injectedDigest == null && type .isFile ()) {
562
564
// We don't have an injected digest and there is no digest in the file value (which attempts a
563
565
// fast digest). Manually compute the digest instead.
564
- injectedDigest =
565
- DigestUtils .manuallyComputeDigest (artifactPathResolver .toPath (artifact ), value .getSize ());
566
+ Path path = statAndValue .pathNoFollow ();
567
+ if (statAndValue .statNoFollow () != null
568
+ && statAndValue .statNoFollow ().isSymbolicLink ()
569
+ && statAndValue .realPath () != null ) {
570
+ // If the file is a symlink, we compute the digest using the target path so that it's
571
+ // possible to hit the digest cache - we probably already computed the digest for the
572
+ // target during previous action execution.
573
+ path = statAndValue .realPath ();
574
+ }
575
+
576
+ injectedDigest = DigestUtils .manuallyComputeDigest (path , value .getSize ());
566
577
}
567
578
return FileArtifactValue .createFromInjectedDigest (value , injectedDigest );
568
579
}
@@ -582,15 +593,37 @@ static FileArtifactValue fileArtifactValueFromArtifact(
582
593
@ Nullable TimestampGranularityMonitor tsgm )
583
594
throws IOException {
584
595
return fileArtifactValueFromArtifact (
585
- artifact ,
586
- ArtifactPathResolver .IDENTITY ,
587
- statNoFollow ,
588
- /*digestWillBeInjected=*/ false ,
589
- xattrProvider ,
590
- tsgm );
596
+ artifact ,
597
+ ArtifactPathResolver .IDENTITY ,
598
+ statNoFollow ,
599
+ /* digestWillBeInjected= */ false ,
600
+ xattrProvider ,
601
+ tsgm ).fileArtifactValue ();
602
+ }
603
+
604
+ @ AutoValue
605
+ abstract static class FileArtifactStatAndValue {
606
+ public static FileArtifactStatAndValue create (
607
+ Path pathNoFollow ,
608
+ @ Nullable Path realPath ,
609
+ @ Nullable FileStatusWithDigest statNoFollow ,
610
+ FileArtifactValue fileArtifactValue ) {
611
+ return new AutoValue_ActionMetadataHandler_FileArtifactStatAndValue (
612
+ pathNoFollow , realPath , statNoFollow , fileArtifactValue );
613
+ }
614
+
615
+ public abstract Path pathNoFollow ();
616
+
617
+ @ Nullable
618
+ public abstract Path realPath ();
619
+
620
+ @ Nullable
621
+ public abstract FileStatusWithDigest statNoFollow ();
622
+
623
+ public abstract FileArtifactValue fileArtifactValue ();
591
624
}
592
625
593
- private static FileArtifactValue fileArtifactValueFromArtifact (
626
+ private static FileArtifactStatAndValue fileArtifactValueFromArtifact (
594
627
Artifact artifact ,
595
628
ArtifactPathResolver artifactPathResolver ,
596
629
@ Nullable FileStatusWithDigest statNoFollow ,
@@ -604,7 +637,8 @@ private static FileArtifactValue fileArtifactValueFromArtifact(
604
637
// If we expect a symlink, we can readlink it directly and handle errors appropriately - there
605
638
// is no need for the stat below.
606
639
if (artifact .isSymlink ()) {
607
- return FileArtifactValue .createForUnresolvedSymlink (pathNoFollow );
640
+ var fileArtifactValue = FileArtifactValue .createForUnresolvedSymlink (pathNoFollow );
641
+ return FileArtifactStatAndValue .create (pathNoFollow , /* realPath= */ null , statNoFollow , fileArtifactValue );
608
642
}
609
643
610
644
RootedPath rootedPathNoFollow =
@@ -621,8 +655,11 @@ private static FileArtifactValue fileArtifactValueFromArtifact(
621
655
}
622
656
623
657
if (statNoFollow == null || !statNoFollow .isSymbolicLink ()) {
624
- return fileArtifactValueFromStat (
625
- rootedPathNoFollow , statNoFollow , digestWillBeInjected , xattrProvider , tsgm );
658
+ var fileArtifactValue =
659
+ fileArtifactValueFromStat (
660
+ rootedPathNoFollow , statNoFollow , digestWillBeInjected , xattrProvider , tsgm );
661
+ return FileArtifactStatAndValue .create (
662
+ pathNoFollow , /* realPath= */ null , statNoFollow , fileArtifactValue );
626
663
}
627
664
628
665
// We use FileStatus#isSymbolicLink over Path#isSymbolicLink to avoid the unnecessary stat
@@ -642,8 +679,9 @@ private static FileArtifactValue fileArtifactValueFromArtifact(
642
679
// and is a source file (since changes to those are checked separately).
643
680
FileStatus realStat = realRootedPath .asPath ().statIfFound (Symlinks .NOFOLLOW );
644
681
FileStatusWithDigest realStatWithDigest = FileStatusWithDigestAdapter .maybeAdapt (realStat );
645
- return fileArtifactValueFromStat (
682
+ var fileArtifactValue = fileArtifactValueFromStat (
646
683
realRootedPath , realStatWithDigest , digestWillBeInjected , xattrProvider , tsgm );
684
+ return FileArtifactStatAndValue .create (pathNoFollow , realPath , statNoFollow , fileArtifactValue );
647
685
}
648
686
649
687
private static FileArtifactValue fileArtifactValueFromStat (
0 commit comments