Skip to content

Commit

Permalink
Update starlark apis that consume toolchain types to use
Browse files Browse the repository at this point in the history
ToolchainTypeRequirement.

Part of Optional Toolchains (bazelbuild#14726).
  • Loading branch information
katre committed Mar 3, 2022
1 parent d70d329 commit accd880
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

package com.google.devtools.build.lib.analysis.starlark;

import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.RUN_UNDER;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.TEST_RUNNER_EXEC_GROUP;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.TIMEOUT_DEFAULT;
Expand Down Expand Up @@ -102,8 +101,10 @@
import com.google.devtools.build.lib.util.FileTypeSet;
import com.google.devtools.build.lib.util.Pair;
import com.google.errorprone.annotations.FormatMethod;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;
import net.starlark.java.eval.Debug;
import net.starlark.java.eval.Dict;
Expand Down Expand Up @@ -401,7 +402,7 @@ public StarlarkCallable rule(
: Label.createUnvalidated(PackageIdentifier.EMPTY_PACKAGE_ID, "dummy_label"),
bzlModule != null ? bzlModule.bzlTransitiveDigest() : new byte[0]);

builder.addRequiredToolchains(parseToolchains(toolchains, thread));
builder.addToolchainTypes(parseToolchainTypes(toolchains, thread));
if (useToolchainTransition) {
builder.useToolchainTransition(ToolchainTransitionMode.ENABLED);
}
Expand Down Expand Up @@ -559,41 +560,21 @@ private static void checkAttributeName(String name) throws EvalException {
return attributes.build();
}

/**
* Parses a sequence of label strings with a repo mapping.
*
* @param inputs sequence of input strings
* @param thread repository mapping
* @param adjective describes the purpose of the label; used for errors
* @throws EvalException if the label can't be parsed
*/
private static ImmutableList<Label> parseLabels(
Iterable<String> inputs, StarlarkThread thread, String adjective) throws EvalException {
private static ImmutableList<Label> parseExecCompatibleWith(
Sequence<?> inputs, StarlarkThread thread) throws EvalException {
ImmutableList.Builder<Label> parsedLabels = new ImmutableList.Builder<>();
LabelConverter converter = LabelConverter.forThread(thread);
for (String input : inputs) {
for (String input : Sequence.cast(inputs, String.class, "exec_compatible_with")) {
try {
Label label = converter.convert(input);
parsedLabels.add(label);
} catch (LabelSyntaxException e) {
throw Starlark.errorf(
"Unable to parse %s label '%s': %s", adjective, input, e.getMessage());
throw Starlark.errorf("Unable to parse constraint label '%s': %s", input, e.getMessage());
}
}
return parsedLabels.build();
}

private static ImmutableList<Label> parseToolchains(Sequence<?> inputs, StarlarkThread thread)
throws EvalException {
return parseLabels(Sequence.cast(inputs, String.class, "toolchains"), thread, "toolchain");
}

private static ImmutableList<Label> parseExecCompatibleWith(
Sequence<?> inputs, StarlarkThread thread) throws EvalException {
return parseLabels(
Sequence.cast(inputs, String.class, "exec_compatible_with"), thread, "constraint");
}

@Override
public StarlarkAspect aspect(
StarlarkFunction implementation,
Expand Down Expand Up @@ -698,7 +679,6 @@ public StarlarkAspect aspect(
"An aspect cannot simultaneously have required providers and apply to generating rules.");
}

ImmutableList<Label> toolchainTypes = parseToolchains(toolchains, thread);
return new StarlarkDefinedAspect(
implementation,
attrAspects.build(),
Expand All @@ -712,9 +692,7 @@ public StarlarkAspect aspect(
ImmutableSet.copyOf(Sequence.cast(fragments, String.class, "fragments")),
HostTransition.INSTANCE,
ImmutableSet.copyOf(Sequence.cast(hostFragments, String.class, "host_fragments")),
toolchainTypes.stream()
.map(tt -> ToolchainTypeRequirement.create(tt))
.collect(toImmutableSet()),
parseToolchainTypes(toolchains, thread),
useToolchainTransition,
applyToGeneratingRules);
}
Expand Down Expand Up @@ -1049,13 +1027,62 @@ public ExecGroup execGroup(
return ExecGroup.copyFromDefault();
}

ImmutableSet<Label> toolchainTypes = ImmutableSet.copyOf(parseToolchains(toolchains, thread));
ImmutableSet<ToolchainTypeRequirement> toolchainTypes = parseToolchainTypes(toolchains, thread);
ImmutableSet<Label> constraints =
ImmutableSet.copyOf(parseExecCompatibleWith(execCompatibleWith, thread));
return ExecGroup.builder()
.requiredToolchains(toolchainTypes)
.toolchainTypes(toolchainTypes)
.execCompatibleWith(constraints)
.copyFrom(null)
.build();
}

private static ImmutableSet<ToolchainTypeRequirement> parseToolchainTypes(
Sequence<?> rawToolchains, StarlarkThread thread) throws EvalException {
ImmutableSet.Builder<ToolchainTypeRequirement> toolchainTypes = new ImmutableSet.Builder<>();
Set<Label> toolchainTypesSeen = new HashSet<>();
LabelConverter converter = LabelConverter.forThread(thread);

for (Object rawToolchain : rawToolchains) {
ToolchainTypeRequirement toolchainType = parseToolchainType(converter, rawToolchain);
if (toolchainTypesSeen.contains(toolchainType.toolchainType())) {
// throw an error for duplicates.
throw Starlark.errorf("Duplicate toolchain type %s", toolchainType.toolchainType());
}
toolchainTypes.add(toolchainType);
toolchainTypesSeen.add(toolchainType.toolchainType());
}

return toolchainTypes.build();
}

private static ToolchainTypeRequirement parseToolchainType(
LabelConverter converter, Object rawToolchain) throws EvalException {
// Handle actual ToolchainTypeRequirement objects.
if (rawToolchain instanceof ToolchainTypeRequirement) {
return (ToolchainTypeRequirement) rawToolchain;
}

// Handle Label-like objects.
Label toolchainLabel = null;
if (rawToolchain instanceof Label) {
toolchainLabel = (Label) rawToolchain;
} else if (rawToolchain instanceof String) {
try {
toolchainLabel = converter.convert((String) rawToolchain);
} catch (LabelSyntaxException e) {
throw Starlark.errorf(
"Unable to parse toolchain_type label '%s': %s", rawToolchain, e.getMessage());
}
}

if (toolchainLabel != null) {
return ToolchainTypeRequirement.builder(toolchainLabel).mandatory(true).build();
}

// It's not a valid type.
throw Starlark.errorf(
"'toolchains' takes a toolchain_type, Label, or String, but instead got a %s",
rawToolchain.getClass().getSimpleName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,6 @@ public ExecGroup inheritFrom(ExecGroup other) {
@AutoValue.Builder
public interface Builder {

/** Sets the required toolchain types. */
// TODO(katre): Remove this once all callers use toolchainTypes.
default Builder requiredToolchains(ImmutableSet<Label> toolchainTypes) {
ImmutableSet<ToolchainTypeRequirement> toolchainTypeRequirements =
toolchainTypes.stream()
.map(label -> ToolchainTypeRequirement.create(label))
.collect(toImmutableSet());
return this.toolchainTypes(toolchainTypeRequirements);
}

/** Sets the toolchain type requirements. */
default Builder toolchainTypes(ImmutableSet<ToolchainTypeRequirement> toolchainTypes) {
toolchainTypes.forEach(this::addToolchainType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,13 +333,14 @@ Object provider(String doc, Object fields, Object init, StarlarkThread thread)
+ "Starlark rules. This flag may be removed in the future."),
@Param(
name = TOOLCHAINS_PARAM,
allowedTypes = {@ParamType(type = Sequence.class, generic1 = String.class)},
allowedTypes = {@ParamType(type = Sequence.class, generic1 = Object.class)},
named = true,
defaultValue = "[]",
doc =
"If set, the set of toolchains this rule requires. Toolchains will be "
+ "found by checking the current platform, and provided to the rule "
+ "implementation via <code>ctx.toolchain</code>."),
"If set, the set of toolchains this rule requires. The list can contain String,"
+ " Label, or StarlarkToolchainTypeApi objects, in any combination. Toolchains"
+ " will be found by checking the current platform, and provided to the rule"
+ " implementation via <code>ctx.toolchain</code>."),
@Param(
name = "incompatible_use_toolchain_transition",
defaultValue = "False",
Expand Down Expand Up @@ -608,13 +609,14 @@ StarlarkCallable rule(
+ "in host configuration."),
@Param(
name = TOOLCHAINS_PARAM,
allowedTypes = {@ParamType(type = Sequence.class, generic1 = String.class)},
allowedTypes = {@ParamType(type = Sequence.class, generic1 = Object.class)},
named = true,
defaultValue = "[]",
doc =
"If set, the set of toolchains this rule requires. Toolchains will be "
+ "found by checking the current platform, and provided to the rule "
+ "implementation via <code>ctx.toolchain</code>."),
"If set, the set of toolchains this rule requires. The list can contain String,"
+ " Label, or StarlarkToolchainTypeApi objects, in any combination. Toolchains"
+ " will be found by checking the current platform, and provided to the rule"
+ " implementation via <code>ctx.toolchain</code>."),
@Param(
name = "incompatible_use_toolchain_transition",
defaultValue = "False",
Expand Down Expand Up @@ -688,11 +690,13 @@ StarlarkAspectApi aspect(
parameters = {
@Param(
name = TOOLCHAINS_PARAM,
allowedTypes = {@ParamType(type = Sequence.class, generic1 = String.class)},
allowedTypes = {@ParamType(type = Sequence.class, generic1 = Object.class)},
named = true,
positional = false,
defaultValue = "[]",
doc = "The set of toolchains this execution group requires."),
doc =
"The set of toolchains this execution group requires. The list can contain String,"
+ " Label, or StarlarkToolchainTypeApi objects, in any combination."),
@Param(
name = EXEC_COMPATIBLE_WITH_PARAM,
allowedTypes = {@ParamType(type = Sequence.class, generic1 = String.class)},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ java_library(
"ExecGroupSubject.java",
"ResolvedToolchainContextSubject.java",
"RuleClassSubject.java",
"StarlarkDefinedAspectSubject.java",
"ToolchainCollectionSubject.java",
"ToolchainContextSubject.java",
"ToolchainInfoSubject.java",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2022 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.testing;

import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.truth.Truth.assertAbout;

import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.MapSubject;
import com.google.common.truth.Subject;
import com.google.devtools.build.lib.analysis.config.ToolchainTypeRequirement;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.StarlarkDefinedAspect;
import java.util.Map;

/** A Truth {@link Subject} for {@link StarlarkDefinedAspect}. */
public class StarlarkDefinedAspectSubject extends Subject {
// Static data.

/** Entry point for test assertions related to {@link StarlarkDefinedAspect}. */
public static StarlarkDefinedAspectSubject assertThat(
StarlarkDefinedAspect StarlarkDefinedAspect) {
return assertAbout(StarlarkDefinedAspectSubject::new).that(StarlarkDefinedAspect);
}

/** Static method for getting the subject factory (for use with assertAbout()). */
public static Subject.Factory<StarlarkDefinedAspectSubject, StarlarkDefinedAspect>
StarlarkDefinedAspects() {
return StarlarkDefinedAspectSubject::new;
}

// Instance fields.

private final StarlarkDefinedAspect actual;
private final Map<Label, ToolchainTypeRequirement> toolchainTypesMap;

protected StarlarkDefinedAspectSubject(
FailureMetadata failureMetadata, StarlarkDefinedAspect subject) {
super(failureMetadata, subject);
this.actual = subject;
this.toolchainTypesMap = makeToolchainTypesMap(subject);
}

private static ImmutableMap<Label, ToolchainTypeRequirement> makeToolchainTypesMap(
StarlarkDefinedAspect subject) {
return subject.getToolchainTypes().stream()
.collect(toImmutableMap(ToolchainTypeRequirement::toolchainType, Functions.identity()));
}

public MapSubject toolchainTypes() {
return check("getToolchainTypes()").that(toolchainTypesMap);
}

public ToolchainTypeRequirementSubject toolchainType(String toolchainTypeLabel) {
return toolchainType(Label.parseAbsoluteUnchecked(toolchainTypeLabel));
}

public ToolchainTypeRequirementSubject toolchainType(Label toolchainType) {
return check("toolchainType(%s)", toolchainType)
.about(ToolchainTypeRequirementSubject.toolchainTypeRequirements())
.that(toolchainTypesMap.get(toolchainType));
}

public void hasToolchainType(String toolchainTypeLabel) {
toolchainType(toolchainTypeLabel).isNotNull();
}

public void hasToolchainType(Label toolchainType) {
toolchainType(toolchainType).isNotNull();
}

// TODO(blaze-team): Add more useful methods.
}
Loading

0 comments on commit accd880

Please sign in to comment.