aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar nharmata <nharmata@google.com>2017-06-07 17:03:52 -0400
committerGravatar John Cater <jcater@google.com>2017-06-08 10:52:52 -0400
commitff688bf287af54049f4f6d9b060fed1d2b649380 (patch)
tree216a01dd25e8ee26b4cb2fc3d579cfc872394dcc
parent24d3709cd57690f5458675dc68948502a5800189 (diff)
Make PackageFunction's strategy for handling unreadable BUILD files configurable. Add a test for the current behavior of treating an unreadable BUILD file as a package loading error.
RELNOTES: None PiperOrigin-RevId: 158314187
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/BazelSkyframeExecutorConstants.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java74
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java31
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoader.java6
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java37
8 files changed, 144 insertions, 28 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BazelSkyframeExecutorConstants.java b/src/main/java/com/google/devtools/build/lib/skyframe/BazelSkyframeExecutorConstants.java
index 9fb17e97d8..6b892a8319 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BazelSkyframeExecutorConstants.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BazelSkyframeExecutorConstants.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.skyframe;
import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.skyframe.PackageFunction.ActionOnIOExceptionReadingBuildFile;
import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
import com.google.devtools.build.lib.skyframe.PackageLookupValue.BuildFileName;
@@ -27,4 +28,8 @@ public class BazelSkyframeExecutorConstants {
public static final ImmutableList<BuildFileName> BUILD_FILES_BY_PRIORITY =
ImmutableList.of(BuildFileName.BUILD_DOT_BAZEL, BuildFileName.BUILD);
+
+ public static final ActionOnIOExceptionReadingBuildFile
+ ACTION_ON_IO_EXCEPTION_READING_BUILD_FILE =
+ ActionOnIOExceptionReadingBuildFile.UseOriginalIOException.INSTANCE;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
index 1e8a955019..994472e787 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
@@ -101,6 +101,8 @@ public class PackageFunction implements SkyFunction {
// Not final only for testing.
@Nullable private SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining;
+ private final ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile;
+
static final PathFragment DEFAULTS_PACKAGE_NAME = PathFragment.create("tools/defaults");
public PackageFunction(
@@ -111,7 +113,8 @@ public class PackageFunction implements SkyFunction {
Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache,
AtomicInteger numPackagesLoaded,
@Nullable SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining,
- @Nullable PackageProgressReceiver packageProgress) {
+ @Nullable PackageProgressReceiver packageProgress,
+ ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile) {
this.skylarkImportLookupFunctionForInlining = skylarkImportLookupFunctionForInlining;
// Can be null in tests.
this.preludeLabel = packageFactory == null
@@ -124,6 +127,7 @@ public class PackageFunction implements SkyFunction {
this.astCache = astCache;
this.numPackagesLoaded = numPackagesLoaded;
this.packageProgress = packageProgress;
+ this.actionOnIOExceptionReadingBuildFile = actionOnIOExceptionReadingBuildFile;
}
public PackageFunction(
@@ -142,7 +146,8 @@ public class PackageFunction implements SkyFunction {
astCache,
numPackagesLoaded,
skylarkImportLookupFunctionForInlining,
- null);
+ null,
+ ActionOnIOExceptionReadingBuildFile.UseOriginalIOException.INSTANCE);
}
public void setSkylarkImportLookupFunctionForInliningForTesting(
@@ -150,6 +155,45 @@ public class PackageFunction implements SkyFunction {
this.skylarkImportLookupFunctionForInlining = skylarkImportLookupFunctionForInlining;
}
+ /**
+ * What to do when encountering an {@link IOException} trying to read the contents of a BUILD
+ * file.
+ *
+ * <p>Any choice besides
+ * {@link ActionOnIOExceptionReadingBuildFile.UseOriginalIOException#INSTANCE} is potentially
+ * incrementally unsound: if the initial {@link IOException} is transient, then Blaze will
+ * "incorrectly" not attempt to redo package loading for this BUILD file on incremental builds.
+ *
+ * <p>The fact that this behavior is configurable and potentially unsound is a concession to
+ * certain desired use cases with fancy filesystems.
+ */
+ public interface ActionOnIOExceptionReadingBuildFile {
+ /**
+ * Given the {@link IOException} encountered when reading the contents of a BUILD file,
+ * returns the contents that should be used, or {@code null} if the original {@link IOException}
+ * should be respected (that is, we should error-out with a package loading error).
+ */
+ @Nullable
+ byte[] maybeGetBuildFileContentsToUse(IOException originalExn);
+
+ /**
+ * A {@link ActionOnIOExceptionReadingBuildFile} whose {@link #maybeGetBuildFileContentsToUse}
+ * has the sensible behavior of always respecting the initial {@link IOException}.
+ */
+ public static class UseOriginalIOException implements ActionOnIOExceptionReadingBuildFile {
+ public static final UseOriginalIOException INSTANCE = new UseOriginalIOException();
+
+ private UseOriginalIOException() {
+ }
+
+ @Override
+ @Nullable
+ public byte[] maybeGetBuildFileContentsToUse(IOException originalExn) {
+ return null;
+ }
+ }
+ }
+
/** An entry in {@link PackageFunction}'s internal caches. */
public static class CacheEntryWithGlobDeps<T> {
private final T value;
@@ -1142,23 +1186,29 @@ public class PackageFunction implements SkyFunction {
ParserInputSource input;
if (replacementContents == null) {
Preconditions.checkNotNull(buildFileValue, packageId);
+ byte[] buildFileBytes = null;
try {
- byte[] buildFileBytes =
+ buildFileBytes =
buildFileValue.isSpecialFile()
? FileSystemUtils.readContent(buildFilePath)
: FileSystemUtils.readWithKnownFileSize(
buildFilePath, buildFileValue.getSize());
- input =
- ParserInputSource.create(
- FileSystemUtils.convertFromLatin1(buildFileBytes),
- buildFilePath.asFragment());
} catch (IOException e) {
- // Note that we did this work, so we should conservatively report this error as
- // transient.
- throw new PackageFunctionException(
- new BuildFileContainsErrorsException(packageId, e.getMessage(), e),
- Transience.TRANSIENT);
+ buildFileBytes =
+ actionOnIOExceptionReadingBuildFile.maybeGetBuildFileContentsToUse(e);
+ if (buildFileBytes == null) {
+ // Note that we did the work that led to this IOException, so we should
+ // conservatively report this error as transient.
+ throw new PackageFunctionException(new BuildFileContainsErrorsException(
+ packageId, e.getMessage(), e), Transience.TRANSIENT);
+ }
+ // If control flow reaches here, we're in territory that is deliberately unsound.
+ // See the javadoc for ActionOnIOExceptionReadingBuildFile.
}
+ input =
+ ParserInputSource.create(
+ FileSystemUtils.convertFromLatin1(buildFileBytes),
+ buildFilePath.asFragment());
} else {
input = ParserInputSource.create(replacementContents, buildFilePath.asFragment());
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index 26e146b88b..845429ec3f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -47,6 +47,7 @@ import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.UnionDirtine
import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction;
import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFilesKnowledge;
import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.FileType;
+import com.google.devtools.build.lib.skyframe.PackageFunction.ActionOnIOExceptionReadingBuildFile;
import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
import com.google.devtools.build.lib.skyframe.PackageLookupValue.BuildFileName;
import com.google.devtools.build.lib.syntax.SkylarkSemanticsOptions;
@@ -126,7 +127,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
PathFragment blacklistedPackagePrefixesFile,
String productName,
CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy,
- List<BuildFileName> buildFilesByPriority) {
+ List<BuildFileName> buildFilesByPriority,
+ ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile) {
super(
evaluatorSupplier,
pkgFactory,
@@ -141,7 +143,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
blacklistedPackagePrefixesFile,
productName,
crossRepositoryLabelViolationStrategy,
- buildFilesByPriority);
+ buildFilesByPriority,
+ actionOnIOExceptionReadingBuildFile);
this.diffAwarenessManager = new DiffAwarenessManager(diffAwarenessFactories);
this.customDirtinessCheckers = customDirtinessCheckers;
}
@@ -160,7 +163,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
PathFragment blacklistedPackagePrefixesFile,
String productName,
CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy,
- List<BuildFileName> buildFilesByPriority) {
+ List<BuildFileName> buildFilesByPriority,
+ ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile) {
SequencedSkyframeExecutor skyframeExecutor =
new SequencedSkyframeExecutor(
InMemoryMemoizingEvaluator.SUPPLIER,
@@ -177,7 +181,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
blacklistedPackagePrefixesFile,
productName,
crossRepositoryLabelViolationStrategy,
- buildFilesByPriority);
+ buildFilesByPriority,
+ actionOnIOExceptionReadingBuildFile);
skyframeExecutor.init();
return skyframeExecutor;
}
@@ -195,7 +200,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
Iterable<SkyValueDirtinessChecker> customDirtinessCheckers,
String productName,
CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy,
- List<BuildFileName> buildFilesByPriority) {
+ List<BuildFileName> buildFilesByPriority,
+ ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile) {
return create(
pkgFactory,
directories,
@@ -210,7 +216,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
/*blacklistedPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT,
productName,
crossRepositoryLabelViolationStrategy,
- buildFilesByPriority);
+ buildFilesByPriority,
+ actionOnIOExceptionReadingBuildFile);
}
@VisibleForTesting
@@ -239,7 +246,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
customDirtinessCheckers,
productName,
BazelSkyframeExecutorConstants.CROSS_REPOSITORY_LABEL_VIOLATION_STRATEGY,
- BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
+ BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY,
+ BazelSkyframeExecutorConstants.ACTION_ON_IO_EXCEPTION_READING_BUILD_FILE);
}
@VisibleForTesting
@@ -256,7 +264,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
Iterable<SkyValueDirtinessChecker> customDirtinessCheckers,
String productName,
CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy,
- ImmutableList<BuildFileName> buildFilesByPriority) {
+ ImmutableList<BuildFileName> buildFilesByPriority,
+ ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile) {
return create(
pkgFactory,
directories,
@@ -271,7 +280,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
/*blacklistedPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT,
productName,
crossRepositoryLabelViolationStrategy,
- buildFilesByPriority);
+ buildFilesByPriority,
+ actionOnIOExceptionReadingBuildFile);
}
@VisibleForTesting
@@ -298,7 +308,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor {
blacklistedPackagePrefixesFile,
productName,
BazelSkyframeExecutorConstants.CROSS_REPOSITORY_LABEL_VIOLATION_STRATEGY,
- BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
+ BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY,
+ BazelSkyframeExecutorConstants.ACTION_ON_IO_EXCEPTION_READING_BUILD_FILE);
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
index b6e91fec82..3617c13f13 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
@@ -56,6 +56,7 @@ public class SequencedSkyframeExecutorFactory implements SkyframeExecutorFactory
customDirtinessCheckers,
productName,
BazelSkyframeExecutorConstants.CROSS_REPOSITORY_LABEL_VIOLATION_STRATEGY,
- BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
+ BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY,
+ BazelSkyframeExecutorConstants.ACTION_ON_IO_EXCEPTION_READING_BUILD_FILE);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 77d8394679..69c4bbc0e5 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -108,6 +108,7 @@ import com.google.devtools.build.lib.profiler.AutoProfiler;
import com.google.devtools.build.lib.skyframe.AspectValue.AspectValueKey;
import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.FileDirtinessChecker;
import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction;
+import com.google.devtools.build.lib.skyframe.PackageFunction.ActionOnIOExceptionReadingBuildFile;
import com.google.devtools.build.lib.skyframe.PackageFunction.CacheEntryWithGlobDeps;
import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
import com.google.devtools.build.lib.skyframe.PackageLookupValue.BuildFileName;
@@ -284,6 +285,8 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
private final List<BuildFileName> buildFilesByPriority;
+ private final ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile;
+
private PerBuildSyscallCache perBuildSyscallCache;
private int lastConcurrencyLevel = -1;
@@ -303,7 +306,8 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
PathFragment blacklistedPackagePrefixesFile,
String productName,
CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy,
- List<BuildFileName> buildFilesByPriority) {
+ List<BuildFileName> buildFilesByPriority,
+ ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile) {
// Strictly speaking, these arguments are not required for initialization, but all current
// callsites have them at hand, so we might as well set them during construction.
this.evaluatorSupplier = evaluatorSupplier;
@@ -335,6 +339,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
this.productName = productName;
this.crossRepositoryLabelViolationStrategy = crossRepositoryLabelViolationStrategy;
this.buildFilesByPriority = buildFilesByPriority;
+ this.actionOnIOExceptionReadingBuildFile = actionOnIOExceptionReadingBuildFile;
this.removeActionsAfterEvaluation.set(false);
}
@@ -472,7 +477,8 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
astCache,
numPackagesLoaded,
null,
- packageProgress);
+ packageProgress,
+ actionOnIOExceptionReadingBuildFile);
}
protected SkyFunction newSkylarkImportLookupFunction(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
index 9d5a1b0634..00a4a1257b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
@@ -50,6 +50,7 @@ import com.google.devtools.build.lib.skyframe.FileSymlinkCycleUniquenessFunction
import com.google.devtools.build.lib.skyframe.FileSymlinkInfiniteExpansionUniquenessFunction;
import com.google.devtools.build.lib.skyframe.GlobFunction;
import com.google.devtools.build.lib.skyframe.PackageFunction;
+import com.google.devtools.build.lib.skyframe.PackageFunction.ActionOnIOExceptionReadingBuildFile;
import com.google.devtools.build.lib.skyframe.PackageFunction.CacheEntryWithGlobDeps;
import com.google.devtools.build.lib.skyframe.PackageLookupFunction;
import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
@@ -310,6 +311,7 @@ public abstract class AbstractPackageLoader implements PackageLoader {
protected abstract CrossRepositoryLabelViolationStrategy
getCrossRepositoryLabelViolationStrategy();
protected abstract ImmutableList<BuildFileName> getBuildFilesByPriority();
+ protected abstract ActionOnIOExceptionReadingBuildFile getActionOnIOExceptionReadingBuildFile();
protected abstract ImmutableMap<SkyFunctionName, SkyFunction> getExtraExtraSkyFunctions();
protected final ImmutableMap<SkyFunctionName, SkyFunction> makeFreshSkyFunctions() {
@@ -368,7 +370,9 @@ public abstract class AbstractPackageLoader implements PackageLoader {
packageFunctionCache,
astCache,
/*numPackagesLoaded=*/ new AtomicInteger(0),
- null))
+ /*skylarkImportLookupFunctionForInlining=*/ null,
+ /*packageProgress=*/ null,
+ getActionOnIOExceptionReadingBuildFile()))
.putAll(extraSkyFunctions)
.putAll(getExtraExtraSkyFunctions());
return builder.build();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoader.java b/src/main/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoader.java
index aa88fd59dc..7c388e5536 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoader.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoader.java
@@ -21,6 +21,7 @@ import com.google.devtools.build.lib.packages.RuleClassProvider;
import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants;
import com.google.devtools.build.lib.skyframe.LocalRepositoryLookupFunction;
+import com.google.devtools.build.lib.skyframe.PackageFunction.ActionOnIOExceptionReadingBuildFile;
import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
import com.google.devtools.build.lib.skyframe.PackageLookupValue.BuildFileName;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
@@ -86,6 +87,11 @@ public class BazelPackageLoader extends AbstractPackageLoader {
}
@Override
+ protected ActionOnIOExceptionReadingBuildFile getActionOnIOExceptionReadingBuildFile() {
+ return BazelSkyframeExecutorConstants.ACTION_ON_IO_EXCEPTION_READING_BUILD_FILE;
+ }
+
+ @Override
protected ImmutableMap<SkyFunctionName, SkyFunction> getExtraExtraSkyFunctions() {
return ImmutableMap.<SkyFunctionName, SkyFunction>of(
SkyFunctions.LOCAL_REPOSITORY_LOOKUP, new LocalRepositoryLookupFunction());
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
index da738d6220..f9ff08e22d 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
@@ -26,6 +26,7 @@ import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.pkgcache.PackageCacheOptions;
import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
@@ -50,6 +51,7 @@ import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import com.google.devtools.common.options.Options;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -662,6 +664,23 @@ public class PackageFunctionTest extends BuildViewTestCase {
}
}
+ @Test
+ public void testPackageLoadingErrorOnIOExceptionReadingBuildFile() throws Exception {
+ Path fooBuildFilePath = scratch.file("foo/BUILD");
+ IOException exn = new IOException("nope");
+ fs.throwExceptionOnGetInputStream(fooBuildFilePath, exn);
+
+ SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
+ EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
+ getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
+ assertThat(result.hasError()).isTrue();
+ ErrorInfo errorInfo = result.getError(skyKey);
+ String errorMessage = errorInfo.getException().getMessage();
+ assertThat(errorMessage).contains("nope");
+ assertThat(errorInfo.getException()).isInstanceOf(NoSuchPackageException.class);
+ assertThat(errorInfo.getException()).hasCauseThat().isSameAs(exn);
+ }
+
private static class CustomInMemoryFs extends InMemoryFileSystem {
private abstract static class FileStatusOrException {
abstract FileStatus get() throws IOException;
@@ -696,8 +715,9 @@ public class PackageFunctionTest extends BuildViewTestCase {
}
}
- private Map<Path, FileStatusOrException> stubbedStats = Maps.newHashMap();
- private Set<Path> makeUnreadableAfterReaddir = Sets.newHashSet();
+ private final Map<Path, FileStatusOrException> stubbedStats = Maps.newHashMap();
+ private final Set<Path> makeUnreadableAfterReaddir = Sets.newHashSet();
+ private final Map<Path, IOException> pathsToErrorOnGetInputStream = Maps.newHashMap();
public CustomInMemoryFs(ManualClock manualClock) {
super(manualClock);
@@ -731,5 +751,18 @@ public class PackageFunctionTest extends BuildViewTestCase {
}
return result;
}
+
+ public void throwExceptionOnGetInputStream(Path path, IOException exn) {
+ pathsToErrorOnGetInputStream.put(path, exn);
+ }
+
+ @Override
+ protected InputStream getInputStream(Path path) throws IOException {
+ IOException exnToThrow = pathsToErrorOnGetInputStream.get(path);
+ if (exnToThrow != null) {
+ throw exnToThrow;
+ }
+ return super.getInputStream(path);
+ }
}
}