diff options
author | 2016-03-28 19:11:39 +0000 | |
---|---|---|
committer | 2016-03-29 10:52:31 +0000 | |
commit | 54e24df757464ba7c4d6d579d2251e26eb7d34c4 (patch) | |
tree | 244676972b0ad2b09837e8086e15a5404c721f7f /src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java | |
parent | 6b3294b5594c610fc463b8eadef570c96b8a1eb0 (diff) |
Provide descriptive error messages on external mutable source files encountered during a build
Currently when evaluating a file or symlink leading to an external mutable object, Blaze throws an exception with unclear messages. The message does not contain the actual path but rather [/]/[] instead. This change updates FileFunction to allow bubbling up the error with the accurate path.
--
MOS_MIGRATED_REVID=118381323
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java | 69 |
1 files changed, 59 insertions, 10 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java index da6b9d989a..6eb962114c 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java @@ -29,6 +29,7 @@ import com.google.devtools.build.skyframe.SkyFunctionException.Transience; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; +import java.io.IOException; import java.util.ArrayList; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicReference; @@ -62,8 +63,19 @@ public class FileFunction implements SkyFunction { // symlink cycle, we want to detect that quickly as it gives a more informative error message // than we'd get doing bogus filesystem operations. if (!relativePath.equals(PathFragment.EMPTY_FRAGMENT)) { - Pair<RootedPath, FileStateValue> resolvedState = - resolveFromAncestors(rootedPath, env); + Pair<RootedPath, FileStateValue> resolvedState = null; + + try { + resolvedState = resolveFromAncestors(rootedPath, env); + } catch (FileOutsidePackageRootsException e) { + // When getting a FileOutsidePackageRootsException caused by an external file symlink + // somewhere in this file's path, rethrow an exception with this file's path, so the error + // message mentions this file instead of the first ancestor path where the external file + // error is observed + throw new FileFunctionException( + new FileOutsidePackageRootsException(rootedPath), Transience.PERSISTENT); + } + if (resolvedState == null) { return null; } @@ -71,7 +83,18 @@ public class FileFunction implements SkyFunction { realFileStateValue = resolvedState.getSecond(); } - FileStateValue fileStateValue = (FileStateValue) env.getValue(FileStateValue.key(rootedPath)); + FileStateValue fileStateValue = null; + + try { + fileStateValue = + (FileStateValue) + env.getValueOrThrow( + FileStateValue.key(rootedPath), FileOutsidePackageRootsException.class); + } catch (FileOutsidePackageRootsException e) { + throw new FileFunctionException( + new FileOutsidePackageRootsException(rootedPath), Transience.PERSISTENT); + } + if (fileStateValue == null) { return null; } @@ -109,15 +132,21 @@ public class FileFunction implements SkyFunction { * {@code null} if there was a missing dep. */ @Nullable - private Pair<RootedPath, FileStateValue> resolveFromAncestors(RootedPath rootedPath, - Environment env) throws FileFunctionException { + private Pair<RootedPath, FileStateValue> resolveFromAncestors( + RootedPath rootedPath, Environment env) + throws FileFunctionException, FileOutsidePackageRootsException { PathFragment relativePath = rootedPath.getRelativePath(); RootedPath realRootedPath = rootedPath; FileValue parentFileValue = null; if (!relativePath.equals(PathFragment.EMPTY_FRAGMENT)) { RootedPath parentRootedPath = RootedPath.toRootedPath(rootedPath.getRoot(), relativePath.getParentDirectory()); - parentFileValue = (FileValue) env.getValue(FileValue.key(parentRootedPath)); + + parentFileValue = + (FileValue) + env.getValueOrThrow( + FileValue.key(parentRootedPath), FileOutsidePackageRootsException.class); + if (parentFileValue == null) { return null; } @@ -125,13 +154,17 @@ public class FileFunction implements SkyFunction { RootedPath parentRealRootedPath = parentFileValue.realRootedPath(); realRootedPath = RootedPath.toRootedPath(parentRealRootedPath.getRoot(), parentRealRootedPath.getRelativePath().getRelative(baseName)); + if (!parentFileValue.exists()) { return Pair.<RootedPath, FileStateValue>of( realRootedPath, FileStateValue.NONEXISTENT_FILE_STATE_NODE); } } FileStateValue realFileStateValue = - (FileStateValue) env.getValue(FileStateValue.key(realRootedPath)); + (FileStateValue) + env.getValueOrThrow( + FileStateValue.key(realRootedPath), FileOutsidePackageRootsException.class); + if (realFileStateValue == null) { return null; } @@ -230,8 +263,9 @@ public class FileFunction implements SkyFunction { ImmutableList.copyOf( Iterables.concat(symlinkChain, ImmutableList.of(symlinkTargetRootedPath)))); uniquenessKey = FileSymlinkInfiniteExpansionUniquenessFunction.key(pathAndChain.getSecond()); - fse = new FileSymlinkInfiniteExpansionException( - pathAndChain.getFirst(), pathAndChain.getSecond()); + fse = + new FileSymlinkInfiniteExpansionException( + pathAndChain.getFirst(), pathAndChain.getSecond()); } if (uniquenessKey != null) { if (env.getValue(uniquenessKey) == null) { @@ -241,7 +275,18 @@ public class FileFunction implements SkyFunction { } throw new FileFunctionException(Preconditions.checkNotNull(fse, rootedPath)); } - return resolveFromAncestors(symlinkTargetRootedPath, env); + + try { + return resolveFromAncestors(symlinkTargetRootedPath, env); + } catch (FileOutsidePackageRootsException e) { + // At this point we know this file node is a symlink leading to an external file. Mark the + // exception to be a specific SymlinkOutsidePackageRootsException. The error will be bubbled + // up further but no path information will be updated again. This allows preserving the + // information about the symlink crossing the internal/external boundary. + throw new FileFunctionException( + new SymlinkOutsidePackageRootsException(rootedPath, symlinkTargetRootedPath), + Transience.PERSISTENT); + } } private static final Predicate<RootedPath> isPathPredicate(final Path path) { @@ -272,5 +317,9 @@ public class FileFunction implements SkyFunction { public FileFunctionException(FileSymlinkException e) { super(e, Transience.PERSISTENT); } + + public FileFunctionException(IOException e, Transience transience) { + super(e, transience); + } } } |