Adds the target_platform_has_constraint method to allow rules to check the target platform.

Fixes #10368.

RELNOTES: Adds ctx.target_platform_has_constraint to allow rules to check the target platform's constraints.
PiperOrigin-RevId: 286001442
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index a2b2ca0..02ba0cf 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -57,6 +57,7 @@
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics;
+import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.analysis.stringtemplate.TemplateContext;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -1225,6 +1226,13 @@
     return toolchainContext;
   }
 
+  public boolean targetPlatformHasConstraint(ConstraintValueInfo constraintValue) {
+    if (toolchainContext == null || toolchainContext.targetPlatform() == null) {
+      return false;
+    }
+    return toolchainContext.targetPlatform().constraints().hasConstraintValue(constraintValue);
+  }
+
   public ConstraintSemantics getConstraintSemantics() {
     return constraintSemantics;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java
index 1caa9a1..15e1dfd 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java
@@ -693,6 +693,11 @@
   }
 
   @Override
+  public boolean targetPlatformHasConstraint(ConstraintValueInfo constraintValue) {
+    return ruleContext.targetPlatformHasConstraint(constraintValue);
+  }
+
+  @Override
   public String toString() {
     return ruleLabelCanonicalName;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleContextApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleContextApi.java
index 4fa981a..8a134cc 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleContextApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleContextApi.java
@@ -318,6 +318,19 @@
   ToolchainContextApi toolchains() throws EvalException;
 
   @SkylarkCallable(
+      name = "target_platform_has_constraint",
+      doc = "Returns true if the given constraint value is part of the current target platform.",
+      parameters = {
+        @Param(
+            name = "constraintValue",
+            positional = true,
+            named = false,
+            type = ConstraintValueInfoApi.class,
+            doc = "The constraint value to check the target platform against.")
+      })
+  boolean targetPlatformHasConstraint(ConstraintValueT constraintValue);
+
+  @SkylarkCallable(
       name = "tokenize",
       doc = "Splits a shell command into a list of tokens.",
       // TODO(cparsons): Look into flipping this to true.
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RuleContextTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RuleContextTest.java
index 985cb9c..bfeeb7e 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/RuleContextTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/RuleContextTest.java
@@ -30,11 +30,9 @@
 public class RuleContextTest extends ToolchainTestCase {
 
   @Test
-  public void testMockRuleContextHasToolchains() throws Exception {
+  public void testToolchains() throws Exception {
     mockToolsConfig.create("x/BUILD", "mock_toolchain_rule(name='x')");
-    useConfiguration(
-        "--host_platform=//platforms:linux",
-        "--platforms=//platforms:mac");
+    useConfiguration("--host_platform=//platforms:linux", "--platforms=//platforms:mac");
     RuleContext ruleContext = getRuleContext(getConfiguredTarget("//x"));
     assertThat(ruleContext.getToolchainContext().resolvedToolchainLabels())
         .contains(Label.parseAbsolute("//toolchain:toolchain_1_impl", ImmutableMap.of()));
@@ -45,4 +43,22 @@
             .forToolchainType(Label.parseAbsolute("//toolchain:test_toolchain", ImmutableMap.of()));
     assertThat(toolchain.getValue("data")).isEqualTo("foo");
   }
+
+  @Test
+  public void testTargetPlatformHasConstraint_mac() throws Exception {
+    scratch.file("a/BUILD", "filegroup(name = 'a')");
+    useConfiguration("--platforms=//platforms:mac");
+    RuleContext ruleContext = getRuleContext(getConfiguredTarget("//a"));
+    assertThat(ruleContext.targetPlatformHasConstraint(macConstraint)).isTrue();
+    assertThat(ruleContext.targetPlatformHasConstraint(linuxConstraint)).isFalse();
+  }
+
+  @Test
+  public void testTargetPlatformHasConstraint_linux() throws Exception {
+    scratch.file("a/BUILD", "filegroup(name = 'a')");
+    useConfiguration("--platforms=//platforms:linux");
+    RuleContext ruleContext = getRuleContext(getConfiguredTarget("//a"));
+    assertThat(ruleContext.targetPlatformHasConstraint(macConstraint)).isFalse();
+    assertThat(ruleContext.targetPlatformHasConstraint(linuxConstraint)).isTrue();
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java
index 68fe632..afa97ad 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java
@@ -2627,4 +2627,57 @@
     value = getToolchainResult("//demo");
     assertThat(value).isEqualTo("bar");
   }
+
+  @Test
+  public void testTargetPlatformHasConstraint() throws Exception {
+    createPlatforms();
+
+    scratch.file(
+        "demo/test_rule.bzl",
+        "result = provider()",
+        "def _impl(ctx):",
+        "    constraint = ctx.attr._constraint[platform_common.ConstraintValueInfo]",
+        "    has_constraint = ctx.target_platform_has_constraint(constraint)",
+        "    return [result(",
+        "        has_constraint = has_constraint,",
+        "    )]",
+        "test_rule = rule(",
+        "    implementation = _impl,",
+        "    attrs = {",
+        "        '_constraint': attr.label(default = '//platform:constraint_1'),",
+        "    },",
+        ")");
+    scratch.file(
+        "demo/BUILD",
+        "load(':test_rule.bzl', 'test_rule')",
+        "test_rule(",
+        "    name = 'demo',",
+        ")");
+
+    useConfiguration("--platforms=//platform:platform_1");
+
+    ConfiguredTarget myRuleTarget = getConfiguredTarget("//demo");
+    StructImpl info =
+        (StructImpl)
+            myRuleTarget.get(
+                new SkylarkKey(
+                    Label.parseAbsolute("//demo:test_rule.bzl", ImmutableMap.of()), "result"));
+
+    assertThat(info).isNotNull();
+    boolean hasConstraint = (boolean) info.getValue("has_constraint");
+    assertThat(hasConstraint).isTrue();
+
+    // Re-test with the other platform.
+    useConfiguration("--platforms=//platform:platform_2");
+    myRuleTarget = getConfiguredTarget("//demo");
+    info =
+        (StructImpl)
+            myRuleTarget.get(
+                new SkylarkKey(
+                    Label.parseAbsolute("//demo:test_rule.bzl", ImmutableMap.of()), "result"));
+
+    assertThat(info).isNotNull();
+    hasConstraint = (boolean) info.getValue("has_constraint");
+    assertThat(hasConstraint).isFalse();
+  }
 }