TargetPatternFunction: immediately take blacklisted directories into account

...instead of filtering for them afterwards. In this way, we can also ignore
malformed content, like symlink cycles, in those directories.

Fixes #4888.

Change-Id: If3bf8458d5ecc38d8a5db7faacce556439cd5844
PiperOrigin-RevId: 208971121
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
index c256c5f..a9c367e 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
@@ -159,17 +159,6 @@
       Class<E> exceptionClass)
       throws TargetParsingException, E, InterruptedException;
 
-  protected void assertBlacklistedAndExcludedSubdirectoriesEmpty(
-      ImmutableSet<PathFragment> blacklistedSubdirectories,
-      ImmutableSet<PathFragment> excludedSubdirectories) {
-    Preconditions.checkArgument(blacklistedSubdirectories.isEmpty(),
-        "Target pattern %s of type %s cannot be evaluated with blacklisted subdirectories: %s.",
-        getOriginalPattern(), getType(), blacklistedSubdirectories);
-    Preconditions.checkArgument(excludedSubdirectories.isEmpty(),
-        "Target pattern %s of type %s cannot be evaluated with excluded subdirectories: %s.",
-        getOriginalPattern(), getType(), excludedSubdirectories);
-  }
-
   /**
    * Evaluates this {@link TargetPattern} synchronously, feeding the result to the given
    * {@code callback}, and then returns an appropriate immediate {@link ListenableFuture}.
@@ -334,8 +323,6 @@
         ImmutableSet<PathFragment> excludedSubdirectories,
         BatchCallback<T, E> callback,
         Class<E> exceptionClass) throws TargetParsingException, E, InterruptedException {
-      assertBlacklistedAndExcludedSubdirectoriesEmpty(
-          blacklistedSubdirectories, excludedSubdirectories);
       callback.process(resolver.getExplicitTarget(label(targetName)).getTargets());
     }
 
@@ -393,8 +380,6 @@
         ImmutableSet<PathFragment> excludedSubdirectories,
         BatchCallback<T, E> callback, Class<E> exceptionClass)
         throws TargetParsingException, E, InterruptedException {
-      assertBlacklistedAndExcludedSubdirectoriesEmpty(
-          blacklistedSubdirectories, excludedSubdirectories);
       if (resolver.isPackage(PackageIdentifier.createInMainRepo(path))) {
         // User has specified a package name. lookout for default target.
         callback.process(resolver.getExplicitTarget(label("//" + path)).getTargets());
@@ -480,8 +465,6 @@
         ImmutableSet<PathFragment> excludedSubdirectories,
         BatchCallback<T, E> callback, Class<E> exceptionClass)
         throws TargetParsingException, E, InterruptedException {
-      assertBlacklistedAndExcludedSubdirectoriesEmpty(
-          blacklistedSubdirectories, excludedSubdirectories);
       if (checkWildcardConflict) {
         ResolvedTargets<T> targets = getWildcardConflict(resolver);
         if (targets != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternFunction.java
index 754917d..52308fd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternFunction.java
@@ -47,6 +47,11 @@
   @Override
   public SkyValue compute(SkyKey key, Environment env) throws TargetPatternFunctionException,
       InterruptedException {
+    BlacklistedPackagePrefixesValue blacklisted =
+        (BlacklistedPackagePrefixesValue) env.getValue(BlacklistedPackagePrefixesValue.key());
+    if (env.valuesMissing()) {
+      return null;
+    }
     TargetPatternValue.TargetPatternKey patternKey =
         ((TargetPatternValue.TargetPatternKey) key.argument());
     ResolvedTargets<Target> resolvedTargets;
@@ -71,7 +76,7 @@
           };
       parsedPattern.eval(
           resolver,
-          /*blacklistedSubdirectories=*/ ImmutableSet.of(),
+          blacklisted.getPatterns(),
           excludedSubdirectories,
           callback,
           // The exception type here has to match the one on the BatchCallback. Since the callback
diff --git a/src/test/shell/bazel/bazelignore_test.sh b/src/test/shell/bazel/bazelignore_test.sh
index 3e6aa1c..843e3da 100755
--- a/src/test/shell/bazel/bazelignore_test.sh
+++ b/src/test/shell/bazel/bazelignore_test.sh
@@ -39,7 +39,21 @@
     echo; echo
     echo ignoreme > .bazelignore
     bazel build ... \
-        || fail "directory mentioned in .bazelrc not ignored as it should"
+        || fail "directory mentioned in .bazelignore not ignored as it should"
+}
+
+test_symlink_loop_ignored() {
+    rm -rf work && mkdir work && cd work
+    touch WORKSPACE
+    mkdir -p ignoreme/deep
+    (cd ignoreme/deep && ln -s . loop)
+    touch BUILD
+    bazel build ... && fail "Expected failure" || :
+
+    echo; echo
+    echo ignoreme > .bazelignore
+    bazel build ... \
+        || fail "directory mentioned in .bazelignore not ignored as it should"
 }
 
 run_suite "Integration tests for .bazelignore"