Skip to content

Commit 1e66ccd

Browse files
haxorzlberki
authored andcommitted
RELNOTES: Symlink dirents of directories containing a file named "DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN" will *not* be traversed for transitive target patterns. The motivation here is to allow directories that intentionally contain wonky symlinks (e.g. foo/bar -> foo) to opt out of being consumed by Blaze. For example, given
<workspace>/foo bar bad -> . DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN the 'bad' symlink will *not* be traversed by the pattern '//foo/...'. -- MOS_MIGRATED_REVID=107738930
1 parent f686677 commit 1e66ccd

3 files changed

Lines changed: 36 additions & 4 deletions

File tree

site/docs/bazel-user-manual.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ <h3 id='target-patterns'>Specifying targets to build</h3>
396396
//foo/...:all Matches all rules in all packages beneath directory 'foo'.
397397
//foo/... (ditto)
398398

399+
By default, directory symlinks are followed when performing this recursive traversal. But we
400+
understand that your workspace may intentionally contain directories with weird symlink structures
401+
that you don't want consumed. As such, if a directory has a file named
402+
'DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN' then symlinks
403+
in that directory won't be followed when evaluating recursive target patterns.
404+
399405
Working-directory relative forms: (assume cwd = 'workspace/foo')
400406

401407
Target patterns which do not begin with '//' are taken relative to

src/main/java/com/google/devtools/build/lib/runtime/commands/target-syntax.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ Specifying all rules recursively beneath a package:
2525
//foo/...:all Matches all rules in all packages beneath directory 'foo'.
2626
//foo/... (ditto)
2727

28+
By default, directory symlinks are followed when performing this recursive
29+
traversal. But we understand that your workspace may intentionally contain
30+
directories with weird symlink structures that you don't want consumed. As
31+
such, if a directory has a file named
32+
'DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN'
33+
then symlinks in that directory won't be followed when evaluating recursive
34+
target patterns.
35+
2836
Working-directory relative forms: (assume cwd = 'workspace/foo')
2937

3038
Target patterns which do not begin with '//' are taken relative to

src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
*/
4949
abstract class RecursiveDirectoryTraversalFunction
5050
<TVisitor extends RecursiveDirectoryTraversalFunction.Visitor, TReturn> {
51+
private static final String SENTINEL_FILE_NAME_FOR_NOT_TRAVERSING_SYMLINKS =
52+
"DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN";
5153

5254
/**
5355
* Returned from {@link #visitDirectory} if its {@code recursivePkgKey} is a symlink or not a
@@ -232,16 +234,18 @@ TReturn visitDirectory(RecursivePkgKey recursivePkgKey, Environment env) {
232234
}
233235

234236
List<SkyKey> childDeps = Lists.newArrayList();
237+
boolean followSymlinks = shouldFollowSymlinksWhenTraversing(dirListingValue.getDirents());
235238
for (Dirent dirent : dirListingValue.getDirents()) {
236-
if (dirent.getType() != Type.DIRECTORY && dirent.getType() != Type.SYMLINK) {
239+
Type type = dirent.getType();
240+
if (type != Type.DIRECTORY
241+
&& (type != Type.SYMLINK || (type == Type.SYMLINK && !followSymlinks))) {
237242
// Non-directories can never host packages. Symlinks to non-directories are weeded out at
238243
// the next level of recursion when we check if its FileValue is a directory. This is slower
239244
// if there are a lot of symlinks in the tree, but faster if there are only a few, which is
240245
// the case most of the time.
241246
//
242-
// We are not afraid of weird symlink structure here: cyclical ones are diagnosed by
243-
// FileValue and ones that give rise to infinite directory trees work just like they do with
244-
// globbing: they work until a certain level of nesting, after which they fail.
247+
// We are not afraid of weird symlink structure here: both cyclical ones and ones that give
248+
// rise to infinite directory trees are diagnosed by FileValue.
245249
continue;
246250
}
247251
String basename = dirent.getName();
@@ -282,6 +286,20 @@ TReturn visitDirectory(RecursivePkgKey recursivePkgKey, Environment env) {
282286
return aggregateWithSubdirectorySkyValues(visitor, subdirectorySkyValues);
283287
}
284288

289+
private static boolean shouldFollowSymlinksWhenTraversing(Dirents dirents) {
290+
for (Dirent dirent : dirents) {
291+
// This is a specical sentinel file whose existence tells Blaze not to follow symlinks when
292+
// recursively traversing through this directory.
293+
//
294+
// This admittedly ugly feature is used to support workspaces with directories with weird
295+
// symlink structures that aren't intended to be consumed by Blaze.
296+
if (dirent.getName().equals(SENTINEL_FILE_NAME_FOR_NOT_TRAVERSING_SYMLINKS)) {
297+
return false;
298+
}
299+
}
300+
return true;
301+
}
302+
285303
// Ignore all errors in traversal and return an empty value.
286304
private TReturn reportErrorAndReturn(String errorPrefix, Exception e,
287305
PathFragment rootRelativePath, EventHandler handler) {

0 commit comments

Comments
 (0)