diff --git a/site/_includes/documentation-sidebar/1 b/site/_includes/documentation-sidebar/1
deleted file mode 120000
index e440e5c8425869..00000000000000
--- a/site/_includes/documentation-sidebar/1
+++ /dev/null
@@ -1 +0,0 @@
-3
\ No newline at end of file
diff --git a/site/_includes/documentation-sidebar/1/sidebar.html b/site/_includes/documentation-sidebar/1/sidebar.html
new file mode 100644
index 00000000000000..0cc4b853565e3a
--- /dev/null
+++ b/site/_includes/documentation-sidebar/1/sidebar.html
@@ -0,0 +1,228 @@
+
Home
+
+
+Installing Bazel
+
+
+Tutorials
+
+
+Using Bazel
+
+
+Reference
+
+
+Extending Bazel
+
diff --git a/site/_includes/documentation-sidebar/2 b/site/_includes/documentation-sidebar/2
deleted file mode 120000
index e440e5c8425869..00000000000000
--- a/site/_includes/documentation-sidebar/2
+++ /dev/null
@@ -1 +0,0 @@
-3
\ No newline at end of file
diff --git a/site/_includes/documentation-sidebar/2/sidebar.html b/site/_includes/documentation-sidebar/2/sidebar.html
new file mode 100644
index 00000000000000..0cc4b853565e3a
--- /dev/null
+++ b/site/_includes/documentation-sidebar/2/sidebar.html
@@ -0,0 +1,228 @@
+Home
+
+
+Installing Bazel
+
+
+Tutorials
+
+
+Using Bazel
+
+
+Reference
+
+
+Extending Bazel
+
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 b6180c3e37d3fe..21eb22f4f3b847 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
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.cmdline;
import static com.google.common.util.concurrent.Futures.immediateCancelledFuture;
+import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
@@ -551,14 +552,17 @@ public void eval(
"Fully excluded target pattern %s should have already been filtered out (%s)",
this,
excludedSubdirectories);
- ImmutableSet filteredIgnored =
+ IgnoredPathFragmentsInScopeOrFilteringIgnorer ignoredIntersection =
getAllIgnoredSubdirectoriesToExclude(ignoredSubdirectories);
+ if (warnIfFiltered(ignoredIntersection, resolver)) {
+ return;
+ }
resolver.findTargetsBeneathDirectory(
directory.getRepository(),
getOriginalPattern(),
directory.getPackageFragment().getPathString(),
rulesOnly,
- filteredIgnored,
+ ignoredIntersection.ignoredPathFragments(),
excludedSubdirectories,
callback,
exceptionClass);
@@ -577,38 +581,136 @@ public ListenableFuture evalAsync(
"Fully excluded target pattern %s should have already been filtered out (%s)",
this,
excludedSubdirectories);
- ImmutableSet filteredIgnored;
+ IgnoredPathFragmentsInScopeOrFilteringIgnorer ignoredIntersection;
try {
- filteredIgnored = getAllIgnoredSubdirectoriesToExclude(ignoredSubdirectories);
+ ignoredIntersection = getAllIgnoredSubdirectoriesToExclude(ignoredSubdirectories);
} catch (InterruptedException e) {
return immediateCancelledFuture();
}
+ if (warnIfFiltered(ignoredIntersection, resolver)) {
+ return immediateVoidFuture();
+ }
return resolver.findTargetsBeneathDirectoryAsync(
directory.getRepository(),
getOriginalPattern(),
directory.getPackageFragment().getPathString(),
rulesOnly,
- filteredIgnored,
+ ignoredIntersection.ignoredPathFragments(),
excludedSubdirectories,
callback,
exceptionClass,
executor);
}
- public ImmutableSet getAllIgnoredSubdirectoriesToExclude(
+ private boolean warnIfFiltered(
+ IgnoredPathFragmentsInScopeOrFilteringIgnorer ignoredIntersection,
+ TargetPatternResolver> resolver) {
+ if (ignoredIntersection.wasFiltered()) {
+ resolver.warn(
+ "Pattern '"
+ + getOriginalPattern()
+ + "' was filtered out by ignored directory '"
+ + ignoredIntersection.filteringIgnorer().getPathString()
+ + "'");
+ return true;
+ }
+ return false;
+ }
+
+ public IgnoredPathFragmentsInScopeOrFilteringIgnorer getAllIgnoredSubdirectoriesToExclude(
InterruptibleSupplier> ignoredPackagePrefixes)
throws InterruptedException {
- ImmutableSet ignoredPaths = ignoredPackagePrefixes.get();
ImmutableSet.Builder ignoredPathsBuilder =
ImmutableSet.builderWithExpectedSize(0);
- for (PathFragment ignoredPackagePrefix : ignoredPaths) {
+ for (PathFragment ignoredPackagePrefix : ignoredPackagePrefixes.get()) {
+ if (this.containedIn(ignoredPackagePrefix)) {
+ return new IgnoredPathFragmentsInScopeOrFilteringIgnorer.FilteringIgnorer(
+ ignoredPackagePrefix);
+ }
PackageIdentifier pkgIdForIgnoredDirectorPrefix =
PackageIdentifier.create(this.getDirectory().getRepository(), ignoredPackagePrefix);
if (this.containsAllTransitiveSubdirectories(pkgIdForIgnoredDirectorPrefix)) {
ignoredPathsBuilder.add(ignoredPackagePrefix);
}
}
- return ignoredPathsBuilder.build();
+ return IgnoredPathFragmentsInScopeOrFilteringIgnorer.IgnoredPathFragments.of(
+ ignoredPathsBuilder.build());
+ }
+
+ /**
+ * Morally an {@code Either, PathFragment>}, saying whether the given
+ * set of ignored directories intersected a directory (in which case the directories that were
+ * in the intersection are returned) or completely contained it (in which case a containing
+ * directory is returned).
+ */
+ public abstract static class IgnoredPathFragmentsInScopeOrFilteringIgnorer {
+ public abstract boolean wasFiltered();
+
+ public abstract ImmutableSet ignoredPathFragments();
+
+ public abstract PathFragment filteringIgnorer();
+
+ private static class IgnoredPathFragments
+ extends IgnoredPathFragmentsInScopeOrFilteringIgnorer {
+ private static final IgnoredPathFragments EMPTYSET_IGNORED =
+ new IgnoredPathFragments(ImmutableSet.of());
+
+ private final ImmutableSet ignoredPathFragments;
+
+ private IgnoredPathFragments(ImmutableSet ignoredPathFragments) {
+ this.ignoredPathFragments = ignoredPathFragments;
+ }
+
+ static IgnoredPathFragments of(ImmutableSet ignoredPathFragments) {
+ if (ignoredPathFragments.isEmpty()) {
+ return EMPTYSET_IGNORED;
+ }
+ return new IgnoredPathFragments(ignoredPathFragments);
+ }
+
+ @Override
+ public boolean wasFiltered() {
+ return false;
+ }
+
+ @Override
+ public ImmutableSet ignoredPathFragments() {
+ return ignoredPathFragments;
+ }
+
+ @Override
+ public PathFragment filteringIgnorer() {
+ throw new UnsupportedOperationException("No filter: " + ignoredPathFragments);
+ }
+ }
+
+ private static class FilteringIgnorer extends IgnoredPathFragmentsInScopeOrFilteringIgnorer {
+ private final PathFragment filteringIgnorer;
+
+ FilteringIgnorer(PathFragment filteringIgnorer) {
+ this.filteringIgnorer = filteringIgnorer;
+ }
+
+ @Override
+ public boolean wasFiltered() {
+ return true;
+ }
+
+ @Override
+ public ImmutableSet ignoredPathFragments() {
+ throw new UnsupportedOperationException("was filtered: " + filteringIgnorer);
+ }
+
+ @Override
+ public PathFragment filteringIgnorer() {
+ return filteringIgnorer;
+ }
+ }
+ }
+
+ /** Is {@code containingDirectory} an ancestor of or equal to this {@link #directory}? */
+ public boolean containedIn(PathFragment containingDirectory) {
+ return directory.getPackageFragment().startsWith(containingDirectory);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
index 378905e8f06b2a..4df9df50adff63 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
@@ -46,16 +46,20 @@ public interface RecursivePackageProvider extends PackageProvider {
* @param eventHandler any errors emitted during package lookup and loading for {@code directory}
* and non-excluded directories beneath it will be reported here
* @param directory a {@link RootedPath} specifying the directory to search
- * @param blacklistedSubdirectories a set of {@link PathFragment}s specifying transitive
- * subdirectories that have been blacklisted
+ * @param ignoredSubdirectories a set of {@link PathFragment}s specifying transitive
+ * subdirectories that are ignored. {@code directory} must not be a subdirectory of any of
+ * these
* @param excludedSubdirectories a set of {@link PathFragment}s specifying transitive
+ * subdirectories that are excluded from this traversal. Different from {@code
+ * ignoredSubdirectories} only in that these directories should not be embedded in any {@code
+ * SkyKey}s that are created during the traversal, instead filtered out later
*/
void streamPackagesUnderDirectory(
BatchCallback results,
ExtendedEventHandler eventHandler,
RepositoryName repository,
PathFragment directory,
- ImmutableSet blacklistedSubdirectories,
+ ImmutableSet ignoredSubdirectories,
ImmutableSet excludedSubdirectories)
throws InterruptedException, QueryException;
@@ -121,7 +125,7 @@ public void streamPackagesUnderDirectory(
ExtendedEventHandler eventHandler,
RepositoryName repository,
PathFragment directory,
- ImmutableSet blacklistedSubdirectories,
+ ImmutableSet ignoredSubdirectories,
ImmutableSet excludedSubdirectories) {
throw new UnsupportedOperationException();
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
index aaf7a40f755d0c..24a43c7260fd0a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
@@ -171,14 +171,9 @@ public void streamPackagesUnderDirectory(
roots.add(Root.fromPath(repositoryValue.getPath()));
}
- if (ignoredSubdirectories.contains(directory)) {
- return;
- }
ImmutableSet filteredIgnoredSubdirectories =
ImmutableSet.copyOf(
- Iterables.filter(
- ignoredSubdirectories,
- path -> !path.equals(directory) && path.startsWith(directory)));
+ Iterables.filter(ignoredSubdirectories, path -> path.startsWith(directory)));
for (Root root : roots) {
RecursivePkgValue lookup =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
index 22bd0206068c24..18c59d255dcab7 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
@@ -159,14 +159,7 @@ public boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier pa
}
private ImmutableList checkValidDirectoryAndGetRoots(
- RepositoryName repository,
- PathFragment directory,
- ImmutableSet ignoredSubdirectories,
- ImmutableSet excludedSubdirectories)
- throws InterruptedException {
- if (ignoredSubdirectories.contains(directory) || excludedSubdirectories.contains(directory)) {
- return ImmutableList.of();
- }
+ RepositoryName repository, PathFragment directory) throws InterruptedException {
// Check that this package is covered by at least one of our universe patterns.
boolean inUniverse = false;
@@ -209,9 +202,7 @@ public void streamPackagesUnderDirectory(
ImmutableSet ignoredSubdirectories,
ImmutableSet excludedSubdirectories)
throws InterruptedException, QueryException {
- ImmutableList roots =
- checkValidDirectoryAndGetRoots(
- repository, directory, ignoredSubdirectories, excludedSubdirectories);
+ ImmutableList roots = checkValidDirectoryAndGetRoots(repository, directory);
rootPackageExtractor.streamPackagesFromRoots(
results,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java
index 77497fe3f822a2..f623937e4a7c38 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java
@@ -260,9 +260,6 @@ public void findTargetsBeneathDirectory(
Class exceptionClass)
throws TargetParsingException, E, InterruptedException {
PathFragment directoryPathFragment = TargetPatternResolverUtil.getPathFragment(directory);
- if (repositoryIgnoredSubdirectories.contains(directoryPathFragment)) {
- return;
- }
Preconditions.checkArgument(excludedSubdirectories.isEmpty(), excludedSubdirectories);
FilteringPolicy policy =
rulesOnly ? FilteringPolicies.RULES_ONLY : FilteringPolicies.NO_FILTER;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgValueRootPackageExtractor.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgValueRootPackageExtractor.java
index 580105ecb188b7..bc0e7b5f21a136 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgValueRootPackageExtractor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgValueRootPackageExtractor.java
@@ -45,9 +45,7 @@ public void streamPackagesFromRoots(
throws InterruptedException, QueryException {
ImmutableSet filteredIgnoredSubdirectories =
ImmutableSet.copyOf(
- Iterables.filter(
- ignoredSubdirectories,
- path -> !path.equals(directory) && path.startsWith(directory)));
+ Iterables.filter(ignoredSubdirectories, path -> path.startsWith(directory)));
for (Root root : roots) {
RootedPath rootedPath = RootedPath.toRootedPath(root, directory);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java
index c3af37c885ac15..fecdf3d08b446b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java
@@ -288,8 +288,8 @@ public static class TargetPatternKey implements SkyKey, Serializable {
private final PathFragment offset;
/**
* Must be "compatible" with {@link #parsedPattern}: if {@link #parsedPattern} is a {@link
- * TargetsBelowDirectory} object, then no element of {@code excludedSubdirectories} fully
- * contains it.
+ * TargetsBelowDirectory} object, then {@link TargetsBelowDirectory#containedIn} is false for
+ * every element of {@code excludedSubdirectories}.
*/
private final ImmutableSet excludedSubdirectories;
diff --git a/src/test/shell/bazel/bazelignore_test.sh b/src/test/shell/bazel/bazelignore_test.sh
index 6113c30b785c86..c42bb9bb7bfab4 100755
--- a/src/test/shell/bazel/bazelignore_test.sh
+++ b/src/test/shell/bazel/bazelignore_test.sh
@@ -90,14 +90,57 @@ test_broken_BUILD_files_ignored() {
echo This is a broken BUILD file > ignoreme/deep/reallydep/BUILD
echo This is a broken BUILD file > ignoreme/deep/reallydep/stillignoreme/BUILD
touch BUILD
- bazel build ... && fail "Expected failure" || :
+ bazel build ... >& "$TEST_log" && fail "Expected failure" || :
- echo; echo
echo ignoreme > .bazelignore
- bazel build ... \
+ bazel build ... >& "$TEST_log" \
|| fail "directory mentioned in .bazelignore not ignored as it should"
}
+test_broken_BUILD_files_ignored_subdir() {
+ rm -rf work && mkdir work && cd work
+ create_workspace_with_default_repos WORKSPACE
+ mkdir -p ignoreme/deep || fail "Couldn't mkdir"
+ ln -s deeper ignoreme/deep/deeper || fail "Couldn't create cycle"
+ touch BUILD
+ bazel build //ignoreme/deep/... >& "$TEST_log" && fail "Expected failure" \
+ || :
+ expect_log "circular symlinks detected"
+ expect_log "ignoreme/deep/deeper"
+
+ echo ignoreme > .bazelignore
+ bazel build //ignoreme/deep/... >& "$TEST_log" || fail "Expected success"
+ expect_log "WARNING: Pattern '//ignoreme/deep/...' was filtered out by ignored directory 'ignoreme'"
+ expect_not_log "circular symlinks detected"
+ expect_not_log "ignoreme/deep/deeper"
+
+ bazel query //ignoreme/deep/... >& "$TEST_log" || fail "Expected success"
+ expect_log "WARNING: Pattern '//ignoreme/deep/...' was filtered out by ignored directory 'ignoreme'"
+ expect_not_log "circular symlinks detected"
+ expect_not_log "ignoreme/deep/deeper"
+ expect_log "Empty results"
+
+ bazel query //ignoreme/deep/... --universe_scope=//ignoreme/deep/... \
+ --order_output=no >& "$TEST_log" || fail "Expected success"
+ expect_log "WARNING: Pattern '//ignoreme/deep/...' was filtered out by ignored directory 'ignoreme'"
+ expect_not_log "circular symlinks detected"
+ expect_not_log "ignoreme/deep/deeper"
+ expect_log "Empty results"
+
+ # Test patterns with exclude.
+ bazel build -- //ignoreme/deep/... -//ignoreme/... >& "$TEST_log" \
+ || fail "Expected success"
+ expect_log "WARNING: Pattern '//ignoreme/deep/...' was filtered out by ignored directory 'ignoreme'"
+ expect_not_log "circular symlinks detected"
+ expect_not_log "ignoreme/deep/deeper"
+
+ bazel build -- //ignoreme/... -//ignoreme/deep/... >& "$TEST_log" \
+ || fail "Expected success"
+ expect_log "WARNING: Pattern '//ignoreme/...' was filtered out by ignored directory 'ignoreme'"
+ expect_not_log "circular symlinks detected"
+ expect_not_log "ignoreme/deep/deeper"
+}
+
test_symlink_cycle_ignored() {
rm -rf work && mkdir work && cd work
create_workspace_with_default_repos WORKSPACE