diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/CollectPackagesUnderDirectoryValue.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skyframe/CollectPackagesUnderDirectoryValue.java | 230 |
1 files changed, 172 insertions, 58 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/CollectPackagesUnderDirectoryValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/CollectPackagesUnderDirectoryValue.java index 1a431e2ca0..f7f48e59ad 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/CollectPackagesUnderDirectoryValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/CollectPackagesUnderDirectoryValue.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.cmdline.RepositoryName; @@ -23,88 +24,201 @@ import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; - import java.util.Objects; +import javax.annotation.Nullable; /** * The value computed by {@link CollectPackagesUnderDirectoryFunction}. Contains a mapping for all - * its non-excluded directories to whether there are packages beneath them. + * its non-excluded directories to whether there are packages or error messages beneath them. * - * <p>This value is used by {@link GraphBackedRecursivePackageProvider#getPackagesUnderDirectory} - * to help it traverse the graph and find the set of packages under a directory, recursively by - * {@link CollectPackagesUnderDirectoryFunction} which computes a value for a directory by - * aggregating results calculated from its subdirectories, and by - * {@link PrepareDepsOfTargetsUnderDirectoryFunction} which uses this value to find transitive - * targets to load. + * <p>This value is used by {@link GraphBackedRecursivePackageProvider#getPackagesUnderDirectory} to + * help it traverse the graph and find the set of packages under a directory, recursively by {@link + * CollectPackagesUnderDirectoryFunction} which computes a value for a directory by aggregating + * results calculated from its subdirectories, and by {@link + * PrepareDepsOfTargetsUnderDirectoryFunction} which uses this value to find transitive targets to + * load. * - * <p>Note that even though the {@link CollectPackagesUnderDirectoryFunction} is evaluated in - * part because of its side-effects (i.e. loading transitive dependencies of targets), this value + * <p>Note that even though the {@link CollectPackagesUnderDirectoryFunction} is evaluated in part + * because of its side-effects (i.e. loading transitive dependencies of targets), this value * interacts safely with change pruning, despite the fact that this value is a lossy representation * of the packages beneath a directory (i.e. it doesn't care <b>which</b> packages are under a - * directory, just whether there are any). When the targets in a package change, the - * {@link PackageValue} that {@link CollectPackagesUnderDirectoryFunction} depends on will be - * invalidated, and the PrepareDeps function for that package's directory will be reevaluated, - * loading any new transitive dependencies. Change pruning may prevent the reevaluation of - * PrepareDeps for directories above that one, but they don't need to be re-run. + * directory, just whether there are any). When the targets in a package change, the {@link + * PackageValue} that {@link CollectPackagesUnderDirectoryFunction} depends on will be invalidated, + * and the PrepareDeps function for that package's directory will be reevaluated, loading any new + * transitive dependencies. Change pruning may prevent the reevaluation of PrepareDeps for + * directories above that one, but they don't need to be re-run. */ -public class CollectPackagesUnderDirectoryValue implements SkyValue { - public static final CollectPackagesUnderDirectoryValue EMPTY = - new CollectPackagesUnderDirectoryValue(false, ImmutableMap.<RootedPath, Boolean>of()); +public abstract class CollectPackagesUnderDirectoryValue implements SkyValue { - private final boolean isDirectoryPackage; - private final ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackages; + private final ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackagesOrErrors; - private CollectPackagesUnderDirectoryValue( - boolean isDirectoryPackage, - ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackages) { - this.subdirectoryTransitivelyContainsPackages = subdirectoryTransitivelyContainsPackages; - this.isDirectoryPackage = isDirectoryPackage; + CollectPackagesUnderDirectoryValue( + ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackagesOrErrors) { + this.subdirectoryTransitivelyContainsPackagesOrErrors = + Preconditions.checkNotNull(subdirectoryTransitivelyContainsPackagesOrErrors); } - public static CollectPackagesUnderDirectoryValue of( - boolean isDirectoryPackage, - ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackages) { - if (!isDirectoryPackage && subdirectoryTransitivelyContainsPackages.isEmpty()) { - return EMPTY; + /** Represents a successfully loaded package or a directory without a BUILD file. */ + public static class NoErrorCollectPackagesUnderDirectoryValue + extends CollectPackagesUnderDirectoryValue { + public static final NoErrorCollectPackagesUnderDirectoryValue EMPTY = + new NoErrorCollectPackagesUnderDirectoryValue(false, ImmutableMap.of()); + + private final boolean isDirectoryPackage; + + private NoErrorCollectPackagesUnderDirectoryValue( + boolean isDirectoryPackage, + ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackagesOrErrors) { + super(subdirectoryTransitivelyContainsPackagesOrErrors); + this.isDirectoryPackage = isDirectoryPackage; } - return new CollectPackagesUnderDirectoryValue( - isDirectoryPackage, subdirectoryTransitivelyContainsPackages); - } - public boolean isDirectoryPackage() { - return isDirectoryPackage; - } + @Override + public boolean isDirectoryPackage() { + return isDirectoryPackage; + } - public ImmutableMap<RootedPath, Boolean> getSubdirectoryTransitivelyContainsPackages() { - return subdirectoryTransitivelyContainsPackages; - } + @Nullable + @Override + public String getErrorMessage() { + return null; + } + + @Override + public int hashCode() { + return Objects.hash( + isDirectoryPackage, getSubdirectoryTransitivelyContainsPackagesOrErrors()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof NoErrorCollectPackagesUnderDirectoryValue)) { + return false; + } + NoErrorCollectPackagesUnderDirectoryValue that = + (NoErrorCollectPackagesUnderDirectoryValue) o; + return this.isDirectoryPackage == that.isDirectoryPackage + && Objects.equals( + this.getSubdirectoryTransitivelyContainsPackagesOrErrors(), + that.getSubdirectoryTransitivelyContainsPackagesOrErrors()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("isDirectoryPackage", isDirectoryPackage) + .add( + "subdirectoryTransitivelyContainsPackagesOrErrors", + getSubdirectoryTransitivelyContainsPackagesOrErrors()) + .toString(); + } - @Override - public int hashCode() { - return Objects.hash(isDirectoryPackage, subdirectoryTransitivelyContainsPackages); } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + /** Represents a directory with a BUILD file that failed to load. */ + public static class ErrorCollectPackagesUnderDirectoryValue + extends CollectPackagesUnderDirectoryValue { + private final String errorMessage; + + private ErrorCollectPackagesUnderDirectoryValue( + String errorMessage, + ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackagesOrErrors) { + super(subdirectoryTransitivelyContainsPackagesOrErrors); + this.errorMessage = Preconditions.checkNotNull(errorMessage); } - if (!(o instanceof CollectPackagesUnderDirectoryValue)) { + + @Override + public boolean isDirectoryPackage() { return false; } - CollectPackagesUnderDirectoryValue that = (CollectPackagesUnderDirectoryValue) o; - return this.isDirectoryPackage == that.isDirectoryPackage - && this - .subdirectoryTransitivelyContainsPackages.equals( - that.subdirectoryTransitivelyContainsPackages); + + @Override + public String getErrorMessage() { + return errorMessage; + } + + @Override + public int hashCode() { + return Objects.hash(errorMessage, getSubdirectoryTransitivelyContainsPackagesOrErrors()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ErrorCollectPackagesUnderDirectoryValue)) { + return false; + } + ErrorCollectPackagesUnderDirectoryValue that = (ErrorCollectPackagesUnderDirectoryValue) o; + return Objects.equals(this.errorMessage, that.errorMessage) + && Objects.equals( + this.getSubdirectoryTransitivelyContainsPackagesOrErrors(), + that.getSubdirectoryTransitivelyContainsPackagesOrErrors()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("errorMessage", errorMessage) + .add( + "subdirectoryTransitivelyContainsPackagesOrErrors", + getSubdirectoryTransitivelyContainsPackagesOrErrors()) + .toString(); + } } - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("isDirectoryPackage", isDirectoryPackage) - .add("subdirectoryTransitivelyContainsPackages", subdirectoryTransitivelyContainsPackages) - .toString(); + /** + * Constructs a {@link CollectPackagesUnderDirectoryValue} for a directory with a BUILD file that + * failed to load as a package. + */ + public static CollectPackagesUnderDirectoryValue ofError( + String errorMessage, + ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackagesOrErrors) { + Preconditions.checkNotNull(errorMessage, "errorMessage"); + return new ErrorCollectPackagesUnderDirectoryValue( + errorMessage, subdirectoryTransitivelyContainsPackagesOrErrors); + } + + /** + * Constructs a {@link CollectPackagesUnderDirectoryValue} for a directory without a BUILD file or + * that has a BUILD file that successfully loads as a package. + */ + public static CollectPackagesUnderDirectoryValue ofNoError( + boolean isDirectoryPackage, + ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackagesOrErrors) { + if (!isDirectoryPackage && subdirectoryTransitivelyContainsPackagesOrErrors.isEmpty()) { + return NoErrorCollectPackagesUnderDirectoryValue.EMPTY; + } + return new NoErrorCollectPackagesUnderDirectoryValue( + isDirectoryPackage, subdirectoryTransitivelyContainsPackagesOrErrors); + } + + /** + * Returns whether there is a BUILD file in this directory that can be loaded as a package. If + * this returns {@code true}, then {@link #getErrorMessage()} returns {@code null}. + */ + public abstract boolean isDirectoryPackage(); + + /** + * Returns an error describing why the BUILD file in this directory cannot be loaded as a package, + * if there is one and it can't be. Otherwise returns {@code null}. If this returns non-{@code + * null}, then {@link #isDirectoryPackage()} returns {@code false}. + */ + @Nullable + public abstract String getErrorMessage(); + + /** + * Returns an {@link ImmutableMap} describing each immediate subdirectory of this directory and + * whether there are any packages, or BUILD files that couldn't be loaded, in or beneath that + * subdirectory. + */ + public final ImmutableMap<RootedPath, Boolean> + getSubdirectoryTransitivelyContainsPackagesOrErrors() { + return subdirectoryTransitivelyContainsPackagesOrErrors; } /** Create a collect packages under directory request. */ |