blob: 3366b6b3ab39fe648f7ea7ba910faaa22db7adf4 [file] [log] [blame]
// Copyright 2019 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.analysis.platform;
import build.bazel.remote.execution.v2.Platform;
import build.bazel.remote.execution.v2.Platform.Property;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Ordering;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.UserExecException;
import com.google.devtools.build.lib.remote.options.RemoteOptions;
import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.Spawn.Code;
import com.google.protobuf.TextFormat;
import com.google.protobuf.TextFormat.ParseException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import javax.annotation.Nullable;
/** Utilities for accessing platform properties. */
public final class PlatformUtils {
private static void sortPlatformProperties(Platform.Builder builder) {
List<Platform.Property> properties =
Ordering.from(Comparator.comparing(Platform.Property::getName))
.sortedCopy(builder.getPropertiesList());
builder.clearProperties();
builder.addAllProperties(properties);
}
@Nullable
public static Platform buildPlatformProto(Map<String, String> executionProperties) {
if (executionProperties.isEmpty()) {
return null;
}
Platform.Builder builder = Platform.newBuilder();
for (Map.Entry<String, String> keyValue : executionProperties.entrySet()) {
Property property =
Property.newBuilder().setName(keyValue.getKey()).setValue(keyValue.getValue()).build();
builder.addProperties(property);
}
sortPlatformProperties(builder);
return builder.build();
}
@Nullable
public static Platform getPlatformProto(Spawn spawn, @Nullable RemoteOptions remoteOptions)
throws UserExecException {
return getPlatformProto(spawn, remoteOptions, ImmutableMap.of());
}
@Nullable
public static Platform getPlatformProto(
Spawn spawn, @Nullable RemoteOptions remoteOptions, Map<String, String> additionalProperties)
throws UserExecException {
SortedMap<String, String> defaultExecProperties =
remoteOptions != null
? remoteOptions.getRemoteDefaultExecProperties()
: ImmutableSortedMap.of();
if (spawn.getExecutionPlatform() == null
&& spawn.getCombinedExecProperties().isEmpty()
&& defaultExecProperties.isEmpty()
&& additionalProperties.isEmpty()) {
return null;
}
Map<String, String> properties = new HashMap<>();
if (!spawn.getCombinedExecProperties().isEmpty()) {
// Apply default exec properties if the execution platform does not already set
// exec_properties
if (spawn.getExecutionPlatform() == null
|| spawn.getExecutionPlatform().execProperties().isEmpty()) {
properties.putAll(defaultExecProperties);
properties.putAll(spawn.getCombinedExecProperties());
} else {
properties = spawn.getCombinedExecProperties();
}
} else if (spawn.getExecutionPlatform() != null) {
String remoteExecutionProperties = spawn.getExecutionPlatform().remoteExecutionProperties();
if (!remoteExecutionProperties.isEmpty()) {
Platform.Builder platformBuilder = Platform.newBuilder();
// Try and get the platform info from the execution properties.
try {
TextFormat.getParser()
.merge(spawn.getExecutionPlatform().remoteExecutionProperties(), platformBuilder);
} catch (ParseException e) {
String message =
String.format(
"Failed to parse remote_execution_properties from platform %s",
spawn.getExecutionPlatform().label());
throw new UserExecException(
e, createFailureDetail(message, Code.INVALID_REMOTE_EXECUTION_PROPERTIES));
}
for (Property property : platformBuilder.getPropertiesList()) {
properties.put(property.getName(), property.getValue());
}
} else {
properties.putAll(spawn.getExecutionPlatform().execProperties());
}
}
if (properties.isEmpty()) {
properties = defaultExecProperties;
}
if (!additionalProperties.isEmpty()) {
if (properties.isEmpty()) {
properties = additionalProperties;
} else {
// Merge the two maps.
properties = new HashMap<>(properties);
properties.putAll(additionalProperties);
}
}
Platform.Builder platformBuilder = Platform.newBuilder();
for (Map.Entry<String, String> entry : properties.entrySet()) {
platformBuilder.addPropertiesBuilder().setName(entry.getKey()).setValue(entry.getValue());
}
sortPlatformProperties(platformBuilder);
return platformBuilder.build();
}
private static FailureDetail createFailureDetail(String message, Code detailedCode) {
return FailureDetail.newBuilder()
.setMessage(message)
.setSpawn(FailureDetails.Spawn.newBuilder().setCode(detailedCode))
.build();
}
}