Skip to content

Commit

Permalink
Add --output=files mode to cquery
Browse files Browse the repository at this point in the history
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
  • Loading branch information
fmeum authored and copybara-github committed Jul 22, 2022
1 parent 89d77ec commit 681f534
Show file tree
Hide file tree
Showing 17 changed files with 342 additions and 32 deletions.
18 changes: 18 additions & 0 deletions site/en/docs/cquery.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,24 @@ This option generates output as a Graphviz-compatible .dot file. See `query`'s
also supports [`--graph:node_limit`](/reference/query#graph-nodelimit) and
[`--graph:factored`](/reference/query#graph-factored).

### Files output {:#files-output}

<pre>
--output=files
</pre>

This option prints a list of the output files produced by each target matched
by the query similar to the list printed at the end of a `bazel build`
invocation. The output contains only the files advertised in the requested
output groups as determined by the
[`--output_groups`](/reference/command-line-reference#flag--output_groups) flag
and never contains source files.

Note: The output of `bazel cquery --output=files //pkg:foo` contains the output
files of `//pkg:foo` in *all* configurations that occur in the build (also see
the [section on target pattern evaluation](#target-pattern-evaluation)). If that
is not desired, wrap you query in [`config(..., target)`](#config).

### Defining the output format using Starlark {:#output-format-definition}

<pre>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.configuredtargets.InputFileConfiguredTarget;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
import com.google.devtools.build.lib.analysis.test.TestProvider;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSet.Node;
Expand Down Expand Up @@ -236,6 +238,36 @@ static ArtifactsToBuild getAllArtifactsToBuild(
allOutputGroups.buildOrThrow(), /*allOutputGroupsImportant=*/ allOutputGroupsImportant);
}

/**
* Returns false if the build outputs provided by the target should never be shown to users.
*
* <p>Always returns false for hidden rules and source file targets.
*/
public static boolean shouldConsiderForDisplay(ConfiguredTarget configuredTarget) {
// TODO(bazel-team): this is quite ugly. Add a marker provider for this check.
if (configuredTarget instanceof InputFileConfiguredTarget) {
// Suppress display of source files (because we do no work to build them).
return false;
}
if (configuredTarget instanceof RuleConfiguredTarget) {
RuleConfiguredTarget ruleCt = (RuleConfiguredTarget) configuredTarget;
if (ruleCt.getRuleClassString().contains("$")) {
// Suppress display of hidden rules
return false;
}
}
return true;
}

/**
* Returns true if the given artifact should be shown to users as a build output.
*
* <p>Always returns false for middleman and source artifacts.
*/
public static boolean shouldDisplay(Artifact artifact) {
return !artifact.isSourceArtifact() && !artifact.isMiddlemanArtifact();
}

/**
* Recursive procedure filtering a target/aspect's declared {@code
* NestedSet<ArtifactsInOutputGroup>} and {@code NestedSet<Artifact>} to only include {@link
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.configuredtargets.InputFileConfiguredTarget;
import com.google.devtools.build.lib.analysis.configuredtargets.OutputFileConfiguredTarget;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
Expand Down Expand Up @@ -140,7 +138,7 @@ void showBuildResult(
TopLevelArtifactHelper.getAllArtifactsToBuild(target, context)
.getImportantArtifacts()
.toList()) {
if (shouldPrint(artifact)) {
if (TopLevelArtifactHelper.shouldDisplay(artifact)) {
if (headerFlag) {
outErr.printErr("Target " + label + " up-to-date:\n");
headerFlag = false;
Expand Down Expand Up @@ -195,7 +193,7 @@ void showBuildResult(
outErr.printErr("Aspect " + aspectName + " of " + label + " up-to-date:\n");
headerFlag = false;
}
if (shouldPrint(importantArtifact)) {
if (TopLevelArtifactHelper.shouldDisplay(importantArtifact)) {
outErr.printErrLn(formatArtifactForShowResults(prettyPrinter, importantArtifact));
}
}
Expand All @@ -216,10 +214,6 @@ void showBuildResult(
}
}

private boolean shouldPrint(Artifact artifact) {
return !artifact.isSourceArtifact() && !artifact.isMiddlemanArtifact();
}

private String formatArtifactForShowResults(PathPrettyPrinter prettyPrinter, Artifact artifact) {
return " " + prettyPrinter.getPrettyPath(artifact.getPath().asFragment());
}
Expand Down Expand Up @@ -268,18 +262,9 @@ private Collection<ConfiguredTarget> filterTargetsToPrint(
Collection<ConfiguredTarget> configuredTargets) {
ImmutableList.Builder<ConfiguredTarget> result = ImmutableList.builder();
for (ConfiguredTarget configuredTarget : configuredTargets) {
// TODO(bazel-team): this is quite ugly. Add a marker provider for this check.
if (configuredTarget instanceof InputFileConfiguredTarget) {
// Suppress display of source files (because we do no work to build them).
if (!TopLevelArtifactHelper.shouldConsiderForDisplay(configuredTarget)) {
continue;
}
if (configuredTarget instanceof RuleConfiguredTarget) {
RuleConfiguredTarget ruleCt = (RuleConfiguredTarget) configuredTarget;
if (ruleCt.getRuleClassString().contains("$")) {
// Suppress display of hidden rules
continue;
}
}
if (configuredTarget instanceof OutputFileConfiguredTarget) {
// Suppress display of generated files (because they appear underneath
// their generating rule), EXCEPT those ones which are not part of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ protected ConfiguredTargetQueryEnvironment getQueryEnvironment(
env.getRelativeWorkingDirectory(),
env.getPackageManager().getPackagePath(),
() -> walkableGraph,
cqueryOptions);
cqueryOptions,
request.getTopLevelArtifactContext());
}
}
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/query2/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/analysis:target_and_configuration",
"//src/main/java/com/google/devtools/build/lib/analysis:toolchain_collection",
"//src/main/java/com/google/devtools/build/lib/analysis:toolchain_context",
"//src/main/java/com/google/devtools/build/lib/analysis:top_level_artifact_context",
"//src/main/java/com/google/devtools/build/lib/bugreport",
"//src/main/java/com/google/devtools/build/lib/buildeventstream",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class BuildOutputFormatterCallback extends CqueryThreadsafeCallback {
OutputStream out,
SkyframeExecutor skyframeExecutor,
TargetAccessor<KeyedConfiguredTarget> accessor) {
super(eventHandler, options, out, skyframeExecutor, accessor);
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.common.util.concurrent.MoreExecutors;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
Expand Down Expand Up @@ -80,6 +81,8 @@ public class ConfiguredTargetQueryEnvironment

private CqueryOptions cqueryOptions;

private final TopLevelArtifactContext topLevelArtifactContext;

private final KeyExtractor<KeyedConfiguredTarget, ConfiguredTargetKey>
configuredTargetKeyExtractor;

Expand Down Expand Up @@ -118,7 +121,8 @@ public ConfiguredTargetQueryEnvironment(
PathFragment parserPrefix,
PathPackageLocator pkgPath,
Supplier<WalkableGraph> walkableGraphSupplier,
Set<Setting> settings)
Set<Setting> settings,
TopLevelArtifactContext topLevelArtifactContext)
throws InterruptedException {
super(
keepGoing,
Expand All @@ -134,6 +138,7 @@ public ConfiguredTargetQueryEnvironment(
this.configuredTargetKeyExtractor = KeyedConfiguredTarget::getConfiguredTargetKey;
this.transitiveConfigurations =
getTransitiveConfigurations(transitiveConfigurationKeys, walkableGraphSupplier.get());
this.topLevelArtifactContext = topLevelArtifactContext;
}

public ConfiguredTargetQueryEnvironment(
Expand All @@ -146,7 +151,8 @@ public ConfiguredTargetQueryEnvironment(
PathFragment parserPrefix,
PathPackageLocator pkgPath,
Supplier<WalkableGraph> walkableGraphSupplier,
CqueryOptions cqueryOptions)
CqueryOptions cqueryOptions,
TopLevelArtifactContext topLevelArtifactContext)
throws InterruptedException {
this(
keepGoing,
Expand All @@ -158,7 +164,8 @@ public ConfiguredTargetQueryEnvironment(
parserPrefix,
pkgPath,
walkableGraphSupplier,
cqueryOptions.toSettings());
cqueryOptions.toSettings(),
topLevelArtifactContext);
this.cqueryOptions = cqueryOptions;
}

Expand Down Expand Up @@ -247,7 +254,9 @@ private static ImmutableMap<String, BuildConfigurationValue> getTransitiveConfig
accessor,
kct -> getFwdDeps(ImmutableList.of(kct))),
new StarlarkOutputFormatterCallback(
eventHandler, cqueryOptions, out, skyframeExecutor, accessor));
eventHandler, cqueryOptions, out, skyframeExecutor, accessor),
new FilesOutputFormatterCallback(
eventHandler, cqueryOptions, out, skyframeExecutor, accessor, topLevelArtifactContext));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@


import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.query2.NamedThreadSafeOutputFormatterCallback;
Expand Down Expand Up @@ -55,14 +56,16 @@ public abstract class CqueryThreadsafeCallback
protected final ConfiguredTargetAccessor accessor;

private final List<String> result = new ArrayList<>();
private final boolean uniquifyResults;

@SuppressWarnings("DefaultCharset")
CqueryThreadsafeCallback(
ExtendedEventHandler eventHandler,
CqueryOptions options,
OutputStream out,
SkyframeExecutor skyframeExecutor,
TargetAccessor<KeyedConfiguredTarget> accessor) {
TargetAccessor<KeyedConfiguredTarget> accessor,
boolean uniquifyResults) {
this.eventHandler = eventHandler;
this.options = options;
if (out != null) {
Expand All @@ -72,6 +75,7 @@ public abstract class CqueryThreadsafeCallback
}
this.skyframeExecutor = skyframeExecutor;
this.accessor = (ConfiguredTargetAccessor) accessor;
this.uniquifyResults = uniquifyResults;
}

public void addResult(String string) {
Expand All @@ -86,7 +90,8 @@ public List<String> getResult() {
@Override
public void close(boolean failFast) throws InterruptedException, IOException {
if (!failFast && printStream != null) {
for (String s : result) {
List<String> resultsToPrint = uniquifyResults ? ImmutableSet.copyOf(result).asList() : result;
for (String s : resultsToPrint) {
// TODO(ulfjack): We should use queryOptions.getLineTerminator() instead.
printStream.append(s).append("\n");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2022 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.cquery;

import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import java.io.IOException;
import java.io.OutputStream;

/**
* Cquery output formatter that prints the set of output files advertised by the matched targets.
*/
public class FilesOutputFormatterCallback extends CqueryThreadsafeCallback {

private final TopLevelArtifactContext topLevelArtifactContext;

FilesOutputFormatterCallback(
ExtendedEventHandler eventHandler,
CqueryOptions options,
OutputStream out,
SkyframeExecutor skyframeExecutor,
TargetAccessor<KeyedConfiguredTarget> accessor,
TopLevelArtifactContext topLevelArtifactContext) {
// Different targets may provide the same artifact, so we deduplicate the collection of all
// results at the end.
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ true);
this.topLevelArtifactContext = topLevelArtifactContext;
}

@Override
public String getName() {
return "files";
}

@Override
public void processOutput(Iterable<KeyedConfiguredTarget> partialResult)
throws IOException, InterruptedException {
for (KeyedConfiguredTarget keyedTarget : partialResult) {
ConfiguredTarget target = keyedTarget.getConfiguredTarget();
if (!TopLevelArtifactHelper.shouldConsiderForDisplay(target)) {
continue;
}
TopLevelArtifactHelper.getAllArtifactsToBuild(target, topLevelArtifactContext)
.getImportantArtifacts()
.toList()
.stream()
.filter(TopLevelArtifactHelper::shouldDisplay)
.map(Artifact::getExecPathString)
.forEach(this::addResult);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public Comparator<KeyedConfiguredTarget> comparator() {
SkyframeExecutor skyframeExecutor,
TargetAccessor<KeyedConfiguredTarget> accessor,
DepsRetriever depsRetriever) {
super(eventHandler, options, out, skyframeExecutor, accessor);
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
this.depsRetriever = depsRetriever;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class LabelAndConfigurationOutputFormatterCallback extends CqueryThreadsa
SkyframeExecutor skyframeExecutor,
TargetAccessor<KeyedConfiguredTarget> accessor,
boolean showKind) {
super(eventHandler, options, out, skyframeExecutor, accessor);
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
this.showKind = showKind;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public ImmutableList<Configuration> getConfigurations() {
AspectResolver resolver,
OutputType outputType,
@Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory) {
super(eventHandler, options, out, skyframeExecutor, accessor);
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
this.outputType = outputType;
this.skyframeExecutor = skyframeExecutor;
this.resolver = resolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public Object providers(ConfiguredTarget target) {
SkyframeExecutor skyframeExecutor,
TargetAccessor<KeyedConfiguredTarget> accessor)
throws QueryException, InterruptedException {
super(eventHandler, options, out, skyframeExecutor, accessor);
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);

ParserInput input = null;
String exceptionMessagePrefix;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public String getName() {
TargetAccessor<KeyedConfiguredTarget> accessor,
BuildConfigurationValue hostConfiguration,
@Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory) {
super(eventHandler, options, out, skyframeExecutor, accessor);
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
this.hostConfiguration = hostConfiguration;
this.trimmingTransitionFactory = trimmingTransitionFactory;
this.partialResultMap = Maps.newHashMap();
Expand Down
Loading

0 comments on commit 681f534

Please sign in to comment.