Add registration of execution platforms

Part of #4442.

Change-Id: I6debbf7cfdf560d2113e736176702c2cd889c0d2
PiperOrigin-RevId: 182763864
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java
index c37ffa3..b07d02a 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Package.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java
@@ -203,6 +203,7 @@
   private ImmutableList<Event> events;
   private ImmutableList<Postable> posts;
 
+  private ImmutableList<Label> registeredExecutionPlatformLabels;
   private ImmutableList<Label> registeredToolchainLabels;
 
   /**
@@ -339,6 +340,8 @@
     this.features = ImmutableSortedSet.copyOf(builder.features);
     this.events = ImmutableList.copyOf(builder.events);
     this.posts = ImmutableList.copyOf(builder.posts);
+    this.registeredExecutionPlatformLabels =
+        ImmutableList.copyOf(builder.registeredExecutionPlatformLabels);
     this.registeredToolchainLabels = ImmutableList.copyOf(builder.registeredToolchainLabels);
   }
 
@@ -656,6 +659,10 @@
     return defaultRestrictedTo;
   }
 
+  public ImmutableList<Label> getRegisteredExecutionPlatformLabels() {
+    return registeredExecutionPlatformLabels;
+  }
+
   public ImmutableList<Label> getRegisteredToolchainLabels() {
     return registeredToolchainLabels;
   }
@@ -775,6 +782,7 @@
     protected Map<Label, Path> subincludes = null;
     protected ImmutableList<Label> skylarkFileDependencies = ImmutableList.of();
 
+    protected List<Label> registeredExecutionPlatformLabels = new ArrayList<>();
     protected List<Label> registeredToolchainLabels = new ArrayList<>();
 
     /**
@@ -1298,6 +1306,10 @@
       addRuleUnchecked(rule);
     }
 
+    public void addRegisteredExecutionPlatformLabels(List<Label> platforms) {
+      this.registeredExecutionPlatformLabels.addAll(platforms);
+    }
+
     void addRegisteredToolchainLabels(List<Label> toolchains) {
       this.registeredToolchainLabels.addAll(toolchains);
     }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
index 1982200..9e1326b 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
@@ -274,6 +274,7 @@
     if (aPackage.containsErrors()) {
       builder.setContainsErrors();
     }
+    builder.addRegisteredExecutionPlatformLabels(aPackage.getRegisteredExecutionPlatformLabels());
     builder.addRegisteredToolchainLabels(aPackage.getRegisteredToolchainLabels());
     for (Rule rule : aPackage.getTargets(Rule.class)) {
       try {
@@ -388,6 +389,57 @@
   }
 
   @SkylarkSignature(
+    name = "register_execution_platforms",
+    objectType = Object.class,
+    returnType = NoneType.class,
+    doc = "Registers a platform so that it is available to execute actions.",
+    extraPositionals =
+        @Param(
+          name = "platform_labels",
+          type = SkylarkList.class,
+          generic1 = String.class,
+          doc = "The labels of the platforms to register."
+        ),
+    useAst = true,
+    useEnvironment = true
+  )
+  private static final BuiltinFunction.Factory newRegisterExecutionPlatformsFunction =
+      new BuiltinFunction.Factory("register_execution_platforms") {
+        public BuiltinFunction create(final RuleFactory ruleFactory) {
+          return new BuiltinFunction(
+              "register_execution_platforms",
+              FunctionSignature.POSITIONALS,
+              BuiltinFunction.USE_AST_ENV) {
+            public Object invoke(
+                SkylarkList<String> platformLabels, FuncallExpression ast, Environment env)
+                throws EvalException, InterruptedException {
+
+              // Collect the platform labels.
+              List<Label> platforms = new ArrayList<>();
+              for (String rawLabel : platformLabels.getContents(String.class, "platform_labels")) {
+                try {
+                  platforms.add(Label.parseAbsolute(rawLabel));
+                } catch (LabelSyntaxException e) {
+                  throw new EvalException(
+                      ast.getLocation(),
+                      String.format(
+                          "In register_execution_platforms: unable to parse platform label %s: %s",
+                          rawLabel, e.getMessage()),
+                      e);
+                }
+              }
+
+              // Add to the package definition for later.
+              Package.Builder builder = PackageFactory.getContext(env, ast).pkgBuilder;
+              builder.addRegisteredExecutionPlatformLabels(platforms);
+
+              return NONE;
+            }
+          };
+        }
+      };
+
+  @SkylarkSignature(
     name = "register_toolchains",
     objectType = Object.class,
     returnType = NoneType.class,
@@ -484,6 +536,8 @@
       boolean allowOverride, RuleFactory ruleFactory) {
     Map<String, BaseFunction> map = new HashMap<>();
     map.put("bind", newBindFunction(ruleFactory));
+    map.put(
+        "register_execution_platforms", newRegisterExecutionPlatformsFunction.apply(ruleFactory));
     map.put("register_toolchains", newRegisterToolchainsFunction.apply(ruleFactory));
     for (String ruleClass : ruleFactory.getRuleClassNames()) {
       if (!map.containsKey(ruleClass)) {