blob: 401a34a148f2bdea4cd50b1f4feefd2982e072ac [file] [log] [blame]
// Copyright 2017 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;
import static java.util.stream.Collectors.joining;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkbuildapi.ToolchainContextApi;
import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.StarlarkContext;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
/** Represents the data needed for a specific target's use of toolchains and platforms. */
@AutoValue
@Immutable
@ThreadSafe
public abstract class ToolchainContext implements ToolchainContextApi {
static Builder builder() {
return new AutoValue_ToolchainContext.Builder();
}
/** Builder interface to help create new instances of {@link ToolchainContext}. */
@AutoValue.Builder
interface Builder {
/** Sets a description of the target being used, for error messaging. */
Builder setTargetDescription(String targetDescription);
/** Sets the selected execution platform that these toolchains use. */
Builder setExecutionPlatform(PlatformInfo executionPlatform);
/** Sets the target platform that these toolchains generate output for. */
Builder setTargetPlatform(PlatformInfo targetPlatform);
/** Sets the toolchain types that were requested. */
Builder setRequiredToolchainTypes(Set<ToolchainTypeInfo> requiredToolchainTypes);
/** Sets the map from toolchain type to toolchain provider. */
Builder setToolchains(ImmutableMap<ToolchainTypeInfo, ToolchainInfo> toolchains);
/** Sets the template variables that these toolchains provide. */
Builder setTemplateVariableProviders(ImmutableList<TemplateVariableInfo> providers);
/** Sets the labels of the specific toolchains being used. */
Builder setResolvedToolchainLabels(ImmutableSet<Label> resolvedToolchainLabels);
/** Returns a new {@link ToolchainContext}. */
ToolchainContext build();
}
/** Returns a description of the target being used, for error messaging. */
abstract String targetDescription();
/** Returns the selected execution platform that these toolchains use. */
public abstract PlatformInfo executionPlatform();
/** Returns the target platform that these toolchains generate output for. */
public abstract PlatformInfo targetPlatform();
/** Returns the toolchain types that were requested. */
public abstract ImmutableSet<ToolchainTypeInfo> requiredToolchainTypes();
abstract ImmutableMap<ToolchainTypeInfo, ToolchainInfo> toolchains();
/** Returns the template variables that these toolchains provide. */
public abstract ImmutableList<TemplateVariableInfo> templateVariableProviders();
/** Returns the labels of the specific toolchains being used. */
public abstract ImmutableSet<Label> resolvedToolchainLabels();
/**
* Returns the toolchain for the given type, or {@code null} if the toolchain type was not
* required in this context.
*/
@Nullable
public ToolchainInfo forToolchainType(Label toolchainTypeLabel) {
Optional<ToolchainTypeInfo> toolchainType =
toolchains().keySet().stream()
.filter(info -> info.typeLabel().equals(toolchainTypeLabel))
.findFirst();
if (toolchainType.isPresent()) {
return forToolchainType(toolchainType.get());
} else {
return null;
}
}
@Nullable
public ToolchainInfo forToolchainType(ToolchainTypeInfo toolchainType) {
return toolchains().get(toolchainType);
}
@Override
public boolean isImmutable() {
return true;
}
@Override
public void repr(SkylarkPrinter printer) {
printer.append("<toolchain_context.resolved_labels: ");
printer.append(
toolchains().keySet().stream()
.map(ToolchainTypeInfo::typeLabel)
.map(Label::toString)
.collect(joining(", ")));
printer.append(">");
}
private Label transformKey(Object key, Location loc) throws EvalException {
if (key instanceof Label) {
return (Label) key;
} else if (key instanceof ToolchainTypeInfo) {
return ((ToolchainTypeInfo) key).typeLabel();
} else if (key instanceof String) {
Label toolchainType;
String rawLabel = (String) key;
try {
toolchainType = Label.parseAbsolute(rawLabel, ImmutableMap.of());
} catch (LabelSyntaxException e) {
throw new EvalException(
loc, String.format("Unable to parse toolchain %s: %s", rawLabel, e.getMessage()), e);
}
return toolchainType;
} else {
throw new EvalException(
loc,
String.format(
"Toolchains only supports indexing by toolchain type, got %s instead",
EvalUtils.getDataTypeName(key)));
}
}
@Override
public ToolchainInfo getIndex(Object key, Location loc, StarlarkContext context)
throws EvalException {
Label toolchainTypeLabel = transformKey(key, loc);
if (!containsKey(key, loc, context)) {
throw new EvalException(
loc,
String.format(
"In %s, toolchain type %s was requested but only types [%s] are configured",
targetDescription(),
toolchainTypeLabel,
requiredToolchainTypes().stream()
.map(ToolchainTypeInfo::typeLabel)
.map(Label::toString)
.collect(joining(", "))));
}
return forToolchainType(toolchainTypeLabel);
}
@Override
public boolean containsKey(Object key, Location loc, StarlarkContext context)
throws EvalException {
Label toolchainTypeLabel = transformKey(key, loc);
Optional<Label> matching =
toolchains().keySet().stream()
.map(ToolchainTypeInfo::typeLabel)
.filter(label -> label.equals(toolchainTypeLabel))
.findAny();
return matching.isPresent();
}
}