Skip to content

Commit ad241fb

Browse files
philsccopybara-github
authored andcommitted
Allow cquery to filter out incompatible targets
This patch exposes the `IncompatiblePlatformProvider` to Starlark just enough that it can be used with `cquery`'s `platforms()` function. I added an example of this to the documentation. The motivation here is to let users filter out incompatible targets from queries that provide things like the list of targets to build for CI. This patch is minimal on purpose. It does not allow users to instantiate an `IncompatiblePlatformProvider` in Starlark. This may be added in a future patch to address a different use case. Fixes bazelbuild#12917. Closes bazelbuild#12935. PiperOrigin-RevId: 356580943
1 parent c6838bd commit ad241fb

File tree

7 files changed

+123
-8
lines changed

7 files changed

+123
-8
lines changed

site/docs/platforms.md

+23
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,26 @@ cc_library(
225225
)
226226
```
227227

228+
### Detecting incompatible targets using `bazel cquery`
229+
230+
You can use the
231+
[`IncompatiblePlatformProvider`](skylark/lib/IncompatiblePlatformProvider.html)
232+
in `bazel cquery`'s [Starlark output
233+
format](cquery.html#defining-the-output-format-using-starlark) to distinguish
234+
incompatible targets from compatible ones.
235+
236+
This can be used to filter out incompatible targets. The example below will
237+
only print the labels for targets that are compatible. Incompatible targets are
238+
not printed.
239+
240+
```console
241+
$ cat example.cquery
242+
243+
def format(target):
244+
if "IncompatiblePlatformProvider" not in providers(target):
245+
return target.label
246+
return ""
247+
248+
249+
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
250+
```

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,10 @@ java_library(
797797
srcs = ["IncompatiblePlatformProvider.java"],
798798
deps = [
799799
":configured_target",
800-
":transitive_info_provider",
801800
"//src/main/java/com/google/devtools/build/lib/analysis/platform",
801+
"//src/main/java/com/google/devtools/build/lib/concurrent",
802+
"//src/main/java/com/google/devtools/build/lib/packages",
803+
"//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform",
802804
"//third_party:auto_value",
803805
"//third_party:guava",
804806
"//third_party:jsr305",

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

+25-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
import com.google.common.base.Preconditions;
1919
import com.google.common.collect.ImmutableList;
2020
import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
21+
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
22+
import com.google.devtools.build.lib.packages.BuiltinProvider;
23+
import com.google.devtools.build.lib.packages.Info;
24+
import com.google.devtools.build.lib.starlarkbuildapi.platform.IncompatiblePlatformProviderApi;
2125
import javax.annotation.Nullable;
2226

2327
/**
@@ -34,8 +38,23 @@
3438
* target is incompatible because one of its dependencies is incompatible, then all the incompatible
3539
* dependencies are available via {@code getTargetResponsibleForIncompatibility()}.
3640
*/
41+
@Immutable
3742
@AutoValue
38-
public abstract class IncompatiblePlatformProvider implements TransitiveInfoProvider {
43+
public abstract class IncompatiblePlatformProvider
44+
implements Info, IncompatiblePlatformProviderApi {
45+
/** Name used in Starlark for accessing this provider. */
46+
public static final String STARLARK_NAME = "IncompatiblePlatformProvider";
47+
48+
/** Provider singleton constant. */
49+
public static final BuiltinProvider<IncompatiblePlatformProvider> PROVIDER =
50+
new BuiltinProvider<IncompatiblePlatformProvider>(
51+
STARLARK_NAME, IncompatiblePlatformProvider.class) {};
52+
53+
@Override
54+
public BuiltinProvider<IncompatiblePlatformProvider> getProvider() {
55+
return PROVIDER;
56+
}
57+
3958
public static IncompatiblePlatformProvider incompatibleDueToTargets(
4059
ImmutableList<ConfiguredTarget> targetsResponsibleForIncompatibility) {
4160
Preconditions.checkNotNull(targetsResponsibleForIncompatibility);
@@ -50,6 +69,11 @@ public static IncompatiblePlatformProvider incompatibleDueToConstraints(
5069
return new AutoValue_IncompatiblePlatformProvider(null, constraints);
5170
}
5271

72+
@Override
73+
public boolean isImmutable() {
74+
return true; // immutable and Starlark-hashable
75+
}
76+
5377
/**
5478
* Returns the incompatible dependencies that caused this provider to be present.
5579
*

src/main/java/com/google/devtools/build/lib/analysis/constraints/RuleContextConstraintSemantics.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ public static IncompatibleCheckResult checkForIncompatibility(ConfiguredTarget t
880880
target = ((OutputFileConfiguredTarget) target).getGeneratingRule();
881881
}
882882
return IncompatibleCheckResult.create(
883-
target.getProvider(IncompatiblePlatformProvider.class) != null, target);
883+
target.get(IncompatiblePlatformProvider.PROVIDER) != null, target);
884884
}
885885

886886
/**
@@ -996,13 +996,11 @@ private static ConfiguredTarget createIncompatibleConfiguredTarget(
996996
builder.setFilesToBuild(filesToBuild);
997997

998998
if (targetsResponsibleForIncompatibility != null) {
999-
builder.add(
1000-
IncompatiblePlatformProvider.class,
999+
builder.addNativeDeclaredProvider(
10011000
IncompatiblePlatformProvider.incompatibleDueToTargets(
10021001
targetsResponsibleForIncompatibility));
10031002
} else if (violatedConstraints != null) {
1004-
builder.add(
1005-
IncompatiblePlatformProvider.class,
1003+
builder.addNativeDeclaredProvider(
10061004
IncompatiblePlatformProvider.incompatibleDueToConstraints(violatedConstraints));
10071005
} else {
10081006
throw new IllegalArgumentException(

src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ private static String reportOnIncompatibility(ConfiguredTarget target) {
195195
// save the user bazel round trips.
196196
while (target != null) {
197197
message += "\n " + target.getLabel();
198-
provider = target.getProvider(IncompatiblePlatformProvider.class);
198+
provider = target.get(IncompatiblePlatformProvider.PROVIDER);
199199
ImmutableList<ConfiguredTarget> targetList = provider.targetsResponsibleForIncompatibility();
200200
if (targetList == null) {
201201
target = null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2021 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+
15+
package com.google.devtools.build.lib.starlarkbuildapi.platform;
16+
17+
import com.google.devtools.build.docgen.annot.DocCategory;
18+
import net.starlark.java.annot.StarlarkBuiltin;
19+
import net.starlark.java.eval.StarlarkValue;
20+
21+
/** Targets that are incompatible with the target platform. */
22+
@StarlarkBuiltin(
23+
name = "IncompatiblePlatformProvider",
24+
doc =
25+
"A provider for targets that are incompatible with the target platform. See "
26+
+ "<a href='../../platforms.html#detecting-incompatible-targets-using-bazel-cquery'>"
27+
+ "Detecting incompatible targets using <code>bazel cquery</code></a> for more "
28+
+ "information.",
29+
category = DocCategory.PROVIDER)
30+
public interface IncompatiblePlatformProviderApi extends StarlarkValue {}

src/test/shell/integration/target_compatible_with_test.sh

+38
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,44 @@ function test_cquery_incompatible_target() {
912912
expect_log "target platform didn't satisfy constraint //target_skipping:foo1"
913913
}
914914
915+
# Runs a cquery and makes sure that we can properly distinguish between
916+
# incompatible targets and compatible targets.
917+
function test_cquery_with_starlark_formatting() {
918+
cat > target_skipping/compatibility.cquery <<EOF
919+
def format(target):
920+
if "IncompatiblePlatformProvider" in providers(target):
921+
result = "incompatible"
922+
else:
923+
result = "compatible"
924+
925+
return "%s is %s" % (target.label, result)
926+
EOF
927+
928+
cd target_skipping || fail "couldn't cd into workspace"
929+
930+
bazel cquery \
931+
--host_platform=//target_skipping:foo1_bar1_platform \
932+
--platforms=//target_skipping:foo1_bar1_platform \
933+
:all \
934+
--output=starlark --starlark:file=target_skipping/compatibility.cquery \
935+
&> "${TEST_log}"
936+
937+
expect_log '^//target_skipping:pass_on_foo1 is compatible$'
938+
expect_log '^//target_skipping:fail_on_foo2 is incompatible$'
939+
expect_log '^//target_skipping:some_foo3_target is incompatible$'
940+
941+
bazel cquery \
942+
--host_platform=//target_skipping:foo3_platform \
943+
--platforms=//target_skipping:foo3_platform \
944+
:all \
945+
--output=starlark --starlark:file=target_skipping/compatibility.cquery \
946+
&> "${TEST_log}"
947+
948+
expect_log '^//target_skipping:pass_on_foo1 is incompatible$'
949+
expect_log '^//target_skipping:fail_on_foo2 is incompatible$'
950+
expect_log '^//target_skipping:some_foo3_target is compatible$'
951+
}
952+
915953
# Run an aquery on a target that is compatible. This should pass.
916954
function test_aquery_compatible_target() {
917955
write_query_test_targets

0 commit comments

Comments
 (0)