Allow exec properties to be set during RuleContext building. If not set, use the value of the attached target's exec_properties attribute. This allows aspects to not inherit exec_properties from the attached target since it should have a different set of exec groups anyway.

Aspect exec groups are not implemented yet so currently aspects exec_properties are always set to an empty map. Aspects currently do not have an exec_properties attribute.

PiperOrigin-RevId: 321367125
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 fca3374..e51ccca 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
@@ -258,7 +258,7 @@
     this.actionOwnerSymbolGenerator = new SymbolGenerator<>(actionLookupKey);
     reporter = builder.reporter;
     this.toolchainContexts = toolchainContexts;
-    this.execProperties = parseExecProperties();
+    this.execProperties = parseExecProperties(builder.rawExecProperties);
     this.constraintSemantics = constraintSemantics;
     this.requiredConfigFragments = requiredConfigFragments;
   }
@@ -1288,13 +1288,13 @@
     return ans.build();
   }
 
-  private ImmutableMap<String, ImmutableMap<String, String>> parseExecProperties()
-      throws InvalidExecGroupException {
-    if (!isAttrDefined(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT)) {
+  private ImmutableMap<String, ImmutableMap<String, String>> parseExecProperties(
+      Map<String, String> execProperties) throws InvalidExecGroupException {
+    if (execProperties.isEmpty()) {
       return ImmutableMap.of(DEFAULT_EXEC_GROUP_NAME, ImmutableMap.of());
     } else {
       return parseExecProperties(
-          attributes.get(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT),
+          execProperties,
           toolchainContexts == null ? ImmutableSet.of() : toolchainContexts.getExecGroups());
     }
   }
@@ -1747,6 +1747,7 @@
     private ImmutableMap<String, Attribute> aspectAttributes;
     private ImmutableList<Aspect> aspects;
     private ToolchainCollection<ResolvedToolchainContext> toolchainContexts;
+    private ImmutableMap<String, String> rawExecProperties;
     private ConstraintSemantics<RuleContext> constraintSemantics;
     private ImmutableSet<String> requiredConfigFragments = ImmutableSet.of();
 
@@ -1789,6 +1790,14 @@
       ListMultimap<String, ConfiguredTargetAndData> targetMap = createTargetMap();
       ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap =
           createFilesetEntryMap(target.getAssociatedRule(), configConditions);
+      if (rawExecProperties == null) {
+        if (!attributes.has(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT)) {
+          rawExecProperties = ImmutableMap.of();
+        } else {
+          rawExecProperties =
+              ImmutableMap.copyOf(attributes.get(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT));
+        }
+      }
       return new RuleContext(
           this,
           attributes,
@@ -1877,6 +1886,15 @@
       return this;
     }
 
+    /**
+     * Warning: if you set the exec properties using this method any exec_properties attribute value
+     * will be ignored in favor of this value.
+     */
+    public Builder setExecProperties(ImmutableMap<String, String> execProperties) {
+      this.rawExecProperties = execProperties;
+      return this;
+    }
+
     public Builder setConstraintSemantics(ConstraintSemantics<RuleContext> constraintSemantics) {
       this.constraintSemantics = constraintSemantics;
       return this;