diff options
6 files changed, 52 insertions, 13 deletions
diff --git a/site/docs/bazel-user-manual.html b/site/docs/bazel-user-manual.html index 7c2320bf40..e712d562df 100644 --- a/site/docs/bazel-user-manual.html +++ b/site/docs/bazel-user-manual.html @@ -396,9 +396,11 @@ Specifying all rules recursively beneath a package: //foo/...:all Matches all rules in all packages beneath directory 'foo'. //foo/... (ditto) - By default, directory symlinks are followed when performing this recursive traversal. But we - understand that your workspace may intentionally contain directories with weird symlink structures - that you don't want consumed. As such, if a directory has a file named + By default, directory symlinks are followed when performing this recursive traversal, except + those that point to under the output base (for example, the convenience symlinks that are created + in the root directory of the workspace) But we understand that your workspace may intentionally + contain directories with unusual symlink structures that you don't want consumed. As such, if a + directory has a file named 'DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN' then symlinks in that directory won't be followed when evaluating recursive target patterns. diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/target-syntax.txt b/src/main/java/com/google/devtools/build/lib/runtime/commands/target-syntax.txt index 3eec42e21b..df0089bf8b 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/commands/target-syntax.txt +++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/target-syntax.txt @@ -25,10 +25,11 @@ Specifying all rules recursively beneath a package: //foo/...:all Matches all rules in all packages beneath directory 'foo'. //foo/... (ditto) - By default, directory symlinks are followed when performing this recursive - traversal. But we understand that your workspace may intentionally contain - directories with weird symlink structures that you don't want consumed. As - such, if a directory has a file named + By default, directory symlinks are followed when performing this recursive traversal, except + those that point to under the output base (for example, the convenience symlinks that are created + in the root directory of the workspace) But we understand that your workspace may intentionally + contain directories with weird symlink structures that you don't want consumed. As such, if a + directory has a file named 'DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN' then symlinks in that directory won't be followed when evaluating recursive target patterns. diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfTargetsUnderDirectoryFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfTargetsUnderDirectoryFunction.java index e7d487fb4f..e1f3105280 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfTargetsUnderDirectoryFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfTargetsUnderDirectoryFunction.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName; import com.google.devtools.build.lib.cmdline.ResolvedTargets; import com.google.devtools.build.lib.packages.NoSuchPackageException; @@ -48,6 +49,11 @@ import javax.annotation.Nullable; * subdirectories. */ public class PrepareDepsOfTargetsUnderDirectoryFunction implements SkyFunction { + private final BlazeDirectories directories; + + public PrepareDepsOfTargetsUnderDirectoryFunction(BlazeDirectories directories) { + this.directories = directories; + } @Override public SkyValue compute(SkyKey skyKey, Environment env) { @@ -58,13 +64,14 @@ public class PrepareDepsOfTargetsUnderDirectoryFunction implements SkyFunction { return new MyTraversalFunction(filteringPolicy).visitDirectory(recursivePkgKey, env); } - private static class MyTraversalFunction + private class MyTraversalFunction extends RecursiveDirectoryTraversalFunction<MyVisitor, PrepareDepsOfTargetsUnderDirectoryValue> { private final FilteringPolicy filteringPolicy; private MyTraversalFunction(FilteringPolicy filteringPolicy) { + super(directories); this.filteringPolicy = filteringPolicy; } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java index 5c4a4349dd..203e54a7f4 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java @@ -16,8 +16,8 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName; import com.google.devtools.build.lib.events.Event; @@ -37,6 +37,7 @@ import com.google.devtools.build.skyframe.SkyValue; import com.google.devtools.build.skyframe.ValueOrException4; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -51,6 +52,12 @@ abstract class RecursiveDirectoryTraversalFunction private static final String SENTINEL_FILE_NAME_FOR_NOT_TRAVERSING_SYMLINKS = "DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN"; + private final BlazeDirectories directories; + + protected RecursiveDirectoryTraversalFunction(BlazeDirectories directories) { + this.directories = directories; + } + /** * Returned from {@link #visitDirectory} if its {@code recursivePkgKey} is a symlink or not a * directory, or if a dependency value lookup returns an error. @@ -144,6 +151,18 @@ abstract class RecursiveDirectoryTraversalFunction PackageIdentifier packageId = PackageIdentifier.create( recursivePkgKey.getRepository(), rootRelativePath); + + if (packageId.getRepository().isDefault() + && fileValue.isSymlink() + && fileValue.getUnresolvedLinkTarget().startsWith(directories.getOutputBase().asFragment())) { + // Symlinks back to the output base are not traversed so that we avoid convenience symlinks. + // Note that it's not enough to just check for the convenience symlinks themselves, because + // if the value of --symlink_prefix changes, the old symlinks are left in place. This + // algorithm also covers more creative use cases where people create convenience symlinks + // somewhere in the directory tree manually. + return getEmptyReturn(); + } + SkyKey pkgLookupKey = PackageLookupValue.key(packageId); SkyKey dirListingKey = DirectoryListingValue.key(rootedPath); Map<SkyKey, @@ -233,8 +252,8 @@ abstract class RecursiveDirectoryTraversalFunction throw new IllegalStateException(e); } - List<SkyKey> childDeps = Lists.newArrayList(); boolean followSymlinks = shouldFollowSymlinksWhenTraversing(dirListingValue.getDirents()); + List<SkyKey> childDeps = new ArrayList<>(); for (Dirent dirent : dirListingValue.getDirents()) { Type type = dirent.getType(); if (type != Type.DIRECTORY diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java index b42d9b45c8..dbbbe8cd6d 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; @@ -38,15 +39,24 @@ import javax.annotation.Nullable; * "foo/subpkg". */ public class RecursivePkgFunction implements SkyFunction { + private final BlazeDirectories directories; + + public RecursivePkgFunction(BlazeDirectories directories) { + this.directories = directories; + } @Override public SkyValue compute(SkyKey skyKey, Environment env) { return new MyTraversalFunction().visitDirectory((RecursivePkgKey) skyKey.argument(), env); } - private static class MyTraversalFunction + private class MyTraversalFunction extends RecursiveDirectoryTraversalFunction<MyVisitor, RecursivePkgValue> { + private MyTraversalFunction() { + super(directories); + } + @Override protected RecursivePkgValue getEmptyReturn() { return RecursivePkgValue.EMPTY; 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 f3e5d16c76..9a316f4aa1 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 @@ -344,12 +344,12 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory { map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERNS, new PrepareDepsOfPatternsFunction()); map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERN, new PrepareDepsOfPatternFunction(pkgLocator)); map.put(SkyFunctions.PREPARE_DEPS_OF_TARGETS_UNDER_DIRECTORY, - new PrepareDepsOfTargetsUnderDirectoryFunction()); + new PrepareDepsOfTargetsUnderDirectoryFunction(directories)); map.put(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES, new BlacklistedPackagePrefixesFunction()); map.put(SkyFunctions.TESTS_IN_SUITE, new TestsInSuiteFunction()); map.put(SkyFunctions.TEST_SUITE_EXPANSION, new TestSuiteExpansionFunction()); map.put(SkyFunctions.TARGET_PATTERN_PHASE, new TargetPatternPhaseFunction()); - map.put(SkyFunctions.RECURSIVE_PKG, new RecursivePkgFunction()); + map.put(SkyFunctions.RECURSIVE_PKG, new RecursivePkgFunction(directories)); map.put( SkyFunctions.PACKAGE, newPackageFunction( |