diff --git a/internal/compiler-interface/src/main/java/xsbti/VirtualFile.java b/internal/compiler-interface/src/main/java/xsbti/VirtualFile.java
index 32c6487e73..2d969319d9 100644
--- a/internal/compiler-interface/src/main/java/xsbti/VirtualFile.java
+++ b/internal/compiler-interface/src/main/java/xsbti/VirtualFile.java
@@ -13,6 +13,38 @@
import java.io.InputStream;
+/**
+ * VirtualFile
is an abstraction for file-like objects.
+ * Unlike java.io.File
or java.nio.file.Path
+ * that are tied to filesystem-related capabilities, VirtualFile
+ * is designed to be a less-capable object with identity, content reading,
+ * and content hashing.
+ * See also {@link VirtualFileRef}
+ *
+ *
One of the goals of this virtual file (as opposed to concrete file)
+ * is abtraction from the machine and user specifics.
+ * Previous Analysis
file that records the relationships among
+ * the incremental compilation stored the file names using java.io.File
.
+ * This prevented the Analysis
information to be shared across machines
+ * without manipulating the absolute paths in the file names.
+ *
To create a VirtualFile
, one way of doing so is creating
+ * an instance of {@link FileConverter}, such as MappedFileConverter
.
+ * MappedFileConverter
internally stores the root paths to the working directory,
+ * Coursier cache etc, and it will create a VirtualFile
with an id
+ * that looks like ${0}/src/main/example/A.scala
.
+ *
Note that VirtualFile
can also be implemented with just plain Java objects
+ * using String
to represent the content, without "real" files.
+ *
IncrementalCompile.scala
.
+ * At the top layer of Zinc, we are passing in the source files as a
+ * sequence of {@link VirtualFile}s.
+ * The files then gets wrapped by a datatype called VirtualFileWrap
,
+ * which extends scala.reflect.io.AbstractFile
,
+ * which the compiler is able to compile.
+ */
public interface VirtualFile extends VirtualFileRef {
long contentHash();
InputStream input();
diff --git a/internal/compiler-interface/src/main/java/xsbti/VirtualFileRef.java b/internal/compiler-interface/src/main/java/xsbti/VirtualFileRef.java
index 9ecf354359..4ff1d56d89 100644
--- a/internal/compiler-interface/src/main/java/xsbti/VirtualFileRef.java
+++ b/internal/compiler-interface/src/main/java/xsbti/VirtualFileRef.java
@@ -11,8 +11,74 @@
package xsbti;
-/*
- * Represents a reference to a file-like object.
+/**
+ * VirtualFileRef
represents a reference to a file-like object.
+ * Unlike java.io.File
or java.nio.file.Path
+ * that are tied to filesystem-related capabilities, VirtualFileRef
+ * is designed to be a less-capable pointer to an object whose
+ * main feature is having a path-like identity.
+ * The equality is expected to be implemented using the equality
+ * of the id()
alone. See {@link BasicVirtualFileRef}.
+ *
+ * {@link VirtualFile}, a subtype of VirtualFileRef
+ * supports minimally viable file-like opration needed for compilation.
+ * To illustrate the difference between the two, consider the
+ * following flow of operation.
+ *
Suppose that there are two people Alice and Bob who are working on the same repo.
+ * On Alice's machine, the build tool would construct
+ * an instance of {@link FileConverter} used for the entire build.
+ * The reference implementation is sbt.internal.inc.MappedFileConverter
.
+ * The build tool would pass the usual suspect of absolute paths
+ * to this MappedFileConverter
such as the base directory
+ * of the working directory, Coursier cache directory, etc.
+ * Given the sequence of Scala and Java source files,
+ * MappedFileConverter
will create a sequence of
+ * MappedVirtualFile
whose id
would look like
+ * ${0}/src/main/example/A.scala
.
+ *
When Alice runs the compilation, Analysis
file
+ * will store the VirtualFileRef
represented by
+ * its id
. This extends not only to the source files,
+ * but also to *.class
products and library JAR files.
+ * See MRelationsNameHashing
.
+ *
Suppose then we are able to package the Analysis
+ * together with the *.class
files in a JAR file,
+ * Bob on a different machine can extract it, and have the same
+ * Analysis
file. The only difference would be that on
+ * his machine the build tool would have created a slightly different
+ * {@link FileConverter} with different base paths.
+ * Because ${0}/src/main/example/A.scala
would still
+ * be called the same, hopefully he can resume incremental compilation.
+ *
VirtualFileRef
on its own can only have identity
+ * information to be compared against another.
+ * At the most basic level this could be implemented as
+ * {@link BasicVirtualFileRef} that has no ability of reading the content.
+ * On the other hand, {@link VirtualFile} is internally able to
+ * thaw itself back to the "real" file with the help of the
+ * {@link FileConverter}, and thus it might even be aware of the
+ * absolute paths.
+ *
So when we look at the two types VirtualFileRef
+ * and VirtualFile
, VirtualFileRef
could
+ * represent a "path" for either the local machine or someone else's
+ * machine; on the other hand, VirtualFile
would
+ * represent something more concrete, like a local file or
+ * an in-memory file.
+ *
+ *
IncrementalCompile.scala
.
+ * At the top layer of Zinc, we are passing in the source files as a
+ * sequence of {@link VirtualFile}s.
+ * The files then gets wrapped by a datatype called VirtualFileWrap
,
+ * which extends scala.reflect.io.AbstractFile
,
+ * which the compiler is able to compile.
*/
public interface VirtualFileRef {
public static VirtualFileRef of(String id) {
@@ -21,11 +87,11 @@ public static VirtualFileRef of(String id) {
/**
* Returns unique identifier for the file.
- * For Java compilation
- * it needs to contain the path structure matching
- * the package name.
+ * For Java compilation it needs to contain the path
+ * structure matching the package name
+ * for example com/acme/Foo.java.
*
- * However, it must end with the same value as name(),
+ * It also must end with the same value as name(),
* Java files must end with ".java",
* and Scala files must end with ".scala".
*/