blob: 9a8482cce09bd67ddf90dcf9e28d70a0bd50d669 [file] [log] [blame]
Googler68ee1e42024-07-19 14:38:45 -07001// Copyright 2024 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.analysis;
16
17import com.google.auto.value.AutoValue;
18import com.google.common.base.Preconditions;
Googler419fdac2024-10-28 10:34:49 -070019import com.google.common.collect.ImmutableList;
Googler68ee1e42024-07-19 14:38:45 -070020import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.ImmutableMultimap;
22import com.google.common.collect.Iterables;
23import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget;
Googler60203aa2024-08-09 05:06:06 -070024import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.MergingException;
Googler68ee1e42024-07-19 14:38:45 -070025import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
26import com.google.devtools.build.lib.cmdline.Label;
27import com.google.devtools.build.lib.packages.Provider;
28import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
29import com.google.devtools.build.lib.skyframe.toolchains.UnloadedToolchainContext;
30import javax.annotation.Nullable;
31import net.starlark.java.eval.EvalException;
32import net.starlark.java.eval.Printer;
33import net.starlark.java.eval.Starlark;
34import net.starlark.java.eval.StarlarkIndexable;
35import net.starlark.java.eval.StarlarkSemantics;
Googler419fdac2024-10-28 10:34:49 -070036import net.starlark.java.eval.Structure;
Googler68ee1e42024-07-19 14:38:45 -070037
38/**
39 * A toolchain context for the aspect's base target toolchains. It is used to represent the result
40 * of applying the aspects propagation to the base target toolchains.
41 */
42@AutoValue
43public abstract class AspectBaseTargetResolvedToolchainContext
44 implements ResolvedToolchainsDataInterface<
45 AspectBaseTargetResolvedToolchainContext.ToolchainAspectsProviders> {
46
47 public abstract ImmutableMap<ToolchainTypeInfo, ToolchainAspectsProviders> getToolchains();
48
49 public static AspectBaseTargetResolvedToolchainContext load(
50 UnloadedToolchainContext unloadedToolchainContext,
51 String targetDescription,
52 ImmutableMultimap<ToolchainTypeInfo, ConfiguredTargetAndData> toolchainTargets)
Googler60203aa2024-08-09 05:06:06 -070053 throws MergingException {
Googler68ee1e42024-07-19 14:38:45 -070054
55 ImmutableMap.Builder<ToolchainTypeInfo, ToolchainAspectsProviders> toolchainsBuilder =
56 new ImmutableMap.Builder<>();
57
58 for (var toolchainType : unloadedToolchainContext.toolchainTypeToResolved().keySet()) {
59 Preconditions.checkArgument(toolchainTargets.get(toolchainType).size() == 1);
60
61 var toolchainTarget =
62 Iterables.getOnlyElement(toolchainTargets.get(toolchainType)).getConfiguredTarget();
63
64 if (toolchainTarget instanceof MergedConfiguredTarget mergedConfiguredTarget) {
65 // Only add the aspects providers from the toolchains that the aspects applied to.
66 toolchainsBuilder.put(
67 toolchainType,
68 new ToolchainAspectsProviders(
69 mergedConfiguredTarget.getAspectsProviders(), mergedConfiguredTarget.getLabel()));
70 } else {
71 // Add empty providers for the toolchains that the aspects did not apply to.
72 toolchainsBuilder.put(
73 toolchainType,
74 new ToolchainAspectsProviders(
75 new TransitiveInfoProviderMapBuilder().build(), toolchainTarget.getLabel()));
76 }
77 }
78 ImmutableMap<ToolchainTypeInfo, ToolchainAspectsProviders> toolchains =
79 toolchainsBuilder.buildOrThrow();
80
81 return new AutoValue_AspectBaseTargetResolvedToolchainContext(
82 // ToolchainContext:
83 unloadedToolchainContext.key(),
84 unloadedToolchainContext.executionPlatform(),
85 unloadedToolchainContext.targetPlatform(),
86 unloadedToolchainContext.toolchainTypes(),
87 unloadedToolchainContext.resolvedToolchainLabels(),
88 // ResolvedToolchainsDataInterface:
89 targetDescription,
90 unloadedToolchainContext.requestedLabelToToolchainType(),
91 // this:
92 toolchains);
93 }
94
95 @Override
96 @Nullable
97 public ToolchainAspectsProviders forToolchainType(Label toolchainTypeLabel) {
98 if (requestedToolchainTypeLabels().containsKey(toolchainTypeLabel)) {
99 return getToolchains().get(requestedToolchainTypeLabels().get(toolchainTypeLabel));
100 }
101
102 return null;
103 }
104
105 /**
106 * A Starlark-indexable wrapper used to represent the providers of the aspects applied on the base
107 * target toolchains.
108 */
109 public static class ToolchainAspectsProviders
Googler419fdac2024-10-28 10:34:49 -0700110 implements StarlarkIndexable, Structure, ResolvedToolchainData {
Googler68ee1e42024-07-19 14:38:45 -0700111
112 private final TransitiveInfoProviderMap aspectsProviders;
113 private final Label label;
114
115 private ToolchainAspectsProviders(TransitiveInfoProviderMap aspectsProviders, Label label) {
116 this.aspectsProviders = aspectsProviders;
117 this.label = label;
118 }
119
120 @Override
121 public final Object getIndex(StarlarkSemantics semantics, Object key) throws EvalException {
122 Provider constructor = selectExportedProvider(key, "index");
123 Object declaredProvider = aspectsProviders.get(constructor.getKey());
124 if (declaredProvider != null) {
125 return declaredProvider;
126 }
127 throw Starlark.errorf(
128 "%s doesn't contain declared provider '%s'",
129 Starlark.repr(this), constructor.getPrintableName());
130 }
131
132 @Override
133 public boolean containsKey(StarlarkSemantics semantics, Object key) throws EvalException {
134 return aspectsProviders.get(selectExportedProvider(key, "query").getKey()) != null;
135 }
136
137 /**
138 * Selects the provider identified by {@code key}, throwing a Starlark error if the key is not a
139 * provider or not exported.
140 */
141 private Provider selectExportedProvider(Object key, String operation) throws EvalException {
142 if (!(key instanceof Provider constructor)) {
143 throw Starlark.errorf(
144 "This type only supports %sing by object constructors, got %s instead",
145 operation, Starlark.type(key));
146 }
147 if (!constructor.isExported()) {
148 throw Starlark.errorf(
149 "%s only supports %sing by exported providers. Assign the provider a name "
150 + "in a top-level assignment statement.",
151 Starlark.repr(this), operation);
152 }
153 return constructor;
154 }
155
156 @Override
157 public void repr(Printer printer) {
158 printer.append("<ToolchainAspectsProviders for toolchain target: " + label + ">");
159 }
Googler419fdac2024-10-28 10:34:49 -0700160
161 @Nullable
162 @Override
163 public Object getValue(String name) {
164 if (name.equals(MergedConfiguredTarget.LABEL_FIELD)) {
165 return label;
166 }
167 return null;
168 }
169
170 @Override
171 public ImmutableList<String> getFieldNames() {
172 return ImmutableList.of(MergedConfiguredTarget.LABEL_FIELD);
173 }
174
175 @Nullable
176 @Override
177 public String getErrorMessageForUnknownField(String field) {
178 // Use the default error message.
179 return null;
180 }
Googler68ee1e42024-07-19 14:38:45 -0700181 }
182}