3636import java .io .IOException ;
3737import java .util .Arrays ;
3838import java .util .Objects ;
39+ import java .util .Optional ;
3940import javax .annotation .Nullable ;
4041
4142/**
@@ -172,6 +173,19 @@ protected boolean couldBeModifiedByMetadata(FileArtifactValue lastKnown) {
172173 return true ;
173174 }
174175
176+ /**
177+ * Optional materialization path.
178+ *
179+ * <p>If present, this artifact is a copy of another artifact. It is still tracked as a
180+ * non-symlink by Bazel, but materialized in the local filesystem as a symlink to the original
181+ * artifact, whose contents live at this location. This is used by {@link
182+ * com.google.devtools.build.lib.remote.AbstractActionInputPrefetcher} to implement zero-cost
183+ * copies of remotely stored artifacts.
184+ */
185+ public Optional <PathFragment > getMaterializationExecPath () {
186+ return Optional .empty ();
187+ }
188+
175189 /**
176190 * Marker interface for singleton implementations of this class.
177191 *
@@ -514,9 +528,7 @@ public long getModifiedTime() {
514528 @ Override
515529 public String toString () {
516530 return MoreObjects .toStringHelper (this )
517- .add (
518- "digest" ,
519- digest == null ? "(null)" : BaseEncoding .base16 ().lowerCase ().encode (digest ))
531+ .add ("digest" , BaseEncoding .base16 ().lowerCase ().encode (digest ))
520532 .add ("size" , size )
521533 .add ("proxy" , proxy )
522534 .toString ();
@@ -535,10 +547,10 @@ protected boolean couldBeModifiedByMetadata(FileArtifactValue o) {
535547
536548 /** Metadata for remotely stored files. */
537549 public static class RemoteFileArtifactValue extends FileArtifactValue {
538- private final byte [] digest ;
539- private final long size ;
540- private final int locationIndex ;
541- private final String actionId ;
550+ protected final byte [] digest ;
551+ protected final long size ;
552+ protected final int locationIndex ;
553+ protected final String actionId ;
542554
543555 private RemoteFileArtifactValue (byte [] digest , long size , int locationIndex , String actionId ) {
544556 this .digest = Preconditions .checkNotNull (digest , actionId );
@@ -556,6 +568,19 @@ public static RemoteFileArtifactValue create(byte[] digest, long size, int locat
556568 return new RemoteFileArtifactValue (digest , size , locationIndex , /* actionId= */ "" );
557569 }
558570
571+ public static RemoteFileArtifactValue create (
572+ byte [] digest ,
573+ long size ,
574+ int locationIndex ,
575+ String actionId ,
576+ @ Nullable PathFragment materializationExecPath ) {
577+ if (materializationExecPath != null ) {
578+ return new RemoteFileArtifactValueWithMaterializationPath (
579+ digest , size , locationIndex , actionId , materializationExecPath );
580+ }
581+ return new RemoteFileArtifactValue (digest , size , locationIndex , actionId );
582+ }
583+
559584 @ Override
560585 public boolean equals (Object o ) {
561586 if (!(o instanceof RemoteFileArtifactValue )) {
@@ -602,7 +627,7 @@ public String getActionId() {
602627 @ Override
603628 public long getModifiedTime () {
604629 throw new UnsupportedOperationException (
605- "RemoteFileArifactValue doesn't support getModifiedTime" );
630+ "RemoteFileArtifactValue doesn't support getModifiedTime" );
606631 }
607632
608633 @ Override
@@ -626,6 +651,65 @@ public String toString() {
626651 .add ("digest" , bytesToString (digest ))
627652 .add ("size" , size )
628653 .add ("locationIndex" , locationIndex )
654+ .add ("actionId" , actionId )
655+ .toString ();
656+ }
657+ }
658+
659+ /**
660+ * A remote artifact that should be materialized in the local filesystem as a symlink to another
661+ * location.
662+ *
663+ * <p>See the documentation for {@link FileArtifactValue#getMaterializationExecPath}.
664+ */
665+ public static final class RemoteFileArtifactValueWithMaterializationPath
666+ extends RemoteFileArtifactValue {
667+ private final PathFragment materializationExecPath ;
668+
669+ private RemoteFileArtifactValueWithMaterializationPath (
670+ byte [] digest ,
671+ long size ,
672+ int locationIndex ,
673+ String actionId ,
674+ PathFragment materializationExecPath ) {
675+ super (digest , size , locationIndex , actionId );
676+ this .materializationExecPath = Preconditions .checkNotNull (materializationExecPath );
677+ }
678+
679+ @ Override
680+ public Optional <PathFragment > getMaterializationExecPath () {
681+ return Optional .ofNullable (materializationExecPath );
682+ }
683+
684+ @ Override
685+ public boolean equals (Object o ) {
686+ if (!(o instanceof RemoteFileArtifactValueWithMaterializationPath )) {
687+ return false ;
688+ }
689+
690+ RemoteFileArtifactValueWithMaterializationPath that =
691+ (RemoteFileArtifactValueWithMaterializationPath ) o ;
692+ return Arrays .equals (digest , that .digest )
693+ && size == that .size
694+ && locationIndex == that .locationIndex
695+ && Objects .equals (actionId , that .actionId )
696+ && Objects .equals (materializationExecPath , that .materializationExecPath );
697+ }
698+
699+ @ Override
700+ public int hashCode () {
701+ return Objects .hash (
702+ Arrays .hashCode (digest ), size , locationIndex , actionId , materializationExecPath );
703+ }
704+
705+ @ Override
706+ public String toString () {
707+ return MoreObjects .toStringHelper (this )
708+ .add ("digest" , bytesToString (digest ))
709+ .add ("size" , size )
710+ .add ("locationIndex" , locationIndex )
711+ .add ("actionId" , actionId )
712+ .add ("materializationExecPath" , materializationExecPath )
629713 .toString ();
630714 }
631715 }
0 commit comments