Introduce the 'siblings' query function. RELNOTES[NEW]: There is now a 'siblings' query function. See the query documentation for more details. PiperOrigin-RevId: 165010653
diff --git a/site/docs/query-how-to.md b/site/docs/query-how-to.md index a27fb9d..6b5577e 100644 --- a/site/docs/query-how-to.md +++ b/site/docs/query-how-to.md
@@ -86,6 +86,8 @@ `//third_party/jpeg`?](#Why_does_library_photos_fronten) * [What depends on ...](#What_depends_on_) * [What rules under bar depend on Y?](#What_rules_under_bar_depend_o) + * [What targets directly depend on T, in T's + package](#What_are_the_intra_package_direct_rdeps) * [How do I break a dependency ...](#How_do_I_break_a_dependency_) * [What dependency paths do I have to break to make `bar` no longer depend on X?](#What_dependency_paths_do_I_have_) @@ -269,7 +271,7 @@ ``` <a name="What_build_rule_contains_file_ja"></a> -#### What build rule contains file `src/main/java/com/example/cache/LRUCache.java` as a source? +#### What rule target(s) contain file `src/main/java/com/example/cache/LRUCache.java` as a source? ```sh fullname=$(bazel query src/main/java/com/example/cache/LRUCache.java) @@ -428,6 +430,13 @@ depend on Y?" If expression X is non-trivial, it may be convenient to bind a name to it using `let` to avoid duplication. +<a name="What_are_the_intra_package_direct_rdeps"></a> +#### What targets directly depend on T, in T's package? + +```sh +bazel query 'let t = T in rdeps(siblings($t), $t, 1)' +``` + <a name="How_do_I_break_a_dependency_"></a> ### How do I break a dependency ...
diff --git a/site/docs/query.html b/site/docs/query.html index d919091..c4c3359 100644 --- a/site/docs/query.html +++ b/site/docs/query.html
@@ -486,6 +486,7 @@ <a href="#labels">labels</a><br/> <a href="#loadfiles">loadfiles</a><br/> <a href="#rdeps">rdeps</a><br/> +<a href="#siblings">siblings</a><br/> <a href="#some">some</a><br/> <a href="#path-operators">somepath</a><br/> <a href="#tests">tests</a><br/> @@ -556,6 +557,13 @@ <var>depth</var> parameter is omitted, the search is unbounded. </p> +<h3 id="siblings">Dealing with a target's package: siblings</h3> +<pre>expr ::= siblings(<var>expr</var>)</pre> +<p> + The <code>siblings(<var>x</var>)</code> operator evalutes to the full set of targets that are in + the same package as a target in the argument set. +</p> + <h3 id="some">Arbitrary choice: some</h3> <pre>expr ::= some(<var>expr</var>)</pre> <p>
diff --git a/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java index 2781b0f..fe267b9 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java +++ b/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java
@@ -127,6 +127,14 @@ } @Override + public Collection<Target> getSiblingTargetsInPackage(Target target) { + Collection<Target> siblings = target.getPackage().getTargets().values(); + // Ensure that the sibling targets are in the graph being built-up. + siblings.forEach(this::getNode); + return siblings; + } + + @Override public QueryTaskFuture<Void> getTargetsMatchingPattern( QueryExpression owner, String pattern, Callback<Target> callback) { try {
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 84313ae..a9130f7 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
@@ -691,6 +691,12 @@ @ThreadSafe @Override + public Collection<Target> getSiblingTargetsInPackage(Target target) { + return target.getPackage().getTargets().values(); + } + + @ThreadSafe + @Override public QueryTaskFuture<Void> getTargetsMatchingPattern( QueryExpression owner, String pattern, Callback<Target> callback) { TargetPatternKey targetPatternKey;
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java index 453a049..1edc658 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java +++ b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
@@ -16,6 +16,7 @@ import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; +import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; @@ -142,6 +143,9 @@ } } + /** Returns all of the targets in <code>target</code>'s package, in some stable order. */ + Collection<T> getSiblingTargetsInPackage(T target); + /** * Invokes {@code callback} with the set of target nodes in the graph for the specified target * pattern, in 'blaze build' syntax. @@ -545,16 +549,17 @@ ImmutableList<QueryFunction> DEFAULT_QUERY_FUNCTIONS = ImmutableList.of( new AllPathsFunction(), - new BuildFilesFunction(), - new LoadFilesFunction(), new AttrFunction(), + new BuildFilesFunction(), + new DepsFunction(), new FilterFunction(), - new LabelsFunction(), new KindFunction(), + new LabelsFunction(), + new LoadFilesFunction(), + new RdepsFunction(), + new SiblingsFunction(), new SomeFunction(), new SomePathFunction(), new TestsFunction(), - new DepsFunction(), - new RdepsFunction(), new VisibleFunction()); }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/SiblingsFunction.java b/src/main/java/com/google/devtools/build/lib/query2/engine/SiblingsFunction.java new file mode 100644 index 0000000..5d03bfd --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/query2/engine/SiblingsFunction.java
@@ -0,0 +1,72 @@ +// Copyright 2017 The Bazel Authors. 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.query2.engine; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Argument; +import com.google.devtools.build.lib.query2.engine.QueryEnvironment.ArgumentType; +import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction; +import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryTaskFuture; +import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor; +import java.util.List; +import java.util.Set; + +/** + * A "siblings" query expression, which computes all of the targets in all of the packages of all + * the targets to which the argument evaluates. + * + * <pre>expr ::= SIBLINGS '(' expr ')'</pre> + */ +public class SiblingsFunction implements QueryFunction { + @Override + public String getName() { + return "siblings"; + } + + @Override + public int getMandatoryArguments() { + return 1; + } + + @Override + public Iterable<ArgumentType> getArgumentTypes() { + return ImmutableList.of(ArgumentType.EXPRESSION); + } + + @Override + public <T> QueryTaskFuture<Void> eval( + QueryEnvironment<T> env, + VariableContext<T> context, + final QueryExpression expression, + List<Argument> args, + final Callback<T> callback) { + final TargetAccessor<T> targetAccessor = env.getAccessor(); + Set<String> packageNames = Sets.newConcurrentHashSet(); + return env.eval( + args.get(0).getExpression(), + context, + new Callback<T>() { + @Override + public void process(Iterable<T> partialResult) + throws QueryException, InterruptedException { + for (T target : partialResult) { + if (packageNames.add(targetAccessor.getPackage(target))) { + callback.process(env.getSiblingTargetsInPackage(target)); + } + } + } + }); + } +}