| // Copyright 2023 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.actions; |
| |
| import com.google.common.collect.ImmutableSet; |
| import com.google.devtools.build.lib.actions.AbstractAction; |
| import com.google.devtools.build.lib.actions.Action; |
| import com.google.devtools.build.lib.actions.ActionKeyContext; |
| import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; |
| import com.google.devtools.build.lib.actions.CommandLineLimits; |
| import com.google.devtools.build.lib.actions.ExecutionRequirements; |
| import com.google.devtools.build.lib.actions.PathMapper; |
| import com.google.devtools.build.lib.actions.Spawn; |
| import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; |
| import com.google.devtools.build.lib.analysis.config.CoreOptions; |
| import com.google.devtools.build.lib.analysis.config.CoreOptions.OutputPathsMode; |
| import com.google.devtools.build.lib.util.Fingerprint; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import java.util.Map; |
| import javax.annotation.Nullable; |
| |
| /** |
| * Utility methods that are the canonical way for actions to support path mapping (see {@link |
| * PathMapper}). |
| */ |
| public final class PathMappers { |
| // TODO: Remove actions from this list by adding ExecutionRequirements.SUPPORTS_PATH_MAPPING to |
| // their execution info instead. |
| private static final ImmutableSet<String> SUPPORTED_MNEMONICS = |
| ImmutableSet.of( |
| "AndroidLint", |
| "CompileAndroidResources", |
| "DeJetify", |
| "DejetifySrcs", |
| "Desugar", |
| "DexBuilder", |
| "Jetify", |
| "JetifySrcs", |
| "LinkAndroidResources", |
| "MergeAndroidAssets", |
| "MergeManifests", |
| "ParseAndroidResources", |
| "StarlarkAARGenerator", |
| "StarlarkMergeCompiledAndroidResources", |
| "StarlarkRClassGenerator", |
| "Mock action"); |
| |
| /** |
| * Actions that support path mapping should call this method from {@link |
| * Action#getKey(ActionKeyContext, ArtifactExpander)}. |
| * |
| * <p>Compared to {@link #create(AbstractAction, OutputPathsMode)}, this method does not flatten |
| * nested sets and thus can't result in memory regressions. |
| * |
| * @param mnemonic the mnemonic of the action |
| * @param executionInfo the execution info of the action |
| * @param outputPathsMode the value of {@link CoreOptions#outputPathsMode} |
| * @param fingerprint the fingerprint to add to |
| */ |
| public static void addToFingerprint( |
| String mnemonic, |
| Map<String, String> executionInfo, |
| OutputPathsMode outputPathsMode, |
| Fingerprint fingerprint) { |
| // Creating a new PathMapper instance can be expensive, but isn't needed here: Whether and |
| // how path mapping applies to the action only depends on the output paths mode and the action |
| // inputs, which are already part of the action key. |
| OutputPathsMode effectiveOutputPathsMode = |
| getEffectiveOutputPathsMode(outputPathsMode, mnemonic, executionInfo); |
| if (effectiveOutputPathsMode == OutputPathsMode.STRIP) { |
| fingerprint.addString(StrippingPathMapper.GUID); |
| } |
| } |
| |
| /** |
| * Actions that support path mapping should call this method when creating their {@link Spawn}. |
| * |
| * <p>The returned {@link PathMapper} has to be passed to {@link |
| * com.google.devtools.build.lib.actions.CommandLine#arguments(ArtifactExpander, PathMapper)}, |
| * {@link com.google.devtools.build.lib.actions.CommandLines#expand(ArtifactExpander, |
| * PathFragment, PathMapper, CommandLineLimits)} )} or any other variants of these functions. The |
| * same instance should also be passed to the {@link Spawn} constructor so that the executor can |
| * obtain it via {@link Spawn#getPathMapper()}. |
| * |
| * <p>Note: This method flattens nested sets and should thus not be called from methods that are |
| * executed in the analysis phase. |
| * |
| * <p>Actions calling this method should also call {@link #addToFingerprint(String, Map, |
| * OutputPathsMode, Fingerprint)} from {@link Action#getKey(ActionKeyContext, ArtifactExpander)} |
| * to ensure correct incremental builds. |
| * |
| * @param action the {@link AbstractAction} for which a {@link Spawn} is to be created |
| * @param outputPathsMode the value of {@link CoreOptions#outputPathsMode} |
| * @return a {@link PathMapper} that maps paths of the action's inputs and outputs. May be {@link |
| * PathMapper#NOOP} if path mapping is not applicable to the action. |
| */ |
| public static PathMapper create(AbstractAction action, OutputPathsMode outputPathsMode) { |
| if (getEffectiveOutputPathsMode( |
| outputPathsMode, action.getMnemonic(), action.getExecutionInfo()) |
| != OutputPathsMode.STRIP) { |
| return PathMapper.NOOP; |
| } |
| return StrippingPathMapper.tryCreate(action).orElse(PathMapper.NOOP); |
| } |
| |
| /** |
| * Helper method to simplify calling {@link #create(SpawnAction, OutputPathsMode)} for actions |
| * that store the configuration directly. |
| * |
| * @param configuration the configuration |
| * @return the value of |
| */ |
| public static OutputPathsMode getOutputPathsMode( |
| @Nullable BuildConfigurationValue configuration) { |
| if (configuration == null) { |
| return OutputPathsMode.OFF; |
| } |
| return configuration.getOptions().get(CoreOptions.class).outputPathsMode; |
| } |
| |
| private static OutputPathsMode getEffectiveOutputPathsMode( |
| OutputPathsMode outputPathsMode, String mnemonic, Map<String, String> executionInfo) { |
| if (outputPathsMode == OutputPathsMode.STRIP |
| && (SUPPORTED_MNEMONICS.contains(mnemonic) |
| || executionInfo.containsKey(ExecutionRequirements.SUPPORTS_PATH_MAPPING))) { |
| return OutputPathsMode.STRIP; |
| } |
| return OutputPathsMode.OFF; |
| } |
| |
| private PathMappers() {} |
| } |