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. + *

+ *

ok, so how would the compiler compile this?

+ * See 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. + *

+ * + *

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. + *

+ * + *

Difference between VirtualFileRef and VirtualFile

+ *

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. + * + *

ok, so how would the compiler compile this?

+ * See 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". */