On-the-fly target pattern resolution in SkyQueryEnvironment
Moves pattern resolving logic from TargetPatternFunction.Resolver to
a top level class. Adds a layer of abstraction to the Resolver
implementation enabling it to be backed by either an Environment or
a Graph, for use in SkyFunction evaluation or on-the-fly evaluation,
respectively. Finally, SkyQueryEnvironment#preloadOrThrow now checks
to see if each target pattern exists in the graph, and any that
don't will be resolved on-the-fly.
--
MOS_MIGRATED_REVID=88861201
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 caca634..2c9d4ad 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
@@ -117,8 +117,7 @@
* Evaluates the current target pattern and returns the result.
*/
public abstract <T> ResolvedTargets<T> eval(TargetPatternResolver<T> resolver)
- throws TargetParsingException, InterruptedException,
- TargetPatternResolver.MissingDepException;
+ throws TargetParsingException, InterruptedException;
private static final class SingleTarget extends TargetPattern {
@@ -131,8 +130,7 @@
@Override
public <T> ResolvedTargets<T> eval(TargetPatternResolver<T> resolver)
- throws TargetParsingException, InterruptedException,
- TargetPatternResolver.MissingDepException {
+ throws TargetParsingException, InterruptedException {
return resolver.getExplicitTarget(targetName);
}
}
@@ -148,8 +146,7 @@
@Override
public <T> ResolvedTargets<T> eval(TargetPatternResolver<T> resolver)
- throws TargetParsingException, InterruptedException,
- TargetPatternResolver.MissingDepException {
+ throws TargetParsingException, InterruptedException {
if (resolver.isPackage(path)) {
// User has specified a package name. lookout for default target.
return resolver.getExplicitTarget("//" + path);
@@ -194,8 +191,7 @@
@Override
public <T> ResolvedTargets<T> eval(TargetPatternResolver<T> resolver)
- throws TargetParsingException, InterruptedException,
- TargetPatternResolver.MissingDepException {
+ throws TargetParsingException, InterruptedException {
if (checkWildcardConflict) {
ResolvedTargets<T> targets = getWildcardConflict(resolver);
if (targets != null) {
@@ -214,7 +210,7 @@
* is such a target. Otherwise, return null.
*/
private <T> ResolvedTargets<T> getWildcardConflict(TargetPatternResolver<T> resolver)
- throws InterruptedException, TargetPatternResolver.MissingDepException {
+ throws InterruptedException {
if (!isAbsolute) {
return null;
}
@@ -255,8 +251,7 @@
@Override
public <T> ResolvedTargets<T> eval(TargetPatternResolver<T> resolver)
- throws TargetParsingException, InterruptedException,
- TargetPatternResolver.MissingDepException {
+ throws TargetParsingException, InterruptedException {
return resolver.findTargetsBeneathDirectory(originalPattern, pathPrefix, rulesOnly);
}
}
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 109179f..ae91caa 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
@@ -32,13 +32,13 @@
* Returns a single target corresponding to the given name, or null. This method may only throw an
* exception if the current thread was interrupted.
*/
- T getTargetOrNull(String targetName) throws InterruptedException, MissingDepException;
+ T getTargetOrNull(String targetName) throws InterruptedException;
/**
* Returns a single target corresponding to the given name, or an empty or failed result.
*/
ResolvedTargets<T> getExplicitTarget(String targetName)
- throws TargetParsingException, InterruptedException, MissingDepException;
+ throws TargetParsingException, InterruptedException;
/**
* Returns the set containing the targets found in the given package. The specified directory is
@@ -50,7 +50,7 @@
* @param rulesOnly whether to return rules only
*/
ResolvedTargets<T> getTargetsInPackage(String originalPattern, String packageName,
- boolean rulesOnly) throws TargetParsingException, InterruptedException, MissingDepException;
+ boolean rulesOnly) throws TargetParsingException, InterruptedException;
/**
* Returns the set containing the targets found below the given {@code pathPrefix}. Conceptually,
@@ -71,24 +71,18 @@
* @param rulesOnly whether to return rules only
*/
ResolvedTargets<T> findTargetsBeneathDirectory(String originalPattern, String pathPrefix,
- boolean rulesOnly) throws TargetParsingException, InterruptedException, MissingDepException;
+ boolean rulesOnly) throws TargetParsingException, InterruptedException;
/**
* Returns true, if and only if the given name corresponds to a package, i.e., a file with the
* name {@code packageName/BUILD} exists.
*/
- boolean isPackage(String packageName) throws MissingDepException;
+ boolean isPackage(String packageName);
/**
* Returns the target kind of the given target, for example {@code cc_library rule}.
*/
String getTargetKind(T target);
- /**
- * A missing dependency is needed before target parsing can proceed. Currently used only in
- * skyframe to notify the framework of missing dependencies.
- */
- // TODO(bazel-team): Avoid this use of exception for expected control flow management.
- public class MissingDepException extends Exception {
- }
+
}
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java b/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java
index 0573768e..5363cb5 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java
@@ -55,6 +55,9 @@
*
* <p> If these don't hold, then attempting to read the package with {@link #getPackage} may fail
* or may return a package containing errors.
+ *
+ * @param eventHandler the eventHandler on which to report warnings and errors
+ * @param packageName the name of the package.
*/
- boolean isPackage(String packageName);
+ boolean isPackage(EventHandler eventHandler, String packageName);
}
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 8d7bd1d..5c17e92 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
@@ -13,12 +13,8 @@
// limitations under the License.
package com.google.devtools.build.lib.pkgcache;
-import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.vfs.PathFragment;
-
-import java.util.concurrent.ThreadPoolExecutor;
-
-import javax.annotation.Nullable;
+import com.google.devtools.build.lib.vfs.RootedPath;
/**
* Support for resolving {@code package/...} target patterns.
@@ -26,32 +22,9 @@
public interface RecursivePackageProvider extends PackageProvider {
/**
- * <p>Visits the names of all packages beneath the given directory recursively and concurrently.
- *
- * <p>Note: This operation needs to stat directories recursively. It could be very expensive when
- * there is a big tree under the given directory.
- *
- * <p>Over a single iteration, package names are unique.
- *
- * <p>This method uses the given thread pool to call the observer method, possibly concurrently
- * (depending on the thread pool). When this method terminates, however, all such threads will
- * have completed.
- *
- * <p>To abort the traversal, call {@link Thread#interrupt()} on the calling thread.
- *
- * <p>This method guarantees that all BUILD files it returns correspond to valid package names
- * that are not marked as deleted within the current build.
- *
- * @param eventHandler an eventHandler which should be used to log any errors that occur while
- * scanning directories for BUILD files
- * @param directory a relative, canonical path specifying the directory to search
- * @param useTopLevelExcludes whether to skip a pre-set list of top level directories
- * @param visitorPool the thread pool to use to visit packages in parallel
- * @param observer is called for each path fragment found; thread-safe if the thread pool supports
- * multiple parallel threads
- * @throws InterruptedException if the calling thread was interrupted.
+ * Returns the names of all the packages under a given directory.
+
+ * @param directory a {@link RootedPath} specifying the directory to search
*/
- void visitPackageNamesRecursively(EventHandler eventHandler, PathFragment directory,
- boolean useTopLevelExcludes, @Nullable ThreadPoolExecutor visitorPool,
- PathPackageLocator.AcceptsPathFragment observer) throws InterruptedException;
+ Iterable<PathFragment> getPackagesUnderDirectory(RootedPath directory);
}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java
index 96e8509..537738e 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java
@@ -26,6 +26,7 @@
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.pkgcache.PackageProvider;
+import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator;
import com.google.devtools.build.lib.pkgcache.TransitivePackageLoader;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment;
@@ -43,6 +44,8 @@
import java.util.Map;
import java.util.Set;
+import javax.annotation.Nullable;
+
/**
* {@link QueryEnvironment} that can evaluate queries to produce a result, and implements as much
* of QueryEnvironment as possible while remaining mostly agnostic as to the objects being stored.
@@ -92,10 +95,12 @@
PackageProvider packageProvider,
TargetPatternEvaluator targetPatternEvaluator, boolean keepGoing, boolean orderedResults,
List<String> universeScope, int loadingPhaseThreads,
- EventHandler eventHandler, Set<Setting> settings, Iterable<QueryFunction> functions) {
+ EventHandler eventHandler, Set<Setting> settings, Iterable<QueryFunction> functions,
+ @Nullable PathPackageLocator packagePath) {
return newQueryEnvironment(transitivePackageLoader, graphFactory, packageProvider,
targetPatternEvaluator, keepGoing, /*strictScope=*/true, orderedResults,
- universeScope, loadingPhaseThreads, Rule.ALL_LABELS, eventHandler, settings, functions);
+ universeScope, loadingPhaseThreads, Rule.ALL_LABELS, eventHandler, settings, functions,
+ packagePath);
}
public static AbstractBlazeQueryEnvironment<Target> newQueryEnvironment(
@@ -104,15 +109,17 @@
TargetPatternEvaluator targetPatternEvaluator, boolean keepGoing, boolean strictScope,
boolean orderedResults, List<String> universeScope, int loadingPhaseThreads,
Predicate<Label> labelFilter,
- EventHandler eventHandler, Set<Setting> settings, Iterable<QueryFunction> functions) {
+ EventHandler eventHandler, Set<Setting> settings, Iterable<QueryFunction> functions,
+ @Nullable PathPackageLocator packagePath) {
Preconditions.checkNotNull(universeScope);
- return orderedResults || universeScope.isEmpty()
+ return orderedResults || universeScope.isEmpty() || packagePath == null
? new BlazeQueryEnvironment(transitivePackageLoader, packageProvider,
targetPatternEvaluator, keepGoing, strictScope, loadingPhaseThreads,
labelFilter, eventHandler, settings, functions)
: new SkyQueryEnvironment(
keepGoing, strictScope, loadingPhaseThreads, labelFilter, eventHandler, settings,
- functions, targetPatternEvaluator.getOffset(), graphFactory, universeScope);
+ functions, targetPatternEvaluator.getOffset(), graphFactory, universeScope,
+ packagePath);
}
/**
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 4a0dae6..0b01884 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
@@ -21,17 +21,21 @@
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.cmdline.ResolvedTargets;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
+import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.graph.Digraph;
import com.google.devtools.build.lib.packages.NoSuchThingException;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator;
import com.google.devtools.build.lib.query2.engine.QueryEvalResult;
import com.google.devtools.build.lib.query2.engine.QueryException;
import com.google.devtools.build.lib.query2.engine.QueryExpression;
+import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider;
import com.google.devtools.build.lib.skyframe.PackageValue;
+import com.google.devtools.build.lib.skyframe.RecursivePackageProviderBackedTargetPatternResolver;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.skyframe.TargetPatternValue;
import com.google.devtools.build.lib.skyframe.TransitiveTargetValue;
@@ -69,6 +73,7 @@
private final WalkableGraphFactory graphFactory;
private final List<String> universeScope;
private final String parserPrefix;
+ private final PathPackageLocator pkgPath;
public SkyQueryEnvironment(boolean keepGoing, boolean strictScope, int loadingPhaseThreads,
Predicate<Label> labelFilter,
@@ -76,13 +81,14 @@
Set<Setting> settings,
Iterable<QueryFunction> extraFunctions, String parserPrefix,
WalkableGraphFactory graphFactory,
- List<String> universeScope) {
+ List<String> universeScope, PathPackageLocator pkgPath) {
super(keepGoing, strictScope, labelFilter,
eventHandler,
settings,
extraFunctions);
this.loadingPhaseThreads = loadingPhaseThreads;
this.graphFactory = graphFactory;
+ this.pkgPath = pkgPath;
this.universeScope = Preconditions.checkNotNull(universeScope);
this.parserPrefix = parserPrefix;
Preconditions.checkState(!universeScope.isEmpty(),
@@ -307,20 +313,40 @@
protected Map<String, ResolvedTargets<Target>> preloadOrThrow(Collection<String> patterns)
throws QueryException, TargetParsingException {
- Map<String, ResolvedTargets<Target>> result =
- Maps.newHashMapWithExpectedSize(patterns.size());
+ Map<String, ResolvedTargets<Target>> result = Maps.newHashMapWithExpectedSize(patterns.size());
for (String pattern : patterns) {
SkyKey patternKey = TargetPatternValue.key(pattern,
TargetPatternEvaluator.DEFAULT_FILTERING_POLICY, parserPrefix);
- checkExistence(patternKey);
- TargetPatternValue value = (TargetPatternValue) graph.getValue(patternKey);
- if (value != null) {
- result.put(pattern, value.getTargets());
- } else if (!keepGoing) {
- throw (TargetParsingException) Preconditions.checkNotNull(graph.getException(patternKey),
- pattern);
+
+ TargetPatternValue.TargetPattern targetPattern =
+ ((TargetPatternValue.TargetPattern) patternKey.argument());
+
+ if (graph.exists(patternKey)) {
+ // If the graph already contains a value for this target pattern, use it.
+ TargetPatternValue value = (TargetPatternValue) graph.getValue(patternKey);
+ if (value != null) {
+ result.put(pattern, value.getTargets());
+ } else if (!keepGoing) {
+ throw (TargetParsingException) Preconditions.checkNotNull(graph.getException(patternKey),
+ pattern);
+ } else {
+ result.put(pattern, ResolvedTargets.<Target>builder().setError().build());
+ }
} else {
- result.put(pattern, ResolvedTargets.<Target>builder().setError().build());
+ // If the graph doesn't contain a value for this target pattern, try to directly evaluate
+ // it, by making use of packages already present in the graph.
+ TargetPattern.Parser parser = new TargetPattern.Parser(targetPattern.getOffset());
+ GraphBackedRecursivePackageProvider provider =
+ new GraphBackedRecursivePackageProvider(graph);
+ RecursivePackageProviderBackedTargetPatternResolver resolver =
+ new RecursivePackageProviderBackedTargetPatternResolver(provider, eventHandler,
+ targetPattern.getPolicy(), pkgPath);
+ TargetPattern parsedPattern = parser.parse(targetPattern.getPattern());
+ try {
+ result.put(pattern, parsedPattern.eval(resolver));
+ } catch (InterruptedException e) {
+ throw new QueryException(e.getMessage());
+ }
}
}
return result;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
index e1d1fdd..09d2ec5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
@@ -44,8 +44,7 @@
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
-import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
-import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
+import com.google.devtools.build.lib.pkgcache.PackageProvider;
import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator;
import com.google.devtools.build.lib.query2.AbstractBlazeQueryEnvironment;
import com.google.devtools.build.lib.query2.engine.BlazeQueryEvalResult;
@@ -82,7 +81,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ThreadPoolExecutor;
import javax.annotation.Nullable;
@@ -213,23 +211,20 @@
@Nullable
private byte[] executeQuery(RuleContext ruleContext, QueryOptions queryOptions,
Set<Target> scope, String query) throws InterruptedException {
- RecursivePackageProvider packageProvider;
- Predicate<Label> labelFilter;
- TargetPatternEvaluator evaluator;
SkyFunction.Environment env = ruleContext.getAnalysisEnvironment().getSkyframeEnv();
Pair<ImmutableMap<PackageIdentifier, Package>, Set<Label>> closureInfo =
constructPackageMap(env, scope);
ImmutableMap<PackageIdentifier, Package> packageMap = closureInfo.first;
Set<Label> validTargets = closureInfo.second;
- packageProvider = new PreloadedMapPackageProvider(packageMap, validTargets);
- evaluator = new SkyframeEnvTargetPatternEvaluator(env);
- labelFilter = Predicates.in(validTargets);
+ PackageProvider packageProvider = new PreloadedMapPackageProvider(packageMap, validTargets);
+ TargetPatternEvaluator evaluator = new SkyframeEnvTargetPatternEvaluator(env);
+ Predicate<Label> labelFilter = Predicates.in(validTargets);
return doQuery(queryOptions, packageProvider, labelFilter, evaluator, query, ruleContext);
}
- private byte[] doQuery(QueryOptions queryOptions, RecursivePackageProvider packageProvider,
+ private byte[] doQuery(QueryOptions queryOptions, PackageProvider packageProvider,
Predicate<Label> labelFilter, TargetPatternEvaluator evaluator,
String query, RuleContext ruleContext)
throws InterruptedException {
@@ -267,7 +262,8 @@
labelFilter,
getEventHandler(ruleContext),
settings,
- ImmutableList.<QueryFunction>of()).evaluateQuery(query);
+ ImmutableList.<QueryFunction>of(),
+ /*packagePath=*/null).evaluateQuery(query);
} catch (SkyframeRestartQueryException e) {
// Do not emit errors for skyframe restarts. They make output of the ConfiguredTargetFunction
// inconsistent from run to run, and make detecting legitimate errors more difficult.
@@ -374,7 +370,7 @@
/**
* Provide packages and targets to the query operations using precomputed transitive closure.
*/
- private static final class PreloadedMapPackageProvider implements RecursivePackageProvider {
+ private static final class PreloadedMapPackageProvider implements PackageProvider {
private final ImmutableMap<PackageIdentifier, Package> pkgMap;
private final Set<Label> targets;
@@ -401,17 +397,7 @@
}
@Override
- public boolean isPackage(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void visitPackageNamesRecursively(EventHandler eventHandler,
- PathFragment directory,
- boolean useTopLevelExcludes,
- ThreadPoolExecutor visitorPool,
- PathPackageLocator.AcceptsPathFragment observer)
- throws InterruptedException {
+ public boolean isPackage(EventHandler eventHandler, String packageName) {
throw new UnsupportedOperationException();
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
index c2851b2..7b54eb1 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
@@ -174,6 +174,7 @@
runtime.getTargetPatternEvaluator(),
keepGoing, orderedResults, universeScope, loadingPhaseThreads, runtime.getReporter(),
settings,
- functions.build());
+ functions.build(),
+ runtime.getPackageManager().getPackagePath());
}
}
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
new file mode 100644
index 0000000..901e877
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
@@ -0,0 +1,116 @@
+// Copyright 2015 Google Inc. 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.Iterables;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.NoSuchTargetException;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.packages.PackageIdentifier;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.RootedPath;
+import com.google.devtools.build.skyframe.SkyFunction.Environment;
+import com.google.devtools.build.skyframe.SkyKey;
+
+/**
+ * A {@link RecursivePackageProvider} backed by an {@link Environment}. Its methods
+ * may throw {@link MissingDepException} if the package values this depends on haven't been
+ * calculated and added to its environment.
+ *
+ * <p>That exception will be caught by the compute method in {@link TargetPatternFunction}, which
+ * then returns {@code null} in accordance with the skyframe missing dependency policy.
+ */
+public final class EnvironmentBackedRecursivePackageProvider implements RecursivePackageProvider {
+
+ private final Environment env;
+
+ public EnvironmentBackedRecursivePackageProvider(Environment env) {
+ this.env = env;
+ }
+
+ @Override
+ public Package getPackage(EventHandler eventHandler, PackageIdentifier packageName)
+ throws NoSuchPackageException, MissingDepException {
+ SkyKey pkgKey = PackageValue.key(packageName);
+ Package pkg;
+ try {
+ PackageValue pkgValue =
+ (PackageValue) env.getValueOrThrow(pkgKey, NoSuchPackageException.class);
+ if (pkgValue == null) {
+ throw new MissingDepException();
+ }
+ pkg = pkgValue.getPackage();
+ } catch (NoSuchPackageException e) {
+ pkg = e.getPackage();
+ if (pkg == null) {
+ throw e;
+ }
+ }
+ return pkg;
+ }
+
+ @Override
+ public boolean isPackage(EventHandler eventHandler, String packageName)
+ throws MissingDepException {
+ SkyKey packageLookupKey = PackageLookupValue.key(new PathFragment(packageName));
+ try {
+ PackageLookupValue packageLookupValue =
+ (PackageLookupValue) env.getValueOrThrow(packageLookupKey, NoSuchPackageException.class,
+ InconsistentFilesystemException.class);
+ if (packageLookupValue == null) {
+ throw new MissingDepException();
+ }
+ return packageLookupValue.packageExists();
+ } catch (NoSuchPackageException | InconsistentFilesystemException e) {
+ eventHandler.handle(Event.error(e.getMessage()));
+ return false;
+ }
+ }
+
+ @Override
+ public Iterable<PathFragment> getPackagesUnderDirectory(RootedPath directory)
+ throws MissingDepException {
+ RecursivePkgValue lookup = (RecursivePkgValue) env.getValue(RecursivePkgValue.key(directory));
+ 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 getValue
+ // call returns null, it can only mean a missing dependency, because
+ // RecursivePkgFunction#compute never throws.
+ throw new MissingDepException();
+ }
+ // TODO(bazel-team): Make RecursivePkgValue return NestedSet<PathFragment> so this transform is
+ // unnecessary.
+ return Iterables.transform(lookup.getPackages(), PathFragment.TO_PATH_FRAGMENT);
+ }
+
+ @Override
+ public Target getTarget(EventHandler eventHandler, Label label) throws NoSuchPackageException,
+ NoSuchTargetException, MissingDepException {
+ return getPackage(eventHandler, label.getPackageIdentifier()).getTarget(label.getName());
+ }
+
+ /**
+ * Indicates that a missing dependency is needed before target parsing can proceed. Currently
+ * used only in skyframe to notify the framework of missing dependencies. Caught by the compute
+ * method in {@link com.google.devtools.build.lib.skyframe.TargetPatternFunction}, which then
+ * returns null in accordance with the skyframe missing dependency policy.
+ */
+ class MissingDepException extends RuntimeException {
+ }
+}
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
new file mode 100644
index 0000000..62f1e68
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
@@ -0,0 +1,111 @@
+// Copyright 2015 Google Inc. 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.Iterables;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.NoSuchTargetException;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.packages.PackageIdentifier;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.RootedPath;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.WalkableGraph;
+
+import java.util.Collections;
+
+/** A {@link RecursivePackageProvider} backed by a {@link WalkableGraph}. */
+public final class GraphBackedRecursivePackageProvider implements RecursivePackageProvider {
+
+ private final WalkableGraph graph;
+
+ public GraphBackedRecursivePackageProvider(WalkableGraph graph) {
+ this.graph = graph;
+ }
+
+ @Override
+ public Package getPackage(EventHandler eventHandler, PackageIdentifier packageName)
+ throws NoSuchPackageException {
+ SkyKey pkgKey = PackageValue.key(packageName);
+
+ PackageValue pkgValue;
+ if (graph.exists(pkgKey)) {
+ pkgValue = (PackageValue) graph.getValue(pkgKey);
+ if (pkgValue == null) {
+ throw (NoSuchPackageException) Preconditions.checkNotNull(graph.getException(pkgKey));
+ }
+ } else {
+ // If the package key does not exist in the graph, then it must not correspond to any package,
+ // because the SkyQuery environment has already loaded the universe.
+ throw new BuildFileNotFoundException(packageName.toString(),
+ "BUILD file not found on package path");
+ }
+ return pkgValue.getPackage();
+ }
+
+ @Override
+ public boolean isPackage(EventHandler eventHandler, String packageName) {
+ SkyKey packageLookupKey = PackageLookupValue.key(new PathFragment(packageName));
+ if (!graph.exists(packageLookupKey)) {
+ // If the package lookup key does not exist in the graph, then it must not correspond to any
+ // package, because the SkyQuery environment has already loaded the universe.
+ return false;
+ }
+ PackageLookupValue packageLookupValue = (PackageLookupValue) graph.getValue(packageLookupKey);
+ if (packageLookupValue == null) {
+ Exception exception = Preconditions.checkNotNull(graph.getException(packageLookupKey),
+ "During package lookup for '%s', got null for exception", packageName);
+ if (exception instanceof NoSuchPackageException
+ || exception instanceof InconsistentFilesystemException) {
+ eventHandler.handle(Event.error(exception.getMessage()));
+ return false;
+ } else {
+ throw new IllegalStateException("During package lookup for '" + packageName
+ + "', got unexpected exception type", exception);
+ }
+ }
+ return packageLookupValue.packageExists();
+ }
+
+ @Override
+ public Iterable<PathFragment> getPackagesUnderDirectory(RootedPath directory) {
+ SkyKey recursivePackageKey = RecursivePkgValue.key(directory);
+ if (!graph.exists(recursivePackageKey)) {
+ // If the recursive package key does not exist in the graph, then it must not correspond to
+ // any directory transitively containing packages, because the SkyQuery environment has
+ // already loaded the universe.
+ return Collections.emptyList();
+ }
+ // If the recursive package key exists in the graph, then it must have a value and must not
+ // have an exception, because RecursivePkgFunction#compute never throws.
+ RecursivePkgValue lookup =
+ (RecursivePkgValue) Preconditions.checkNotNull(graph.getValue(recursivePackageKey));
+ // TODO(bazel-team): Make RecursivePkgValue return NestedSet<PathFragment> so this transform is
+ // unnecessary.
+ return Iterables.transform(lookup.getPackages(), PathFragment.TO_PATH_FRAGMENT);
+ }
+
+ @Override
+ public Target getTarget(EventHandler eventHandler, Label label)
+ throws NoSuchPackageException, NoSuchTargetException {
+ return getPackage(eventHandler, label.getPackageIdentifier()).getTarget(label.getName());
+ }
+}
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
new file mode 100644
index 0000000..a1b16f0
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
@@ -0,0 +1,206 @@
+// Copyright 2015 Google Inc. 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.devtools.build.lib.cmdline.LabelValidator;
+import com.google.devtools.build.lib.cmdline.ResolvedTargets;
+import com.google.devtools.build.lib.cmdline.TargetParsingException;
+import com.google.devtools.build.lib.cmdline.TargetPatternResolver;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.packages.PackageIdentifier;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
+import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
+import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
+import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
+import com.google.devtools.build.lib.pkgcache.TargetPatternResolverUtil;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.RootedPath;
+
+/**
+ * A {@link TargetPatternResolver} backed by a {@link RecursivePackageProvider}.
+ */
+public class RecursivePackageProviderBackedTargetPatternResolver
+ implements TargetPatternResolver<Target> {
+
+ private final RecursivePackageProvider recursivePackageProvider;
+ private final EventHandler eventHandler;
+ private final FilteringPolicy policy;
+ private final PathPackageLocator pkgPath;
+
+ public RecursivePackageProviderBackedTargetPatternResolver(
+ final RecursivePackageProvider recursivePackageProvider,
+ EventHandler eventHandler,
+ FilteringPolicy policy,
+ PathPackageLocator pkgPath) {
+ this.recursivePackageProvider = recursivePackageProvider;
+ this.eventHandler = eventHandler;
+ this.policy = policy;
+ this.pkgPath = pkgPath;
+ }
+
+ @Override
+ public void warn(String msg) {
+ eventHandler.handle(Event.warn(msg));
+ }
+
+ /**
+ * Gets a {@link Package} from the {@link RecursivePackageProvider}. May return a {@link Package}
+ * that has errors.
+ */
+ private Package getPackage(PackageIdentifier pkgIdentifier)
+ throws NoSuchPackageException, InterruptedException {
+ Package pkg;
+ try {
+ pkg = recursivePackageProvider.getPackage(eventHandler, pkgIdentifier);
+ } catch (NoSuchPackageException e) {
+ pkg = e.getPackage();
+ if (pkg == null) {
+ throw e;
+ }
+ }
+ return pkg;
+ }
+
+ @Override
+ public Target getTargetOrNull(String targetName) throws InterruptedException {
+ try {
+ Label label = Label.parseAbsolute(targetName);
+ if (!isPackage(label.getPackageName())) {
+ return null;
+ }
+ return recursivePackageProvider.getTarget(eventHandler, label);
+ } catch (Label.SyntaxException | NoSuchThingException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public ResolvedTargets<Target> getExplicitTarget(String targetName)
+ throws TargetParsingException, InterruptedException {
+ Label label = TargetPatternResolverUtil.label(targetName);
+ try {
+ Target target = recursivePackageProvider.getTarget(eventHandler, label);
+ return policy.shouldRetain(target, true)
+ ? ResolvedTargets.of(target)
+ : ResolvedTargets.<Target>empty();
+ } catch (NoSuchThingException e) {
+ throw new TargetParsingException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public ResolvedTargets<Target> getTargetsInPackage(String originalPattern, String packageName,
+ boolean rulesOnly)
+ throws TargetParsingException, InterruptedException {
+ FilteringPolicy actualPolicy = rulesOnly
+ ? FilteringPolicies.and(FilteringPolicies.RULES_ONLY, policy)
+ : policy;
+ return getTargetsInPackage(originalPattern, new PathFragment(packageName), actualPolicy);
+ }
+
+ private ResolvedTargets<Target> getTargetsInPackage(String originalPattern,
+ PathFragment packageNameFragment, FilteringPolicy policy)
+ throws TargetParsingException, InterruptedException {
+ String packageName = packageNameFragment.toString();
+
+ // It's possible for this check to pass, but for
+ // Label.validatePackageNameFull to report an error because the
+ // package name is illegal. That's a little weird, but we can live with
+ // that for now--see test case: testBadPackageNameButGoodEnoughForALabel.
+ if (LabelValidator.validatePackageName(packageName) != null) {
+ throw new TargetParsingException("'" + packageName + "' is not a valid package name");
+ }
+ if (!isPackage(packageName)) {
+ throw new TargetParsingException(
+ TargetPatternResolverUtil.getParsingErrorMessage(
+ "no such package '" + packageName + "': BUILD file not found on package path",
+ originalPattern));
+ }
+
+ try {
+ Package pkg = getPackage(PackageIdentifier.createInDefaultRepo(packageNameFragment));
+ return TargetPatternResolverUtil.resolvePackageTargets(pkg, policy);
+ } catch (NoSuchThingException e) {
+ String message = TargetPatternResolverUtil.getParsingErrorMessage(
+ "package contains errors", originalPattern);
+ throw new TargetParsingException(message, e);
+ }
+ }
+
+ @Override
+ public boolean isPackage(String packageName) {
+ return recursivePackageProvider.isPackage(eventHandler, packageName);
+ }
+
+ @Override
+ public String getTargetKind(Target target) {
+ return target.getTargetKind();
+ }
+
+ @Override
+ public ResolvedTargets<Target> findTargetsBeneathDirectory(
+ String originalPattern, String pathPrefix, boolean rulesOnly)
+ throws TargetParsingException, InterruptedException {
+ FilteringPolicy actualPolicy = rulesOnly
+ ? FilteringPolicies.and(FilteringPolicies.RULES_ONLY, policy)
+ : policy;
+
+ PathFragment directory = new PathFragment(pathPrefix);
+ if (directory.containsUplevelReferences()) {
+ throw new TargetParsingException("up-level references are not permitted: '"
+ + directory.getPathString() + "'");
+ }
+ if (!pathPrefix.isEmpty() && (LabelValidator.validatePackageName(pathPrefix) != null)) {
+ throw new TargetParsingException("'" + pathPrefix + "' is not a valid package name");
+ }
+
+ ResolvedTargets.Builder<Target> builder = ResolvedTargets.builder();
+
+ for (Path root : pkgPath.getPathEntries()) {
+ RootedPath rootedPath = RootedPath.toRootedPath(root, directory);
+ Iterable<PathFragment> packagesUnderDirectory = recursivePackageProvider
+ .getPackagesUnderDirectory(rootedPath);
+ for (PathFragment pkg : packagesUnderDirectory) {
+ builder.merge(getTargetsInPackage(originalPattern, pkg, FilteringPolicies.NO_FILTER));
+ }
+ }
+
+ if (builder.isEmpty()) {
+ throw new TargetParsingException("no targets found beneath '" + directory + "'");
+ }
+
+ // Apply the transform after the check so we only return the
+ // error if the tree really contains no targets.
+ ResolvedTargets<Target> intermediateResult = builder.build();
+ ResolvedTargets.Builder<Target> filteredBuilder = ResolvedTargets.builder();
+ if (intermediateResult.hasError()) {
+ filteredBuilder.setError();
+ }
+ for (Target target : intermediateResult.getTargets()) {
+ if (actualPolicy.shouldRetain(target, false)) {
+ filteredBuilder.add(target);
+ }
+ }
+ return filteredBuilder.build();
+ }
+
+}
+
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java
index cc32bf8..3e9b6ca 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java
@@ -136,7 +136,7 @@
}
@Override
- public boolean isPackage(String packageName) {
+ public boolean isPackage(EventHandler eventHandler, String packageName) {
return getBuildFileForPackage(packageName) != 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 b17a282..9322998 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
@@ -13,32 +13,15 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
-import com.google.devtools.build.lib.cmdline.LabelValidator;
-import com.google.devtools.build.lib.cmdline.ResolvedTargets;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.cmdline.TargetPattern;
-import com.google.devtools.build.lib.cmdline.TargetPatternResolver;
-import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.packages.NoSuchPackageException;
-import com.google.devtools.build.lib.packages.NoSuchThingException;
-import com.google.devtools.build.lib.packages.Package;
-import com.google.devtools.build.lib.packages.PackageIdentifier;
-import com.google.devtools.build.lib.packages.Target;
-import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
-import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
-import com.google.devtools.build.lib.pkgcache.TargetPatternResolverUtil;
-import com.google.devtools.build.lib.syntax.Label;
-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.lib.skyframe.EnvironmentBackedRecursivePackageProvider.MissingDepException;
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.util.ArrayList;
-import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
@@ -60,15 +43,23 @@
InterruptedException {
TargetPatternValue.TargetPattern patternKey =
((TargetPatternValue.TargetPattern) key.argument());
-
TargetPattern.Parser parser = new TargetPattern.Parser(patternKey.getOffset());
try {
- Resolver resolver = new Resolver(env, patternKey.getPolicy(), pkgPath);
+ EnvironmentBackedRecursivePackageProvider provider =
+ new EnvironmentBackedRecursivePackageProvider(env);
+ RecursivePackageProviderBackedTargetPatternResolver resolver =
+ new RecursivePackageProviderBackedTargetPatternResolver(provider, env.getListener(),
+ patternKey.getPolicy(), pkgPath.get());
TargetPattern resolvedPattern = parser.parse(patternKey.getPattern());
return new TargetPatternValue(resolvedPattern.eval(resolver));
} catch (TargetParsingException e) {
throw new TargetPatternFunctionException(e);
- } catch (TargetPatternResolver.MissingDepException e) {
+ } catch (MissingDepException e) {
+ // The EnvironmentBackedRecursivePackageProvider constructed above might throw
+ // MissingDepException to signal when it has a dependency on a missing Environment value.
+ // Note that MissingDepException extends RuntimeException because the methods called
+ // on EnvironmentBackedRecursivePackageProvider all belong to an interface shared with other
+ // implementations that are unconcerned with MissingDepExceptions.
return null;
}
}
@@ -79,192 +70,7 @@
return null;
}
- private static class Resolver implements TargetPatternResolver<Target> {
- private final Environment env;
- private final FilteringPolicy policy;
- private final AtomicReference<PathPackageLocator> pkgPath;
- public Resolver(Environment env, FilteringPolicy policy,
- AtomicReference<PathPackageLocator> pkgPath) {
- this.policy = policy;
- this.env = env;
- this.pkgPath = pkgPath;
- }
-
- @Override
- public void warn(String msg) {
- env.getListener().handle(Event.warn(msg));
- }
-
- /**
- * Gets a Package via the Skyframe env. May return a Package that has errors.
- */
- private Package getPackage(PackageIdentifier pkgIdentifier)
- throws MissingDepException, NoSuchThingException {
- SkyKey pkgKey = PackageValue.key(pkgIdentifier);
- Package pkg;
- try {
- PackageValue pkgValue =
- (PackageValue) env.getValueOrThrow(pkgKey, NoSuchPackageException.class);
- if (pkgValue == null) {
- throw new MissingDepException();
- }
- pkg = pkgValue.getPackage();
- } catch (NoSuchPackageException e) {
- pkg = e.getPackage();
- if (pkg == null) {
- throw e;
- }
- }
- return pkg;
- }
-
- @Override
- public Target getTargetOrNull(String targetName) throws InterruptedException,
- MissingDepException {
- try {
- Label label = Label.parseAbsolute(targetName);
- if (!isPackage(label.getPackageName())) {
- return null;
- }
- Package pkg = getPackage(label.getPackageIdentifier());
- return pkg.getTarget(label.getName());
- } catch (Label.SyntaxException | NoSuchThingException e) {
- return null;
- }
- }
-
- @Override
- public ResolvedTargets<Target> getExplicitTarget(String targetName)
- throws TargetParsingException, InterruptedException, MissingDepException {
- Label label = TargetPatternResolverUtil.label(targetName);
- try {
- Package pkg = getPackage(label.getPackageIdentifier());
- Target target = pkg.getTarget(label.getName());
- return policy.shouldRetain(target, true)
- ? ResolvedTargets.of(target)
- : ResolvedTargets.<Target>empty();
- } catch (NoSuchThingException e) {
- throw new TargetParsingException(e.getMessage(), e);
- }
- }
-
- @Override
- public ResolvedTargets<Target> getTargetsInPackage(String originalPattern, String packageName,
- boolean rulesOnly)
- throws TargetParsingException, InterruptedException, MissingDepException {
- FilteringPolicy actualPolicy = rulesOnly
- ? FilteringPolicies.and(FilteringPolicies.RULES_ONLY, policy)
- : policy;
- return getTargetsInPackage(originalPattern, packageName, actualPolicy);
- }
-
- private ResolvedTargets<Target> getTargetsInPackage(String originalPattern, String packageName,
- FilteringPolicy policy)
- throws TargetParsingException, MissingDepException {
- // Normalise, e.g "foo//bar" -> "foo/bar"; "foo/" -> "foo":
- PathFragment packageNameFragment = new PathFragment(packageName);
- packageName = packageNameFragment.toString();
-
- // It's possible for this check to pass, but for
- // Label.validatePackageNameFull to report an error because the
- // package name is illegal. That's a little weird, but we can live with
- // that for now--see test case: testBadPackageNameButGoodEnoughForALabel.
- // (BTW I tried duplicating that validation logic in Label but it was
- // extremely tricky.)
- if (LabelValidator.validatePackageName(packageName) != null) {
- throw new TargetParsingException("'" + packageName + "' is not a valid package name");
- }
- if (!isPackage(packageName)) {
- throw new TargetParsingException(
- TargetPatternResolverUtil.getParsingErrorMessage(
- "no such package '" + packageName + "': BUILD file not found on package path",
- originalPattern));
- }
-
- try {
- Package pkg = getPackage(
- PackageIdentifier.createInDefaultRepo(packageNameFragment.toString()));
- return TargetPatternResolverUtil.resolvePackageTargets(pkg, policy);
- } catch (NoSuchThingException e) {
- String message = TargetPatternResolverUtil.getParsingErrorMessage(
- "package contains errors", originalPattern);
- throw new TargetParsingException(message, e);
- }
- }
-
- @Override
- public boolean isPackage(String packageName) throws MissingDepException {
- SkyKey packageLookupKey;
- packageLookupKey = PackageLookupValue.key(new PathFragment(packageName));
- PackageLookupValue packageLookupValue = (PackageLookupValue) env.getValue(packageLookupKey);
- if (packageLookupValue == null) {
- throw new MissingDepException();
- }
- return packageLookupValue.packageExists();
- }
-
- @Override
- public String getTargetKind(Target target) {
- return target.getTargetKind();
- }
-
- @Override
- public ResolvedTargets<Target> findTargetsBeneathDirectory(
- String originalPattern, String pathPrefix, boolean rulesOnly)
- throws TargetParsingException, MissingDepException {
- FilteringPolicy actualPolicy = rulesOnly
- ? FilteringPolicies.and(FilteringPolicies.RULES_ONLY, policy)
- : policy;
-
- PathFragment directory = new PathFragment(pathPrefix);
- if (directory.containsUplevelReferences()) {
- throw new TargetParsingException("up-level references are not permitted: '"
- + directory.getPathString() + "'");
- }
- if (!pathPrefix.isEmpty() && (LabelValidator.validatePackageName(pathPrefix) != null)) {
- throw new TargetParsingException("'" + pathPrefix + "' is not a valid package name");
- }
-
- ResolvedTargets.Builder<Target> builder = ResolvedTargets.builder();
-
- List<RecursivePkgValue> lookupValues = new ArrayList<>();
- for (Path root : pkgPath.get().getPathEntries()) {
- SkyKey key = RecursivePkgValue.key(RootedPath.toRootedPath(root, directory));
- RecursivePkgValue lookup = (RecursivePkgValue) env.getValue(key);
- if (lookup != null) {
- lookupValues.add(lookup);
- }
- }
- if (env.valuesMissing()) {
- throw new MissingDepException();
- }
-
- for (RecursivePkgValue value : lookupValues) {
- for (String pkg : value.getPackages()) {
- builder.merge(getTargetsInPackage(originalPattern, pkg, FilteringPolicies.NO_FILTER));
- }
- }
-
- if (builder.isEmpty()) {
- throw new TargetParsingException("no targets found beneath '" + directory + "'");
- }
-
- // Apply the transform after the check so we only return the
- // error if the tree really contains no targets.
- ResolvedTargets<Target> intermediateResult = builder.build();
- ResolvedTargets.Builder<Target> filteredBuilder = ResolvedTargets.builder();
- if (intermediateResult.hasError()) {
- filteredBuilder.setError();
- }
- for (Target target : intermediateResult.getTargets()) {
- if (actualPolicy.shouldRetain(target, false)) {
- filteredBuilder.add(target);
- }
- }
- return filteredBuilder.build();
- }
- }
/**
* Used to declare all the exception types that can be wrapped in the exception thrown by