Allow package blacklisting to be done via a file checked into the depot. By default this is disabled.

--
MOS_MIGRATED_REVID=107644420
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesFunction.java
new file mode 100644
index 0000000..11c78ae
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesFunction.java
@@ -0,0 +1,110 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.io.CharStreams;
+import com.google.common.io.LineProcessor;
+import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.RootedPath;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nullable;
+
+/**
+ * A function that retrieves a set of blacklisted package pattern prefixes from the file given by
+ * PrecomputedValue.BLACKLISTED_PACKAGE_PREFIXES_FILE.
+ */
+public class BlacklistedPackagePrefixesFunction implements SkyFunction {
+  @Nullable
+  @Override
+  public SkyValue compute(SkyKey key, Environment env)
+      throws SkyFunctionException, InterruptedException {
+    PathPackageLocator pkgLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env);
+    PathFragment patternsFile = PrecomputedValue.BLACKLISTED_PACKAGE_PREFIXES_FILE.get(env);
+    if (env.valuesMissing()) {
+      return null;
+    }
+
+    if (patternsFile.equals(PathFragment.EMPTY_FRAGMENT)) {
+      return new BlacklistedPackagePrefixesValue(ImmutableSet.<PathFragment>of());
+    }
+
+    for (Path packagePathEntry : pkgLocator.getPathEntries()) {
+      RootedPath rootedPatternFile = RootedPath.toRootedPath(packagePathEntry, patternsFile);
+      FileValue patternFileValue = (FileValue) env.getValue(FileValue.key(rootedPatternFile));
+      if (patternFileValue == null) {
+        return null;
+      }
+      if (patternFileValue.isFile()) {
+        try {
+          try (InputStreamReader reader =
+              new InputStreamReader(rootedPatternFile.asPath().getInputStream(),
+                  StandardCharsets.UTF_8)) {
+            return new BlacklistedPackagePrefixesValue(
+                CharStreams.readLines(reader, new PathFragmentLineProcessor()));
+          }
+        } catch (IOException e) {
+          String errorMessage = e.getMessage() != null
+              ? "error '" + e.getMessage() + "'" : "an error";
+          throw new BlacklistedPatternsFunctionException(
+              new InconsistentFilesystemException(
+                  rootedPatternFile.asPath() + " is not readable because: " +  errorMessage
+                      + ". Was it modified mid-build?"));
+        }
+      }
+    }
+
+    return new BlacklistedPackagePrefixesValue(ImmutableSet.<PathFragment>of());
+  }
+
+  private static final class PathFragmentLineProcessor
+      implements LineProcessor<ImmutableSet<PathFragment>> {
+    private final ImmutableSet.Builder<PathFragment> fragments = ImmutableSet.builder();
+
+    @Override
+    public boolean processLine(String line) throws IOException {
+      if (!line.isEmpty()) {
+        fragments.add(new PathFragment(line));
+      }
+      return true;
+    }
+
+    @Override
+    public ImmutableSet<PathFragment> getResult() {
+      return fragments.build();
+    }
+  }
+
+  @Nullable
+  @Override
+  public String extractTag(SkyKey skyKey) {
+    return null;
+  }
+
+  private static final class BlacklistedPatternsFunctionException extends SkyFunctionException {
+    public BlacklistedPatternsFunctionException(InconsistentFilesystemException e) {
+      super(e, Transience.TRANSIENT);
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesValue.java
new file mode 100644
index 0000000..036f055
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BlacklistedPackagePrefixesValue.java
@@ -0,0 +1,56 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+/**
+ * An immutable set of package name prefixes that should be blacklisted.
+ */
+public class BlacklistedPackagePrefixesValue implements SkyValue {
+  private final ImmutableSet<PathFragment> patterns;
+
+  private static final SkyKey BLACKLIST_KEY =
+      new SkyKey(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES, "");
+
+  public BlacklistedPackagePrefixesValue(ImmutableSet<PathFragment> exclusions) {
+    this.patterns = Preconditions.checkNotNull(exclusions);
+  }
+
+  public static SkyKey key() {
+    return BLACKLIST_KEY;
+  }
+
+  public ImmutableSet<PathFragment> getPatterns() {
+    return patterns;
+  }
+
+  @Override
+  public int hashCode() {
+    return patterns.hashCode();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof BlacklistedPackagePrefixesValue) {
+      BlacklistedPackagePrefixesValue other = (BlacklistedPackagePrefixesValue) obj;
+      return this.patterns.equals(other.patterns);
+    }
+    return false;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
index 3a4f7d6..28557d1 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
@@ -73,13 +73,14 @@
       return PackageLookupValue.DELETED_PACKAGE_VALUE;
     }
 
-    ImmutableSet<PathFragment> patterns = PrecomputedValue.BLACKLISTED_PKG_PREFIXES.get(env);
-    if (patterns == null) {
+    BlacklistedPackagePrefixesValue blacklistedPatternsValue =
+        (BlacklistedPackagePrefixesValue) env.getValue(BlacklistedPackagePrefixesValue.key());
+    if (blacklistedPatternsValue == null) {
       return null;
     }
 
     PathFragment buildFileFragment = packageKey.getPackageFragment();
-    for (PathFragment pattern : patterns) {
+    for (PathFragment pattern : blacklistedPatternsValue.getPatterns()) {
       if (buildFileFragment.startsWith(pattern)) {
         return PackageLookupValue.DELETED_PACKAGE_VALUE;
       }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrecomputedValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrecomputedValue.java
index 518b538..0e17d97 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrecomputedValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrecomputedValue.java
@@ -19,7 +19,6 @@
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
@@ -77,8 +76,9 @@
   public static final Precomputed<String> DEFAULTS_PACKAGE_CONTENTS =
       new Precomputed<>(new SkyKey(SkyFunctions.PRECOMPUTED, "default_pkg"));
 
-  public static final Precomputed<ImmutableSet<PathFragment>> BLACKLISTED_PKG_PREFIXES =
-          new Precomputed<>(new SkyKey(SkyFunctions.PRECOMPUTED, "blacklisted_pkg_patterns"));
+  public static final Precomputed<PathFragment> BLACKLISTED_PACKAGE_PREFIXES_FILE =
+          new Precomputed<>(
+              new SkyKey(SkyFunctions.PRECOMPUTED, "blacklisted_package_prefixes_file"));
 
   public static final Precomputed<RuleVisibility> DEFAULT_VISIBILITY =
       new Precomputed<>(new SkyKey(SkyFunctions.PRECOMPUTED, "default_visibility"));
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java
index 3286908..4ee7430 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java
@@ -113,11 +113,13 @@
    */
   TReturn visitDirectory(RecursivePkgKey recursivePkgKey, Environment env) {
     RootedPath rootedPath = recursivePkgKey.getRootedPath();
-    ImmutableSet<PathFragment> blacklist = PrecomputedValue.BLACKLISTED_PKG_PREFIXES.get(env);
+    BlacklistedPackagePrefixesValue blacklist =
+        (BlacklistedPackagePrefixesValue) env.getValue(BlacklistedPackagePrefixesValue.key());
     if (blacklist == null) {
       return null;
     }
-    Set<PathFragment> excludedPaths = Sets.union(recursivePkgKey.getExcludedPaths(), blacklist);
+    Set<PathFragment> excludedPaths =
+        Sets.union(recursivePkgKey.getExcludedPaths(), blacklist.getPatterns());
     Path root = rootedPath.getRoot();
     PathFragment rootRelativePath = rootedPath.getRelativePath();
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
index b041211..3ed5488 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
@@ -51,6 +51,8 @@
       SkyFunctionName.create("PREPARE_DEPS_OF_PATTERN");
   public static final SkyFunctionName PREPARE_DEPS_OF_TARGETS_UNDER_DIRECTORY =
       SkyFunctionName.create("PREPARE_DEPS_OF_TARGETS_UNDER_DIRECTORY");
+  public static final SkyFunctionName BLACKLISTED_PACKAGE_PREFIXES =
+      SkyFunctionName.create("BLACKLISTED_PACKAGE_PREFIXES");
   public static final SkyFunctionName TEST_SUITE_EXPANSION =
       SkyFunctionName.create("TEST_SUITE_EXPANSION");
   public static final SkyFunctionName TESTS_IN_SUITE = SkyFunctionName.create("TESTS_IN_SUITE");
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 76ad0e7..c21a416 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -344,6 +344,7 @@
     map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERN, new PrepareDepsOfPatternFunction(pkgLocator));
     map.put(SkyFunctions.PREPARE_DEPS_OF_TARGETS_UNDER_DIRECTORY,
         new PrepareDepsOfTargetsUnderDirectoryFunction());
+    map.put(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES, new BlacklistedPackagePrefixesFunction());
     map.put(SkyFunctions.TESTS_IN_SUITE, new TestsInSuiteFunction());
     map.put(SkyFunctions.TEST_SUITE_EXPANSION, new TestSuiteExpansionFunction());
     map.put(SkyFunctions.TARGET_PATTERN_PHASE, new TargetPatternPhaseFunction());
@@ -499,8 +500,8 @@
     }
   }
 
-  protected ImmutableSet<PathFragment> getBlacklistedPkgPrefixes() {
-    return ImmutableSet.of();
+  protected PathFragment getBlacklistedPackagePrefixesFile() {
+    return PathFragment.EMPTY_FRAGMENT;
   }
 
   class BuildViewProvider {
@@ -861,8 +862,8 @@
   public abstract void setDeletedPackages(Iterable<PackageIdentifier> pkgs);
 
   @VisibleForTesting
-  public final void setBlacklistedPkgPrefixes(ImmutableSet<PathFragment> blacklist) {
-    PrecomputedValue.BLACKLISTED_PKG_PREFIXES.set(injectable(), blacklist);
+  public final void setBlacklistedPackagePrefixesFile(PathFragment blacklistedPkgFile) {
+    PrecomputedValue.BLACKLISTED_PACKAGE_PREFIXES_FILE.set(injectable(), blacklistedPkgFile);
   }
 
   /**
@@ -879,7 +880,7 @@
 
     maybeInjectPrecomputedValuesForAnalysis();
     setCommandId(commandId);
-    setBlacklistedPkgPrefixes(getBlacklistedPkgPrefixes());
+    setBlacklistedPackagePrefixesFile(getBlacklistedPackagePrefixesFile());
     setShowLoadingProgress(showLoadingProgress);
     setDefaultVisibility(defaultVisibility);
     setupDefaultPackage(defaultsPackageContents);