// Copyright 2016 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.skyframe; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.actions.ActionKeyContext; import com.google.devtools.build.lib.actions.ActionLookupValue; import com.google.devtools.build.lib.actions.ActionTemplate; import com.google.devtools.build.lib.actions.ActionTemplate.ActionTemplateExpansionException; import com.google.devtools.build.lib.actions.Actions; import com.google.devtools.build.lib.actions.Actions.GeneratingActions; import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; import com.google.devtools.build.lib.actions.ArtifactPrefixConflictException; import com.google.devtools.build.lib.actions.ArtifactSkyKey; import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.skyframe.ActionTemplateExpansionValue.ActionTemplateExpansionKey; import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyFunctionException; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import java.util.Map; import javax.annotation.Nullable; /** * The SkyFunction for {@link ActionTemplateExpansionValue}. * *

Given an action template, this function resolves its input TreeArtifact, then expands the * action template into a list of actions using the expanded {@link TreeFileArtifact}s under the * input TreeArtifact. */ public class ActionTemplateExpansionFunction implements SkyFunction { private final ActionKeyContext actionKeyContext; ActionTemplateExpansionFunction(ActionKeyContext actionKeyContext) { this.actionKeyContext = actionKeyContext; } @Override public SkyValue compute(SkyKey skyKey, Environment env) throws ActionTemplateExpansionFunctionException, InterruptedException { ActionTemplateExpansionKey key = (ActionTemplateExpansionKey) skyKey.argument(); ActionLookupValue value = (ActionLookupValue) env.getValue(key.getActionLookupKey()); if (value == null) { // Shouldn't actually happen in practice, but tolerate. return null; } ActionTemplate actionTemplate = value.getActionTemplate(key.getActionIndex()); // Requests the TreeArtifactValue object for the input TreeArtifact. SkyKey artifactValueKey = ArtifactSkyKey.key(actionTemplate.getInputTreeArtifact(), true); TreeArtifactValue treeArtifactValue = (TreeArtifactValue) env.getValue(artifactValueKey); // Input TreeArtifact is not ready yet. if (env.valuesMissing()) { return null; } Iterable inputTreeFileArtifacts = treeArtifactValue.getChildren(); GeneratingActions generatingActions; try { // Expand the action template using the list of expanded input TreeFileArtifacts. // TODO(rduan): Add a check to verify the inputs of expanded actions are subsets of inputs // of the ActionTemplate. generatingActions = checkActionAndArtifactConflicts( actionTemplate.generateActionForInputArtifacts(inputTreeFileArtifacts, key)); } catch (ActionConflictException e) { e.reportTo(env.getListener()); throw new ActionTemplateExpansionFunctionException(e); } catch (ArtifactPrefixConflictException e) { env.getListener().handle(Event.error(e.getMessage())); throw new ActionTemplateExpansionFunctionException(e); } catch (ActionTemplateExpansionException e) { env.getListener().handle(Event.error(e.getMessage())); throw new ActionTemplateExpansionFunctionException(e); } return new ActionTemplateExpansionValue(generatingActions); } /** Exception thrown by {@link ActionTemplateExpansionFunction}. */ public static final class ActionTemplateExpansionFunctionException extends SkyFunctionException { ActionTemplateExpansionFunctionException(ActionConflictException e) { super(e, Transience.PERSISTENT); } ActionTemplateExpansionFunctionException(ArtifactPrefixConflictException e) { super(e, Transience.PERSISTENT); } ActionTemplateExpansionFunctionException(ActionTemplateExpansionException e) { super(e, Transience.PERSISTENT); } } private GeneratingActions checkActionAndArtifactConflicts(Iterable actions) throws ActionConflictException, ArtifactPrefixConflictException { GeneratingActions generatingActions = Actions.findAndThrowActionConflict(actionKeyContext, ImmutableList.copyOf(actions)); Map artifactPrefixConflictMap = Actions.findArtifactPrefixConflicts( ActionLookupValue.getMapForConsistencyCheck( generatingActions.getGeneratingActionIndex(), generatingActions.getActions())); if (!artifactPrefixConflictMap.isEmpty()) { throw artifactPrefixConflictMap.values().iterator().next(); } return generatingActions; } @Nullable @Override public String extractTag(SkyKey skyKey) { return null; } }