Skip to content

Commit 681f534

Browse files
fmeumcopybara-github
authored andcommitted
Add --output=files mode to cquery
With the new output mode `--output=files`, cquery lists all files advertised by the matched targets in the currently requested output groups. This new mode has the following advantages over `--output=starlark` combined with an appropriate handcrafted `--starlark:expr`: * provides a canonical answer to the very common "Where are my build outputs?" question * is more friendly to new users as it doesn't require knowing about providers and non-BUILD dialect Starlark * takes the value of `--output_groups` into account * stays as close to the logic for build summaries printed by `bazel build` as possible Fixes #8739 RELNOTES: `cquery`'s new output mode [`--output=files`](https://bazel.build/docs/cquery#files-output) lists the output files of the targets matching the query. It takes the current value of `--output_groups` into account. Closes #15552. PiperOrigin-RevId: 462630629 Change-Id: Ic648f22aa160ee57b476180561b444f08799ebb6
1 parent 89d77ec commit 681f534

17 files changed

+342
-32
lines changed

site/en/docs/cquery.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,24 @@ This option generates output as a Graphviz-compatible .dot file. See `query`'s
357357
also supports [`--graph:node_limit`](/reference/query#graph-nodelimit) and
358358
[`--graph:factored`](/reference/query#graph-factored).
359359

360+
### Files output {:#files-output}
361+
362+
<pre>
363+
--output=files
364+
</pre>
365+
366+
This option prints a list of the output files produced by each target matched
367+
by the query similar to the list printed at the end of a `bazel build`
368+
invocation. The output contains only the files advertised in the requested
369+
output groups as determined by the
370+
[`--output_groups`](/reference/command-line-reference#flag--output_groups) flag
371+
and never contains source files.
372+
373+
Note: The output of `bazel cquery --output=files //pkg:foo` contains the output
374+
files of `//pkg:foo` in *all* configurations that occur in the build (also see
375+
the [section on target pattern evaluation](#target-pattern-evaluation)). If that
376+
is not desired, wrap you query in [`config(..., target)`](#config).
377+
360378
### Defining the output format using Starlark {:#output-format-definition}
361379

362380
<pre>

src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import com.google.common.collect.ImmutableSet;
2222
import com.google.common.collect.Iterables;
2323
import com.google.devtools.build.lib.actions.Artifact;
24+
import com.google.devtools.build.lib.analysis.configuredtargets.InputFileConfiguredTarget;
25+
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
2426
import com.google.devtools.build.lib.analysis.test.TestProvider;
2527
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
2628
import com.google.devtools.build.lib.collect.nestedset.NestedSet.Node;
@@ -236,6 +238,36 @@ static ArtifactsToBuild getAllArtifactsToBuild(
236238
allOutputGroups.buildOrThrow(), /*allOutputGroupsImportant=*/ allOutputGroupsImportant);
237239
}
238240

241+
/**
242+
* Returns false if the build outputs provided by the target should never be shown to users.
243+
*
244+
* <p>Always returns false for hidden rules and source file targets.
245+
*/
246+
public static boolean shouldConsiderForDisplay(ConfiguredTarget configuredTarget) {
247+
// TODO(bazel-team): this is quite ugly. Add a marker provider for this check.
248+
if (configuredTarget instanceof InputFileConfiguredTarget) {
249+
// Suppress display of source files (because we do no work to build them).
250+
return false;
251+
}
252+
if (configuredTarget instanceof RuleConfiguredTarget) {
253+
RuleConfiguredTarget ruleCt = (RuleConfiguredTarget) configuredTarget;
254+
if (ruleCt.getRuleClassString().contains("$")) {
255+
// Suppress display of hidden rules
256+
return false;
257+
}
258+
}
259+
return true;
260+
}
261+
262+
/**
263+
* Returns true if the given artifact should be shown to users as a build output.
264+
*
265+
* <p>Always returns false for middleman and source artifacts.
266+
*/
267+
public static boolean shouldDisplay(Artifact artifact) {
268+
return !artifact.isSourceArtifact() && !artifact.isMiddlemanArtifact();
269+
}
270+
239271
/**
240272
* Recursive procedure filtering a target/aspect's declared {@code
241273
* NestedSet<ArtifactsInOutputGroup>} and {@code NestedSet<Artifact>} to only include {@link

src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
2626
import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
2727
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
28-
import com.google.devtools.build.lib.analysis.configuredtargets.InputFileConfiguredTarget;
2928
import com.google.devtools.build.lib.analysis.configuredtargets.OutputFileConfiguredTarget;
30-
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
3129
import com.google.devtools.build.lib.cmdline.Label;
3230
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
3331
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
@@ -140,7 +138,7 @@ void showBuildResult(
140138
TopLevelArtifactHelper.getAllArtifactsToBuild(target, context)
141139
.getImportantArtifacts()
142140
.toList()) {
143-
if (shouldPrint(artifact)) {
141+
if (TopLevelArtifactHelper.shouldDisplay(artifact)) {
144142
if (headerFlag) {
145143
outErr.printErr("Target " + label + " up-to-date:\n");
146144
headerFlag = false;
@@ -195,7 +193,7 @@ void showBuildResult(
195193
outErr.printErr("Aspect " + aspectName + " of " + label + " up-to-date:\n");
196194
headerFlag = false;
197195
}
198-
if (shouldPrint(importantArtifact)) {
196+
if (TopLevelArtifactHelper.shouldDisplay(importantArtifact)) {
199197
outErr.printErrLn(formatArtifactForShowResults(prettyPrinter, importantArtifact));
200198
}
201199
}
@@ -216,10 +214,6 @@ void showBuildResult(
216214
}
217215
}
218216

219-
private boolean shouldPrint(Artifact artifact) {
220-
return !artifact.isSourceArtifact() && !artifact.isMiddlemanArtifact();
221-
}
222-
223217
private String formatArtifactForShowResults(PathPrettyPrinter prettyPrinter, Artifact artifact) {
224218
return " " + prettyPrinter.getPrettyPath(artifact.getPath().asFragment());
225219
}
@@ -268,18 +262,9 @@ private Collection<ConfiguredTarget> filterTargetsToPrint(
268262
Collection<ConfiguredTarget> configuredTargets) {
269263
ImmutableList.Builder<ConfiguredTarget> result = ImmutableList.builder();
270264
for (ConfiguredTarget configuredTarget : configuredTargets) {
271-
// TODO(bazel-team): this is quite ugly. Add a marker provider for this check.
272-
if (configuredTarget instanceof InputFileConfiguredTarget) {
273-
// Suppress display of source files (because we do no work to build them).
265+
if (!TopLevelArtifactHelper.shouldConsiderForDisplay(configuredTarget)) {
274266
continue;
275267
}
276-
if (configuredTarget instanceof RuleConfiguredTarget) {
277-
RuleConfiguredTarget ruleCt = (RuleConfiguredTarget) configuredTarget;
278-
if (ruleCt.getRuleClassString().contains("$")) {
279-
// Suppress display of hidden rules
280-
continue;
281-
}
282-
}
283268
if (configuredTarget instanceof OutputFileConfiguredTarget) {
284269
// Suppress display of generated files (because they appear underneath
285270
// their generating rule), EXCEPT those ones which are not part of the

src/main/java/com/google/devtools/build/lib/buildtool/CqueryProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ protected ConfiguredTargetQueryEnvironment getQueryEnvironment(
5858
env.getRelativeWorkingDirectory(),
5959
env.getPackageManager().getPackagePath(),
6060
() -> walkableGraph,
61-
cqueryOptions);
61+
cqueryOptions,
62+
request.getTopLevelArtifactContext());
6263
}
6364
}

src/main/java/com/google/devtools/build/lib/query2/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ java_library(
5252
"//src/main/java/com/google/devtools/build/lib/analysis:target_and_configuration",
5353
"//src/main/java/com/google/devtools/build/lib/analysis:toolchain_collection",
5454
"//src/main/java/com/google/devtools/build/lib/analysis:toolchain_context",
55+
"//src/main/java/com/google/devtools/build/lib/analysis:top_level_artifact_context",
5556
"//src/main/java/com/google/devtools/build/lib/bugreport",
5657
"//src/main/java/com/google/devtools/build/lib/buildeventstream",
5758
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",

src/main/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallback.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class BuildOutputFormatterCallback extends CqueryThreadsafeCallback {
3838
OutputStream out,
3939
SkyframeExecutor skyframeExecutor,
4040
TargetAccessor<KeyedConfiguredTarget> accessor) {
41-
super(eventHandler, options, out, skyframeExecutor, accessor);
41+
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
4242
}
4343

4444
@Override

src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.google.common.util.concurrent.MoreExecutors;
2626
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
2727
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
28+
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
2829
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
2930
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
3031
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
@@ -80,6 +81,8 @@ public class ConfiguredTargetQueryEnvironment
8081

8182
private CqueryOptions cqueryOptions;
8283

84+
private final TopLevelArtifactContext topLevelArtifactContext;
85+
8386
private final KeyExtractor<KeyedConfiguredTarget, ConfiguredTargetKey>
8487
configuredTargetKeyExtractor;
8588

@@ -118,7 +121,8 @@ public ConfiguredTargetQueryEnvironment(
118121
PathFragment parserPrefix,
119122
PathPackageLocator pkgPath,
120123
Supplier<WalkableGraph> walkableGraphSupplier,
121-
Set<Setting> settings)
124+
Set<Setting> settings,
125+
TopLevelArtifactContext topLevelArtifactContext)
122126
throws InterruptedException {
123127
super(
124128
keepGoing,
@@ -134,6 +138,7 @@ public ConfiguredTargetQueryEnvironment(
134138
this.configuredTargetKeyExtractor = KeyedConfiguredTarget::getConfiguredTargetKey;
135139
this.transitiveConfigurations =
136140
getTransitiveConfigurations(transitiveConfigurationKeys, walkableGraphSupplier.get());
141+
this.topLevelArtifactContext = topLevelArtifactContext;
137142
}
138143

139144
public ConfiguredTargetQueryEnvironment(
@@ -146,7 +151,8 @@ public ConfiguredTargetQueryEnvironment(
146151
PathFragment parserPrefix,
147152
PathPackageLocator pkgPath,
148153
Supplier<WalkableGraph> walkableGraphSupplier,
149-
CqueryOptions cqueryOptions)
154+
CqueryOptions cqueryOptions,
155+
TopLevelArtifactContext topLevelArtifactContext)
150156
throws InterruptedException {
151157
this(
152158
keepGoing,
@@ -158,7 +164,8 @@ public ConfiguredTargetQueryEnvironment(
158164
parserPrefix,
159165
pkgPath,
160166
walkableGraphSupplier,
161-
cqueryOptions.toSettings());
167+
cqueryOptions.toSettings(),
168+
topLevelArtifactContext);
162169
this.cqueryOptions = cqueryOptions;
163170
}
164171

@@ -247,7 +254,9 @@ private static ImmutableMap<String, BuildConfigurationValue> getTransitiveConfig
247254
accessor,
248255
kct -> getFwdDeps(ImmutableList.of(kct))),
249256
new StarlarkOutputFormatterCallback(
250-
eventHandler, cqueryOptions, out, skyframeExecutor, accessor));
257+
eventHandler, cqueryOptions, out, skyframeExecutor, accessor),
258+
new FilesOutputFormatterCallback(
259+
eventHandler, cqueryOptions, out, skyframeExecutor, accessor, topLevelArtifactContext));
251260
}
252261

253262
@Override

src/main/java/com/google/devtools/build/lib/query2/cquery/CqueryThreadsafeCallback.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616

1717
import com.google.common.annotations.VisibleForTesting;
18+
import com.google.common.collect.ImmutableSet;
1819
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
1920
import com.google.devtools.build.lib.events.ExtendedEventHandler;
2021
import com.google.devtools.build.lib.query2.NamedThreadSafeOutputFormatterCallback;
@@ -55,14 +56,16 @@ public abstract class CqueryThreadsafeCallback
5556
protected final ConfiguredTargetAccessor accessor;
5657

5758
private final List<String> result = new ArrayList<>();
59+
private final boolean uniquifyResults;
5860

5961
@SuppressWarnings("DefaultCharset")
6062
CqueryThreadsafeCallback(
6163
ExtendedEventHandler eventHandler,
6264
CqueryOptions options,
6365
OutputStream out,
6466
SkyframeExecutor skyframeExecutor,
65-
TargetAccessor<KeyedConfiguredTarget> accessor) {
67+
TargetAccessor<KeyedConfiguredTarget> accessor,
68+
boolean uniquifyResults) {
6669
this.eventHandler = eventHandler;
6770
this.options = options;
6871
if (out != null) {
@@ -72,6 +75,7 @@ public abstract class CqueryThreadsafeCallback
7275
}
7376
this.skyframeExecutor = skyframeExecutor;
7477
this.accessor = (ConfiguredTargetAccessor) accessor;
78+
this.uniquifyResults = uniquifyResults;
7579
}
7680

7781
public void addResult(String string) {
@@ -86,7 +90,8 @@ public List<String> getResult() {
8690
@Override
8791
public void close(boolean failFast) throws InterruptedException, IOException {
8892
if (!failFast && printStream != null) {
89-
for (String s : result) {
93+
List<String> resultsToPrint = uniquifyResults ? ImmutableSet.copyOf(result).asList() : result;
94+
for (String s : resultsToPrint) {
9095
// TODO(ulfjack): We should use queryOptions.getLineTerminator() instead.
9196
printStream.append(s).append("\n");
9297
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2022 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package com.google.devtools.build.lib.query2.cquery;
15+
16+
import com.google.devtools.build.lib.actions.Artifact;
17+
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
18+
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
19+
import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
20+
import com.google.devtools.build.lib.events.ExtendedEventHandler;
21+
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
22+
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
23+
import java.io.IOException;
24+
import java.io.OutputStream;
25+
26+
/**
27+
* Cquery output formatter that prints the set of output files advertised by the matched targets.
28+
*/
29+
public class FilesOutputFormatterCallback extends CqueryThreadsafeCallback {
30+
31+
private final TopLevelArtifactContext topLevelArtifactContext;
32+
33+
FilesOutputFormatterCallback(
34+
ExtendedEventHandler eventHandler,
35+
CqueryOptions options,
36+
OutputStream out,
37+
SkyframeExecutor skyframeExecutor,
38+
TargetAccessor<KeyedConfiguredTarget> accessor,
39+
TopLevelArtifactContext topLevelArtifactContext) {
40+
// Different targets may provide the same artifact, so we deduplicate the collection of all
41+
// results at the end.
42+
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ true);
43+
this.topLevelArtifactContext = topLevelArtifactContext;
44+
}
45+
46+
@Override
47+
public String getName() {
48+
return "files";
49+
}
50+
51+
@Override
52+
public void processOutput(Iterable<KeyedConfiguredTarget> partialResult)
53+
throws IOException, InterruptedException {
54+
for (KeyedConfiguredTarget keyedTarget : partialResult) {
55+
ConfiguredTarget target = keyedTarget.getConfiguredTarget();
56+
if (!TopLevelArtifactHelper.shouldConsiderForDisplay(target)) {
57+
continue;
58+
}
59+
TopLevelArtifactHelper.getAllArtifactsToBuild(target, topLevelArtifactContext)
60+
.getImportantArtifacts()
61+
.toList()
62+
.stream()
63+
.filter(TopLevelArtifactHelper::shouldDisplay)
64+
.map(Artifact::getExecPathString)
65+
.forEach(this::addResult);
66+
}
67+
}
68+
}

src/main/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallback.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public Comparator<KeyedConfiguredTarget> comparator() {
8686
SkyframeExecutor skyframeExecutor,
8787
TargetAccessor<KeyedConfiguredTarget> accessor,
8888
DepsRetriever depsRetriever) {
89-
super(eventHandler, options, out, skyframeExecutor, accessor);
89+
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
9090
this.depsRetriever = depsRetriever;
9191
}
9292

0 commit comments

Comments
 (0)