|  | // Copyright 2014 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.actions; | 
|  |  | 
|  | import com.google.common.annotations.VisibleForTesting; | 
|  | import com.google.common.base.Function; | 
|  | import com.google.common.base.Functions; | 
|  | import com.google.common.collect.Collections2; | 
|  | import com.google.common.collect.ImmutableSet; | 
|  | import com.google.common.collect.Iterables; | 
|  | import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; | 
|  | import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; | 
|  | import com.google.devtools.build.lib.util.Preconditions; | 
|  | import com.google.devtools.build.lib.vfs.PathFragment; | 
|  |  | 
|  | import java.util.ArrayList; | 
|  | import java.util.Collection; | 
|  | import java.util.List; | 
|  | import java.util.Set; | 
|  |  | 
|  | /** | 
|  | * Helper utility to create ActionInput instances. | 
|  | */ | 
|  | public final class ActionInputHelper { | 
|  | private ActionInputHelper() { | 
|  | } | 
|  |  | 
|  | @VisibleForTesting | 
|  | public static ArtifactExpander actionGraphArtifactExpander( | 
|  | final ActionGraph actionGraph) { | 
|  | return new ArtifactExpander() { | 
|  | @Override | 
|  | public void expand(Artifact mm, Collection<? super Artifact> output) { | 
|  | // Skyframe is stricter in that it checks that "mm" is a input of the action, because | 
|  | // it cannot expand arbitrary middlemen without access to a global action graph. | 
|  | // We could check this constraint here too, but it seems unnecessary. This code is | 
|  | // going away anyway. | 
|  | Preconditions.checkArgument(mm.isMiddlemanArtifact(), | 
|  | "%s is not a middleman artifact", mm); | 
|  | ActionAnalysisMetadata middlemanAction = actionGraph.getGeneratingAction(mm); | 
|  | Preconditions.checkState(middlemanAction != null, mm); | 
|  | // TODO(bazel-team): Consider expanding recursively or throwing an exception here. | 
|  | // Most likely, this code will cause silent errors if we ever have a middleman that | 
|  | // contains a middleman. | 
|  | if (middlemanAction.getActionType() == Action.MiddlemanType.AGGREGATING_MIDDLEMAN) { | 
|  | Artifact.addNonMiddlemanArtifacts(middlemanAction.getInputs(), output, | 
|  | Functions.<Artifact>identity()); | 
|  | } | 
|  |  | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Most ActionInputs are created and never used again. On the off chance that one is, however, we | 
|  | * implement equality via path comparison. Since file caches are keyed by ActionInput, equality | 
|  | * checking does come up. | 
|  | */ | 
|  | private static class BasicActionInput implements ActionInput { | 
|  | private final String path; | 
|  | public BasicActionInput(String path) { | 
|  | this.path = Preconditions.checkNotNull(path); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String getExecPathString() { | 
|  | return path; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | return path.hashCode(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean equals(Object other) { | 
|  | if (this == other) { | 
|  | return true; | 
|  | } | 
|  | if (other == null) { | 
|  | return false; | 
|  | } | 
|  | if (!this.getClass().equals(other.getClass())) { | 
|  | return false; | 
|  | } | 
|  | return this.path.equals(((BasicActionInput) other).path); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | return "BasicActionInput: " + path; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates an ActionInput with just the given relative path and no digest. | 
|  | * | 
|  | * @param path the relative path of the input. | 
|  | * @return a ActionInput. | 
|  | */ | 
|  | public static ActionInput fromPath(String path) { | 
|  | return new BasicActionInput(path); | 
|  | } | 
|  |  | 
|  | private static final Function<String, ActionInput> FROM_PATH = | 
|  | new Function<String, ActionInput>() { | 
|  | @Override | 
|  | public ActionInput apply(String path) { | 
|  | return fromPath(path); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Creates a sequence of {@link ActionInput}s from a sequence of string paths. | 
|  | */ | 
|  | public static Collection<ActionInput> fromPaths(Collection<String> paths) { | 
|  | return Collections2.transform(paths, FROM_PATH); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Instantiates a concrete TreeFileArtifact with the given parent Artifact and path | 
|  | * relative to that Artifact. | 
|  | */ | 
|  | public static TreeFileArtifact treeFileArtifact( | 
|  | Artifact parent, PathFragment relativePath) { | 
|  | Preconditions.checkState(parent.isTreeArtifact(), | 
|  | "Given parent %s must be a TreeArtifact", parent); | 
|  | return new TreeFileArtifact(parent, relativePath); | 
|  | } | 
|  |  | 
|  | public static TreeFileArtifact treeFileArtifact( | 
|  | Artifact parent, PathFragment relativePath, ArtifactOwner artifactOwner) { | 
|  | Preconditions.checkState(parent.isTreeArtifact(), | 
|  | "Given parent %s must be a TreeArtifact", parent); | 
|  | return new TreeFileArtifact( | 
|  | parent, | 
|  | relativePath, | 
|  | artifactOwner); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Instantiates a concrete TreeFileArtifact with the given parent Artifact and path | 
|  | * relative to that Artifact. | 
|  | */ | 
|  | public static TreeFileArtifact treeFileArtifact(Artifact parent, String relativePath) { | 
|  | return treeFileArtifact(parent, new PathFragment(relativePath)); | 
|  | } | 
|  |  | 
|  | /** Returns an Iterable of TreeFileArtifacts with the given parent and parent relative paths. */ | 
|  | public static Iterable<TreeFileArtifact> asTreeFileArtifacts( | 
|  | final Artifact parent, Iterable<? extends PathFragment> parentRelativePaths) { | 
|  | Preconditions.checkState(parent.isTreeArtifact(), | 
|  | "Given parent %s must be a TreeArtifact", parent); | 
|  | return Iterables.transform(parentRelativePaths, | 
|  | new Function<PathFragment, TreeFileArtifact>() { | 
|  | @Override | 
|  | public TreeFileArtifact apply(PathFragment pathFragment) { | 
|  | return treeFileArtifact(parent, pathFragment); | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | /** Returns a Set of TreeFileArtifacts with the given parent and parent-relative paths. */ | 
|  | public static Set<TreeFileArtifact> asTreeFileArtifacts( | 
|  | final Artifact parent, Set<? extends PathFragment> parentRelativePaths) { | 
|  | Preconditions.checkState(parent.isTreeArtifact(), | 
|  | "Given parent %s must be a TreeArtifact", parent); | 
|  |  | 
|  | ImmutableSet.Builder<TreeFileArtifact> builder = ImmutableSet.builder(); | 
|  | for (PathFragment path : parentRelativePaths) { | 
|  | builder.add(treeFileArtifact(parent, path)); | 
|  | } | 
|  |  | 
|  | return builder.build(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Expands middleman artifacts in a sequence of {@link ActionInput}s. | 
|  | * | 
|  | * <p>Non-middleman artifacts are returned untouched. | 
|  | */ | 
|  | public static List<ActionInput> expandArtifacts(Iterable<? extends ActionInput> inputs, | 
|  | ArtifactExpander artifactExpander) { | 
|  |  | 
|  | List<ActionInput> result = new ArrayList<>(); | 
|  | List<Artifact> containedArtifacts = new ArrayList<>(); | 
|  | for (ActionInput input : inputs) { | 
|  | if (!(input instanceof Artifact)) { | 
|  | result.add(input); | 
|  | continue; | 
|  | } | 
|  | containedArtifacts.add((Artifact) input); | 
|  | } | 
|  | Artifact.addExpandedArtifacts(containedArtifacts, result, artifactExpander); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /** Formatter for execPath String output. Public because {@link Artifact} uses it directly. */ | 
|  | public static final Function<ActionInput, String> EXEC_PATH_STRING_FORMATTER = | 
|  | new Function<ActionInput, String>() { | 
|  | @Override | 
|  | public String apply(ActionInput input) { | 
|  | return input.getExecPathString(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | public static Iterable<String> toExecPaths(Iterable<? extends ActionInput> artifacts) { | 
|  | return Iterables.transform(artifacts, EXEC_PATH_STRING_FORMATTER); | 
|  | } | 
|  | } |