aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
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 /src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
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
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java74
1 files changed, 62 insertions, 12 deletions
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());
}