1818import static com .google .common .base .Preconditions .checkState ;
1919import static java .util .concurrent .TimeUnit .MINUTES ;
2020
21+ import com .google .auto .value .AutoValue ;
2122import com .google .common .base .MoreObjects ;
2223import com .google .common .collect .ImmutableList ;
2324import com .google .common .collect .ImmutableMap ;
@@ -505,7 +506,7 @@ private FileArtifactValue constructFileArtifactValue(
505506 throws IOException {
506507 checkState (!artifact .isTreeArtifact (), "%s is a tree artifact" , artifact );
507508
508- FileArtifactValue value =
509+ var statAndValue =
509510 fileArtifactValueFromArtifact (
510511 artifact ,
511512 artifactPathResolver ,
@@ -515,6 +516,7 @@ private FileArtifactValue constructFileArtifactValue(
515516 // Prevent constant metadata artifacts from notifying the timestamp granularity monitor
516517 // and potentially delaying the build for no reason.
517518 artifact .isConstantMetadata () ? null : tsgm );
519+ var value = statAndValue .fileArtifactValue ();
518520
519521 // Ensure that we don't have both an injected digest and a digest from the filesystem.
520522 byte [] fileDigest = value .getDigest ();
@@ -561,8 +563,17 @@ private FileArtifactValue constructFileArtifactValue(
561563 if (injectedDigest == null && type .isFile ()) {
562564 // We don't have an injected digest and there is no digest in the file value (which attempts a
563565 // 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 ());
566577 }
567578 return FileArtifactValue .createFromInjectedDigest (value , injectedDigest );
568579 }
@@ -582,15 +593,37 @@ static FileArtifactValue fileArtifactValueFromArtifact(
582593 @ Nullable TimestampGranularityMonitor tsgm )
583594 throws IOException {
584595 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 ();
591624 }
592625
593- private static FileArtifactValue fileArtifactValueFromArtifact (
626+ private static FileArtifactStatAndValue fileArtifactValueFromArtifact (
594627 Artifact artifact ,
595628 ArtifactPathResolver artifactPathResolver ,
596629 @ Nullable FileStatusWithDigest statNoFollow ,
@@ -604,7 +637,8 @@ private static FileArtifactValue fileArtifactValueFromArtifact(
604637 // If we expect a symlink, we can readlink it directly and handle errors appropriately - there
605638 // is no need for the stat below.
606639 if (artifact .isSymlink ()) {
607- return FileArtifactValue .createForUnresolvedSymlink (pathNoFollow );
640+ var fileArtifactValue = FileArtifactValue .createForUnresolvedSymlink (pathNoFollow );
641+ return FileArtifactStatAndValue .create (pathNoFollow , /* realPath= */ null , statNoFollow , fileArtifactValue );
608642 }
609643
610644 RootedPath rootedPathNoFollow =
@@ -621,8 +655,11 @@ private static FileArtifactValue fileArtifactValueFromArtifact(
621655 }
622656
623657 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 );
626663 }
627664
628665 // We use FileStatus#isSymbolicLink over Path#isSymbolicLink to avoid the unnecessary stat
@@ -642,8 +679,9 @@ private static FileArtifactValue fileArtifactValueFromArtifact(
642679 // and is a source file (since changes to those are checked separately).
643680 FileStatus realStat = realRootedPath .asPath ().statIfFound (Symlinks .NOFOLLOW );
644681 FileStatusWithDigest realStatWithDigest = FileStatusWithDigestAdapter .maybeAdapt (realStat );
645- return fileArtifactValueFromStat (
682+ var fileArtifactValue = fileArtifactValueFromStat (
646683 realRootedPath , realStatWithDigest , digestWillBeInjected , xattrProvider , tsgm );
684+ return FileArtifactStatAndValue .create (pathNoFollow , realPath , statNoFollow , fileArtifactValue );
647685 }
648686
649687 private static FileArtifactValue fileArtifactValueFromStat (
0 commit comments