Introduce TreeFileArtifact, which represents files under TreeArtifacts.
Remove ArtifactFile, which is rendered obsolete by TreeFileArtifact.
--
MOS_MIGRATED_REVID=119789154
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index 4e8989f..f28683b 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -70,7 +70,7 @@
* In the usual case, an Artifact represents a single file. However, an Artifact may
* also represent the following:
* <ul>
- * <li>A TreeArtifact, which is a directory containing a tree of unknown {@link ArtifactFile}s.
+ * <li>A TreeArtifact, which is a directory containing a tree of unknown {@link Artifact}s.
* In the future, Actions will be able to examine these files as inputs and declare them as outputs
* at execution time, but this is not yet implemented. This is used for Actions where
* the inputs and/or outputs might not be discoverable except during Action execution.
@@ -87,8 +87,8 @@
* by new rule implementations.
* </ul>
* <p/>
- * This class implements {@link ArtifactFile}, and is modeled as an Artifact "containing" itself
- * as an ArtifactFile.
+ * This class implements {@link Artifact}, and is modeled as an Artifact "containing" itself
+ * as an Artifact.
* <p/>
* <p>This class is "theoretically" final; it should not be subclassed except by
* {@link SpecialArtifact}.
@@ -98,7 +98,7 @@
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, ArtifactFile, SkylarkValue , Comparable<Object> {
+ implements FileType.HasFilename, ActionInput, SkylarkValue, Comparable<Object> {
/**
* Compares artifact according to their exec paths. Sorts null values first.
@@ -136,7 +136,7 @@
* <p>{@code artifact.isMiddlemanArtifact() || artifact.isTreeArtifact()} must be true.
* Only aggregating middlemen and tree artifacts are expanded.
*/
- void expand(Artifact artifact, Collection<? super ArtifactFile> output);
+ void expand(Artifact artifact, Collection<? super Artifact> output);
}
public static final ImmutableList<Artifact> NO_ARTIFACTS = ImmutableList.of();
@@ -239,20 +239,20 @@
root.getExecPath().getRelative(rootRelativePath), ArtifactOwner.NULL_OWNER);
}
- @Override
public final Path getPath() {
return path;
}
+ public boolean hasParent() {
+ return getParent() != null;
+ }
+
/**
- * Returns the Artifact containing this ArtifactFile. Since normal Artifacts correspond
- * to only one ArtifactFile -- itself -- for normal Artifacts, this method returns {@code this}.
- * For special artifacts, throws {@link UnsupportedOperationException}.
- * See also {@link ArtifactFile#getParent()}.
+ * Returns the parent Artifact containing this Artifact. Artifacts without parents shall
+ * return null.
*/
- @Override
- public Artifact getParent() throws UnsupportedOperationException {
- return this;
+ @Nullable public Artifact getParent() {
+ return null;
}
/**
@@ -307,7 +307,6 @@
* 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().
*/
- @Override
@SkylarkCallable(name = "root", structField = true,
doc = "The root beneath which this file resides."
)
@@ -315,18 +314,16 @@
return root;
}
- @Override
public final PathFragment getExecPath() {
return execPath;
}
/**
- * Returns the path of this ArtifactFile relative to this containing Artifact. Since
- * ordinary Artifacts correspond to only one ArtifactFile -- itself -- for ordinary Artifacts,
+ * Returns the path of this Artifact relative to this containing Artifact. Since
+ * ordinary Artifacts correspond to only one Artifact -- itself -- for ordinary Artifacts,
* this just returns the empty path. For special Artifacts, throws
- * {@link UnsupportedOperationException}. See also {@link ArtifactFile#getParentRelativePath()}.
+ * {@link UnsupportedOperationException}. See also {@link Artifact#getParentRelativePath()}.
*/
- @Override
public PathFragment getParentRelativePath() {
return PathFragment.EMPTY_FRAGMENT;
}
@@ -350,7 +347,7 @@
}
/**
- * Returns true iff this is a TreeArtifact representing a directory tree containing ArtifactFiles.
+ * Returns true iff this is a TreeArtifact representing a directory tree containing Artifacts.
*/
public boolean isTreeArtifact() {
return false;
@@ -418,13 +415,77 @@
}
@Override
+ public boolean hasParent() {
+ return false;
+ }
+
+ @Override
+ @Nullable
public Artifact getParent() {
- throw new UnsupportedOperationException();
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public PathFragment getParentRelativePath() {
+ return null;
+ }
+ }
+
+ /**
+ * A special kind of artifact that represents a concrete file created at execution time under
+ * its associated TreeArtifact.
+ *
+ * <p> TreeFileArtifacts should be only created during execution time inside some special actions
+ * to support action inputs and outputs that are unpredictable at analysis time.
+ * TreeFileArtifacts should not be created directly by any rules at analysis time.
+ *
+ * <p>We subclass {@link Artifact} instead of storing the extra fields directly inside in order
+ * to save memory. The proportion of TreeFileArtifacts is very small, and by not having to keep
+ * around the extra fields for the rest we save some memory.
+ */
+ @Immutable
+ public static final class TreeFileArtifact extends Artifact {
+ private final Artifact parentTreeArtifact;
+ private final PathFragment parentRelativePath;
+
+ /**
+ * Constructs a TreeFileArtifact with the given parent-relative path under the given parent
+ * TreeArtifact. The {@link ArtifactOwner} of the TreeFileArtifact is the {@link ArtifactOwner}
+ * of the parent TreeArtifact.
+ */
+ TreeFileArtifact(Artifact parent, PathFragment parentRelativePath) {
+ this(parent, parentRelativePath, parent.getArtifactOwner());
+ }
+
+ /**
+ * Constructs a TreeFileArtifact with the given parent-relative path under the given parent
+ * TreeArtifact, owned by the given {@code artifactOwner}.
+ */
+ TreeFileArtifact(Artifact parent, PathFragment parentRelativePath,
+ ArtifactOwner artifactOwner) {
+ super(
+ parent.getPath().getRelative(parentRelativePath),
+ parent.getRoot(),
+ parent.getExecPath().getRelative(parentRelativePath),
+ artifactOwner);
+ Preconditions.checkState(
+ parent.isTreeArtifact(),
+ "The parent of TreeFileArtifact (parent-relative path: %s) is not a TreeArtifact: %s",
+ parentRelativePath,
+ parent);
+ this.parentTreeArtifact = parent;
+ this.parentRelativePath = parentRelativePath;
+ }
+
+ @Override
+ public Artifact getParent() {
+ return parentTreeArtifact;
}
@Override
public PathFragment getParentRelativePath() {
- throw new UnsupportedOperationException();
+ return parentRelativePath;
}
}
@@ -432,7 +493,6 @@
* Returns the relative path to this artifact relative to its root. (Useful
* when deriving output filenames from input files, etc.)
*/
- @Override
public final PathFragment getRootRelativePath() {
return rootRelativePath;
}
@@ -478,7 +538,6 @@
return getRootRelativePath().getPathString();
}
- @Override
public final String prettyPrint() {
// toDetailString would probably be more useful to users, but lots of tests rely on the
// current values.
@@ -550,26 +609,26 @@
/**
* Formatter for execPath PathFragment output.
*/
- private static final Function<ArtifactFile, PathFragment> EXEC_PATH_FORMATTER =
- new Function<ArtifactFile, PathFragment>() {
+ private static final Function<Artifact, PathFragment> EXEC_PATH_FORMATTER =
+ new Function<Artifact, PathFragment>() {
@Override
- public PathFragment apply(ArtifactFile input) {
+ public PathFragment apply(Artifact input) {
return input.getExecPath();
}
};
- public static final Function<ArtifactFile, String> ROOT_RELATIVE_PATH_STRING =
- new Function<ArtifactFile, String>() {
+ public static final Function<Artifact, String> ROOT_RELATIVE_PATH_STRING =
+ new Function<Artifact, String>() {
@Override
- public String apply(ArtifactFile artifact) {
+ public String apply(Artifact artifact) {
return artifact.getRootRelativePath().getPathString();
}
};
- public static final Function<ArtifactFile, String> ABSOLUTE_PATH_STRING =
- new Function<ArtifactFile, String>() {
+ public static final Function<Artifact, String> ABSOLUTE_PATH_STRING =
+ new Function<Artifact, String>() {
@Override
- public String apply(ArtifactFile artifact) {
+ public String apply(Artifact artifact) {
return artifact.getPath().getPathString();
}
};
@@ -654,8 +713,8 @@
* {@link MiddlemanType#AGGREGATING_MIDDLEMAN} middleman actions expanded once.
*/
public static void addExpandedArtifacts(Iterable<Artifact> artifacts,
- Collection<? super ArtifactFile> output, ArtifactExpander artifactExpander) {
- addExpandedArtifacts(artifacts, output, Functions.<ArtifactFile>identity(), artifactExpander);
+ Collection<? super Artifact> output, ArtifactExpander artifactExpander) {
+ addExpandedArtifacts(artifacts, output, Functions.<Artifact>identity(), artifactExpander);
}
/**
@@ -690,7 +749,7 @@
*/
private static <E> void addExpandedArtifacts(Iterable<? extends Artifact> artifacts,
Collection<? super E> output,
- Function<? super ArtifactFile, E> outputFormatter,
+ Function<? super Artifact, E> outputFormatter,
ArtifactExpander artifactExpander) {
for (Artifact artifact : artifacts) {
if (artifact.isMiddlemanArtifact() || artifact.isTreeArtifact()) {
@@ -703,12 +762,12 @@
private static <E> void expandArtifact(Artifact middleman,
Collection<? super E> output,
- Function<? super ArtifactFile, E> outputFormatter,
+ Function<? super Artifact, E> outputFormatter,
ArtifactExpander artifactExpander) {
Preconditions.checkArgument(middleman.isMiddlemanArtifact() || middleman.isTreeArtifact());
- List<ArtifactFile> artifacts = new ArrayList<>();
+ List<Artifact> artifacts = new ArrayList<>();
artifactExpander.expand(middleman, artifacts);
- for (ArtifactFile artifact : artifacts) {
+ for (Artifact artifact : artifacts) {
output.add(outputFormatter.apply(artifact));
}
}
@@ -785,7 +844,7 @@
/**
* Converts artifacts into their exec paths. Returns an immutable list.
*/
- public static List<PathFragment> asPathFragments(Iterable<? extends ArtifactFile> artifacts) {
+ public static List<PathFragment> asPathFragments(Iterable<? extends Artifact> artifacts) {
return ImmutableList.copyOf(Iterables.transform(artifacts, EXEC_PATH_FORMATTER));
}