Generalize some of methods in TargetPattern, PrepareDepsOfPatternValue, and RecursivePackageProvider dealing with the concept of "excluded directories".
RELNOTES: None
PiperOrigin-RevId: 163074794
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 be3bcaa..43f77c8 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
@@ -143,19 +143,32 @@
}
/**
- * Evaluates the current target pattern, excluding targets under directories in
- * {@code excludedSubdirectories}, and returns the result.
+ * Evaluates the current target pattern, excluding targets under directories in both
+ * {@code blacklistedSubdirectories} and {@code excludedSubdirectories}, and returns the result.
*
- * @throws IllegalArgumentException if {@code excludedSubdirectories} is nonempty and this
- * pattern does not have type {@code Type.TARGETS_BELOW_DIRECTORY}.
+ * @throws IllegalArgumentException if either {@code blacklistedSubdirectories} or
+ * {@code excludedSubdirectories} is nonempty and this pattern does not have type
+ * {@code Type.TARGETS_BELOW_DIRECTORY}.
*/
public abstract <T, E extends Exception> void eval(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<T, E> callback,
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}.
@@ -166,11 +179,12 @@
*/
public final <T, E extends Exception> ListenableFuture<Void> evalAdaptedForAsync(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
ThreadSafeBatchCallback<T, E> callback,
Class<E> exceptionClass) {
try {
- eval(resolver, excludedSubdirectories, callback, exceptionClass);
+ eval(resolver, blacklistedSubdirectories, excludedSubdirectories, callback, exceptionClass);
return Futures.immediateFuture(null);
} catch (TargetParsingException e) {
return Futures.immediateFailedFuture(e);
@@ -194,11 +208,13 @@
*/
public <T, E extends Exception> ListenableFuture<Void> evalAsync(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
ThreadSafeBatchCallback<T, E> callback,
Class<E> exceptionClass,
ListeningExecutorService executor) {
- return evalAdaptedForAsync(resolver, excludedSubdirectories, callback, exceptionClass);
+ return evalAdaptedForAsync(
+ resolver, blacklistedSubdirectories, excludedSubdirectories, callback, exceptionClass);
}
/**
@@ -210,19 +226,45 @@
*/
public abstract boolean containsAllTransitiveSubdirectoriesForTBD(PackageIdentifier directory);
+ /** A tristate return value for {@link #containsTBDForTBD}. */
+ public enum ContainsTBDForTBDResult {
+ /**
+ * Evaluating this TBD pattern with a directory exclusion of the other TBD pattern's directory
+ * would result in exactly the same set of targets as evaluating the subtraction of the other
+ * TBD pattern from this one.
+ */
+ DIRECTORY_EXCLUSION_WOULD_BE_EXACT,
+ /**
+ * A directory exclusion of the other TBD pattern's directory would be too broad because this
+ * TBD pattern is not "rules only" and the other one is, meaning that this TBD pattern
+ * potentially matches more targets underneath the directory in question than the other one
+ * does. Thus, a directory exclusion would incorrectly exclude non-rule targets.
+ */
+ DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD,
+ /**
+ * None of the above. Perhaps the other pattern isn't a TBD pattern or perhaps it's not
+ * contained by this pattern.
+ */
+ OTHER,
+ }
+
/**
- * Returns {@code true} iff both this pattern and {@code containedPattern} have type
- * {@code Type.TARGETS_BELOW_DIRECTORY} and the directory in question for {@code containedPattern}
- * is underneath the directory in question for this pattern.
- *
- * <p>That is, when this method returns {@code true} it means every target matched by
- * {@code containedPattern} is also matched by this pattern.
+ * Determines how, if it all, the evaluation of this TBD pattern with a directory exclusion of the
+ * given TBD {@containedPattern}'s directory relates to the evaluation of the subtraction of the
+ * given {@link containedPattern} from this one.
*/
- public boolean containsDirectoryOfTBDForTBD(TargetPattern containedPattern) {
- return containedPattern.getType() != Type.TARGETS_BELOW_DIRECTORY
- ? false
- : containsAllTransitiveSubdirectoriesForTBD(
- containedPattern.getDirectoryForTargetsUnderDirectory());
+ public ContainsTBDForTBDResult containsTBDForTBD(TargetPattern containedPattern) {
+ if (containedPattern.getType() != Type.TARGETS_BELOW_DIRECTORY) {
+ return ContainsTBDForTBDResult.OTHER;
+ } else if (containsAllTransitiveSubdirectoriesForTBD(
+ containedPattern.getDirectoryForTargetsUnderDirectory())) {
+ return !getRulesOnly() && containedPattern.getRulesOnly()
+ ? ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD
+ : ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_EXACT;
+ } else {
+ return ContainsTBDForTBDResult.OTHER;
+ }
+
}
/**
@@ -282,12 +324,12 @@
@Override
public <T, E extends Exception> void eval(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<T, E> callback,
Class<E> exceptionClass) throws TargetParsingException, E, InterruptedException {
- Preconditions.checkArgument(excludedSubdirectories.isEmpty(),
- "Target pattern \"%s\" of type %s cannot be evaluated with excluded subdirectories: %s.",
- getOriginalPattern(), getType(), excludedSubdirectories);
+ assertBlacklistedAndExcludedSubdirectoriesEmpty(
+ blacklistedSubdirectories, excludedSubdirectories);
callback.process(resolver.getExplicitTarget(label(targetName)).getTargets());
}
@@ -336,12 +378,12 @@
@Override
public <T, E extends Exception> void eval(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<T, E> callback, Class<E> exceptionClass)
throws TargetParsingException, E, InterruptedException {
- Preconditions.checkArgument(excludedSubdirectories.isEmpty(),
- "Target pattern \"%s\" of type %s cannot be evaluated with excluded subdirectories: %s.",
- getOriginalPattern(), getType(), excludedSubdirectories);
+ 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());
@@ -423,12 +465,12 @@
@Override
public <T, E extends Exception> void eval(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<T, E> callback, Class<E> exceptionClass)
throws TargetParsingException, E, InterruptedException {
- Preconditions.checkArgument(excludedSubdirectories.isEmpty(),
- "Target pattern \"%s\" of type %s cannot be evaluated with excluded subdirectories: %s.",
- getOriginalPattern(), getType(), excludedSubdirectories);
+ assertBlacklistedAndExcludedSubdirectoriesEmpty(
+ blacklistedSubdirectories, excludedSubdirectories);
if (checkWildcardConflict) {
ResolvedTargets<T> targets = getWildcardConflict(resolver);
if (targets != null) {
@@ -534,6 +576,7 @@
@Override
public <T, E extends Exception> void eval(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<T, E> callback,
Class<E> exceptionClass)
@@ -543,6 +586,7 @@
getOriginalPattern(),
directory.getPackageFragment().getPathString(),
rulesOnly,
+ blacklistedSubdirectories,
excludedSubdirectories,
callback,
exceptionClass);
@@ -551,6 +595,7 @@
@Override
public <T, E extends Exception> ListenableFuture<Void> evalAsync(
TargetPatternResolver<T> resolver,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
ThreadSafeBatchCallback<T, E> callback,
Class<E> exceptionClass,
@@ -560,6 +605,7 @@
getOriginalPattern(),
directory.getPackageFragment().getPathString(),
rulesOnly,
+ blacklistedSubdirectories,
excludedSubdirectories,
callback,
exceptionClass,
@@ -667,6 +713,10 @@
this.relativeDirectory = relativeDirectory;
}
+ public String getRelativeDirectory() {
+ return relativeDirectory;
+ }
+
/**
* Parses the given pattern, and throws an exception if the pattern is invalid.
*
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPatternResolver.java b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPatternResolver.java
index 38b866b..b3e1465 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPatternResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPatternResolver.java
@@ -81,8 +81,10 @@
* @param originalPattern the original target pattern for error reporting purposes
* @param directory the directory in which to look for packages
* @param rulesOnly whether to return rules only
- * @param excludedSubdirectories a set of transitive subdirectories beneath {@code directory}
+ * @param blacklistedSubdirectories a set of transitive subdirectories beneath {@code directory}
* to ignore
+ * @param excludedSubdirectories another set of transitive subdirectories beneath
+ * {@code directory} to ignore
* @param callback the callback to receive the result, possibly in multiple batches.
* @param exceptionClass The class type of the parameterized exception.
* @throws TargetParsingException under implementation-specific failure conditions
@@ -92,6 +94,7 @@
String originalPattern,
String directory,
boolean rulesOnly,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<T, E> callback,
Class<E> exceptionClass)
@@ -106,6 +109,7 @@
String originalPattern,
String directory,
boolean rulesOnly,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
ThreadSafeBatchCallback<T, E> callback,
Class<E> exceptionClass,
@@ -116,6 +120,7 @@
originalPattern,
directory,
rulesOnly,
+ blacklistedSubdirectories,
excludedSubdirectories,
callback,
exceptionClass);
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 9b857d9..1a16b6c 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
@@ -37,6 +37,8 @@
* @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, all of which are beneath
+ * {@code directory}, specifying transitive subdirectories to that have been blacklisted
* @param excludedSubdirectories a set of {@link PathFragment}s, all of which are beneath {@code
* directory}, specifying transitive subdirectories to exclude
*/
@@ -44,6 +46,7 @@
ExtendedEventHandler eventHandler,
RepositoryName repository,
PathFragment directory,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories)
throws InterruptedException;
diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
index 6cc8fd1..8055158 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
@@ -685,24 +685,19 @@
return new UniquifierImpl<>(ReverseDepSkyKeyKeyExtractor.INSTANCE, DEFAULT_THREAD_COUNT);
}
- private Pair<TargetPattern, ImmutableSet<PathFragment>> getPatternAndExcludes(String pattern)
- throws TargetParsingException, InterruptedException {
- TargetPatternKey targetPatternKey =
- TargetPatternValue.key(
- pattern, TargetPatternEvaluator.DEFAULT_FILTERING_POLICY, parserPrefix);
- ImmutableSet<PathFragment> subdirectoriesToExclude =
- targetPatternKey.getAllSubdirectoriesToExclude(blacklistPatternsSupplier);
- return Pair.of(targetPatternKey.getParsedPattern(), subdirectoriesToExclude);
+ private ImmutableSet<PathFragment> getBlacklistedExcludes(TargetPatternKey targetPatternKey)
+ throws InterruptedException {
+ return targetPatternKey.getAllBlacklistedSubdirectoriesToExclude(blacklistPatternsSupplier);
}
@ThreadSafe
@Override
public QueryTaskFuture<Void> getTargetsMatchingPattern(
- final QueryExpression owner, String pattern, Callback<Target> callback) {
- // Directly evaluate the target pattern, making use of packages in the graph.
- Pair<TargetPattern, ImmutableSet<PathFragment>> patternToEvalAndSubdirectoriesToExclude;
+ QueryExpression owner, String pattern, Callback<Target> callback) {
+ TargetPatternKey targetPatternKey;
try {
- patternToEvalAndSubdirectoriesToExclude = getPatternAndExcludes(pattern);
+ targetPatternKey = TargetPatternValue.key(
+ pattern, TargetPatternEvaluator.DEFAULT_FILTERING_POLICY, parserPrefix);
} catch (TargetParsingException tpe) {
try {
reportBuildFileError(owner, tpe.getMessage());
@@ -710,12 +705,22 @@
return immediateFailedFuture(qe);
}
return immediateSuccessfulFuture(null);
+ }
+ return evalTargetPatternKey(owner, targetPatternKey, callback);
+ }
+
+ @ThreadSafe
+ public QueryTaskFuture<Void> evalTargetPatternKey(
+ QueryExpression owner, TargetPatternKey targetPatternKey, Callback<Target> callback) {
+ ImmutableSet<PathFragment> blacklistedSubdirectoriesToExclude;
+ try {
+ blacklistedSubdirectoriesToExclude = getBlacklistedExcludes(targetPatternKey);
} catch (InterruptedException ie) {
return immediateCancelledFuture();
}
- TargetPattern patternToEval = patternToEvalAndSubdirectoriesToExclude.getFirst();
- ImmutableSet<PathFragment> subdirectoriesToExclude =
- patternToEvalAndSubdirectoriesToExclude.getSecond();
+ TargetPattern patternToEval = targetPatternKey.getParsedPattern();
+ ImmutableSet<PathFragment> additionalSubdirectoriesToExclude =
+ targetPatternKey.getExcludedSubdirectories();
AsyncFunction<TargetParsingException, Void> reportBuildFileErrorAsyncFunction =
exn -> {
reportBuildFileError(owner, exn.getMessage());
@@ -723,7 +728,8 @@
};
ListenableFuture<Void> evalFuture = patternToEval.evalAsync(
resolver,
- subdirectoriesToExclude,
+ blacklistedSubdirectoriesToExclude,
+ additionalSubdirectoriesToExclude,
callback,
QueryException.class,
executor);
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/SetExpression.java b/src/main/java/com/google/devtools/build/lib/query2/engine/SetExpression.java
index e1eadf3..57db015 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/engine/SetExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/SetExpression.java
@@ -38,11 +38,11 @@
*
* <pre>expr ::= SET '(' WORD * ')'</pre>
*/
-class SetExpression extends QueryExpression {
+public class SetExpression extends QueryExpression {
private final List<TargetLiteral> words;
- SetExpression(List<TargetLiteral> words) {
+ public SetExpression(List<TargetLiteral> words) {
this.words = words;
}
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 4baa59d..e070b65 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
@@ -19,7 +19,6 @@
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.RepositoryName;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
@@ -37,6 +36,7 @@
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyKey;
import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -115,6 +115,7 @@
ExtendedEventHandler eventHandler,
RepositoryName repository,
PathFragment directory,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories)
throws MissingDepException, InterruptedException {
PathPackageLocator packageLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env);
@@ -140,11 +141,11 @@
roots.add(repositoryValue.getPath());
}
- NestedSetBuilder<String> packageNames = NestedSetBuilder.stableOrder();
+ LinkedHashSet<PathFragment> packageNames = new LinkedHashSet<>();
for (Path root : roots) {
- PathFragment.checkAllPathsAreUnder(excludedSubdirectories, directory);
+ PathFragment.checkAllPathsAreUnder(blacklistedSubdirectories, directory);
RecursivePkgValue lookup = (RecursivePkgValue) env.getValue(RecursivePkgValue.key(
- repository, RootedPath.toRootedPath(root, directory), excludedSubdirectories));
+ repository, RootedPath.toRootedPath(root, directory), blacklistedSubdirectories));
if (lookup == null) {
// Typically a null value from Environment.getValue(k) means that either the key k is
// missing a dependency or an exception was thrown during evaluation of k. Here, if this
@@ -156,11 +157,19 @@
throw new MissingDepException();
}
- packageNames.addTransitive(lookup.getPackages());
+ for (String packageName : lookup.getPackages()) {
+ // TODO(bazel-team): Make RecursivePkgValue return NestedSet<PathFragment> so this transform
+ // is unnecessary.
+ PathFragment packageNamePathFragment = PathFragment.create(packageName);
+ if (!Iterables.any(
+ excludedSubdirectories,
+ excludedSubdirectory -> packageNamePathFragment.startsWith(excludedSubdirectory))) {
+ packageNames.add(packageNamePathFragment);
+ }
+ }
}
- // TODO(bazel-team): Make RecursivePkgValue return NestedSet<PathFragment> so this transform is
- // unnecessary.
- return Iterables.transform(packageNames.build(), PathFragment::create);
+
+ return packageNames;
}
@Override
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 b5ba1da..0cc2097 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
@@ -166,10 +166,16 @@
ExtendedEventHandler eventHandler,
RepositoryName repository,
PathFragment directory,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories)
throws InterruptedException {
+ PathFragment.checkAllPathsAreUnder(blacklistedSubdirectories, directory);
PathFragment.checkAllPathsAreUnder(excludedSubdirectories, directory);
+ if (excludedSubdirectories.contains(directory)) {
+ return ImmutableList.of();
+ }
+
// Check that this package is covered by at least one of our universe patterns.
boolean inUniverse = false;
for (TargetPatternKey patternKey : universeTargetPatternKeys) {
@@ -206,7 +212,8 @@
ImmutableList.Builder<PathFragment> builder = ImmutableList.builder();
for (Path root : roots) {
RootedPath rootedDir = RootedPath.toRootedPath(root, directory);
- TraversalInfo info = new TraversalInfo(rootedDir, excludedSubdirectories);
+ TraversalInfo info =
+ new TraversalInfo(rootedDir, blacklistedSubdirectories, excludedSubdirectories);
collectPackagesUnder(eventHandler, repository, ImmutableSet.of(info), builder);
}
return builder.build();
@@ -225,7 +232,7 @@
@Override
public SkyKey apply(TraversalInfo traversalInfo) {
return CollectPackagesUnderDirectoryValue.key(
- repository, traversalInfo.rootedDir, traversalInfo.excludedSubdirectories);
+ repository, traversalInfo.rootedDir, traversalInfo.blacklistedSubdirectories);
}
});
Map<SkyKey, SkyValue> values = graph.getSuccessfulValues(traversalToKeyMap.values());
@@ -251,11 +258,19 @@
for (RootedPath subdirectory : subdirectoryTransitivelyContainsPackages.keySet()) {
if (subdirectoryTransitivelyContainsPackages.get(subdirectory)) {
PathFragment subdirectoryRelativePath = subdirectory.getRelativePath();
+ ImmutableSet<PathFragment> blacklistedSubdirectoriesBeneathThisSubdirectory =
+ PathFragment.filterPathsStartingWith(
+ info.blacklistedSubdirectories, subdirectoryRelativePath);
ImmutableSet<PathFragment> excludedSubdirectoriesBeneathThisSubdirectory =
PathFragment.filterPathsStartingWith(
info.excludedSubdirectories, subdirectoryRelativePath);
- subdirTraversalBuilder.add(
- new TraversalInfo(subdirectory, excludedSubdirectoriesBeneathThisSubdirectory));
+ if (!excludedSubdirectoriesBeneathThisSubdirectory.contains(subdirectoryRelativePath)) {
+ subdirTraversalBuilder.add(
+ new TraversalInfo(
+ subdirectory,
+ blacklistedSubdirectoriesBeneathThisSubdirectory,
+ excludedSubdirectoriesBeneathThisSubdirectory));
+ }
}
}
}
@@ -275,16 +290,28 @@
private static final class TraversalInfo {
private final RootedPath rootedDir;
+ // Set of blacklisted directories. The graph is assumed to be prepopulated with
+ // CollectPackagesUnderDirectoryValue nodes whose keys have blacklisted packages embedded in
+ // them. Therefore, we need to be careful to request and use the same sort of keys here in our
+ // traversal.
+ private final ImmutableSet<PathFragment> blacklistedSubdirectories;
+ // Set of directories, targets under which should be excluded from the traversal results.
+ // Excluded directory information isn't part of the graph keys in the prepopulated graph, so we
+ // need to perform the filtering ourselves.
private final ImmutableSet<PathFragment> excludedSubdirectories;
- private TraversalInfo(RootedPath rootedDir, ImmutableSet<PathFragment> excludedSubdirectories) {
+ private TraversalInfo(
+ RootedPath rootedDir,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
+ ImmutableSet<PathFragment> excludedSubdirectories) {
this.rootedDir = rootedDir;
+ this.blacklistedSubdirectories = blacklistedSubdirectories;
this.excludedSubdirectories = excludedSubdirectories;
}
@Override
public int hashCode() {
- return Objects.hashCode(rootedDir, excludedSubdirectories);
+ return Objects.hashCode(rootedDir, blacklistedSubdirectories, excludedSubdirectories);
}
@Override
@@ -295,6 +322,7 @@
if (obj instanceof TraversalInfo) {
TraversalInfo otherTraversal = (TraversalInfo) obj;
return Objects.equal(rootedDir, otherTraversal.rootedDir)
+ && Objects.equal(blacklistedSubdirectories, otherTraversal.blacklistedSubdirectories)
&& Objects.equal(excludedSubdirectories, otherTraversal.excludedSubdirectories);
}
return false;
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 a4a3b1b..b2ce5b6 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
@@ -84,15 +84,22 @@
if (blacklist == null) {
return null;
}
- ImmutableSet<PathFragment> subdirectoriesToExclude =
+ // This SkyFunction is used to load the universe, so we want both the blacklisted directories
+ // from the global blacklist and the excluded directories from the TargetPatternKey itself to be
+ // embedded in the SkyKeys created and used by the DepsOfPatternPreparer. The
+ // DepsOfPatternPreparer ignores excludedSubdirectories and embeds blacklistedSubdirectories in
+ // the SkyKeys it creates and uses.
+ ImmutableSet<PathFragment> blacklistedSubdirectories =
patternKey.getAllSubdirectoriesToExclude(blacklist.getPatterns());
+ ImmutableSet<PathFragment> excludedSubdirectories = ImmutableSet.of();
DepsOfPatternPreparer preparer = new DepsOfPatternPreparer(env, pkgPath.get());
try {
parsedPattern.eval(
preparer,
- subdirectoriesToExclude,
+ blacklistedSubdirectories,
+ excludedSubdirectories,
NullCallback.<Void>instance(),
RuntimeException.class);
} catch (TargetParsingException e) {
@@ -227,10 +234,12 @@
String originalPattern,
String directory,
boolean rulesOnly,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<Void, E> callback,
Class<E> exceptionClass)
throws TargetParsingException, E, InterruptedException {
+ Preconditions.checkArgument(excludedSubdirectories.isEmpty(), excludedSubdirectories);
FilteringPolicy policy =
rulesOnly ? FilteringPolicies.RULES_ONLY : FilteringPolicies.NO_FILTER;
PathFragment pathFragment = TargetPatternResolverUtil.getPathFragment(directory);
@@ -257,9 +266,9 @@
env.getValues(
ImmutableList.of(
PrepareDepsOfTargetsUnderDirectoryValue.key(
- repository, rootedPath, excludedSubdirectories, policy),
+ repository, rootedPath, blacklistedSubdirectories, policy),
CollectPackagesUnderDirectoryValue.key(
- repository, rootedPath, excludedSubdirectories)));
+ repository, rootedPath, blacklistedSubdirectories)));
if (env.valuesMissing()) {
throw new MissingDepException();
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java
index f54604d..1dc932d 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java
@@ -14,15 +14,12 @@
package com.google.devtools.build.lib.skyframe;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
-import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.cmdline.TargetPattern.Type;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternSkyKeyOrException;
-import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.LegacySkyKey;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
@@ -58,123 +55,97 @@
return 42;
}
+
/**
- * Returns an iterable of {@link PrepareDepsOfPatternSkyKeyOrException}, with {@link
- * TargetPatternKey} arguments. Negative target patterns of type other than {@link
- * Type#TARGETS_BELOW_DIRECTORY} are not permitted. If a provided pattern fails to parse or is
- * negative but not a {@link Type#TARGETS_BELOW_DIRECTORY}, an element in the returned iterable
- * will throw when its {@link PrepareDepsOfPatternSkyKeyOrException#getSkyKey} method is called
- * and will return the failing pattern when its {@link
- * PrepareDepsOfPatternSkyKeyOrException#getOriginalPattern} method is called.
+ * Returns a {@link PrepareDepsOfPatternSkyKeysAndExceptions}, containing
+ * {@link PrepareDepsOfPatternSkyKeyValue} and {@link PrepareDepsOfPatternSkyKeyException}
+ * instances that have {@link TargetPatternKey} arguments. Negative target patterns of type other
+ * than {@link Type#TARGETS_BELOW_DIRECTORY} are not permitted. If a provided pattern fails to
+ * parse or is negative but not a {@link Type#TARGETS_BELOW_DIRECTORY}, there will be a
+ * corresponding {@link PrepareDepsOfPatternSkyKeyException} in the iterable returned by
+ * {@link PrepareDepsOfPatternSkyKeysAndExceptions#getExceptions} whose
+ * {@link PrepareDepsOfPatternSkyKeyException#getException} and
+ * {@link PrepareDepsOfPatternSkyKeyException#getOriginalPattern} methods return the
+ * {@link TargetParsingException} and original pattern, respectively.
*
- * <p>There may be fewer returned elements than patterns provided as input. This function will
- * combine negative {@link Type#TARGETS_BELOW_DIRECTORY} patterns with preceding patterns to
- * return an iterable of SkyKeys that avoids loading excluded directories during evaluation.
+ * <p>There may be fewer returned elements in
+ * {@link PrepareDepsOfPatternSkyKeysAndExceptions#getValues} than patterns provided as input.
+ * This function will combine negative {@link Type#TARGETS_BELOW_DIRECTORY} patterns with
+ * preceding patterns to return an iterable of SkyKeys that avoids loading excluded directories
+ * during evaluation.
*
* @param patterns The list of patterns, e.g. [//foo/..., -//foo/biz/...]. If a pattern's first
* character is "-", it is treated as a negative pattern.
* @param offset The offset to apply to relative target patterns.
*/
@ThreadSafe
- public static Iterable<PrepareDepsOfPatternSkyKeyOrException> keys(List<String> patterns,
- String offset) {
- List<TargetPatternSkyKeyOrException> keysMaybe =
- ImmutableList.copyOf(TargetPatternValue.keys(patterns, FilteringPolicies.NO_FILTER,
- offset));
-
+ public static PrepareDepsOfPatternSkyKeysAndExceptions keys(
+ List<String> patterns, String offset) {
+ ImmutableList.Builder<PrepareDepsOfPatternSkyKeyValue> resultValuesBuilder =
+ ImmutableList.builder();
+ ImmutableList.Builder<PrepareDepsOfPatternSkyKeyException> resultExceptionsBuilder =
+ ImmutableList.builder();
+ Iterable<TargetPatternSkyKeyOrException> keysMaybe =
+ TargetPatternValue.keys(patterns, FilteringPolicies.NO_FILTER, offset);
+ ImmutableList.Builder<TargetPatternKey> targetPatternKeysBuilder = ImmutableList.builder();
+ for (TargetPatternSkyKeyOrException keyMaybe : keysMaybe) {
+ try {
+ SkyKey key = keyMaybe.getSkyKey();
+ targetPatternKeysBuilder.add((TargetPatternKey) key.argument());
+ } catch (TargetParsingException e) {
+ resultExceptionsBuilder.add(
+ new PrepareDepsOfPatternSkyKeyException(e, keyMaybe.getOriginalPattern()));
+ }
+ }
// This code path is evaluated only for query universe preloading, and the quadratic cost of
// the code below (i.e. for each pattern, consider each later pattern as a candidate for
// subdirectory exclusion) is only acceptable because all the use cases for query universe
// preloading involve short (<10 items) pattern sequences.
- ImmutableList.Builder<PrepareDepsOfPatternSkyKeyOrException> builder = ImmutableList.builder();
- for (int i = 0; i < keysMaybe.size(); i++) {
- TargetPatternSkyKeyOrException keyMaybe = keysMaybe.get(i);
- TargetPatternKey targetPatternKey;
- try {
- targetPatternKey = keyMaybe.getSkyKey();
- } catch (TargetParsingException e) {
- // keyMaybe.getSkyKey() may throw TargetParsingException if its corresponding pattern
- // failed to parse. If so, wrap the exception and return it, so that our caller can
- // deal with it.
- targetPatternKey = null;
- builder.add(new PrepareDepsOfPatternSkyKeyException(e, keyMaybe.getOriginalPattern()));
- }
- if (targetPatternKey != null) {
- if (targetPatternKey.isNegative()) {
- if (!targetPatternKey.getParsedPattern().getType().equals(Type.TARGETS_BELOW_DIRECTORY)) {
- builder.add(
- new PrepareDepsOfPatternSkyKeyException(
- new TargetParsingException(
- "Negative target patterns of types other than \"targets below directory\""
- + " are not permitted."), targetPatternKey.toString()));
- }
- // Otherwise it's a negative TBD pattern which was combined with previous patterns as an
- // excluded directory. These can be skipped because there's no PrepareDepsOfPattern work
- // to be done for them.
- } else {
- builder.add(new PrepareDepsOfPatternSkyKeyValue(setExcludedDirectories(targetPatternKey,
- excludedDirectoriesBeneath(targetPatternKey, i, keysMaybe))));
- }
+ Iterable<TargetPatternKey> combinedTargetPatternKeys =
+ TargetPatternValue.combineNegativeTargetsBelowDirectoryPatterns(
+ targetPatternKeysBuilder.build());
+ for (TargetPatternKey targetPatternKey : combinedTargetPatternKeys) {
+ if (targetPatternKey.isNegative()
+ && !targetPatternKey.getParsedPattern().getType().equals(Type.TARGETS_BELOW_DIRECTORY)) {
+ resultExceptionsBuilder.add(
+ new PrepareDepsOfPatternSkyKeyException(
+ new TargetParsingException(
+ "Negative target patterns of types other than \"targets below directory\""
+ + " are not permitted."), targetPatternKey.toString()));
+ } else {
+ resultValuesBuilder.add(new PrepareDepsOfPatternSkyKeyValue(targetPatternKey));
}
}
- return builder.build();
- }
-
- private static TargetPatternKey setExcludedDirectories(
- TargetPatternKey original, ImmutableSet<PathFragment> excludedSubdirectories) {
- return new TargetPatternKey(original.getParsedPattern(), original.getPolicy(),
- original.isNegative(), original.getOffset(), excludedSubdirectories);
- }
-
- private static ImmutableSet<PathFragment> excludedDirectoriesBeneath(
- TargetPatternKey targetPatternKey,
- int position,
- List<TargetPatternSkyKeyOrException> keysMaybe) {
- ImmutableSet.Builder<PathFragment> excludedDirectoriesBuilder = ImmutableSet.builder();
- for (int j = position + 1; j < keysMaybe.size(); j++) {
- TargetPatternSkyKeyOrException laterPatternMaybe = keysMaybe.get(j);
- TargetPatternKey laterTargetPatternKey;
- try {
- laterTargetPatternKey = laterPatternMaybe.getSkyKey();
- } catch (TargetParsingException ignored) {
- laterTargetPatternKey = null;
- }
- if (laterTargetPatternKey != null) {
- TargetPattern laterParsedPattern = laterTargetPatternKey.getParsedPattern();
- if (laterTargetPatternKey.isNegative()
- && laterParsedPattern.getType() == Type.TARGETS_BELOW_DIRECTORY
- && targetPatternKey.getParsedPattern().containsDirectoryOfTBDForTBD(
- laterParsedPattern)) {
- excludedDirectoriesBuilder.add(
- laterParsedPattern.getDirectoryForTargetsUnderDirectory().getPackageFragment());
- }
- }
- }
- return excludedDirectoriesBuilder.build();
+ return new PrepareDepsOfPatternSkyKeysAndExceptions(
+ resultValuesBuilder.build(), resultExceptionsBuilder.build());
}
/**
- * Wrapper for a prepare deps of pattern {@link SkyKey} or the {@link TargetParsingException}
- * thrown when trying to create it.
+ * A pair of {@link Iterable<PrepareDepsOfPatternSkyKeyValue>} and
+ * {@link Iterable<PrepareDepsOfPatternSkyKeyException>}.
*/
- public interface PrepareDepsOfPatternSkyKeyOrException {
+ public static class PrepareDepsOfPatternSkyKeysAndExceptions {
+ private final Iterable<PrepareDepsOfPatternSkyKeyValue> values;
+ private final Iterable<PrepareDepsOfPatternSkyKeyException> exceptions;
- /**
- * Returns the stored {@link SkyKey} or throws {@link TargetParsingException} if one was thrown
- * when creating the key.
- */
- SkyKey getSkyKey() throws TargetParsingException;
+ public PrepareDepsOfPatternSkyKeysAndExceptions(
+ Iterable<PrepareDepsOfPatternSkyKeyValue> values,
+ Iterable<PrepareDepsOfPatternSkyKeyException> exceptions) {
+ this.values = values;
+ this.exceptions = exceptions;
+ }
- /**
- * Returns the pattern that resulted in the stored {@link SkyKey} or {@link
- * TargetParsingException}.
- */
- String getOriginalPattern();
+ public Iterable<PrepareDepsOfPatternSkyKeyValue> getValues() {
+ return values;
+ }
+
+ public Iterable<PrepareDepsOfPatternSkyKeyException> getExceptions() {
+ return exceptions;
+ }
}
-
- private static class PrepareDepsOfPatternSkyKeyException implements
- PrepareDepsOfPatternSkyKeyOrException {
+ /** Represents a {@link TargetParsingException} when parsing a target pattern string. */
+ public static class PrepareDepsOfPatternSkyKeyException {
private final TargetParsingException exception;
private final String originalPattern;
@@ -185,19 +156,19 @@
this.originalPattern = originalPattern;
}
- @Override
- public SkyKey getSkyKey() throws TargetParsingException {
- throw exception;
+ public TargetParsingException getException() {
+ return exception;
}
- @Override
public String getOriginalPattern() {
return originalPattern;
}
}
- private static class PrepareDepsOfPatternSkyKeyValue implements
- PrepareDepsOfPatternSkyKeyOrException {
+ /**
+ * Represents the successful parsing of a target pattern string into a {@link TargetPatternKey}.
+ */
+ public static class PrepareDepsOfPatternSkyKeyValue {
private final TargetPatternKey targetPatternKey;
@@ -205,12 +176,10 @@
this.targetPatternKey = targetPatternKey;
}
- @Override
- public SkyKey getSkyKey() throws TargetParsingException {
+ public SkyKey getSkyKey() {
return LegacySkyKey.create(SkyFunctions.PREPARE_DEPS_OF_PATTERN, targetPatternKey);
}
- @Override
public String getOriginalPattern() {
return targetPatternKey.getPattern();
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java
index 422462e..3e48fab 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java
@@ -20,7 +20,9 @@
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.pkgcache.ParsingFailedEvent;
-import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternValue.PrepareDepsOfPatternSkyKeyOrException;
+import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternValue.PrepareDepsOfPatternSkyKeyException;
+import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternValue.PrepareDepsOfPatternSkyKeyValue;
+import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternValue.PrepareDepsOfPatternSkyKeysAndExceptions;
import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternsValue.TargetPatternSequence;
import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
import com.google.devtools.build.lib.util.Preconditions;
@@ -39,22 +41,24 @@
public static ImmutableList<SkyKey> getSkyKeys(SkyKey skyKey, ExtendedEventHandler eventHandler) {
TargetPatternSequence targetPatternSequence = (TargetPatternSequence) skyKey.argument();
- Iterable<PrepareDepsOfPatternSkyKeyOrException> keysMaybe =
+ PrepareDepsOfPatternSkyKeysAndExceptions prepareDepsOfPatternSkyKeysAndExceptions =
PrepareDepsOfPatternValue.keys(targetPatternSequence.getPatterns(),
targetPatternSequence.getOffset());
ImmutableList.Builder<SkyKey> skyKeyBuilder = ImmutableList.builder();
- for (PrepareDepsOfPatternSkyKeyOrException skyKeyOrException : keysMaybe) {
- try {
- skyKeyBuilder.add(skyKeyOrException.getSkyKey());
- } catch (TargetParsingException e) {
- // We post an event here rather than in handleTargetParsingException because the
- // TargetPatternFunction already posts an event unless the pattern cannot be parsed, in
- // which case the caller (i.e., us) needs to post an event.
- eventHandler.post(
- new ParsingFailedEvent(skyKeyOrException.getOriginalPattern(), e.getMessage()));
- handleTargetParsingException(eventHandler, skyKeyOrException.getOriginalPattern(), e);
- }
+ for (PrepareDepsOfPatternSkyKeyValue skyKeyValue
+ : prepareDepsOfPatternSkyKeysAndExceptions.getValues()) {
+ skyKeyBuilder.add(skyKeyValue.getSkyKey());
+ }
+ for (PrepareDepsOfPatternSkyKeyException skyKeyException
+ : prepareDepsOfPatternSkyKeysAndExceptions.getExceptions()) {
+ TargetParsingException e = skyKeyException.getException();
+ // We post an event here rather than in handleTargetParsingException because the
+ // TargetPatternFunction already posts an event unless the pattern cannot be parsed, in
+ // which case the caller (i.e., us) needs to post an event.
+ eventHandler.post(
+ new ParsingFailedEvent(skyKeyException.getOriginalPattern(), e.getMessage()));
+ handleTargetParsingException(eventHandler, skyKeyException.getOriginalPattern(), e);
}
return skyKeyBuilder.build();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
index 2fb7486..4ba2122 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
@@ -216,6 +216,7 @@
final String originalPattern,
String directory,
boolean rulesOnly,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
BatchCallback<Target, E> callback,
Class<E> exceptionClass)
@@ -226,6 +227,7 @@
originalPattern,
directory,
rulesOnly,
+ blacklistedSubdirectories,
excludedSubdirectories,
new SynchronizedBatchCallback<Target, E>(callback),
MoreExecutors.newDirectExecutorService()).get();
@@ -242,6 +244,7 @@
String originalPattern,
String directory,
boolean rulesOnly,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
ThreadSafeBatchCallback<Target, E> callback,
Class<E> exceptionClass,
@@ -251,6 +254,7 @@
originalPattern,
directory,
rulesOnly,
+ blacklistedSubdirectories,
excludedSubdirectories,
callback,
executor);
@@ -261,6 +265,7 @@
final String originalPattern,
String directory,
boolean rulesOnly,
+ ImmutableSet<PathFragment> blacklistedSubdirectories,
ImmutableSet<PathFragment> excludedSubdirectories,
final ThreadSafeBatchCallback<Target, E> callback,
ListeningExecutorService executor) {
@@ -273,7 +278,11 @@
pathFragment = TargetPatternResolverUtil.getPathFragment(directory);
packagesUnderDirectory =
recursivePackageProvider.getPackagesUnderDirectory(
- eventHandler, repository, pathFragment, excludedSubdirectories);
+ eventHandler,
+ repository,
+ pathFragment,
+ blacklistedSubdirectories,
+ excludedSubdirectories);
} catch (TargetParsingException e) {
return Futures.immediateFailedFuture(e);
} catch (InterruptedException e) {
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 62b537c..197e0f7 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
@@ -69,7 +69,12 @@
Iterables.addAll(results, partialResult);
}
};
- parsedPattern.eval(resolver, excludedSubdirectories, callback, RuntimeException.class);
+ parsedPattern.eval(
+ resolver,
+ /*blacklistedSubdirectories=*/ ImmutableSet.of(),
+ excludedSubdirectories,
+ callback,
+ RuntimeException.class);
resolvedTargets = ResolvedTargets.<Target>builder().addAll(results).build();
} catch (TargetParsingException e) {
env.getListener().post(new ParsingFailedEvent(patternKey.getPattern(), e.getMessage()));
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 f36a439..f28cdfd 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
@@ -23,6 +23,7 @@
import com.google.devtools.build.lib.cmdline.ResolvedTargets.Builder;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.cmdline.TargetPattern;
+import com.google.devtools.build.lib.cmdline.TargetPattern.ContainsTBDForTBDResult;
import com.google.devtools.build.lib.cmdline.TargetPattern.Type;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
@@ -39,8 +40,10 @@
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
/**
* A value referring to a computed set of resolved targets. This is used for the results of target
@@ -152,6 +155,88 @@
return builder.build();
}
+ @ThreadSafe
+ public static ImmutableList<TargetPatternKey> combineNegativeTargetsBelowDirectoryPatterns(
+ List<TargetPatternKey> keys) {
+ ImmutableList.Builder<TargetPatternKey> builder = ImmutableList.builder();
+ HashSet<Integer> indicesOfNegativePatternsThatNeedToBeIncluded = new HashSet<>();
+ for (int i = 0; i < keys.size(); i++) {
+ TargetPatternKey targetPatternKey = keys.get(i);
+ if (targetPatternKey.isNegative()) {
+ if (!targetPatternKey.getParsedPattern().getType().equals(Type.TARGETS_BELOW_DIRECTORY)
+ || indicesOfNegativePatternsThatNeedToBeIncluded.contains(i)) {
+ builder.add(targetPatternKey);
+ }
+ // Otherwise it's a negative TBD pattern which was combined with previous patterns as an
+ // excluded directory.
+ } else {
+ TargetPatternKeyWithExclusionsResult result =
+ computeTargetPatternKeyWithExclusions(targetPatternKey, i, keys);
+ result.targetPatternKeyMaybe.ifPresent(builder::add);
+ indicesOfNegativePatternsThatNeedToBeIncluded.addAll(
+ result.indicesOfNegativePatternsThatNeedToBeIncluded);
+ }
+ }
+ return builder.build();
+ }
+
+ private static TargetPatternKey setExcludedDirectories(
+ TargetPatternKey original, ImmutableSet<PathFragment> excludedSubdirectories) {
+ return new TargetPatternKey(original.getParsedPattern(), original.getPolicy(),
+ original.isNegative(), original.getOffset(), excludedSubdirectories);
+ }
+
+ private static class TargetPatternKeyWithExclusionsResult {
+ private final Optional<TargetPatternKey> targetPatternKeyMaybe;
+ private final ImmutableList<Integer> indicesOfNegativePatternsThatNeedToBeIncluded;
+
+ private TargetPatternKeyWithExclusionsResult(
+ Optional<TargetPatternKey> targetPatternKeyMaybe,
+ ImmutableList<Integer> indicesOfNegativePatternsThatNeedToBeIncluded) {
+ this.targetPatternKeyMaybe = targetPatternKeyMaybe;
+ this.indicesOfNegativePatternsThatNeedToBeIncluded =
+ indicesOfNegativePatternsThatNeedToBeIncluded;
+ }
+ }
+
+ private static TargetPatternKeyWithExclusionsResult computeTargetPatternKeyWithExclusions(
+ TargetPatternKey targetPatternKey,
+ int position,
+ List<TargetPatternKey> keys) {
+ TargetPattern targetPattern = targetPatternKey.getParsedPattern();
+ ImmutableSet.Builder<PathFragment> excludedDirectoriesBuilder = ImmutableSet.builder();
+ ImmutableList.Builder<Integer> indicesOfNegativePatternsThatNeedToBeIncludedBuilder =
+ ImmutableList.builder();
+ for (int j = position + 1; j < keys.size(); j++) {
+ TargetPatternKey laterTargetPatternKey = keys.get(j);
+ TargetPattern laterParsedPattern = laterTargetPatternKey.getParsedPattern();
+ if (laterTargetPatternKey.isNegative()
+ && laterParsedPattern.getType() == Type.TARGETS_BELOW_DIRECTORY) {
+ if (laterParsedPattern.containsTBDForTBD(targetPattern)
+ == ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_EXACT) {
+ return new TargetPatternKeyWithExclusionsResult(Optional.empty(), ImmutableList.of());
+ } else {
+ switch (targetPattern.containsTBDForTBD(laterParsedPattern)) {
+ case DIRECTORY_EXCLUSION_WOULD_BE_EXACT:
+ excludedDirectoriesBuilder.add(
+ laterParsedPattern.getDirectoryForTargetsUnderDirectory().getPackageFragment());
+ break;
+ case DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD:
+ indicesOfNegativePatternsThatNeedToBeIncludedBuilder.add(j);
+ break;
+ case OTHER:
+ default:
+ // Nothing to do with this pattern.
+ }
+
+ }
+ }
+ }
+ return new TargetPatternKeyWithExclusionsResult(
+ Optional.of(setExcludedDirectories(targetPatternKey, excludedDirectoriesBuilder.build())),
+ indicesOfNegativePatternsThatNeedToBeIncludedBuilder.build());
+ }
+
public ResolvedTargets<Label> getTargets() {
return targets;
}
@@ -214,15 +299,17 @@
ImmutableSet<PathFragment> getAllSubdirectoriesToExclude(
Iterable<PathFragment> blacklistedPackagePrefixes) throws InterruptedException {
- return getAllSubdirectoriesToExclude(
- new InterruptibleSupplier.Instance<>(blacklistedPackagePrefixes));
- }
-
- public ImmutableSet<PathFragment> getAllSubdirectoriesToExclude(
- InterruptibleSupplier<? extends Iterable<PathFragment>> blacklistedPackagePrefixes)
- throws InterruptedException {
ImmutableSet.Builder<PathFragment> excludedPathsBuilder = ImmutableSet.builder();
excludedPathsBuilder.addAll(getExcludedSubdirectories());
+ excludedPathsBuilder.addAll(getAllBlacklistedSubdirectoriesToExclude(
+ new InterruptibleSupplier.Instance<>(blacklistedPackagePrefixes)));
+ return excludedPathsBuilder.build();
+ }
+
+ public ImmutableSet<PathFragment> getAllBlacklistedSubdirectoriesToExclude(
+ InterruptibleSupplier<? extends Iterable<PathFragment>> blacklistedPackagePrefixes)
+ throws InterruptedException {
+ ImmutableSet.Builder<PathFragment> blacklistedPathsBuilder = ImmutableSet.builder();
if (parsedPattern.getType() == Type.TARGETS_BELOW_DIRECTORY) {
for (PathFragment blacklistedPackagePrefix : blacklistedPackagePrefixes.get()) {
PackageIdentifier pkgIdForBlacklistedDirectorPrefix = PackageIdentifier.create(
@@ -230,11 +317,11 @@
blacklistedPackagePrefix);
if (parsedPattern.containsAllTransitiveSubdirectoriesForTBD(
pkgIdForBlacklistedDirectorPrefix)) {
- excludedPathsBuilder.add(blacklistedPackagePrefix);
+ blacklistedPathsBuilder.add(blacklistedPackagePrefix);
}
}
}
- return excludedPathsBuilder.build();
+ return blacklistedPathsBuilder.build();
}
@Override
diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/TargetPatternTest.java b/src/test/java/com/google/devtools/build/lib/cmdline/TargetPatternTest.java
index 1804abb..bcc9e78 100644
--- a/src/test/java/com/google/devtools/build/lib/cmdline/TargetPatternTest.java
+++ b/src/test/java/com/google/devtools/build/lib/cmdline/TargetPatternTest.java
@@ -17,6 +17,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
+import com.google.devtools.build.lib.cmdline.TargetPattern.ContainsTBDForTBDResult;
import com.google.devtools.build.lib.cmdline.TargetPattern.Type;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -86,15 +87,48 @@
}
@Test
+ public void testTargetsBelowDirectoryContainsColonStar() throws Exception {
+ // Given an outer pattern '//foo/...', that matches rules only,
+ TargetPattern outerPattern = parseAsExpectedType("//foo/...", Type.TARGETS_BELOW_DIRECTORY);
+ // And a nested inner pattern '//foo/bar/...:*', that matches all targets,
+ TargetPattern innerPattern =
+ parseAsExpectedType("//foo/bar/...:*", Type.TARGETS_BELOW_DIRECTORY);
+ // Then a directory exclusion would exactly describe the subtraction of the inner pattern from
+ // the outer pattern,
+ assertThat(outerPattern.containsTBDForTBD(innerPattern))
+ .isEqualTo(ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_EXACT);
+ // And the inner pattern does not contain the outer pattern.
+ assertThat(innerPattern.containsTBDForTBD(outerPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ }
+
+ @Test
+ public void testTargetsBelowDirectoryColonStarContains() throws Exception {
+ // Given an outer pattern '//foo/...:*', that matches all targets,
+ TargetPattern outerPattern = parseAsExpectedType("//foo/...:*", Type.TARGETS_BELOW_DIRECTORY);
+ // And a nested inner pattern '//foo/bar/...', that matches rules only,
+ TargetPattern innerPattern =
+ parseAsExpectedType("//foo/bar/...", Type.TARGETS_BELOW_DIRECTORY);
+ // Then a directory exclusion would be too broad,
+ assertThat(outerPattern.containsTBDForTBD(innerPattern))
+ .isEqualTo(ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD);
+ // And the inner pattern does not contain the outer pattern.
+ assertThat(innerPattern.containsTBDForTBD(outerPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ }
+
+ @Test
public void testTargetsBelowDirectoryContainsNestedPatterns() throws Exception {
// Given an outer pattern '//foo/...',
TargetPattern outerPattern = parseAsExpectedType("//foo/...", Type.TARGETS_BELOW_DIRECTORY);
// And a nested inner pattern '//foo/bar/...',
TargetPattern innerPattern = parseAsExpectedType("//foo/bar/...", Type.TARGETS_BELOW_DIRECTORY);
- // Then the outer pattern contains the inner pattern,,
- assertThat(outerPattern.containsDirectoryOfTBDForTBD(innerPattern)).isTrue();
+ // Then the outer pattern contains the inner pattern,
+ assertThat(outerPattern.containsTBDForTBD(innerPattern))
+ .isEqualTo(ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_EXACT);
// And the inner pattern does not contain the outer pattern.
- assertThat(innerPattern.containsDirectoryOfTBDForTBD(outerPattern)).isFalse();
+ assertThat(innerPattern.containsTBDForTBD(outerPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
}
@Test
@@ -104,8 +138,8 @@
// And a pattern '//bar/...',
TargetPattern patternBar = parseAsExpectedType("//bar/...", Type.TARGETS_BELOW_DIRECTORY);
// Then neither pattern contains the other.
- assertThat(patternFoo.containsDirectoryOfTBDForTBD(patternBar)).isFalse();
- assertThat(patternBar.containsDirectoryOfTBDForTBD(patternFoo)).isFalse();
+ assertThat(patternFoo.containsTBDForTBD(patternBar)).isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(patternBar.containsTBDForTBD(patternFoo)).isEqualTo(ContainsTBDForTBDResult.OTHER);
}
@Test
@@ -120,15 +154,21 @@
TargetPattern targetsInPackagePattern = parseAsExpectedType("foo:all", Type.TARGETS_IN_PACKAGE);
// Then the non-TargetsBelowDirectory patterns do not contain tbdFoo.
- assertThat(pathAsTargetPattern.containsDirectoryOfTBDForTBD(tbdFoo)).isFalse();
+ assertThat(pathAsTargetPattern.containsTBDForTBD(tbdFoo))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
// And are not considered to be a contained directory of the TargetsBelowDirectory pattern.
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(pathAsTargetPattern)).isFalse();
+ assertThat(tbdFoo.containsTBDForTBD(pathAsTargetPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
- assertThat(singleTargetPattern.containsDirectoryOfTBDForTBD(tbdFoo)).isFalse();
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(singleTargetPattern)).isFalse();
+ assertThat(singleTargetPattern.containsTBDForTBD(tbdFoo))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(tbdFoo.containsTBDForTBD(singleTargetPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
- assertThat(targetsInPackagePattern.containsDirectoryOfTBDForTBD(tbdFoo)).isFalse();
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(targetsInPackagePattern)).isFalse();
+ assertThat(targetsInPackagePattern.containsTBDForTBD(tbdFoo))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(tbdFoo.containsTBDForTBD(targetsInPackagePattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
}
@Test
@@ -146,10 +186,14 @@
parseAsExpectedType("food:all", Type.TARGETS_IN_PACKAGE);
// Then the non-TargetsBelowDirectory patterns are not contained by tbdFoo.
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(targetsBelowDirectoryPattern)).isFalse();
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(pathAsTargetPattern)).isFalse();
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(singleTargetPattern)).isFalse();
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(targetsInPackagePattern)).isFalse();
+ assertThat(tbdFoo.containsTBDForTBD(targetsBelowDirectoryPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(tbdFoo.containsTBDForTBD(pathAsTargetPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(tbdFoo.containsTBDForTBD(singleTargetPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(tbdFoo.containsTBDForTBD(targetsInPackagePattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
}
@Test
@@ -165,17 +209,24 @@
TargetPattern targetsInPackagePattern = parseAsExpectedType("foo:all", Type.TARGETS_IN_PACKAGE);
// Then the patterns are contained by tbdDepot, and do not contain tbdDepot.
- assertThat(tbdDepot.containsDirectoryOfTBDForTBD(tbdFoo)).isTrue();
- assertThat(tbdFoo.containsDirectoryOfTBDForTBD(tbdDepot)).isFalse();
+ assertThat(tbdDepot.containsTBDForTBD(tbdFoo))
+ .isEqualTo(ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_EXACT);
+ assertThat(tbdFoo.containsTBDForTBD(tbdDepot)).isEqualTo(ContainsTBDForTBDResult.OTHER);
- assertThat(tbdDepot.containsDirectoryOfTBDForTBD(pathAsTargetPattern)).isFalse();
- assertThat(pathAsTargetPattern.containsDirectoryOfTBDForTBD(tbdDepot)).isFalse();
+ assertThat(tbdDepot.containsTBDForTBD(pathAsTargetPattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(pathAsTargetPattern.containsTBDForTBD(tbdDepot))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
- assertThat(tbdDepot.containsDirectoryOfTBDForTBD(singleTargetPattern)).isFalse();
- assertThat(singleTargetPattern.containsDirectoryOfTBDForTBD(tbdDepot)).isFalse();
+ assertThat(tbdDepot.containsTBDForTBD(singleTargetPattern)).
+ isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(singleTargetPattern.containsTBDForTBD(tbdDepot))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
- assertThat(tbdDepot.containsDirectoryOfTBDForTBD(targetsInPackagePattern)).isFalse();
- assertThat(targetsInPackagePattern.containsDirectoryOfTBDForTBD(tbdDepot)).isFalse();
+ assertThat(tbdDepot.containsTBDForTBD(targetsInPackagePattern))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
+ assertThat(targetsInPackagePattern.containsTBDForTBD(tbdDepot))
+ .isEqualTo(ContainsTBDForTBDResult.OTHER);
}
private static TargetPattern parse(String pattern) throws TargetParsingException {