| // Copyright 2024 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.packages; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.devtools.build.lib.events.EventHandler; |
| import net.starlark.java.eval.EvalException; |
| |
| /** |
| * The default value of attributes with materializers. |
| * |
| * <p>It's just a reference to the function that does the materializing. |
| */ |
| public class MaterializingDefault<ValueT, AnalysisContextT> { |
| private final Type<ValueT> type; |
| private final Resolver<ValueT, AnalysisContextT> resolver; |
| private final Class<? extends AnalysisContextT> analysisContextClass; |
| |
| public MaterializingDefault( |
| Type<ValueT> type, |
| Class<? extends AnalysisContextT> analysisContextClass, |
| Resolver<ValueT, AnalysisContextT> resolver) { |
| Preconditions.checkArgument(type == BuildType.LABEL || type == BuildType.LABEL_LIST); |
| this.type = type; |
| this.resolver = resolver; |
| this.analysisContextClass = analysisContextClass; |
| } |
| |
| public ValueT getDefault() { |
| // Materializers can only return dormant dependencies, which are already present in the |
| // transitive closure. So we can safely return "nothing" for "bazel query": the invariant that |
| // everything needed to build a target is returned by "bazel query deps()" holds because |
| // whatever a materializer returns is reachable through dormant dependency edges, which are |
| // traversed by "bazel query". |
| return type.getDefaultValue(); |
| } |
| |
| /** |
| * The implementation of the actual resolution of the late-bound default. |
| * |
| * <p>This is a separate interface because MaterializingDefault must be known to the loading phase |
| * but its implementation necessarily deals with analysis-phase data structures. |
| */ |
| public interface Resolver<ValueT, PrerequisiteT> { |
| |
| /** |
| * Resolves an attribute with a materializer. |
| * |
| * <p>param rule the rule whose attribute is to be resolved. |
| * |
| * @param attributes the attributes of the rule, after resolving {@code select()} and the like |
| * @param prerequisiteMap a map from attribute name to the prerequisites on that attribute. Only |
| * those attributes are present that represent dependencies and which are available for |
| * dependency resolution. The value of the map is in fact {@code List<? extends |
| * TransitiveInfoCollection}, but we can't say that because this class needs to be available |
| * in the loading phase. |
| * @param eventHandler messages from Starlark should be reported here |
| * @return the value of the resolved attribute. |
| */ |
| ValueT resolve( |
| Rule rule, |
| AttributeMap attributes, |
| PrerequisiteT prerequisiteMap, |
| EventHandler eventHandler) |
| throws InterruptedException, EvalException; |
| } |
| |
| public ValueT resolve( |
| Rule rule, |
| AttributeMap attributes, |
| Object analysisContext, |
| EventHandler eventHandler) |
| throws InterruptedException, EvalException { |
| return resolver.resolve( |
| rule, attributes, analysisContextClass.cast(analysisContext), eventHandler); |
| } |
| } |