Adding an option to set the digest function that everything uses. Minor refactoring: enabling potential fast digest computation of more than one digest function type.
Usage: bazel --host_jvm_args="-Dbazel.DigestFunction=SHA1" build ...

Ugliness: using a system property (a static non-final variable), because the better way to do it (a flag) would result in a much, much larger refactoring.

More ugliness: I have updated the minimal amount of tests. A lot of tests are still relying on the default value of MD5. Ideally, they need to be updated as well.

--
MOS_MIGRATED_REVID=139490836
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
index 90aac0e..4d93804 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
@@ -16,6 +16,7 @@
 
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Lists;
 import com.google.common.hash.Hashing;
 import com.google.common.io.ByteSource;
@@ -24,6 +25,8 @@
 import com.google.devtools.build.lib.vfs.Dirent.Type;
 import com.google.devtools.build.lib.vfs.Path.PathFactory;
 import com.google.devtools.build.lib.vfs.Path.PathFactory.TranslatedPath;
+import com.google.devtools.common.options.EnumConverter;
+import com.google.devtools.common.options.OptionsParsingException;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -39,6 +42,49 @@
 @ThreadSafe
 public abstract class FileSystem {
 
+  /** Type of hash function to use for digesting files. */
+  public enum HashFunction {
+    MD5(16),
+    SHA1(20);
+
+    private final int digestSize;
+
+    HashFunction(int digestSize) {
+      this.digestSize = digestSize;
+    }
+
+    /** Converts to {@link HashFunction}. */
+    public static class Converter extends EnumConverter<HashFunction> {
+      public Converter() {
+        super(HashFunction.class, "hash function");
+      }
+    }
+
+    public boolean isValidDigest(byte[] digest) {
+      return digest != null && digest.length == digestSize;
+    }
+  }
+
+  // This is effectively final, should be changed only in unit-tests!
+  private static HashFunction DIGEST_FUNCTION;
+  static {
+    try {
+      DIGEST_FUNCTION = new HashFunction.Converter().convert(
+          System.getProperty("bazel.DigestFunction", "MD5"));
+    } catch (OptionsParsingException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  @VisibleForTesting
+  public static void setDigestFunctionForTesting(HashFunction value) {
+    DIGEST_FUNCTION = value;
+  }
+
+  public static HashFunction getDigestFunction() {
+    return DIGEST_FUNCTION;
+  }
+
   private enum UnixPathFactory implements PathFactory {
     INSTANCE {
       @Override
@@ -261,10 +307,11 @@
   }
 
   /**
-   * Returns the type of digest that may be returned by {@link #getFastDigest}, or {@code null}
-   * if the filesystem doesn't support them.
+   * Gets a fast digest for the given path and hash function type, or {@code null} if there
+   * isn't one available or the filesystem doesn't support them. This digest should be
+   * suitable for detecting changes to the file.
    */
-  protected String getFastDigestFunctionType(Path path) {
+  protected byte[] getFastDigest(Path path, HashFunction hashFunction) throws IOException {
     return null;
   }
 
@@ -273,8 +320,43 @@
    * filesystem doesn't support them. This digest should be suitable for detecting changes to the
    * file.
    */
-  protected byte[] getFastDigest(Path path) throws IOException {
-    return null;
+  protected final byte[] getFastDigest(Path path) throws IOException {
+    return getFastDigest(path, DIGEST_FUNCTION);
+  }
+
+  /**
+   * Returns whether the given digest is a valid digest for the default digest function.
+   */
+  public boolean isValidDigest(byte[] digest) {
+    return DIGEST_FUNCTION.isValidDigest(digest);
+  }
+
+  /**
+   * Returns the digest of the file denoted by the path, following
+   * symbolic links, for the given hash digest function.
+   *
+   * @return a new byte array containing the file's digest
+   * @throws IOException if the digest could not be computed for any reason
+   */
+  protected final byte[] getDigest(final Path path, HashFunction hashFunction) throws IOException {
+    switch(hashFunction) {
+      case MD5:
+        return getMD5Digest(path);
+      case SHA1:
+        return getSHA1Digest(path);
+      default:
+        throw new IOException("Unsupported hash function: " + hashFunction);
+    }
+  }
+
+  /**
+   * Returns the digest of the file denoted by the path, following symbolic links.
+   *
+   * @return a new byte array containing the file's digest
+   * @throws IOException if the digest could not be computed for any reason
+   */
+  protected byte[] getDigest(final Path path) throws IOException {
+    return getDigest(path, DIGEST_FUNCTION);
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/Path.java b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
index 6599952..e039efe 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/Path.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.StringCanonicalizer;
+import com.google.devtools.build.lib.vfs.FileSystem.HashFunction;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -1039,19 +1040,26 @@
   }
 
   /**
-   * Returns the type of digest that may be returned by {@link #getFastDigest}, or {@code null}
-   * if the filesystem doesn't support them.
+   * Gets a fast digest for the given path, or {@code null} if there isn't one available. The
+   * digest should be suitable for detecting changes to the file.
    */
-  public String getFastDigestFunctionType() {
-    return fileSystem.getFastDigestFunctionType(this);
+  public byte[] getFastDigest() throws IOException {
+    return fileSystem.getFastDigest(this);
   }
 
   /**
    * Gets a fast digest for the given path, or {@code null} if there isn't one available. The
    * digest should be suitable for detecting changes to the file.
    */
-  public byte[] getFastDigest() throws IOException {
-    return fileSystem.getFastDigest(this);
+  public byte[] getFastDigest(HashFunction hashFunction) throws IOException {
+    return fileSystem.getFastDigest(this, hashFunction);
+  }
+
+  /**
+   * Returns whether the given digest is a valid digest for the default system digest function.
+   */
+  public boolean isValidDigest(byte[] digest) {
+    return fileSystem.isValidDigest(digest);
   }
 
   /**
@@ -1083,6 +1091,28 @@
   }
 
   /**
+   * Returns the digest of the file denoted by the current path,
+   * following symbolic links.
+   *
+   * @return a new byte array containing the file's digest
+   * @throws IOException if the digest could not be computed for any reason
+   */
+  public byte[] getDigest() throws IOException {
+    return fileSystem.getDigest(this);
+  }
+
+  /**
+   * Returns the digest of the file denoted by the current path and digest function,
+   * following symbolic links.
+   *
+   * @return a new byte array containing the file's digest
+   * @throws IOException if the digest could not be computed for any reason
+   */
+  public byte[] getDigest(HashFunction hashFunction) throws IOException {
+    return fileSystem.getDigest(this, hashFunction);
+  }
+
+  /**
    * Opens the file denoted by this path, following symbolic links, for reading,
    * and returns an input stream to it.
    *
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/UnionFileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/UnionFileSystem.java
index a0a0955..b246aa6 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/UnionFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/UnionFileSystem.java
@@ -18,6 +18,7 @@
 import com.google.devtools.build.lib.concurrent.ThreadSafety;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.StringTrie;
+import com.google.devtools.build.lib.vfs.FileSystem.HashFunction;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -380,15 +381,9 @@
   }
 
   @Override
-  protected String getFastDigestFunctionType(Path path) {
+  protected byte[] getFastDigest(Path path, HashFunction hashFunction) throws IOException {
     FileSystem delegate = getDelegate(path);
-    return delegate.getFastDigestFunctionType(adjustPath(path, delegate));
-  }
-
-  @Override
-  protected byte[] getFastDigest(Path path) throws IOException {
-    FileSystem delegate = getDelegate(path);
-    return delegate.getFastDigest(adjustPath(path, delegate));
+    return delegate.getFastDigest(adjustPath(path, delegate), hashFunction);
   }
 
   @Override