GeneratedPathConflictException(TraversalRequest traversal) { super( String.format( "Generated directory %s conflicts with package under the same path. Additional info: %s", traversal.path.getRelativePath().getPathString(), traversal.errorInfo != null ? traversal.errorInfo : traversal.toString())); }
/** * Checks whether the {@code traversal}'s path refers to a package directory. * * @return the result of the lookup; it contains potentially new {@link TraversalRequest} and * {@link FileInfo} so the caller should use these instead of the old ones (this happens when * a package is found, but under a different root than expected) */ private static PkgLookupResult checkIfPackage( Environment env, TraversalRequest traversal, FileInfo rootInfo) throws MissingDepException { Preconditions.checkArgument( rootInfo.type.exists() && !rootInfo.type.isFile(), "{%s} {%s}", traversal, rootInfo); PackageLookupValue pkgLookup = (PackageLookupValue) getDependentSkyValue(env, PackageLookupValue.key(traversal.path.getRelativePath())); if (pkgLookup.packageExists()) { if (traversal.isGenerated) { // The traversal's root was a generated directory, but its root-relative path conflicts with // an existing package. return PkgLookupResult.conflict(traversal, rootInfo); } else { // The traversal's root was a source directory and it defines a package. Path pkgRoot = pkgLookup.getRoot(); if (!pkgRoot.equals(traversal.path.getRoot())) { // However the root of this package is different from what we expected. stat() the real // BUILD file of that package. traversal = traversal.forChangedRootPath(pkgRoot); rootInfo = lookUpFileInfo(env, traversal); Verify.verify(rootInfo.type.exists(), "{%s} {%s}", traversal, rootInfo); } return PkgLookupResult.pkg(traversal, rootInfo); } } else { // The traversal's root was a directory (source or generated one), no package exists under the // same root-relative path. return PkgLookupResult.directory(traversal, rootInfo); } }
/** * List the directory and create {@code SkyKey}s to request contents of its children recursively. * * <p>The returned keys are of type {@link SkyFunctions#RECURSIVE_FILESYSTEM_TRAVERSAL}. */ private static Collection<SkyKey> createRecursiveTraversalKeys( Environment env, TraversalRequest traversal) throws MissingDepException { // Use the traversal's path, even if it's a symlink. The contents of the directory, as listed // in the result, must be relative to it. DirectoryListingValue dirListing = (DirectoryListingValue) getDependentSkyValue(env, DirectoryListingValue.key(traversal.path)); List<SkyKey> result = new ArrayList<>(); for (Dirent dirent : dirListing.getDirents()) { RootedPath childPath = RootedPath.toRootedPath( traversal.path.getRoot(), traversal.path.getRelativePath().getRelative(dirent.getName())); TraversalRequest childTraversal = traversal.forChildEntry(childPath); result.add(RecursiveFilesystemTraversalValue.key(childTraversal)); } return result; }
@Override public SkyValue compute(SkyKey skyKey, Environment env) throws RecursiveFilesystemTraversalFunctionException { TraversalRequest traversal = (TraversalRequest) skyKey.argument(); try { // Stat the traversal root. FileInfo rootInfo = lookUpFileInfo(env, traversal); if (!rootInfo.type.exists()) { // May be a dangling symlink or a non-existent file. Handle gracefully. if (rootInfo.type.isSymlink()) { return resultForDanglingSymlink(traversal.path, rootInfo); } else { return RecursiveFilesystemTraversalValue.EMPTY; } } if (rootInfo.type.isFile()) { if (traversal.pattern == null || traversal .pattern .matcher(rootInfo.realPath.getRelativePath().getPathString()) .matches()) { // The root is a file or a symlink to one. return resultForFileRoot(traversal.path, rootInfo); } else { return RecursiveFilesystemTraversalValue.EMPTY; } } // Otherwise the root is a directory or a symlink to one. PkgLookupResult pkgLookupResult = checkIfPackage(env, traversal, rootInfo); traversal = pkgLookupResult.traversal; if (pkgLookupResult.isConflicting()) { // The traversal was requested for an output directory whose root-relative path conflicts // with a source package. We can't handle that, bail out. throw new RecursiveFilesystemTraversalFunctionException( new GeneratedPathConflictException(traversal)); } else if (pkgLookupResult.isPackage() && !traversal.skipTestingForSubpackage) { // The traversal was requested for a directory that defines a package. String msg = traversal.errorInfo + " crosses package boundary into package rooted at " + traversal.path.getRelativePath().getPathString(); switch (traversal.crossPkgBoundaries) { case CROSS: // We are free to traverse the subpackage but we need to display a warning. env.getListener().handle(new Event(EventKind.WARNING, null, msg)); break; case DONT_CROSS: // We cannot traverse the subpackage and should skip it silently. Return empty results. return RecursiveFilesystemTraversalValue.EMPTY; case REPORT_ERROR: // We cannot traverse the subpackage and should complain loudly (display an error). throw new RecursiveFilesystemTraversalFunctionException( new CannotCrossPackageBoundaryException(msg)); default: throw new IllegalStateException(traversal.toString()); } } // We are free to traverse this directory. Collection<SkyKey> dependentKeys = createRecursiveTraversalKeys(env, traversal); return resultForDirectory(traversal, rootInfo, traverseChildren(env, dependentKeys)); } catch (MissingDepException e) { return null; } }