| // Copyright 2014 Google Inc. 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.base.Joiner; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.base.Predicate; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.Iterables; | |
| import com.google.devtools.build.lib.actions.Action.MiddlemanType; | |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; | |
| import com.google.devtools.build.lib.syntax.Label; | |
| import com.google.devtools.build.lib.syntax.SkylarkCallable; | |
| import com.google.devtools.build.lib.syntax.SkylarkModule; | |
| import com.google.devtools.build.lib.util.FileType; | |
| import com.google.devtools.build.lib.vfs.Path; | |
| import com.google.devtools.build.lib.vfs.PathFragment; | |
| import java.util.ArrayList; | |
| import java.util.Collection; | |
| import java.util.List; | |
| import javax.annotation.Nullable; | |
| /** | |
| * An Artifact represents a file used by the build system, whether it's a source | |
| * file or a derived (output) file. Not all Artifacts have a corresponding | |
| * FileTarget object in the <code>build.packages</code> API: for example, | |
| * low-level intermediaries internal to a given rule, such as a Java class files | |
| * or C++ object files. However all FileTargets have a corresponding Artifact. | |
| * | |
| * <p>In any given call to Builder#buildArtifacts(), no two Artifacts in the | |
| * action graph may refer to the same path. | |
| * | |
| * <p>Artifacts generally fall into two classifications, source and derived, but | |
| * there exist a few other cases that are fuzzy and difficult to classify. The | |
| * following cases exist: | |
| * <ul> | |
| * <li>Well-formed source Artifacts will have null generating Actions and a root | |
| * that is orthogonal to execRoot. (With the root coming from the package path.) | |
| * <li>Well-formed derived Artifacts will have non-null generating Actions, and | |
| * a root that is below execRoot. | |
| * <li>Symlinked include source Artifacts under the output/include tree will | |
| * appear to be derived artifacts with null generating Actions. | |
| * <li>Some derived Artifacts, mostly in the genfiles tree and mostly discovered | |
| * during include validation, will also have null generating Actions. | |
| * </ul> | |
| * | |
| * <p>This class is "theoretically" final; it should not be subclassed except by | |
| * {@link SpecialArtifact}. | |
| */ | |
| @Immutable | |
| @SkylarkModule(name = "File", | |
| doc = "This type represents a file used by the build system. It can be " | |
| + "either a source file or a derived file produced by a rule.") | |
| public class Artifact implements FileType.HasFilename, Comparable<Artifact>, ActionInput { | |
| /** An object that can expand middleman artifacts. */ | |
| public interface MiddlemanExpander { | |
| /** | |
| * Expands the middleman artifact "mm", and populates "output" with the result. | |
| * | |
| * <p>{@code mm.isMiddlemanArtifact()} must be true. Only aggregating middlemen are expanded. | |
| */ | |
| void expand(Artifact mm, Collection<? super Artifact> output); | |
| } | |
| public static final ImmutableList<Artifact> NO_ARTIFACTS = ImmutableList.of(); | |
| /** | |
| * A Predicate that evaluates to true if the Artifact is not a middleman artifact. | |
| */ | |
| public static final Predicate<Artifact> MIDDLEMAN_FILTER = new Predicate<Artifact>() { | |
| @Override | |
| public boolean apply(Artifact input) { | |
| return !input.isMiddlemanArtifact(); | |
| } | |
| }; | |
| private final Path path; | |
| private final Root root; | |
| private final PathFragment execPath; | |
| private final PathFragment rootRelativePath; | |
| // Non-final only for use when dealing with deserialized artifacts. | |
| private ArtifactOwner owner; | |
| /** | |
| * Constructs an artifact for the specified path, root and execPath. The root must be an ancestor | |
| * of path, and execPath must be a non-absolute tail of path. Outside of testing, this method | |
| * should only be called by ArtifactFactory. The ArtifactOwner may be null. | |
| * | |
| * <p>In a source Artifact, the path tail after the root will be identical to the execPath, but | |
| * the root will be orthogonal to execRoot. | |
| * <pre> | |
| * [path] == [/root/][execPath] | |
| * </pre> | |
| * | |
| * <p>In a derived Artifact, the execPath will overlap with part of the root, which in turn will | |
| * be below of the execRoot. | |
| * <pre> | |
| * [path] == [/root][pathTail] == [/execRoot][execPath] == [/execRoot][rootPrefix][pathTail] | |
| * <pre> | |
| */ | |
| @VisibleForTesting | |
| public Artifact(Path path, Root root, PathFragment execPath, ArtifactOwner owner) { | |
| if (root == null || !path.startsWith(root.getPath())) { | |
| throw new IllegalArgumentException(root + ": illegal root for " + path); | |
| } | |
| if (execPath == null || execPath.isAbsolute() || !path.asFragment().endsWith(execPath)) { | |
| throw new IllegalArgumentException(execPath + ": illegal execPath for " + path); | |
| } | |
| this.path = path; | |
| this.root = root; | |
| this.execPath = execPath; | |
| // These two lines establish the invariant that | |
| // execPath == rootRelativePath <=> execPath.equals(rootRelativePath) | |
| // This is important for isSourceArtifact. | |
| PathFragment rootRel = path.relativeTo(root.getPath()); | |
| if (!execPath.endsWith(rootRel)) { | |
| throw new IllegalArgumentException(execPath + ": illegal execPath doesn't end with " | |
| + rootRel + " at " + path + " with root " + root); | |
| } | |
| this.rootRelativePath = rootRel.equals(execPath) ? execPath : rootRel; | |
| this.owner = Preconditions.checkNotNull(owner, path); | |
| } | |
| /** | |
| * Constructs an artifact for the specified path, root and execPath. The root must be an ancestor | |
| * of path, and execPath must be a non-absolute tail of path. Should only be called for testing. | |
| * | |
| * <p>In a source Artifact, the path tail after the root will be identical to the execPath, but | |
| * the root will be orthogonal to execRoot. | |
| * <pre> | |
| * [path] == [/root/][execPath] | |
| * </pre> | |
| * | |
| * <p>In a derived Artifact, the execPath will overlap with part of the root, which in turn will | |
| * be below of the execRoot. | |
| * <pre> | |
| * [path] == [/root][pathTail] == [/execRoot][execPath] == [/execRoot][rootPrefix][pathTail] | |
| * <pre> | |
| */ | |
| @VisibleForTesting | |
| public Artifact(Path path, Root root, PathFragment execPath) { | |
| this(path, root, execPath, ArtifactOwner.NULL_OWNER); | |
| } | |
| /** | |
| * Constructs a source or derived Artifact for the specified path and specified root. The root | |
| * must be an ancestor of the path. | |
| */ | |
| @VisibleForTesting // Only exists for testing. | |
| public Artifact(Path path, Root root) { | |
| this(path, root, root.getExecPath().getRelative(path.relativeTo(root.getPath())), | |
| ArtifactOwner.NULL_OWNER); | |
| } | |
| /** | |
| * Constructs a source or derived Artifact for the specified root-relative path and root. | |
| */ | |
| @VisibleForTesting // Only exists for testing. | |
| public Artifact(PathFragment rootRelativePath, Root root) { | |
| this(root.getPath().getRelative(rootRelativePath), root, | |
| root.getExecPath().getRelative(rootRelativePath), ArtifactOwner.NULL_OWNER); | |
| } | |
| /** | |
| * Returns the location of this Artifact on the filesystem. | |
| */ | |
| public final Path getPath() { | |
| return path; | |
| } | |
| /** | |
| * Returns the base file name of this artifact. | |
| */ | |
| @Override | |
| public final String getFilename() { | |
| return getExecPath().getBaseName(); | |
| } | |
| /** | |
| * Returns the artifact owner. May be null. | |
| */ | |
| @Nullable public final Label getOwner() { | |
| return owner.getLabel(); | |
| } | |
| /** | |
| * Get the {@code LabelAndConfiguration} of the {@code ConfiguredTarget} that owns this artifact, | |
| * if it was set. Otherwise, this should be a dummy value -- either {@link | |
| * ArtifactOwner#NULL_OWNER} or a dummy owner set in tests. Such a dummy value should only occur | |
| * for source artifacts if created without specifying the owner, or for special derived artifacts, | |
| * such as target completion middleman artifacts, build info artifacts, and the like. | |
| * | |
| * When deserializing artifacts we end up with a dummy owner. In that case, it must be set using | |
| * {@link #setArtifactOwner} before this method is called. | |
| */ | |
| public final ArtifactOwner getArtifactOwner() { | |
| Preconditions.checkState(owner != DESERIALIZED_MARKER_OWNER, this); | |
| return owner; | |
| } | |
| /** | |
| * Sets the artifact owner of this artifact. Should only be called for artifacts that were created | |
| * through deserialization, and so their owner was unknown at the time of creation. | |
| */ | |
| public final void setArtifactOwner(ArtifactOwner owner) { | |
| if (this.owner == DESERIALIZED_MARKER_OWNER) { | |
| // We tolerate multiple calls of this method to accommodate shared actions. | |
| this.owner = Preconditions.checkNotNull(owner, this); | |
| } | |
| } | |
| /** | |
| * Returns the root beneath which this Artifact resides, if any. This may be one of the | |
| * package-path entries (for source Artifacts), or one of the bin, genfiles or includes dirs | |
| * (for derived Artifacts). It will always be an ancestor of getPath(). | |
| */ | |
| public final Root getRoot() { | |
| return root; | |
| } | |
| /** | |
| * Returns the exec path of this Artifact. The exec path is a relative path | |
| * that is suitable for accessing this artifact relative to the execution | |
| * directory for this build. | |
| */ | |
| public final PathFragment getExecPath() { | |
| return execPath; | |
| } | |
| /** | |
| * Returns true iff this is a source Artifact as determined by its path and | |
| * root relationships. Note that this will report all Artifacts in the output | |
| * tree, including in the include symlink tree, as non-source. | |
| */ | |
| public final boolean isSourceArtifact() { | |
| return execPath == rootRelativePath; | |
| } | |
| /** | |
| * Returns true iff this is a middleman Artifact as determined by its root. | |
| */ | |
| public final boolean isMiddlemanArtifact() { | |
| return getRoot().isMiddlemanRoot(); | |
| } | |
| /** | |
| * Returns whether the artifact represents a Fileset. | |
| */ | |
| public boolean isFileset() { | |
| return false; | |
| } | |
| /** | |
| * Returns true iff metadata cache must return constant metadata for the | |
| * given artifact. | |
| */ | |
| public boolean isConstantMetadata() { | |
| return false; | |
| } | |
| /** | |
| * Special artifact types. | |
| * | |
| * @see SpecialArtifact | |
| */ | |
| static enum SpecialArtifactType { | |
| FILESET, | |
| CONSTANT_METADATA, | |
| } | |
| /** | |
| * A special kind of artifact that either is a fileset or needs special metadata caching behavior. | |
| * | |
| * <p>We subclass {@link Artifact} instead of storing the special attributes inside in order | |
| * to save memory. The proportion of artifacts that are special is very small, and by not having | |
| * to keep around the attribute for the rest we save some memory. | |
| */ | |
| @Immutable | |
| @VisibleForTesting | |
| public static final class SpecialArtifact extends Artifact { | |
| private final SpecialArtifactType type; | |
| SpecialArtifact(Path path, Root root, PathFragment execPath, ArtifactOwner owner, | |
| SpecialArtifactType type) { | |
| super(path, root, execPath, owner); | |
| this.type = type; | |
| } | |
| @Override | |
| public final boolean isFileset() { | |
| return type == SpecialArtifactType.FILESET; | |
| } | |
| @Override | |
| public boolean isConstantMetadata() { | |
| return type == SpecialArtifactType.CONSTANT_METADATA; | |
| } | |
| } | |
| /** | |
| * Returns the relative path to this artifact relative to its root. (Useful | |
| * when deriving output filenames from input files, etc.) | |
| */ | |
| public final PathFragment getRootRelativePath() { | |
| return rootRelativePath; | |
| } | |
| /** | |
| * Returns this.getExecPath().getPathString(). | |
| */ | |
| @Override | |
| @SkylarkCallable(name = "path", structField = true, | |
| doc = "The execution path of this file, relative to the execution directory. It consists of " | |
| + "two parts, an optional first part called the <i>root</i> (see also the <a " | |
| + "href=\"#modules.root\">root</a> module), and the second part which is the " | |
| + "<code>short_path</code>. The root may be empty, which it usually is for non-generated " | |
| + "files. For generated files it usually contains a configuration-specific path fragment that" | |
| + " encodes things like the target CPU architecture that was used while building said file.") | |
| public final String getExecPathString() { | |
| return getExecPath().getPathString(); | |
| } | |
| @SkylarkCallable(name = "short_path", structField = true, | |
| doc = "The path of this file relative to its root. This excludes the aforementioned " | |
| + "<i>root</i>, i.e. configuration-specific fragments of the path. This is also the path " | |
| + "under which the file is mapped if its in the runfiles of a binary.") | |
| public final String getRootRelativePathString() { | |
| return getRootRelativePath().getPathString(); | |
| } | |
| /** | |
| * Returns a pretty string representation of the path denoted by this artifact, suitable for use | |
| * in user error messages. Artifacts beneath a root will be printed relative to that root; other | |
| * artifacts will be printed as an absolute path. | |
| * | |
| * <p>(The toString method is intended for developer messages since its more informative.) | |
| */ | |
| public final String prettyPrint() { | |
| // toDetailString would probably be more useful to users, but lots of tests rely on the | |
| // current values. | |
| return rootRelativePath.toString(); | |
| } | |
| @Override | |
| public final boolean equals(Object other) { | |
| if (!(other instanceof Artifact)) { | |
| return false; | |
| } | |
| // We don't bother to check root in the equivalence relation, because we | |
| // assume that 'root' is an ancestor of 'path', and that all possible roots | |
| // are disjoint, so unless things are really screwed up, it's ok. | |
| Artifact that = (Artifact) other; | |
| return this.path.equals(that.path); | |
| } | |
| @Override | |
| public final int compareTo(Artifact o) { | |
| // The artifact factory ensures that there is a unique artifact for a given path. | |
| return this.path.compareTo(o.path); | |
| } | |
| @Override | |
| public final int hashCode() { | |
| return path.hashCode(); | |
| } | |
| @Override | |
| public final String toString() { | |
| return "Artifact:" + toDetailString(); | |
| } | |
| /** | |
| * Returns the root-part of a given path by trimming off the end specified by | |
| * a given tail. Assumes that the tail is known to match, and simply relies on | |
| * the segment lengths. | |
| */ | |
| private static PathFragment trimTail(PathFragment path, PathFragment tail) { | |
| return path.subFragment(0, path.segmentCount() - tail.segmentCount()); | |
| } | |
| /** | |
| * Returns a string representing the complete artifact path information. | |
| */ | |
| public final String toDetailString() { | |
| if (isSourceArtifact()) { | |
| // Source Artifact: relPath == execPath, & real path is not under execRoot | |
| return "[" + root + "]" + rootRelativePath; | |
| } else { | |
| // Derived Artifact: path and root are under execRoot | |
| PathFragment execRoot = trimTail(path.asFragment(), execPath); | |
| return "[[" + execRoot + "]" + root.getPath().asFragment().relativeTo(execRoot) + "]" | |
| + rootRelativePath; | |
| } | |
| } | |
| /** | |
| * Serializes this artifact to a string that has enough data to reconstruct the artifact. | |
| */ | |
| public final String serializeToString() { | |
| // In theory, it should be enough to serialize execPath and rootRelativePath (which is a suffix | |
| // of execPath). However, in practice there is code around that uses other attributes which | |
| // needs cleaning up. | |
| String result = execPath + " /" + rootRelativePath.toString().length(); | |
| if (getOwner() != null) { | |
| result += " " + getOwner(); | |
| } | |
| return result; | |
| } | |
| //--------------------------------------------------------------------------- | |
| // Static methods to assist in working with Artifacts | |
| /** | |
| * Formatter for execPath PathFragment output. | |
| */ | |
| private static final Function<Artifact, PathFragment> EXEC_PATH_FORMATTER = | |
| new Function<Artifact, PathFragment>() { | |
| @Override | |
| public PathFragment apply(Artifact input) { | |
| return input.getExecPath(); | |
| } | |
| }; | |
| private static final Function<Artifact, String> ROOT_RELATIVE_PATH_STRING = | |
| new Function<Artifact, String>() { | |
| @Override | |
| public String apply(Artifact artifact) { | |
| return artifact.getRootRelativePath().getPathString(); | |
| } | |
| }; | |
| /** | |
| * Converts a collection of artifacts into execution-time path strings, and | |
| * adds those to a given collection. Middleman artifacts are ignored by this | |
| * method. | |
| */ | |
| public static void addExecPaths(Iterable<Artifact> artifacts, Collection<String> output) { | |
| addNonMiddlemanArtifacts(artifacts, output, ActionInputHelper.EXEC_PATH_STRING_FORMATTER); | |
| } | |
| /** | |
| * Converts a collection of artifacts into the outputs computed by | |
| * outputFormatter and adds them to a given collection. Middleman artifacts | |
| * are ignored. | |
| */ | |
| static <E> void addNonMiddlemanArtifacts(Iterable<Artifact> artifacts, | |
| Collection<? super E> output, Function<? super Artifact, E> outputFormatter) { | |
| for (Artifact artifact : artifacts) { | |
| if (MIDDLEMAN_FILTER.apply(artifact)) { | |
| output.add(outputFormatter.apply(artifact)); | |
| } | |
| } | |
| } | |
| /** | |
| * Lazily converts artifacts into root-relative path strings. Middleman artifacts are ignored by | |
| * this method. | |
| */ | |
| public static Iterable<String> toRootRelativePaths(Iterable<Artifact> artifacts) { | |
| return Iterables.transform( | |
| Iterables.filter(artifacts, MIDDLEMAN_FILTER), | |
| ROOT_RELATIVE_PATH_STRING); | |
| } | |
| /** | |
| * Lazily converts artifacts into execution-time path strings. Middleman artifacts are ignored by | |
| * this method. | |
| */ | |
| public static Iterable<String> toExecPaths(Iterable<Artifact> artifacts) { | |
| return ActionInputHelper.toExecPaths(Iterables.filter(artifacts, MIDDLEMAN_FILTER)); | |
| } | |
| /** | |
| * Converts a collection of artifacts into execution-time path strings, and | |
| * returns those as an immutable list. Middleman artifacts are ignored by this method. | |
| */ | |
| public static List<String> asExecPaths(Iterable<Artifact> artifacts) { | |
| return ImmutableList.copyOf(toExecPaths(artifacts)); | |
| } | |
| /** | |
| * Renders a collection of artifacts as execution-time paths and joins | |
| * them into a single string. Middleman artifacts are ignored by this method. | |
| */ | |
| public static String joinExecPaths(String delimiter, Iterable<Artifact> artifacts) { | |
| return Joiner.on(delimiter).join(toExecPaths(artifacts)); | |
| } | |
| /** | |
| * Renders a collection of artifacts as root-relative paths and joins | |
| * them into a single string. Middleman artifacts are ignored by this method. | |
| */ | |
| public static String joinRootRelativePaths(String delimiter, Iterable<Artifact> artifacts) { | |
| return Joiner.on(delimiter).join(toRootRelativePaths(artifacts)); | |
| } | |
| /** | |
| * Adds a collection of artifacts to a given collection, with | |
| * {@link MiddlemanType#AGGREGATING_MIDDLEMAN} middleman actions expanded once. | |
| */ | |
| public static void addExpandedArtifacts(Iterable<Artifact> artifacts, | |
| Collection<? super Artifact> output, MiddlemanExpander middlemanExpander) { | |
| addExpandedArtifacts(artifacts, output, Functions.<Artifact>identity(), middlemanExpander); | |
| } | |
| /** | |
| * Converts a collection of artifacts into execution-time path strings, and | |
| * adds those to a given collection. Middleman artifacts for | |
| * {@link MiddlemanType#AGGREGATING_MIDDLEMAN} middleman actions are expanded | |
| * once. | |
| */ | |
| @VisibleForTesting | |
| public static void addExpandedExecPathStrings(Iterable<Artifact> artifacts, | |
| Collection<String> output, | |
| MiddlemanExpander middlemanExpander) { | |
| addExpandedArtifacts(artifacts, output, ActionInputHelper.EXEC_PATH_STRING_FORMATTER, | |
| middlemanExpander); | |
| } | |
| /** | |
| * Converts a collection of artifacts into execution-time path fragments, and | |
| * adds those to a given collection. Middleman artifacts for | |
| * {@link MiddlemanType#AGGREGATING_MIDDLEMAN} middleman actions are expanded | |
| * once. | |
| */ | |
| public static void addExpandedExecPaths(Iterable<Artifact> artifacts, | |
| Collection<PathFragment> output, MiddlemanExpander middlemanExpander) { | |
| addExpandedArtifacts(artifacts, output, EXEC_PATH_FORMATTER, middlemanExpander); | |
| } | |
| /** | |
| * Converts a collection of artifacts into the outputs computed by | |
| * outputFormatter and adds them to a given collection. Middleman artifacts | |
| * are expanded once. | |
| */ | |
| private static <E> void addExpandedArtifacts(Iterable<Artifact> artifacts, | |
| Collection<? super E> output, | |
| Function<? super Artifact, E> outputFormatter, | |
| MiddlemanExpander middlemanExpander) { | |
| for (Artifact artifact : artifacts) { | |
| if (artifact.isMiddlemanArtifact()) { | |
| expandMiddlemanArtifact(artifact, output, outputFormatter, middlemanExpander); | |
| } else { | |
| output.add(outputFormatter.apply(artifact)); | |
| } | |
| } | |
| } | |
| private static <E> void expandMiddlemanArtifact(Artifact middleman, | |
| Collection<? super E> output, | |
| Function<? super Artifact, E> outputFormatter, | |
| MiddlemanExpander middlemanExpander) { | |
| Preconditions.checkArgument(middleman.isMiddlemanArtifact()); | |
| List<Artifact> artifacts = new ArrayList<>(); | |
| middlemanExpander.expand(middleman, artifacts); | |
| for (Artifact artifact : artifacts) { | |
| output.add(outputFormatter.apply(artifact)); | |
| } | |
| } | |
| /** | |
| * Converts a collection of artifacts into execution-time path strings, and | |
| * returns those as a list. Middleman artifacts are expanded once. The | |
| * returned list is mutable. | |
| */ | |
| public static List<String> asExpandedExecPathStrings(Iterable<Artifact> artifacts, | |
| MiddlemanExpander middlemanExpander) { | |
| List<String> result = new ArrayList<>(); | |
| addExpandedExecPathStrings(artifacts, result, middlemanExpander); | |
| return result; | |
| } | |
| /** | |
| * Converts a collection of artifacts into execution-time path fragments, and | |
| * returns those as a list. Middleman artifacts are expanded once. The | |
| * returned list is mutable. | |
| */ | |
| public static List<PathFragment> asExpandedExecPaths(Iterable<Artifact> artifacts, | |
| MiddlemanExpander middlemanExpander) { | |
| List<PathFragment> result = new ArrayList<>(); | |
| addExpandedExecPaths(artifacts, result, middlemanExpander); | |
| return result; | |
| } | |
| /** | |
| * Converts a collection of artifacts into execution-time path strings with | |
| * the root-break delimited with a colon ':', and adds those to a given list. | |
| * <pre> | |
| * Source: sourceRoot/rootRelative => :rootRelative | |
| * Derived: execRoot/rootPrefix/rootRelative => rootPrefix:rootRelative | |
| * </pre> | |
| */ | |
| public static void addRootPrefixedExecPaths(Iterable<Artifact> artifacts, | |
| List<String> output) { | |
| for (Artifact artifact : artifacts) { | |
| output.add(asRootPrefixedExecPath(artifact)); | |
| } | |
| } | |
| /** | |
| * Convenience method to filter the files to build for a certain filetype. | |
| * | |
| * @param artifacts the files to filter | |
| * @param allowedType the allowed filetype | |
| * @return all members of filesToBuild that are of one of the | |
| * allowed filetypes | |
| */ | |
| public static List<Artifact> filterFiles(Iterable<Artifact> artifacts, FileType allowedType) { | |
| List<Artifact> filesToBuild = new ArrayList<>(); | |
| for (Artifact artifact : artifacts) { | |
| if (allowedType.matches(artifact.getFilename())) { | |
| filesToBuild.add(artifact); | |
| } | |
| } | |
| return filesToBuild; | |
| } | |
| @VisibleForTesting | |
| static String asRootPrefixedExecPath(Artifact artifact) { | |
| PathFragment execPath = artifact.getExecPath(); | |
| PathFragment rootRel = artifact.getRootRelativePath(); | |
| if (execPath.equals(rootRel)) { | |
| return ":" + rootRel.getPathString(); | |
| } else { //if (execPath.endsWith(rootRel)) { | |
| PathFragment rootPrefix = trimTail(execPath, rootRel); | |
| return rootPrefix.getPathString() + ":" + rootRel.getPathString(); | |
| } | |
| } | |
| /** | |
| * Converts artifacts into their exec paths. Returns an immutable list. | |
| */ | |
| public static List<PathFragment> asPathFragments(Iterable<Artifact> artifacts) { | |
| return ImmutableList.copyOf(Iterables.transform(artifacts, EXEC_PATH_FORMATTER)); | |
| } | |
| static final ArtifactOwner DESERIALIZED_MARKER_OWNER = new ArtifactOwner() { | |
| @Override | |
| public Label getLabel() { | |
| return null; | |
| }}; | |
| } |