Initial (partial) implementation of configured target query. Activated by passing the --post_build_query flag to a build command, with a query expression as the argument. Bazel then executes this query on the configured target graph as constructed by the build command.
Since the prepare graph -> query workflow is how SkyQueryEnvironment works, this is mostly just copying that.
Main missing features/code cleanups:
* Recursive target patterns (/...) are not supported.
* There is no way to specify the configuration of the targets in your query.
* Configuration output is totally opaque (just the hash, or null if no configuration).
* More generally, no output options.
* Some features (visibility, label attrs) not supported.
* No edge filtering (host deps, implicit deps).
* Aspects are totally ignored.
* Graceful failure on errors, edge cases, incompatible flags (like the TAP flags that discard edges).
* Code hygiene issues (calling test-only method to get to Skyframe graph, some code duplication across ConfiguredTargetQueryEnvironment and SkyQueryEnvironment).
Most of the features I plan to leave to rules-side people, since I think they won't be too hard for a general Blaze developer to implement, and designing the right features and user interfaces for these things is better left to the rules side.
PiperOrigin-RevId: 165747829
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 383a28f..0fb0283 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
@@ -49,7 +49,6 @@
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventKind;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
-import com.google.devtools.build.lib.graph.Digraph;
import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
import com.google.devtools.build.lib.packages.DependencyFilter;
import com.google.devtools.build.lib.packages.NoSuchPackageException;
@@ -107,11 +106,8 @@
import com.google.devtools.build.skyframe.WalkableGraph;
import com.google.devtools.build.skyframe.WalkableGraph.WalkableGraphFactory;
import java.io.IOException;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Deque;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -513,7 +509,7 @@
return getReverseDepsOfTransitiveTraversalKeys(Iterables.transform(targets, TARGET_TO_SKY_KEY));
}
- Collection<Target> getReverseDepsOfTransitiveTraversalKeys(
+ private Collection<Target> getReverseDepsOfTransitiveTraversalKeys(
Iterable<SkyKey> transitiveTraversalKeys) throws InterruptedException {
Map<SkyKey, Collection<Target>> rawReverseDeps = getRawReverseDeps(transitiveTraversalKeys);
return processRawReverseDeps(rawReverseDeps);
@@ -563,51 +559,14 @@
@Override
public ThreadSafeMutableSet<Target> getTransitiveClosure(ThreadSafeMutableSet<Target> targets)
throws InterruptedException {
- ThreadSafeMutableSet<Target> visited = createThreadSafeMutableSet();
- ThreadSafeMutableSet<Target> current = targets;
- while (!current.isEmpty()) {
- Iterable<Target> toVisit = Iterables.filter(current,
- Predicates.not(Predicates.in(visited)));
- current = getFwdDeps(toVisit);
- Iterables.addAll(visited, toVisit);
- }
- return visited;
+ return SkyQueryUtils.getTransitiveClosure(
+ targets, this::getFwdDeps, createThreadSafeMutableSet());
}
- // Implemented with a breadth-first search.
@Override
public ImmutableList<Target> getNodesOnPath(Target from, Target to)
throws InterruptedException {
- // Tree of nodes visited so far.
- Map<Label, Label> nodeToParent = new HashMap<>();
- Map<Label, Target> labelToTarget = new HashMap<>();
- // Contains all nodes left to visit in a (LIFO) stack.
- Deque<Target> toVisit = new ArrayDeque<>();
- toVisit.add(from);
- nodeToParent.put(from.getLabel(), null);
- labelToTarget.put(from.getLabel(), from);
- while (!toVisit.isEmpty()) {
- Target current = toVisit.removeFirst();
- if (to.getLabel().equals(current.getLabel())) {
- List<Label> labelPath = Digraph.getPathToTreeNode(nodeToParent, to.getLabel());
- ImmutableList.Builder<Target> targetPathBuilder = ImmutableList.builder();
- for (Label label : labelPath) {
- targetPathBuilder.add(Preconditions.checkNotNull(labelToTarget.get(label), label));
- }
- return targetPathBuilder.build();
- }
- for (Target dep : getFwdDeps(ImmutableList.of(current))) {
- Label depLabel = dep.getLabel();
- if (!nodeToParent.containsKey(depLabel)) {
- nodeToParent.put(depLabel, current.getLabel());
- labelToTarget.put(depLabel, dep);
- toVisit.addFirst(dep);
- }
- }
- }
- // Note that the only current caller of this method checks first to see if there is a path
- // before calling this method. It is not clear what the return value should be here.
- return null;
+ return SkyQueryUtils.getNodesOnPath(from, to, this::getFwdDeps, Target::getLabel);
}
private <R> ListenableFuture<R> safeSubmit(Callable<R> callable) {